提交 a2f2e628 编写于 作者: P Paul Vick

Merge remote-tracking branch 'upstream/master' into merge-master-into-future20160518-150017

......@@ -3634,6 +3634,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Cannot update &apos;{0}&apos;; attribute &apos;{1}&apos; is missing..
/// </summary>
internal static string ERR_EncUpdateFailedMissingAttribute {
get {
return ResourceManager.GetString("ERR_EncUpdateFailedMissingAttribute", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to #endif directive expected.
/// </summary>
......
......@@ -3839,6 +3839,9 @@ You should consider suppressing the warning only if you're sure that you don't w
<data name="ERR_FixedLocalInLambda" xml:space="preserve">
<value>Cannot use fixed local '{0}' inside an anonymous method, lambda expression, or query expression</value>
</data>
<data name="ERR_EncUpdateFailedMissingAttribute" xml:space="preserve">
<value>Cannot update '{0}'; attribute '{1}' is missing.</value>
</data>
<data name="ERR_ExpressionTreeContainsNamedArgument" xml:space="preserve">
<value>An expression tree may not contain a named argument specification</value>
</data>
......
......@@ -1174,6 +1174,7 @@ internal enum ErrorCode
// ERR_NameIllegallyOverrides3 = 7040, // Not used anymore due to 'Single Meaning' relaxation changes
ERR_ResourceFileNameNotUnique = 7041,
ERR_DllImportOnGenericMethod = 7042,
ERR_EncUpdateFailedMissingAttribute = 7043,
ERR_ParameterNotValidForType = 7045,
ERR_AttributeParameterRequired1 = 7046,
......
......@@ -95,7 +95,7 @@ public override Diagnostic CreateDiagnostic(int code, Location location, params
return new CSDiagnostic(info, location);
}
public override string ConvertSymbolToString(int errorCode, ISymbol symbol)
public override string GetErrorDisplayString(ISymbol symbol)
{
// show extra info for assembly if possible such as version, public key token etc.
if (symbol.Kind == SymbolKind.Assembly || symbol.Kind == SymbolKind.Namespace)
......@@ -205,6 +205,7 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost
public override int ERR_TooManyUserStrings { get { return (int)ErrorCode.ERR_TooManyUserStrings; } }
public override int ERR_PeWritingFailure { get { return (int)ErrorCode.ERR_PeWritingFailure; } }
public override int ERR_ModuleEmitFailure { get { return (int)ErrorCode.ERR_ModuleEmitFailure; } }
public override int ERR_EncUpdateFailedMissingAttribute { get { return (int)ErrorCode.ERR_EncUpdateFailedMissingAttribute; } }
public override void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute)
{
......
......@@ -4756,8 +4756,8 @@ public IEnumerable<int> F()
new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true)));
diff1.EmitResult.Diagnostics.Verify(
// error CS7038: Failed to emit module '{0}'.
Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name));
// error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing.
Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute).WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute"));
}
[Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")]
......@@ -4811,10 +4811,10 @@ public async Task<int> F()
new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true)));
diff1.EmitResult.Diagnostics.Verify(
// error CS7038: Failed to emit module '{0}'.
Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name),
// error CS7038: Failed to emit module '{0}'.
Diagnostic(ErrorCode.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name));
// error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing.
Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute).WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute"),
// error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing.
Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute).WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute"));
}
}
}
......@@ -2226,9 +2226,9 @@ public override int GetWarningLevel(int code)
}
}
public override string ConvertSymbolToString(int errorCode, ISymbol symbol)
public override string GetErrorDisplayString(ISymbol symbol)
{
return MessageProvider.Instance.ConvertSymbolToString(errorCode, symbol);
return MessageProvider.Instance.GetErrorDisplayString(symbol);
}
}
......
......@@ -187,8 +187,10 @@ public void GetChunks_DestructingEnum()
}
}
[Fact]
public void ToArray()
public void ToArray1()
{
var builder = new BlobBuilder(16);
......@@ -226,6 +228,43 @@ public void ToArray()
AssertEx.Equal(new byte[] { 0xdd, 0xcc, 0xbb, 0xaa }, builder.ToArray(13, 4));
}
[Fact]
public void ToArray2()
{
var builder = new BlobBuilder(16);
AssertEx.Equal(new byte[] { }, builder.ToArray(0, 0));
for (int i = 0; i < 34; i++)
{
builder.WriteByte((byte)i);
}
AssertEx.Equal(new byte[]
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21
}, builder.ToArray());
AssertEx.Equal(new byte[]
{
0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21
}, builder.ToArray(0x0e, 20));
AssertEx.Equal(new byte[] { 0x0E }, builder.ToArray(0x0e, 1));
AssertEx.Equal(new byte[] { 0x0E, 0x0F }, builder.ToArray(0x0e, 2));
AssertEx.Equal(new byte[] { 0x0E, 0x0F, 0x10 }, builder.ToArray(0x0e, 3));
AssertEx.Equal(new byte[] { 0x0E, 0x0F, 0x10, 0x11 }, builder.ToArray(0x0e, 4));
AssertEx.Equal(new byte[] { 0x1E }, builder.ToArray(0x1e, 1));
AssertEx.Equal(new byte[] { 0x1E, 0x1F }, builder.ToArray(0x1e, 2));
AssertEx.Equal(new byte[] { 0x1E, 0x1F, 0x20 }, builder.ToArray(0x1e, 3));
AssertEx.Equal(new byte[] { 0x1E, 0x1F, 0x20, 0x21 }, builder.ToArray(0x1e, 4));
}
[Fact]
public void ToArray_Errors()
{
......
......@@ -314,6 +314,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to The compilation references multiple assemblies whose versions only differ in auto-generated build and/or revision numbers..
/// </summary>
internal static string CompilationReferencesAssembliesWithDifferentAutoGeneratedVersion {
get {
return ResourceManager.GetString("CompilationReferencesAssembliesWithDifferentAutoGeneratedVersion", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Analyzer Failure.
/// </summary>
......
......@@ -519,4 +519,7 @@
<data name="TuplesNeedAtLeastTwoElements" xml:space="preserve">
<value>Tuples must have at least two elements.</value>
</data>
<data name="CompilationReferencesAssembliesWithDifferentAutoGeneratedVersion" xml:space="preserve">
<value>The compilation references multiple assemblies whose versions only differ in auto-generated build and/or revision numbers.</value>
</data>
</root>
\ No newline at end of file
......@@ -86,9 +86,9 @@ public Diagnostic CreateDiagnostic(int code, Location location)
public abstract string GetMessagePrefix(string id, DiagnosticSeverity severity, bool isWarningAsError, CultureInfo culture);
/// <summary>
/// convert given symbol to string representation based on given error code
/// Convert given symbol to string representation.
/// </summary>
public abstract string ConvertSymbolToString(int errorCode, ISymbol symbol);
public abstract string GetErrorDisplayString(ISymbol symbol);
/// <summary>
/// Given an error code (like 1234) return the identifier (CS1234 or BC1234).
......@@ -206,6 +206,7 @@ public DiagnosticInfo FilterDiagnosticInfo(DiagnosticInfo diagnosticInfo, Compil
public abstract int ERR_TooManyUserStrings { get; }
public abstract int ERR_PeWritingFailure { get; }
public abstract int ERR_ModuleEmitFailure { get; }
public abstract int ERR_EncUpdateFailedMissingAttribute { get; }
public abstract void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute);
public abstract void ReportInvalidNamedArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex, ITypeSymbol attributeClass, string parameterName);
......
......@@ -356,7 +356,7 @@ protected object[] GetArgumentsToUse(IFormatProvider formatProvider)
if (symbol != null)
{
argumentsToUse = InitializeArgumentListIfNeeded(argumentsToUse);
argumentsToUse[i] = _messageProvider.ConvertSymbolToString(_errorCode, symbol);
argumentsToUse[i] = _messageProvider.GetErrorDisplayString(symbol);
}
}
......
......@@ -195,8 +195,7 @@ private bool TryGetPreviousLocalId(SyntaxNode currentDeclarator, LocalDebugId cu
// Should rarely happen since the IDE reports a rude edit if the attribute type doesn't exist.
if (_hoistedLocalSlotsOpt == null)
{
// TODO: better error message https://github.com/dotnet/roslyn/issues/9196
diagnostics.Add(_messageProvider.CreateDiagnostic(_messageProvider.ERR_ModuleEmitFailure, NoLocation.Singleton, _previousTopLevelMethod.ContainingModule.Name));
ReportMissingStateMachineAttribute(diagnostics);
slotIndex = -1;
return false;
}
......@@ -231,8 +230,7 @@ public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentTy
// Should rarely happen since the IDE reports a rude edit if the attribute type doesn't exist.
if (_awaiterMapOpt == null)
{
// TODO: better error message https://github.com/dotnet/roslyn/issues/9196
diagnostics.Add(_messageProvider.CreateDiagnostic(_messageProvider.ERR_ModuleEmitFailure, NoLocation.Singleton, _previousTopLevelMethod.ContainingModule.Name));
ReportMissingStateMachineAttribute(diagnostics);
slotIndex = -1;
return false;
}
......@@ -240,6 +238,16 @@ public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentTy
return _awaiterMapOpt.TryGetValue(_symbolMap.MapReference(currentType), out slotIndex);
}
private void ReportMissingStateMachineAttribute(DiagnosticBag diagnostics)
{
diagnostics.Add(_messageProvider.CreateDiagnostic(
_messageProvider.ERR_EncUpdateFailedMissingAttribute,
NoLocation.Singleton,
_messageProvider.GetErrorDisplayString(_previousTopLevelMethod),
(_previousTopLevelMethod.IsAsync ? AttributeDescription.AsyncStateMachineAttribute : AttributeDescription.IteratorStateMachineAttribute).FullName));
}
private bool TryGetPreviousSyntaxOffset(SyntaxNode currentSyntax, out int previousSyntaxOffset)
{
// no syntax map
......
......@@ -177,9 +177,7 @@ private static string ResolveRelativePath(PathKind kind, string path, string bas
return path;
default:
// EDMAURER this is not using ExceptionUtilities.UnexpectedValue() because this file
// is shared via linking with other code that doesn't have the ExceptionUtilities.
throw new InvalidOperationException(string.Format("Unexpected PathKind {0}.", kind));
throw ExceptionUtilities.UnexpectedValue(kind);
}
}
......
......@@ -162,6 +162,9 @@ internal Metadata GetMetadataNoCopy()
/// Returns a copy of the <see cref="Metadata"/> object this <see cref="PortableExecutableReference"/>
/// contains. This copy does not need to be <see cref="IDisposable.Dispose"/>d.
/// </summary>
/// <exception cref="BadImageFormatException">If the PE image format is invalid.</exception>
/// <exception cref="IOException">The metadata image content can't be read.</exception>
/// <exception cref="FileNotFoundException">The metadata image is stored in a file that can't be found.</exception>
public Metadata GetMetadata()
{
return GetMetadataNoCopy().Copy();
......
......@@ -514,8 +514,8 @@ internal bool IsBound
if (lazyBuilder.ContainsKey(sourceIdentity))
{
// TODO: localize message, report as diagnostic (https://github.com/dotnet/roslyn/issues/8910)
throw new NotSupportedException("The compilation references multiple assemblies whose versions only differ in auto-generated build and/or revision numbers.");
// The compilation references multiple assemblies whose versions only differ in auto-generated build and/or revision numbers.
throw new NotSupportedException(CodeAnalysisResources.CompilationReferencesAssembliesWithDifferentAutoGeneratedVersion);
}
lazyBuilder.Add(sourceIdentity, originalIdentity);
......
......@@ -289,29 +289,33 @@ public byte[] ToArray(int start, int byteCount)
var result = new byte[byteCount];
int chunkStartPosition = 0;
int resultOffset = 0;
int chunkStart = 0;
int bufferStart = start;
int bufferEnd = start + byteCount;
foreach (var chunk in GetChunks())
{
int chunkEndPosition = chunkStartPosition + chunk.Length;
int chunkEnd = chunkStart + chunk.Length;
Debug.Assert(bufferStart >= chunkStart);
if (chunkEndPosition > start)
if (chunkEnd > bufferStart)
{
int bytesToCopy = Math.Min(chunk.Length, result.Length - resultOffset);
if (bytesToCopy == 0)
int bytesToCopy = Math.Min(bufferEnd, chunkEnd) - bufferStart;
Debug.Assert(bytesToCopy >= 0);
Array.Copy(chunk._buffer, bufferStart - chunkStart, result, bufferStart - start, bytesToCopy);
bufferStart += bytesToCopy;
if (bufferStart == bufferEnd)
{
break;
}
Array.Copy(chunk._buffer, Math.Max(start - chunkStartPosition, 0), result, resultOffset, bytesToCopy);
resultOffset += bytesToCopy;
}
chunkStartPosition = chunkEndPosition;
chunkStart = chunkEnd;
}
Debug.Assert(resultOffset == result.Length);
Debug.Assert(bufferStart == bufferEnd);
return result;
}
......
......@@ -1605,6 +1605,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_PublicKeyContainerFailure = 36981
ERR_InvalidAssemblyCulture = 36982
ERR_EncUpdateFailedMissingAttribute = 36983
ERR_CantAwaitAsyncSub1 = 37001
ERR_ResumableLambdaInExpressionTree = 37050
......
......@@ -95,7 +95,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return New VBDiagnostic(ErrorFactory.ErrorInfo(CType(code, ERRID), args), location)
End Function
Public Overrides Function ConvertSymbolToString(errorCode As Integer, symbol As ISymbol) As String
Public Overrides Function GetErrorDisplayString(symbol As ISymbol) As String
' show extra info for assembly if possible such as version, public key token etc.
If symbol.Kind = SymbolKind.Assembly OrElse symbol.Kind = SymbolKind.Namespace Then
Return symbol.ToString()
......@@ -498,6 +498,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return ERRID.ERR_ModuleEmitFailure
End Get
End Property
Public Overrides ReadOnly Property ERR_EncUpdateFailedMissingAttribute As Integer
Get
Return ERRID.ERR_EncUpdateFailedMissingAttribute
End Get
End Property
End Class
End Namespace
......@@ -3296,6 +3296,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Cannot update &apos;{0}&apos;; attribute &apos;{1}&apos; is missing..
'''</summary>
Friend ReadOnly Property ERR_EncUpdateFailedMissingAttribute() As String
Get
Return ResourceManager.GetString("ERR_EncUpdateFailedMissingAttribute", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to &apos;End Class&apos; must be preceded by a matching &apos;Class&apos;..
'''</summary>
......
......@@ -818,6 +818,9 @@
<data name="ERR_ModuleEmitFailure" xml:space="preserve">
<value>Failed to emit module '{0}'.</value>
</data>
<data name="ERR_EncUpdateFailedMissingAttribute" xml:space="preserve">
<value>Cannot update '{0}'; attribute '{1}' is missing.</value>
</data>
<data name="ERR_OverrideNotNeeded3" xml:space="preserve">
<value>{0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class.</value>
</data>
......
......@@ -4447,7 +4447,7 @@ End Class
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True)))
diff1.EmitResult.Diagnostics.Verify(
Diagnostic(ERRID.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name))
Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute).WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute"))
End Sub
<Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")>
......@@ -4501,8 +4501,8 @@ End Class
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True)))
diff1.EmitResult.Diagnostics.Verify(
Diagnostic(ERRID.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name),
Diagnostic(ERRID.ERR_ModuleEmitFailure).WithArguments(compilation0.SourceModule.Name))
Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute).WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute"),
Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute).WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute"))
End Sub
End Class
End Namespace
......@@ -81,8 +81,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
Return String.Empty
End Function
Public Overrides Function ConvertSymbolToString(errorCode As Integer, symbol As ISymbol) As String
Return MessageProvider.Instance.ConvertSymbolToString(errorCode, symbol)
Public Overrides Function GetErrorDisplayString(symbol As ISymbol) As String
Return MessageProvider.Instance.GetErrorDisplayString(symbol)
End Function
End Class
......
......@@ -1030,8 +1030,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
Return 0
End Function
Public Overrides Function ConvertSymbolToString(errorCode As Integer, symbol As ISymbol) As String
Return MessageProvider.Instance.ConvertSymbolToString(errorCode, symbol)
Public Overrides Function GetErrorDisplayString(symbol As ISymbol) As String
Return MessageProvider.Instance.GetErrorDisplayString(symbol)
End Function
End Class
......
......@@ -99,7 +99,8 @@ public async Task<AnalysisResult> GetAnalysisDataAsync(Project project, bool avo
if (!await TryDeserializeAsync(serializer, project, project.Id, _owner.NonLocalStateName, builder.AddOthers, cancellationToken).ConfigureAwait(false))
{
Contract.Requires(false, "How this can happen?");
// this can happen if SaveAsync is not yet called but active file merge happened. one of case is if user did build before the very first
// analysis happened.
}
return builder.ToResult();
......@@ -178,7 +179,8 @@ public async Task<AnalysisResult> GetProjectAnalysisDataAsync(Project project, b
if (!await TryDeserializeAsync(serializer, project, project.Id, _owner.NonLocalStateName, builder.AddOthers, cancellationToken).ConfigureAwait(false))
{
Contract.Requires(false, "How this can happen?");
// this can happen if SaveAsync is not yet called but active file merge happened. one of case is if user did build before the very first
// analysis happened.
}
return builder.ToResult();
......
......@@ -80,9 +80,7 @@ internal static class RudeEditDiagnosticDescriptors
{ GetDescriptorPair(RudeEditKind.PartiallyExecutedActiveStatementDelete, FeaturesResources.AnActiveStatementHasBeenRemoved) },
{ GetDescriptorPair(RudeEditKind.InsertFile, FeaturesResources.AddingANewFile) },
{ GetDescriptorPair(RudeEditKind.UpdatingStateMachineMethodAroundActiveStatement, FeaturesResources.UpdatingStateMachineMethodAroundActive) },
// TODO: move message to resources https://github.com/dotnet/roslyn/issues/9196
{ GetDescriptorPair(RudeEditKind.UpdatingStateMachineMethodMissingAttribute, "Attribute '{0}' is missing. Updating an async method or an iterator will prevent the debug session from continuing.") },
{ GetDescriptorPair(RudeEditKind.UpdatingStateMachineMethodMissingAttribute, FeaturesResources.UpdatingStateMachineMethodMissingAttribute) },
{ GetDescriptorPair(RudeEditKind.RUDE_EDIT_COMPLEX_QUERY_EXPRESSION, FeaturesResources.ModifyingAWhichContainsComplexQuery) },
// VB specific,
......
......@@ -2475,6 +2475,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Attribute &apos;{0}&apos; is missing. Updating an async method or an iterator will prevent the debug session from continuing..
/// </summary>
internal static string UpdatingStateMachineMethodMissingAttribute {
get {
return ResourceManager.GetString("UpdatingStateMachineMethodMissingAttribute", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Updating the alias of Declare Statement will prevent the debug session from continuing..
/// </summary>
......
......@@ -574,6 +574,9 @@
<data name="AddingANewFile" xml:space="preserve">
<value>Adding a new file will prevent the debug session from continuing.</value>
</data>
<data name="UpdatingStateMachineMethodMissingAttribute" xml:space="preserve">
<value>Attribute '{0}' is missing. Updating an async method or an iterator will prevent the debug session from continuing.</value>
</data>
<data name="UnexpectedInterfaceMemberKind" xml:space="preserve">
<value>Unexpected interface member kind: {0}</value>
</data>
......
......@@ -386,5 +386,13 @@ public override int ERR_ModuleEmitFailure
throw new NotImplementedException();
}
}
public override int ERR_EncUpdateFailedMissingAttribute
{
get
{
throw new NotImplementedException();
}
}
}
}
......@@ -33,6 +33,22 @@ internal sealed class AnalyzerDependencyCheckingService
private Task<AnalyzerDependencyResults> _task = Task.FromResult(AnalyzerDependencyResults.Empty);
private ImmutableHashSet<string> _analyzerPaths = ImmutableHashSet.Create<string>(StringComparer.OrdinalIgnoreCase);
private readonly DiagnosticDescriptor _missingAnalyzerReferenceRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.MissingAnalyzerReferenceId,
title: ServicesVSResources.WRN_MissingAnalyzerReferenceTitle,
messageFormat: ServicesVSResources.WRN_MissingAnalyzerReferenceMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
private readonly DiagnosticDescriptor _analyzerDependencyConflictRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.AnalyzerDependencyConflictId,
title: ServicesVSResources.WRN_AnalyzerDependencyConflictTitle,
messageFormat: ServicesVSResources.WRN_AnalyzerDependencyConflictMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
[ImportingConstructor]
public AnalyzerDependencyCheckingService(
VisualStudioWorkspaceImpl workspace,
......@@ -74,7 +90,12 @@ public async void CheckForConflictsAsync()
if (project.CurrentProjectAnalyzersContains(conflict.AnalyzerFilePath1) ||
project.CurrentProjectAnalyzersContains(conflict.AnalyzerFilePath2))
{
builder.Add(CreateDiagnostic(project.Id, conflict));
var messageArguments = new string[] { conflict.AnalyzerFilePath1, conflict.AnalyzerFilePath2, conflict.Identity.ToString() };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_analyzerDependencyConflictRule, messageArguments, project.Id, _workspace, out diagnostic))
{
builder.Add(diagnostic);
}
}
}
......@@ -82,7 +103,12 @@ public async void CheckForConflictsAsync()
{
if (project.CurrentProjectAnalyzersContains(missingDependency.AnalyzerPath))
{
builder.Add(CreateDiagnostic(project.Id, missingDependency));
var messageArguments = new string[] { missingDependency.AnalyzerPath, missingDependency.DependencyIdentity.ToString() };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_missingAnalyzerReferenceRule, messageArguments, project.Id, _workspace, out diagnostic))
{
builder.Add(diagnostic);
}
}
}
......@@ -123,57 +149,6 @@ private void LogMissingDependency(MissingAnalyzerDependency missingDependency)
}));
}
private DiagnosticData CreateDiagnostic(ProjectId projectId, AnalyzerDependencyConflict conflict)
{
string message = string.Format(
ServicesVSResources.WRN_AnalyzerDependencyConflictMessage,
conflict.AnalyzerFilePath1,
conflict.AnalyzerFilePath2,
conflict.Identity.ToString());
DiagnosticData data = new DiagnosticData(
IDEDiagnosticIds.AnalyzerDependencyConflictId,
FeaturesResources.ErrorCategory,
message,
ServicesVSResources.WRN_AnalyzerDependencyConflictMessage,
severity: DiagnosticSeverity.Warning,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
warningLevel: 0,
customTags: ImmutableArray<string>.Empty,
properties: ImmutableDictionary<string, string>.Empty,
workspace: _workspace,
projectId: projectId,
title: ServicesVSResources.WRN_AnalyzerDependencyConflictTitle);
return data;
}
private DiagnosticData CreateDiagnostic(ProjectId projectId, MissingAnalyzerDependency missingDependency)
{
string message = string.Format(
ServicesVSResources.WRN_MissingAnalyzerReferenceMessage,
missingDependency.AnalyzerPath,
missingDependency.DependencyIdentity.ToString());
DiagnosticData data = new DiagnosticData(
IDEDiagnosticIds.MissingAnalyzerReferenceId,
FeaturesResources.ErrorCategory,
message,
ServicesVSResources.WRN_MissingAnalyzerReferenceMessage,
severity: DiagnosticSeverity.Warning,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
warningLevel: 0,
customTags: ImmutableArray<string>.Empty,
properties: ImmutableDictionary<string, string>.Empty,
workspace: _workspace,
projectId: projectId,
title: ServicesVSResources.WRN_MissingAnalyzerReferenceTitle);
return data;
}
private Task<AnalyzerDependencyResults> GetConflictsAsync()
{
ImmutableHashSet<string> currentAnalyzerPaths = _workspace.CurrentSolution
......
......@@ -29,6 +29,14 @@ internal sealed class AnalyzerFileWatcherService
private readonly object _guard = new object();
private readonly DiagnosticDescriptor _analyzerChangedRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.AnalyzerChangedId,
title: ServicesVSResources.WRN_AnalyzerChangedTitle,
messageFormat: ServicesVSResources.WRN_AnalyzerChangedMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
[ImportingConstructor]
public AnalyzerFileWatcherService(
VisualStudioWorkspaceImpl workspace,
......@@ -67,21 +75,12 @@ internal void RemoveAnalyzerAlreadyLoadedDiagnostics(ProjectId projectId, string
private void RaiseAnalyzerChangedWarning(ProjectId projectId, string analyzerPath)
{
string message = string.Format(ServicesVSResources.WRN_AnalyzerChangedMessage, analyzerPath);
DiagnosticData data = new DiagnosticData(
IDEDiagnosticIds.AnalyzerChangedId,
FeaturesResources.ErrorCategory,
message,
ServicesVSResources.WRN_AnalyzerChangedMessage,
severity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
warningLevel: 0,
workspace: _workspace,
projectId: projectId,
title: ServicesVSResources.WRN_AnalyzerChangedTitle);
_updateSource.UpdateDiagnosticsForProject(projectId, Tuple.Create(s_analyzerChangedErrorId, analyzerPath), SpecializedCollections.SingletonEnumerable(data));
var messageArguments = new string[] { analyzerPath };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_analyzerChangedRule, messageArguments, projectId, _workspace, out diagnostic))
{
_updateSource.UpdateDiagnosticsForProject(projectId, Tuple.Create(s_analyzerChangedErrorId, analyzerPath), SpecializedCollections.SingletonEnumerable(diagnostic));
}
}
private DateTime? GetLastUpdateTimeUtc(string fullPath)
......
......@@ -99,6 +99,14 @@ internal abstract partial class AbstractProject : IVisualStudioHostProject
private static readonly EventHandler<bool> s_additionalDocumentClosingEventHandler = OnAdditionalDocumentClosing;
private static readonly EventHandler s_additionalDocumentUpdatedOnDiskEventHandler = OnAdditionalDocumentUpdatedOnDisk;
private readonly DiagnosticDescriptor _errorReadingRulesetRule = new DiagnosticDescriptor(
id: IDEDiagnosticIds.ErrorReadingRulesetId,
title: ServicesVSResources.ERR_CantReadRulesetFileTitle,
messageFormat: ServicesVSResources.ERR_CantReadRulesetFileMessage,
category: FeaturesResources.ErrorCategory,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
public AbstractProject(
VisualStudioProjectTracker projectTracker,
Func<ProjectId, IVsReportExternalErrors> reportExternalErrorCreatorOpt,
......@@ -1257,20 +1265,12 @@ protected void UpdateRuleSetError(IRuleSetFile ruleSetFile)
}
else
{
string message = string.Format(ServicesVSResources.ERR_CantReadRulesetFileMessage, ruleSetFile.FilePath, ruleSetFile.GetException().Message);
var data = new DiagnosticData(
id: IDEDiagnosticIds.ErrorReadingRulesetId,
category: FeaturesResources.ErrorCategory,
message: message,
enuMessageForBingSearch: ServicesVSResources.ERR_CantReadRulesetFileMessage,
severity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
warningLevel: 0,
workspace: this.Workspace,
projectId: this.Id,
title: ServicesVSResources.ERR_CantReadRulesetFileTitle);
this.HostDiagnosticUpdateSource.UpdateDiagnosticsForProject(this.Id, RuleSetErrorId, SpecializedCollections.SingletonEnumerable(data));
var messageArguments = new string[] { ruleSetFile.FilePath, ruleSetFile.GetException().Message };
DiagnosticData diagnostic;
if (DiagnosticData.TryCreate(_errorReadingRulesetRule, messageArguments, this.Id, this.Workspace, out diagnostic))
{
this.HostDiagnosticUpdateSource.UpdateDiagnosticsForProject(this.Id, RuleSetErrorId, SpecializedCollections.SingletonEnumerable(diagnostic));
}
}
}
......
......@@ -76,6 +76,11 @@ public ImmutableArray<DiagnosticData> GetBuildErrors()
return _lastBuiltResult;
}
public bool SupportedDiagnosticId(ProjectId projectId, string id)
{
return _state?.SupportedDiagnosticId(projectId, id) ?? false;
}
public void ClearErrors(ProjectId projectId)
{
// capture state if it exists
......@@ -88,7 +93,7 @@ public void ClearErrors(ProjectId projectId)
// otherwise (such as closing solution or removing project), no need to record it
state?.Built(projectId);
ClearProjectErrors(projectId);
ClearProjectErrors(state?.Solution ?? _workspace.CurrentSolution, projectId);
}).CompletesAsyncOperation(asyncToken);
}
......@@ -102,7 +107,7 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
case WorkspaceChangeKind.SolutionReloaded:
{
var asyncToken = _listener.BeginAsyncOperation("OnSolutionChanged");
_taskQueue.ScheduleTask(() => e.OldSolution.ProjectIds.Do(p => ClearProjectErrors(p, e.OldSolution))).CompletesAsyncOperation(asyncToken);
_taskQueue.ScheduleTask(() => e.OldSolution.ProjectIds.Do(p => ClearProjectErrors(e.OldSolution, p))).CompletesAsyncOperation(asyncToken);
break;
}
......@@ -110,7 +115,7 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
case WorkspaceChangeKind.ProjectReloaded:
{
var asyncToken = _listener.BeginAsyncOperation("OnProjectChanged");
_taskQueue.ScheduleTask(() => ClearProjectErrors(e.ProjectId, e.OldSolution)).CompletesAsyncOperation(asyncToken);
_taskQueue.ScheduleTask(() => ClearProjectErrors(e.OldSolution, e.ProjectId)).CompletesAsyncOperation(asyncToken);
break;
}
......@@ -118,7 +123,7 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
case WorkspaceChangeKind.DocumentReloaded:
{
var asyncToken = _listener.BeginAsyncOperation("OnDocumentRemoved");
_taskQueue.ScheduleTask(() => ClearDocumentErrors(e.ProjectId, e.DocumentId)).CompletesAsyncOperation(asyncToken);
_taskQueue.ScheduleTask(() => ClearDocumentErrors(e.OldSolution, e.ProjectId, e.DocumentId)).CompletesAsyncOperation(asyncToken);
break;
}
......@@ -169,16 +174,11 @@ internal void OnSolutionBuild(object sender, UIContextChangedEventArgs e)
// pause live analyzer
using (var operation = _notificationService.Start("BuildDone"))
{
// we will have a race here since we can't track version of solution the out of proc build actually used.
// result of the race will be us dropping some diagnostics from the build to the floor.
var solution = _workspace.CurrentSolution;
var supportedIdMap = GetSupportedLiveDiagnosticId(solution, inprogressState);
Func<DiagnosticData, bool> liveDiagnosticChecker = d =>
{
// REVIEW: we probably need a better design on de-duplicating live and build errors. or don't de-dup at all.
// for now, we are special casing compiler error case.
var project = solution.GetProject(d.ProjectId);
var project = inprogressState.Solution.GetProject(d.ProjectId);
if (project == null)
{
// project doesn't exist
......@@ -194,8 +194,7 @@ internal void OnSolutionBuild(object sender, UIContextChangedEventArgs e)
return false;
}
HashSet<string> set;
if (supportedIdMap.TryGetValue(d.ProjectId, out set) && set.Contains(d.Id))
if (inprogressState.SupportedDiagnosticId(d.ProjectId, d.Id))
{
return true;
}
......@@ -206,8 +205,8 @@ internal void OnSolutionBuild(object sender, UIContextChangedEventArgs e)
var diagnosticService = _diagnosticService as DiagnosticAnalyzerService;
if (diagnosticService != null)
{
await CleanupAllLiveErrorsIfNeededAsync(diagnosticService, solution, inprogressState).ConfigureAwait(false);
await SyncBuildErrorsAndReportAsync(diagnosticService, inprogressState.GetLiveDiagnosticsPerProject(liveDiagnosticChecker)).ConfigureAwait(false);
await CleanupAllLiveErrorsIfNeededAsync(diagnosticService, inprogressState.Solution, inprogressState).ConfigureAwait(false);
await SyncBuildErrorsAndReportAsync(diagnosticService, inprogressState.Solution, inprogressState.GetLiveDiagnosticsPerProject(liveDiagnosticChecker)).ConfigureAwait(false);
}
inprogressState.Done();
......@@ -239,7 +238,8 @@ private System.Threading.Tasks.Task CleanupAllLiveErrors(DiagnosticAnalyzerServi
return diagnosticService.SynchronizeWithBuildAsync(_workspace, map);
}
private async System.Threading.Tasks.Task SyncBuildErrorsAndReportAsync(DiagnosticAnalyzerService diagnosticService, ImmutableDictionary<ProjectId, ImmutableArray<DiagnosticData>> map)
private async System.Threading.Tasks.Task SyncBuildErrorsAndReportAsync(
DiagnosticAnalyzerService diagnosticService, Solution solution, ImmutableDictionary<ProjectId, ImmutableArray<DiagnosticData>> map)
{
// make those errors live errors
await diagnosticService.SynchronizeWithBuildAsync(_workspace, map).ConfigureAwait(false);
......@@ -253,56 +253,36 @@ private async System.Threading.Tasks.Task SyncBuildErrorsAndReportAsync(Diagnost
foreach (var projectGroup in group.GroupBy(g => g.ProjectId))
{
Contract.ThrowIfNull(projectGroup.Key);
ReportBuildErrors(projectGroup.Key, projectGroup.ToImmutableArray());
ReportBuildErrors(projectGroup.Key, solution, projectGroup.ToImmutableArray());
}
continue;
}
ReportBuildErrors(group.Key, group.ToImmutableArray());
ReportBuildErrors(group.Key, solution, group.ToImmutableArray());
}
}
private void ReportBuildErrors<T>(T item, ImmutableArray<DiagnosticData> buildErrors)
private void ReportBuildErrors<T>(T item, Solution solution, ImmutableArray<DiagnosticData> buildErrors)
{
var projectId = item as ProjectId;
if (projectId != null)
{
RaiseDiagnosticsCreated(projectId, projectId, null, buildErrors);
RaiseDiagnosticsCreated(projectId, solution, projectId, null, buildErrors);
return;
}
// must be not null
var documentId = item as DocumentId;
RaiseDiagnosticsCreated(documentId, documentId.ProjectId, documentId, buildErrors);
}
private Dictionary<ProjectId, HashSet<string>> GetSupportedLiveDiagnosticId(Solution solution, InprogressState state)
{
var map = new Dictionary<ProjectId, HashSet<string>>();
// here, we don't care about perf that much since build is already expensive work
foreach (var projectId in state.GetProjectsWithErrors(solution))
{
var project = solution.GetProject(projectId);
if (project == null)
{
continue;
}
var descriptorMap = _diagnosticService.GetDiagnosticDescriptors(project);
map.Add(project.Id, new HashSet<string>(descriptorMap.Values.SelectMany(v => v.Select(d => d.Id))));
}
return map;
RaiseDiagnosticsCreated(documentId, solution, documentId.ProjectId, documentId, buildErrors);
}
private void ClearProjectErrors(ProjectId projectId, Solution solution = null)
private void ClearProjectErrors(Solution solution, ProjectId projectId)
{
// remove all project errors
RaiseDiagnosticsRemoved(projectId, projectId, documentId: null);
RaiseDiagnosticsRemoved(projectId, solution, projectId, documentId: null);
var project = (solution ?? _workspace.CurrentSolution).GetProject(projectId);
var project = solution.GetProject(projectId);
if (project == null)
{
return;
......@@ -311,13 +291,25 @@ private void ClearProjectErrors(ProjectId projectId, Solution solution = null)
// remove all document errors
foreach (var documentId in project.DocumentIds)
{
ClearDocumentErrors(projectId, documentId);
ClearDocumentErrors(solution, projectId, documentId);
}
}
private void ClearDocumentErrors(ProjectId projectId, DocumentId documentId)
private void ClearDocumentErrors(Solution solution, ProjectId projectId, DocumentId documentId)
{
RaiseDiagnosticsRemoved(documentId, projectId, documentId);
RaiseDiagnosticsRemoved(documentId, solution, projectId, documentId);
}
public void AddNewErrors(ProjectId projectId, DiagnosticData diagnostic)
{
// capture state that will be processed in background thread.
var state = GetOrCreateInprogressState();
var asyncToken = _listener.BeginAsyncOperation("Project New Errors");
_taskQueue.ScheduleTask(() =>
{
state.AddError(projectId, diagnostic);
}).CompletesAsyncOperation(asyncToken);
}
public void AddNewErrors(DocumentId documentId, DiagnosticData diagnostic)
......@@ -354,22 +346,25 @@ private InprogressState GetOrCreateInprogressState()
{
if (_state == null)
{
Interlocked.CompareExchange(ref _state, new InprogressState(this), null);
// here, we take current snapshot of solution when the state is first created. and through out this code, we use this snapshot.
// since we have no idea what actual snapshot of solution the out of proc build has picked up, it doesn't remove the race we can have
// between build and diagnostic service, but this at least make us to consistent inside of our code.
Interlocked.CompareExchange(ref _state, new InprogressState(this, _workspace.CurrentSolution), null);
}
return _state;
}
private void RaiseDiagnosticsCreated(object id, ProjectId projectId, DocumentId documentId, ImmutableArray<DiagnosticData> items)
private void RaiseDiagnosticsCreated(object id, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray<DiagnosticData> items)
{
DiagnosticsUpdated?.Invoke(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
CreateArgumentKey(id), _workspace, _workspace.CurrentSolution, projectId, documentId, items));
CreateArgumentKey(id), _workspace, solution, projectId, documentId, items));
}
private void RaiseDiagnosticsRemoved(object id, ProjectId projectId, DocumentId documentId)
private void RaiseDiagnosticsRemoved(object id, Solution solution, ProjectId projectId, DocumentId documentId)
{
DiagnosticsUpdated?.Invoke(this, DiagnosticsUpdatedArgs.DiagnosticsRemoved(
CreateArgumentKey(id), _workspace, _workspace.CurrentSolution, projectId, documentId));
CreateArgumentKey(id), _workspace, solution, projectId, documentId));
}
private static ArgumentKey CreateArgumentKey(object id) => new ArgumentKey(id);
......@@ -392,14 +387,17 @@ private void RaiseBuildStarted(bool started)
private class InprogressState
{
private readonly ExternalErrorDiagnosticUpdateSource _owner;
private readonly Solution _solution;
private readonly HashSet<ProjectId> _builtProjects = new HashSet<ProjectId>();
private readonly Dictionary<ProjectId, HashSet<DiagnosticData>> _projectMap = new Dictionary<ProjectId, HashSet<DiagnosticData>>();
private readonly Dictionary<DocumentId, HashSet<DiagnosticData>> _documentMap = new Dictionary<DocumentId, HashSet<DiagnosticData>>();
private readonly Dictionary<ProjectId, HashSet<string>> _diagnosticIdMap = new Dictionary<ProjectId, HashSet<string>>();
public InprogressState(ExternalErrorDiagnosticUpdateSource owner)
public InprogressState(ExternalErrorDiagnosticUpdateSource owner, Solution solution)
{
_owner = owner;
_solution = solution;
// let people know build has started
// TODO: to be more accurate, it probably needs to be counted. but for now,
......@@ -407,11 +405,38 @@ public InprogressState(ExternalErrorDiagnosticUpdateSource owner)
_owner.RaiseBuildStarted(started: true);
}
public Solution Solution => _solution;
public void Done()
{
_owner.RaiseBuildStarted(started: false);
}
public bool SupportedDiagnosticId(ProjectId projectId, string id)
{
HashSet<string> ids;
if (_diagnosticIdMap.TryGetValue(projectId, out ids))
{
return ids.Contains(id);
}
// set ids set
var map = new HashSet<string>();
_diagnosticIdMap.Add(projectId, map);
var project = _solution.GetProject(projectId);
if (project == null)
{
// projectId no longer exist, return false;
return false;
}
var descriptorMap = _owner._diagnosticService.GetDiagnosticDescriptors(project);
map.UnionWith(descriptorMap.Values.SelectMany(v => v.Select(d => d.Id)));
return map.Contains(id);
}
public ImmutableArray<DiagnosticData> GetBuildDiagnostics()
{
return ImmutableArray.CreateRange(_projectMap.Values.SelectMany(d => d).Concat(_documentMap.Values.SelectMany(d => d)));
......@@ -467,6 +492,11 @@ public void AddError(DocumentId key, DiagnosticData diagnostic)
AddError(_documentMap, key, diagnostic);
}
public void AddError(ProjectId key, DiagnosticData diagnostic)
{
AddError(_projectMap, key, diagnostic);
}
private void AddErrors<T>(Dictionary<T, HashSet<DiagnosticData>> map, T key, HashSet<DiagnosticData> diagnostics)
{
var errors = GetErrorSet(map, key);
......
......@@ -24,6 +24,7 @@ internal class ProjectExternalErrorReporter : IVsReportExternalErrors, IVsLangua
private readonly ProjectId _projectId;
private readonly string _errorCodePrefix;
private readonly VisualStudioWorkspaceImpl _workspace;
private readonly ExternalErrorDiagnosticUpdateSource _diagnosticProvider;
......@@ -31,11 +32,23 @@ public ProjectExternalErrorReporter(ProjectId projectId, string errorCodePrefix,
{
_projectId = projectId;
_errorCodePrefix = errorCodePrefix;
_diagnosticProvider = serviceProvider.GetMefService<ExternalErrorDiagnosticUpdateSource>();
_workspace = serviceProvider.GetMefService<VisualStudioWorkspaceImpl>();
_diagnosticProvider = serviceProvider.GetMefService<ExternalErrorDiagnosticUpdateSource>();
Debug.Assert(_diagnosticProvider != null);
Debug.Assert(_workspace != null);
Debug.Assert(_diagnosticProvider != null);
}
private bool CanHandle(string errorId)
{
// we accept all compiler diagnostics
if (errorId.StartsWith(_errorCodePrefix))
{
return true;
}
return _diagnosticProvider.SupportedDiagnosticId(_projectId, errorId);
}
public int AddNewErrors(IVsEnumExternalErrors pErrors)
......@@ -134,28 +147,20 @@ public int ReportError(string bstrErrorMessage, string bstrErrorId, [ComAliasNam
// TODO: Use PreserveSig instead of throwing these exceptions for common cases.
public void ReportError2(string bstrErrorMessage, string bstrErrorId, [ComAliasName("VsShell.VSTASKPRIORITY")]VSTASKPRIORITY nPriority, int iStartLine, int iStartColumn, int iEndLine, int iEndColumn, string bstrFileName)
{
if ((iEndLine >= 0 && iEndColumn >= 0) &&
((iEndLine < iStartLine) ||
(iEndLine == iStartLine && iEndColumn < iStartColumn)))
{
throw new ArgumentException(ServicesVSResources.EndPositionMustBeGreaterThanStart);
}
// We only handle errors that have positions. For the rest, we punt back to the
// project system.
if (iStartLine < 0 || iStartColumn < 0)
// first we check whether given error is something we can take care.
if (!CanHandle(bstrErrorId))
{
// it is not, let project system takes care.
throw new NotImplementedException();
}
var hostProject = _workspace.GetHostProject(_projectId);
if (!hostProject.ContainsFile(bstrFileName))
if ((iEndLine >= 0 && iEndColumn >= 0) &&
((iEndLine < iStartLine) ||
(iEndLine == iStartLine && iEndColumn < iStartColumn)))
{
throw new NotImplementedException();
throw new ArgumentException(ServicesVSResources.EndPositionMustBeGreaterThanStart);
}
var hostDocument = hostProject.GetCurrentDocumentFromPath(bstrFileName);
var priority = (VSTASKPRIORITY)nPriority;
DiagnosticSeverity severity;
switch (priority)
......@@ -173,6 +178,32 @@ public void ReportError2(string bstrErrorMessage, string bstrErrorId, [ComAliasN
throw new ArgumentException(ServicesVSResources.NotAValidValue, nameof(nPriority));
}
if (iStartLine < 0 || iStartColumn < 0)
{
// we now takes care of errors that is not belong to file as well.
var projectDiagnostic = GetDiagnosticData(
null, bstrErrorId, bstrErrorMessage, severity,
null, 0, 0, 0, 0,
bstrFileName, 0, 0, 0, 0);
_diagnosticProvider.AddNewErrors(_projectId, projectDiagnostic);
return;
}
var hostProject = _workspace.GetHostProject(_projectId);
if (!hostProject.ContainsFile(bstrFileName))
{
var projectDiagnostic = GetDiagnosticData(
null, bstrErrorId, bstrErrorMessage, severity,
null, iStartLine, iStartColumn, iEndLine, iEndColumn,
bstrFileName, iStartLine, iStartColumn, iEndLine, iEndColumn);
_diagnosticProvider.AddNewErrors(_projectId, projectDiagnostic);
return;
}
var hostDocument = hostProject.GetCurrentDocumentFromPath(bstrFileName);
var diagnostic = GetDiagnosticData(
hostDocument.Id, bstrErrorId, bstrErrorMessage, severity,
null, iStartLine, iStartColumn, iEndLine, iEndColumn,
......
......@@ -32,8 +32,18 @@ public AbstractOptionPageControl(IServiceProvider serviceProvider)
var checkBoxStyle = new System.Windows.Style(typeof(CheckBox));
checkBoxStyle.Setters.Add(new Setter(CheckBox.MarginProperty, new Thickness() { Bottom = 7 }));
groupBoxStyle.Setters.Add(new Setter(GroupBox.ForegroundProperty, new DynamicResourceExtension(SystemColors.WindowTextBrushKey)));
checkBoxStyle.Setters.Add(new Setter(CheckBox.ForegroundProperty, new DynamicResourceExtension(SystemColors.WindowTextBrushKey)));
Resources.Add(typeof(CheckBox), checkBoxStyle);
var textBoxStyle = new Style(typeof(TextBox));
textBoxStyle.Setters.Add(new Setter(TextBox.MarginProperty, new Thickness() { Left = 7, Right = 7 }));
textBoxStyle.Setters.Add(new Setter(TextBox.ForegroundProperty, new DynamicResourceExtension(SystemColors.WindowTextBrushKey)));
Resources.Add(typeof(TextBox), textBoxStyle);
}
protected void AddBinding(BindingExpressionBase bindingExpression)
{
_bindingExpressions.Add(bindingExpression);
}
protected void BindToOption(CheckBox checkbox, Option<bool> optionKey)
......
......@@ -53,6 +53,21 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
End Using
End Function
<Fact>
Public Async Function TestExternalDiagnostics_SupportedId() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync(String.Empty)
Dim waiter = New Waiter()
Dim service = New TestDiagnosticAnalyzerService()
Dim source = New ExternalErrorDiagnosticUpdateSource(workspace, service, New MockDiagnosticUpdateSourceRegistrationService(), waiter)
Dim project = workspace.CurrentSolution.Projects.First()
source.OnSolutionBuild(Me, Shell.UIContextChangedEventArgs.From(True))
Assert.True(source.SupportedDiagnosticId(project.Id, "CS1002"))
Assert.False(source.SupportedDiagnosticId(project.Id, "CA1002"))
End Using
End Function
<Fact>
Public Async Function TestExternalDiagnostics_DuplicatedError() As Task
Using workspace = Await TestWorkspace.CreateCSharpAsync(String.Empty)
......@@ -169,7 +184,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
End Sub
Public Function GetDiagnosticDescriptors(projectOpt As Project) As ImmutableDictionary(Of String, ImmutableArray(Of DiagnosticDescriptor)) Implements IDiagnosticAnalyzerService.GetDiagnosticDescriptors
Return ImmutableDictionary(Of String, ImmutableArray(Of DiagnosticDescriptor)).Empty
Return ImmutableDictionary(Of String, ImmutableArray(Of DiagnosticDescriptor)).Empty.Add("reference", ImmutableArray.Create(Of DiagnosticDescriptor)(New DiagnosticDescriptor("CS1002", "test", "test", "test", DiagnosticSeverity.Warning, True)))
End Function
Public Function GetDiagnosticsForSpanAsync(document As Document, range As TextSpan, Optional includeSuppressedDiagnostics As Boolean = False, Optional cancellationToken As CancellationToken = Nothing) As Task(Of IEnumerable(Of DiagnosticData)) Implements IDiagnosticAnalyzerService.GetDiagnosticsForSpanAsync
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Roslyn.VisualStudio.DiagnosticsWindow.OptionsPages
{
internal class ForceLowMemoryMode
{
private MemoryHogger _hogger;
public static readonly ForceLowMemoryMode Instance = new ForceLowMemoryMode();
private ForceLowMemoryMode()
{
}
public int Size { get; set; } = 500; // default to 500 MB
public bool Enabled
{
get
{
return _hogger != null;
}
set
{
if (value && _hogger == null)
{
_hogger = new MemoryHogger();
var ignore = _hogger.PopulateAndMonitorAsync(this.Size);
}
else if (!value && _hogger != null)
{
_hogger.Cancel();
_hogger = null;
}
}
}
private class MemoryHogger
{
private const int BlockSize = 1024 * 1024; // megabyte blocks
private const int MonitorDelay = 10000; // 10 seconds
private readonly List<byte[]> _blocks = new List<byte[]>();
private bool _cancelled;
public MemoryHogger()
{
}
public int Count
{
get { return _blocks.Count; }
}
public void Cancel()
{
_cancelled = true;
}
public Task PopulateAndMonitorAsync(int size)
{
// run on background thread
return Task.Run(() => this.PopulateAndMonitorWorkerAsync(size));
}
private async Task PopulateAndMonitorWorkerAsync(int size)
{
try
{
for (int n = 0; n < size && !_cancelled; n++)
{
var block = new byte[BlockSize];
// initialize block bits (so the memory actually gets allocated.. silly runtime!)
for (int i = 0; i < BlockSize; i++)
{
block[i] = 0xFF;
}
_blocks.Add(block);
// don't hog the thread
await Task.Yield();
}
}
catch (OutOfMemoryException)
{
}
// monitor memory to keep it paged in
while (!_cancelled)
{
try
{
// access all block bytes
for (var b = 0; b < _blocks.Count && !_cancelled; b++)
{
var block = _blocks[b];
byte tmp;
for (int i = 0; i < block.Length; i++)
{
tmp = block[i];
}
// don't hog the thread
await Task.Yield();
}
}
catch (OutOfMemoryException)
{
}
await Task.Delay(MonitorDelay);
}
_blocks.Clear();
// force garbage collection
for (int i = 0; i < 5; i++)
{
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
}
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.LanguageServices.Implementation.Options;
using Roslyn.Utilities;
namespace Roslyn.VisualStudio.DiagnosticsWindow.OptionsPages
{
......@@ -13,7 +23,61 @@ internal class InternalFeaturesOnOffPage : AbstractOptionPage
{
protected override AbstractOptionPageControl CreateOptionPage(IServiceProvider serviceProvider)
{
return new InternalOptionsControl(InternalFeatureOnOffOptions.OptionName, serviceProvider);
return new InternalFeaturesOptionsControl(InternalFeatureOnOffOptions.OptionName, serviceProvider);
}
internal class InternalFeaturesOptionsControl : InternalOptionsControl
{
public InternalFeaturesOptionsControl(string featureOptionName, IServiceProvider serviceProvider)
: base(featureOptionName, serviceProvider)
{
}
protected override void AddOptions(Panel panel)
{
base.AddOptions(panel);
// add force low memory mode option
var group = new WrapPanel();
var lowMemoryMode = ForceLowMemoryMode.Instance;
var cb = CreateBoundCheckBox("Forced Low Memory Mode", lowMemoryMode, "Enabled");
group.Children.Add(cb);
var tb = CreateBoundTextBox("", lowMemoryMode, "Size");
group.Children.Add(tb);
var text = new TextBlock() { Text = "MB" };
group.Children.Add(text);
panel.Children.Add(group);
}
private CheckBox CreateBoundCheckBox(string content, object source, string sourcePropertyName)
{
var cb = new CheckBox { Content = content };
var binding = new Binding()
{
Source = source,
Path = new PropertyPath(sourcePropertyName)
};
base.AddBinding(cb.SetBinding(CheckBox.IsCheckedProperty, binding));
return cb;
}
private TextBox CreateBoundTextBox(string content, object source, string sourcePropertyName)
{
var tb = new TextBox { Text = content };
var binding = new Binding()
{
Source = source,
Path = new PropertyPath(sourcePropertyName)
};
base.AddBinding(tb.SetBinding(TextBox.TextProperty, binding));
return tb;
}
}
}
}
......@@ -12,22 +12,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options
{
internal partial class InternalOptionsControl : AbstractOptionPageControl
{
private readonly string _featureOptionName;
public InternalOptionsControl(string featureOptionName, IServiceProvider serviceProvider)
: base(serviceProvider)
{
_featureOptionName = featureOptionName;
var panel = new StackPanel();
foreach (var option in OptionService.GetRegisteredOptions().Where(o => o.Feature == featureOptionName).OrderBy(o => o.Name))
{
if (!option.IsPerLanguage)
{
AddOption(panel, option);
}
else
{
AddPerLanguageOption(panel, option, LanguageNames.CSharp);
AddPerLanguageOption(panel, option, LanguageNames.VisualBasic);
}
}
this.AddOptions(panel);
var viewer = new ScrollViewer();
viewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
......@@ -50,7 +43,23 @@ public InternalOptionsControl(string featureOptionName, IServiceProvider service
this.Content = viewer;
}
private void AddOption(StackPanel panel, IOption option)
protected virtual void AddOptions(Panel panel)
{
foreach (var option in OptionService.GetRegisteredOptions().Where(o => o.Feature == _featureOptionName).OrderBy(o => o.Name))
{
if (!option.IsPerLanguage)
{
AddOption(panel, option);
}
else
{
AddPerLanguageOption(panel, option, LanguageNames.CSharp);
AddPerLanguageOption(panel, option, LanguageNames.VisualBasic);
}
}
}
private void AddOption(Panel panel, IOption option)
{
var uiElement = CreateControl(option);
if (uiElement != null)
......@@ -59,7 +68,7 @@ private void AddOption(StackPanel panel, IOption option)
}
}
private void AddPerLanguageOption(StackPanel panel, IOption option, string languageName)
private void AddPerLanguageOption(Panel panel, IOption option, string languageName)
{
var uiElement = CreateControl(option, languageName);
if (uiElement != null)
......
......@@ -90,7 +90,9 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.ComponentModelHost, Version=$(VisualStudioReferenceAssemblyVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"><Private>false</Private></Reference>
<Reference Include="Microsoft.VisualStudio.ComponentModelHost, Version=$(VisualStudioReferenceAssemblyVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>false</Private>
</Reference>
<Reference Include="envdte, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>false</Private>
</Reference>
......@@ -113,6 +115,7 @@
<ItemGroup>
<Compile Include="DiagnosticsWindow.cs" />
<Compile Include="Guids.cs" />
<Compile Include="OptionPages\ForceLowMemoryMode.cs" />
<Compile Include="OptionPages\InternalSolutionCrawlerPage.cs" />
<Compile Include="OptionPages\InternalComponentsOnOffPage.cs" />
<Compile Include="OptionPages\InternalDiagnosticsPage.cs" />
......
......@@ -431,6 +431,35 @@ public static DiagnosticData Create(Document document, Diagnostic diagnostic)
isSuppressed: diagnostic.IsSuppressed);
}
public static bool TryCreate(DiagnosticDescriptor descriptor, string[] messageArguments, ProjectId projectId, Workspace workspace, out DiagnosticData diagnosticData, CancellationToken cancellationToken = default(CancellationToken))
{
diagnosticData = null;
var project = workspace.CurrentSolution.GetProject(projectId);
if (project == null)
{
return false;
}
var diagnostic = Diagnostic.Create(descriptor, Location.None, messageArguments);
if (project.SupportsCompilation)
{
// Get diagnostic with effective severity.
// Additionally, if the diagnostic was suppressed by a source suppression, effectiveDiagnostics will have a diagnostic with IsSuppressed = true.
var compilation = project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var effectiveDiagnostics = CompilationWithAnalyzers.GetEffectiveDiagnostics(SpecializedCollections.SingletonEnumerable(diagnostic), compilation);
if (effectiveDiagnostics == null || effectiveDiagnostics.IsEmpty())
{
// Rule is disabled by compilation options.
return false;
}
diagnostic = effectiveDiagnostics.Single();
}
diagnosticData = diagnostic.ToDiagnosticData(project);
return true;
}
private static void GetLocationInfo(Document document, Location location, out TextSpan sourceSpan, out FileLinePositionSpan originalLineInfo, out FileLinePositionSpan mappedLineInfo)
{
var diagnosticSpanMappingService = document.Project.Solution.Workspace.Services.GetService<IWorkspaceVenusSpanMappingService>();
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
......@@ -13,6 +14,18 @@ namespace Microsoft.CodeAnalysis.FindSymbols
{
internal partial class SymbolTreeInfo
{
private static Metadata GetMetadataNoThrow(PortableExecutableReference reference)
{
try
{
return reference.GetMetadata();
}
catch (Exception e) when (e is BadImageFormatException || e is IOException)
{
return null;
}
}
/// <summary>
/// this gives you SymbolTreeInfo for a metadata
/// </summary>
......@@ -22,7 +35,7 @@ internal partial class SymbolTreeInfo
bool loadOnly,
CancellationToken cancellationToken)
{
var metadata = reference.GetMetadata();
var metadata = GetMetadataNoThrow(reference);
if (metadata == null)
{
return null;
......@@ -76,7 +89,7 @@ internal partial class SymbolTreeInfo
{
var unsortedNodes = new List<Node> { new Node("", Node.RootNodeParentIndex) };
foreach (var moduleMetadata in GetModuleMetadata(reference.GetMetadata()))
foreach (var moduleMetadata in GetModuleMetadata(GetMetadataNoThrow(reference)))
{
MetadataReader reader;
try
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册