diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
index be6f596a5e50fab662ac45b8bf0006630d3514f6..34a990f0305c02cb3fbfd3da14cfbad9fab747c4 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
@@ -3634,6 +3634,15 @@ internal class CSharpResources {
}
}
+ ///
+ /// Looks up a localized string similar to Cannot update '{0}'; attribute '{1}' is missing..
+ ///
+ internal static string ERR_EncUpdateFailedMissingAttribute {
+ get {
+ return ResourceManager.GetString("ERR_EncUpdateFailedMissingAttribute", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to #endif directive expected.
///
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index b79a6b5f7320cbce4ce1356120e2f08f68b4d429..52a20b1e7345c6b1a69f0b720f9dfa7ac05b7a8c 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -3839,6 +3839,9 @@ You should consider suppressing the warning only if you're sure that you don't w
Cannot use fixed local '{0}' inside an anonymous method, lambda expression, or query expression
+
+ Cannot update '{0}'; attribute '{1}' is missing.
+
An expression tree may not contain a named argument specification
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 150fa469968017113119ba9dc147d112ae8e7097..0b688ed36fe79fd4a0bb146d12f29ba12d8fface 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -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,
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs
index 68f9753fea4295dc49f73562057dfb2358efe697..bfd94287cce2f342c28a559bc37fcf1de93a4c17 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs
@@ -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)
{
diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs
index 206c4255744ff574fed0a01ff36f10e7e8cf96ed..4ae07c8d49447e1bd6316afc6115d1f7d5e46ea1 100644
--- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs
@@ -4756,8 +4756,8 @@ public IEnumerable 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 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"));
}
}
}
diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs
index 57b84c16767e36c74ef8282a50373373c3b4b109..60f4130d5f800df097664361bd736706bc7e6919 100644
--- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs
@@ -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);
}
}
diff --git a/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs b/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs
index d3938cbc6bf839bae0670fcc4ef3fa12f5bc6edd..71e8fe4f0bbe7d439d5039547459c2e57739ae7f 100644
--- a/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs
+++ b/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs
@@ -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()
{
diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs b/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs
index 34a0d23c7995cc7dd95d9a57399a93153c4d954a..8857c7680fa224c6ea525a86a589c9ae97c124bf 100644
--- a/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs
+++ b/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs
@@ -314,6 +314,15 @@ internal class CodeAnalysisResources {
}
}
+ ///
+ /// Looks up a localized string similar to The compilation references multiple assemblies whose versions only differ in auto-generated build and/or revision numbers..
+ ///
+ internal static string CompilationReferencesAssembliesWithDifferentAutoGeneratedVersion {
+ get {
+ return ResourceManager.GetString("CompilationReferencesAssembliesWithDifferentAutoGeneratedVersion", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Analyzer Failure.
///
diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.resx b/src/Compilers/Core/Portable/CodeAnalysisResources.resx
index d6dd1fbcef73ea43703e5d2b72d9db7d763f57ad..217be60dfc3a6ba4ad0d18367fbc6776ac8ca54c 100644
--- a/src/Compilers/Core/Portable/CodeAnalysisResources.resx
+++ b/src/Compilers/Core/Portable/CodeAnalysisResources.resx
@@ -519,4 +519,7 @@
Tuples must have at least two elements.
+
+ The compilation references multiple assemblies whose versions only differ in auto-generated build and/or revision numbers.
+
\ No newline at end of file
diff --git a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs
index 3754056736e2cb0750f6a926ed87fedbde6eaa41..1db72196394a8b9834e003ff37c917195008295f 100644
--- a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs
+++ b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs
@@ -86,9 +86,9 @@ public Diagnostic CreateDiagnostic(int code, Location location)
public abstract string GetMessagePrefix(string id, DiagnosticSeverity severity, bool isWarningAsError, CultureInfo culture);
///
- /// convert given symbol to string representation based on given error code
+ /// Convert given symbol to string representation.
///
- public abstract string ConvertSymbolToString(int errorCode, ISymbol symbol);
+ public abstract string GetErrorDisplayString(ISymbol symbol);
///
/// 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);
diff --git a/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs b/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs
index e8092585d762da24c6b658325dc550331ee24ef5..035a9e55de583c00b9e54faa5f42555666e47feb 100644
--- a/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs
+++ b/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs
@@ -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);
}
}
diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs
index b1c87c8feacec8e1c19700fa7054d39e906b7c7b..89aa9e89e079ca84d39ce0e3dd90d0b5e23a0e45 100644
--- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs
+++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs
@@ -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
diff --git a/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs b/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs
index 8e2502adf5288317f1eba8bd5a3db7bff24bdc1f..7f8f962fa7eea5385a4ba39c252e5ccbea1c4f1a 100644
--- a/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs
+++ b/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs
@@ -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);
}
}
diff --git a/src/Compilers/Core/Portable/MetadataReference/PortableExecutableReference.cs b/src/Compilers/Core/Portable/MetadataReference/PortableExecutableReference.cs
index b5e1c8f704ecd3f1f66e7a16228b7d49362617c1..195e2066b764bfe2f9b19b57ef1393bb4938e851 100644
--- a/src/Compilers/Core/Portable/MetadataReference/PortableExecutableReference.cs
+++ b/src/Compilers/Core/Portable/MetadataReference/PortableExecutableReference.cs
@@ -162,6 +162,9 @@ internal Metadata GetMetadataNoCopy()
/// Returns a copy of the object this
/// contains. This copy does not need to be d.
///
+ /// If the PE image format is invalid.
+ /// The metadata image content can't be read.
+ /// The metadata image is stored in a file that can't be found.
public Metadata GetMetadata()
{
return GetMetadataNoCopy().Copy();
diff --git a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs
index 37a4c052a7ce753018a6407b9968cf23533f637a..acc32315c5896fd9d92f2591ed351d6cf87301d1 100644
--- a/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs
+++ b/src/Compilers/Core/Portable/ReferenceManager/CommonReferenceManager.State.cs
@@ -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);
diff --git a/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.cs b/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.cs
index 775e6427c8a927788525729594972d833105efd6..97101d29bd99fb0bae4b167857e733fa8a626431 100644
--- a/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.cs
+++ b/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.cs
@@ -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;
}
diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb
index e54f8f369bd694c2eea8b78b067d83b6b5196f38..155ce7e89246360488e2baa57f8ac9fb17b7a63f 100644
--- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb
+++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb
@@ -1605,6 +1605,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_PublicKeyContainerFailure = 36981
ERR_InvalidAssemblyCulture = 36982
+ ERR_EncUpdateFailedMissingAttribute = 36983
ERR_CantAwaitAsyncSub1 = 37001
ERR_ResumableLambdaInExpressionTree = 37050
diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb
index 89a95f260994c45dd2671d78745912c868d496b7..4367c4ffbec8e0835554b28665986c79b763e566 100644
--- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb
+++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb
@@ -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
diff --git a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb
index 5709cb39c935728bf218fd5e499ccd5101332f22..1c9f2293646998ffc014d4396367c414e28803b4 100644
--- a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb
+++ b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb
@@ -3296,6 +3296,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
+ '''
+ ''' Looks up a localized string similar to Cannot update '{0}'; attribute '{1}' is missing..
+ '''
+ Friend ReadOnly Property ERR_EncUpdateFailedMissingAttribute() As String
+ Get
+ Return ResourceManager.GetString("ERR_EncUpdateFailedMissingAttribute", resourceCulture)
+ End Get
+ End Property
+
'''
''' Looks up a localized string similar to 'End Class' must be preceded by a matching 'Class'..
'''
diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx
index ba42112d5ed0e8d4a75909680f37e84707818805..8e4fad42679eb3845bd9d79b3b4c3c2a995af42a 100644
--- a/src/Compilers/VisualBasic/Portable/VBResources.resx
+++ b/src/Compilers/VisualBasic/Portable/VBResources.resx
@@ -818,6 +818,9 @@
Failed to emit module '{0}'.
+
+ Cannot update '{0}'; attribute '{1}' is missing.
+
{0} '{1}' cannot be declared 'Overrides' because it does not override a {0} in a base class.
diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb
index acb7dbd0d76cd25baf55a071bff76eaa466c8b53..786280bd43478b3fdec605ee68486b48c3c61a34 100644
--- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb
+++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb
@@ -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
@@ -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
diff --git a/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb
index 14bf73ddd419e5ecd13ded5250661563f62f3933..5f36fccee10183c3f9934bfdbe9808c65fe80478 100644
--- a/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb
+++ b/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb
@@ -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
diff --git a/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb b/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb
index 4b02fecaf9871fb011a2fe003fb1027a01f574ca..9d08ec45f46a62b6016a8853d900a163402519e1 100644
--- a/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb
+++ b/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb
@@ -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
diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs
index d16165ff6ec01f5eac292c3512ab0e3a51f55be0..cc7c5fa4c994f88951b64e890f5afe276bab3988 100644
--- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs
+++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs
@@ -99,7 +99,8 @@ public async Task 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 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();
diff --git a/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnosticDescriptors.cs b/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnosticDescriptors.cs
index 636a5d8d44e7e46490d77e4a04e5b0bf9a2f3f50..d25904d9c2b75b5f4d0620fad0af3aa479970d0d 100644
--- a/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnosticDescriptors.cs
+++ b/src/Features/Core/Portable/EditAndContinue/RudeEditDiagnosticDescriptors.cs
@@ -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,
diff --git a/src/Features/Core/Portable/FeaturesResources.Designer.cs b/src/Features/Core/Portable/FeaturesResources.Designer.cs
index 4f7580c97822bbbe335797ef8a05a6db397dfa8c..8727f58739d52e8a06c3cc1a3de005ff7e6d124c 100644
--- a/src/Features/Core/Portable/FeaturesResources.Designer.cs
+++ b/src/Features/Core/Portable/FeaturesResources.Designer.cs
@@ -2475,6 +2475,15 @@ internal class FeaturesResources {
}
}
+ ///
+ /// Looks up a localized string similar to Attribute '{0}' is missing. Updating an async method or an iterator will prevent the debug session from continuing..
+ ///
+ internal static string UpdatingStateMachineMethodMissingAttribute {
+ get {
+ return ResourceManager.GetString("UpdatingStateMachineMethodMissingAttribute", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Updating the alias of Declare Statement will prevent the debug session from continuing..
///
diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx
index 5c9e26a6f11b5faedad8ee6e0eb40beb1c9b16ec..078c769e58cd1d38d331b154488dc1444c6c9379 100644
--- a/src/Features/Core/Portable/FeaturesResources.resx
+++ b/src/Features/Core/Portable/FeaturesResources.resx
@@ -574,6 +574,9 @@
Adding a new file will prevent the debug session from continuing.
+
+ Attribute '{0}' is missing. Updating an async method or an iterator will prevent the debug session from continuing.
+
Unexpected interface member kind: {0}
diff --git a/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs b/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs
index 3c7c9da4234702e9a946a9d740e34177a3fdbea9..548241f5514e798fe820a5e608d5db8b16091186 100644
--- a/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs
+++ b/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs
@@ -386,5 +386,13 @@ public override int ERR_ModuleEmitFailure
throw new NotImplementedException();
}
}
+
+ public override int ERR_EncUpdateFailedMissingAttribute
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerDependencyCheckingService.cs b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerDependencyCheckingService.cs
index 984bc5de393ba1297ecd276c4ebe5f07a5cc8e3c..7588a8eb050a526e661539f07de995f5ed629875 100644
--- a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerDependencyCheckingService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerDependencyCheckingService.cs
@@ -33,6 +33,22 @@ internal sealed class AnalyzerDependencyCheckingService
private Task _task = Task.FromResult(AnalyzerDependencyResults.Empty);
private ImmutableHashSet _analyzerPaths = ImmutableHashSet.Create(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.Empty,
- properties: ImmutableDictionary.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.Empty,
- properties: ImmutableDictionary.Empty,
- workspace: _workspace,
- projectId: projectId,
- title: ServicesVSResources.WRN_MissingAnalyzerReferenceTitle);
-
- return data;
- }
-
private Task GetConflictsAsync()
{
ImmutableHashSet currentAnalyzerPaths = _workspace.CurrentSolution
diff --git a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs
index b28cd8fb3c51391f474632a44104022ea057e66b..98f059e5a641506f12505dead88010019aa84721 100644
--- a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs
@@ -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)
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs
index f6590821c748d8a0a36e1e259228d412c560ec1a..78ffb0ee69b35dbc5f41484dcb2394c657993dfe 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject.cs
@@ -99,6 +99,14 @@ internal abstract partial class AbstractProject : IVisualStudioHostProject
private static readonly EventHandler 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 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));
+ }
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs
index c588b6ac4b1df7dfe20f747a27119b63df43f3ac..ad753f44031fb7a0dd4c4c3bb2093c442f7b72a6 100644
--- a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs
+++ b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs
@@ -76,6 +76,11 @@ public ImmutableArray 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 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 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> map)
+ private async System.Threading.Tasks.Task SyncBuildErrorsAndReportAsync(
+ DiagnosticAnalyzerService diagnosticService, Solution solution, ImmutableDictionary> 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 item, ImmutableArray buildErrors)
+ private void ReportBuildErrors(T item, Solution solution, ImmutableArray 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> GetSupportedLiveDiagnosticId(Solution solution, InprogressState state)
- {
- var map = new Dictionary>();
-
- // 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(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 items)
+ private void RaiseDiagnosticsCreated(object id, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray 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 _builtProjects = new HashSet();
private readonly Dictionary> _projectMap = new Dictionary>();
private readonly Dictionary> _documentMap = new Dictionary>();
+ private readonly Dictionary> _diagnosticIdMap = new Dictionary>();
- 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 ids;
+ if (_diagnosticIdMap.TryGetValue(projectId, out ids))
+ {
+ return ids.Contains(id);
+ }
+
+ // set ids set
+ var map = new HashSet();
+ _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 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(Dictionary> map, T key, HashSet diagnostics)
{
var errors = GetErrorSet(map, key);
diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs
index 01e4d6816d3095ab76963c49ceb9a01075b2ffe4..1efc6ff67b8049b8ade59e8e370f839793336708 100644
--- a/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs
+++ b/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs
@@ -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();
+
_workspace = serviceProvider.GetMefService();
+ _diagnosticProvider = serviceProvider.GetMefService();
- 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,
diff --git a/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs b/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs
index 600267b6cb7312e337e3a58cb12725210f6e3037..ad16d2c02fdb9496b112c1e0e97b6ebee1633636 100644
--- a/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs
+++ b/src/VisualStudio/Core/Impl/Options/AbstractOptionPageControl.cs
@@ -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 optionKey)
diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb
index 0772d8052bc1eedd8133a424fb0970e43f86510f..4b8c4f1f8442925348c92648981da9abe6f0ea85 100644
--- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb
+++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb
@@ -53,6 +53,21 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
End Using
End Function
+
+ 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
+
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
diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d0b604e51d6c599b808947ca95d6c9bc31b776b6
--- /dev/null
+++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/ForceLowMemoryMode.cs
@@ -0,0 +1,133 @@
+// 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 _blocks = new List();
+ 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();
+ }
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalFeaturesOnOffPage.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalFeaturesOnOffPage.cs
index 4e44c7651c80bbf8cbaf5e89f1ecc4ebcb9454a8..5ed986e9cd107edfd53253d99ab48d4071550070 100644
--- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalFeaturesOnOffPage.cs
+++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalFeaturesOnOffPage.cs
@@ -1,10 +1,20 @@
// 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;
+ }
}
}
}
diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs
index 702c19691ee5f934c933e159c4e463417e0b952e..66e04b3ef9aaceaf6637311bef3259c924d0f176 100644
--- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs
+++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/OptionPages/InternalOptionsControl.cs
@@ -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)
diff --git a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj
index d94ddf82ff3d15ced5fcdb05301de60c4ad9dbd8..146fc58e352a72a7699642bf13b6c7727b150d24 100644
--- a/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj
+++ b/src/VisualStudio/VisualStudioDiagnosticsToolWindow/VisualStudioDiagnosticsWindow.csproj
@@ -90,7 +90,9 @@
- false
+
+ false
+
false
@@ -113,6 +115,7 @@
+
diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs
index b658451ee2bdbf43317e8012acd269fe831ced08..746061315f242b86442e46d5fcca6a9521445e5f 100644
--- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs
+++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.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();
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs
index 4f182b14d43f465ba6cd0ea0cb5c14643a9d20f1..529e465dce777a503dfd83ae8c68ac4a7ed5098a 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs
@@ -1,5 +1,6 @@
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;
+ }
+ }
+
///
/// this gives you SymbolTreeInfo for a metadata
///
@@ -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 { new Node("", Node.RootNodeParentIndex) };
- foreach (var moduleMetadata in GetModuleMetadata(reference.GetMetadata()))
+ foreach (var moduleMetadata in GetModuleMetadata(GetMetadataNoThrow(reference)))
{
MetadataReader reader;
try