|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Common;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess
{
internal class ErrorList_InProc : InProcComponent
{
public static ErrorList_InProc Create()
=> new ErrorList_InProc();
public void WaitForNoErrorsInErrorList(TimeSpan timeout)
{
var stopwatch = Stopwatch.StartNew();
while (GetErrorCount() != 0)
{
if (stopwatch.Elapsed >= timeout)
{
var message = new StringBuilder();
message.AppendLine("Unexpected errors in error list:");
foreach (var error in GetErrorListContents())
{
message.Append(" ").AppendLine(error.ToString());
}
throw new TimeoutException(message.ToString());
}
Thread.Yield();
}
}
public int GetErrorCount(__VSERRORCATEGORY minimumSeverity = __VSERRORCATEGORY.EC_WARNING)
{
var errorItems = GetErrorItems();
try
{
return errorItems
.AsEnumerable()
.Where(e => ((IVsErrorItem)e).GetCategory() <= minimumSeverity)
.Count();
}
catch (IndexOutOfRangeException)
{
// It is entirely possible that the items in the error list are modified
// after we start iterating, in which case we want to try again.
return GetErrorCount(minimumSeverity);
}
}
public ErrorListItem[] GetErrorListContents(__VSERRORCATEGORY minimumSeverity = __VSERRORCATEGORY.EC_WARNING)
{
var errorItems = GetErrorItems();
try
{
return errorItems
.AsEnumerable()
.Where(e => ((IVsErrorItem)e).GetCategory() <= minimumSeverity)
.Select(e => new ErrorListItem(e.GetSeverity(), e.GetDescription(), e.GetProject(), e.GetFileName(), e.GetLine(), e.GetColumn()))
.ToArray();
}
catch (IndexOutOfRangeException)
{
// It is entirely possible that the items in the error list are modified
// after we start iterating, in which case we want to try again.
return GetErrorListContents(minimumSeverity);
}
}
private static IVsEnumTaskItems GetErrorItems()
{
return InvokeOnUIThread(cancellationToken =>
{
var errorList = GetGlobalService<SVsErrorList, IVsTaskList>();
ErrorHandler.ThrowOnFailure(errorList.EnumTaskItems(out var items));
return items;
});
}
}
public static class ErrorListExtensions
{
public static IEnumerable<IVsTaskItem> AsEnumerable(this IVsEnumTaskItems items)
{
var item = new IVsTaskItem[1];
while (true)
{
var hr = items.Next(1, item, null);
ErrorHandler.ThrowOnFailure(hr);
if (hr == VSConstants.S_FALSE)
{
break;
}
yield return item[0];
}
}
public static __VSERRORCATEGORY GetCategory(this IVsErrorItem errorItem)
{
ErrorHandler.ThrowOnFailure(errorItem.GetCategory(out var category));
return (__VSERRORCATEGORY)category;
}
public static string GetSeverity(this IVsTaskItem item)
{
return ((IVsErrorItem)item).GetCategory().AsString();
}
public static string GetDescription(this IVsTaskItem item)
{
ErrorHandler.ThrowOnFailure(item.get_Text(out var description));
return description;
}
public static string GetProject(this IVsTaskItem item)
{
var errorItem = (IVsErrorItem)item;
ErrorHandler.ThrowOnFailure(errorItem.GetHierarchy(out var hierarchy));
ErrorHandler.ThrowOnFailure(hierarchy.GetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Name, out var name));
return (string)name;
}
public static string GetFileName(this IVsTaskItem item)
{
ErrorHandler.ThrowOnFailure(item.Document(out var fileName));
return Path.GetFileName(fileName);
}
public static int GetLine(this IVsTaskItem item)
{
ErrorHandler.ThrowOnFailure(item.Line(out var line));
return line + 1;
}
public static int GetColumn(this IVsTaskItem item)
{
ErrorHandler.ThrowOnFailure(item.Column(out var column));
return column + 1;
}
public static string AsString(this __VSERRORCATEGORY errorCategory)
{
switch (errorCategory)
{
case __VSERRORCATEGORY.EC_MESSAGE:
return "Message";
case __VSERRORCATEGORY.EC_WARNING:
return "Warning";
case __VSERRORCATEGORY.EC_ERROR:
return "Error";
default:
return "Unknown";
}
}
}
}
|