diff --git a/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj b/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj
index 93dad6ec222a3..58201385dd378 100644
--- a/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj
+++ b/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj
@@ -28,6 +28,7 @@
+
diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs
new file mode 100644
index 0000000000000..c89a4925ec046
--- /dev/null
+++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs
@@ -0,0 +1,49 @@
+// 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.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Roslyn.Test.Utilities;
+using Roslyn.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics
+{
+ using SimpleDiagnostic = Diagnostic.SimpleDiagnostic;
+
+ public class CompilationWithAnalyzersTests : TestBase
+ {
+ [Fact]
+ public void GetEffectiveDiagnostics_Errors()
+ {
+ var c = CSharpCompilation.Create("c");
+ var ds = new[] { default(Diagnostic) };
+
+ Assert.Throws(() => CompilationWithAnalyzers.GetEffectiveDiagnostics(default(ImmutableArray), c));
+ Assert.Throws(() => CompilationWithAnalyzers.GetEffectiveDiagnostics(default(IEnumerable), c));
+ Assert.Throws(() => CompilationWithAnalyzers.GetEffectiveDiagnostics(ds, null));
+ }
+
+ [Fact]
+ public void GetEffectiveDiagnostics()
+ {
+ var c = CSharpCompilation.Create("c", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).
+ WithSpecificDiagnosticOptions(
+ new[] { KeyValuePair.Create($"CS{(int)ErrorCode.WRN_AlwaysNull:D4}", ReportDiagnostic.Suppress) }));
+
+ var d1 = SimpleDiagnostic.Create(MessageProvider.Instance, (int)ErrorCode.WRN_AlignmentMagnitude);
+ var d2 = SimpleDiagnostic.Create(MessageProvider.Instance, (int)ErrorCode.WRN_AlwaysNull);
+ var ds = new[] { default(Diagnostic), d1, d2 };
+
+ var filtered = CompilationWithAnalyzers.GetEffectiveDiagnostics(ds, c);
+
+ // overwrite the original value to test eagerness:
+ ds[1] = default(Diagnostic);
+
+ AssertEx.Equal(new[] { d1 }, filtered);
+ }
+ }
+}
diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs
index ae50a0f792ca7..e739a4c31a395 100644
--- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs
+++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs
@@ -1010,8 +1010,18 @@ private static void FreeEventQueue(AsyncQueue eventQueue, Obje
/// 4) Pragma directives for the given .
///
public static IEnumerable GetEffectiveDiagnostics(IEnumerable diagnostics, Compilation compilation)
+ => GetEffectiveDiagnostics(diagnostics.AsImmutableOrNull(), compilation);
+
+ ///
+ /// Given a set of compiler or generated , returns the effective diagnostics after applying the below filters:
+ /// 1) specified for the given .
+ /// 2) specified for the given .
+ /// 3) Diagnostic suppression through applied .
+ /// 4) Pragma directives for the given .
+ ///
+ public static IEnumerable GetEffectiveDiagnostics(ImmutableArray diagnostics, Compilation compilation)
{
- if (diagnostics == null)
+ if (diagnostics.IsDefault)
{
throw new ArgumentNullException(nameof(diagnostics));
}
@@ -1021,16 +1031,20 @@ public static IEnumerable GetEffectiveDiagnostics(IEnumerable GetEffectiveDiagnosticsImpl(ImmutableArray diagnostics, Compilation compilation)
+ {
var suppressMessageState = new SuppressMessageAttributeState(compilation);
- foreach (var diagnostic in diagnostics.ToImmutableArray())
+ foreach (var diagnostic in diagnostics)
{
if (diagnostic != null)
{
var effectiveDiagnostic = compilation.Options.FilterDiagnostic(diagnostic);
if (effectiveDiagnostic != null)
{
- effectiveDiagnostic = suppressMessageState.ApplySourceSuppressions(effectiveDiagnostic);
- yield return effectiveDiagnostic;
+ yield return suppressMessageState.ApplySourceSuppressions(effectiveDiagnostic);
}
}
}
diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
index fc5b10b986d0c..681bd6232b7a6 100644
--- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
+++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
@@ -738,6 +738,7 @@ override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitVariableDeclarati
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitWhileUntilLoopStatement(Microsoft.CodeAnalysis.Semantics.IWhileUntilLoopStatement operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitWithStatement(Microsoft.CodeAnalysis.Semantics.IWithStatement operation) -> void
override Microsoft.CodeAnalysis.Semantics.OperationWalker.VisitYieldBreakStatement(Microsoft.CodeAnalysis.Semantics.IReturnStatement operation) -> void
+static Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers.GetEffectiveDiagnostics(System.Collections.Immutable.ImmutableArray diagnostics, Microsoft.CodeAnalysis.Compilation compilation) -> System.Collections.Generic.IEnumerable
static Microsoft.CodeAnalysis.Semantics.OperationExtensions.Descendants(this Microsoft.CodeAnalysis.IOperation operation) -> System.Collections.Generic.IEnumerable
static Microsoft.CodeAnalysis.Semantics.OperationExtensions.DescendantsAndSelf(this Microsoft.CodeAnalysis.IOperation operation) -> System.Collections.Generic.IEnumerable
static Microsoft.CodeAnalysis.Semantics.OperationExtensions.GetRootOperation(this Microsoft.CodeAnalysis.ISymbol symbol, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IOperation
diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs
index a1d4ad7b361f4..c3a8af723bb37 100644
--- a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs
+++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs
@@ -12,12 +12,22 @@
namespace Microsoft.CodeAnalysis.Editor.Implementation.EditAndContinue
{
+ internal sealed class EncErrorId : BuildToolId.Base
+ {
+ public EncErrorId(DebuggingSession session, object errorId)
+ : base(session, errorId)
+ {
+ }
+
+ public override string BuildTool => PredefinedBuildTools.EnC;
+ }
+
[Export(typeof(EditAndContinueDiagnosticUpdateSource))]
[Shared]
internal sealed class EditAndContinueDiagnosticUpdateSource : IDiagnosticUpdateSource
{
- internal static object DebuggerErrorId = new object();
- internal static object EmitErrorId = new object();
+ internal static readonly object DebuggerErrorId = new object();
+ internal static readonly object EmitErrorId = new object();
[ImportingConstructor]
public EditAndContinueDiagnosticUpdateSource(IDiagnosticUpdateSourceRegistrationService registrationService)
@@ -25,7 +35,7 @@ public EditAndContinueDiagnosticUpdateSource(IDiagnosticUpdateSourceRegistration
registrationService.Register(this);
}
- public bool SupportGetDiagnostics { get { return false; } }
+ public bool SupportGetDiagnostics => false;
public event EventHandler DiagnosticsUpdated;
@@ -34,100 +44,94 @@ public EditAndContinueDiagnosticUpdateSource(IDiagnosticUpdateSourceRegistration
return ImmutableArray.Empty;
}
- public void ClearDiagnostics(DebuggingSession session, Workspace workspace, object kind, ProjectId projectId, ImmutableArray documentIds)
+ public void ClearDiagnostics(EncErrorId errorId, Solution solution, ProjectId projectId, ImmutableArray documentIds)
{
- if (documentIds.IsDefault)
- {
- return;
- }
+ // clear project diagnostics:
+ ClearDiagnostics(errorId, solution, projectId, null);
- foreach (var documentId in documentIds)
+ // clear document diagnostics:
+ foreach (var documentIdOpt in documentIds)
{
- ClearDiagnostics(session, workspace, kind, projectId, documentId);
+ ClearDiagnostics(errorId, solution, projectId, documentIdOpt);
}
}
- public void ClearDiagnostics(DebuggingSession session, Workspace workspace, object errorId, ProjectId projectId, DocumentId documentId)
+ public void ClearDiagnostics(EncErrorId errorId, Solution solution, ProjectId projectId, DocumentId documentIdOpt)
{
- RaiseDiagnosticsUpdated(MakeRemovedArgs(session, workspace, errorId, projectId, documentId));
+ DiagnosticsUpdated?.Invoke(this, DiagnosticsUpdatedArgs.DiagnosticsRemoved(
+ errorId,
+ solution.Workspace,
+ solution: solution,
+ projectId: projectId,
+ documentId: documentIdOpt));
}
- public ImmutableArray ReportDiagnostics(DebuggingSession session, object errorId, ProjectId projectId, Solution solution, IEnumerable diagnostics)
+ public ImmutableArray ReportDiagnostics(object errorId, Solution solution, ProjectId projectId, IEnumerable diagnostics)
{
- var argsByDocument = ImmutableArray.CreateRange(
- from diagnostic in diagnostics
- let document = solution.GetDocument(diagnostic.Location.SourceTree, projectId)
- where document != null
- let item = MakeDiagnosticData(projectId, document, solution, diagnostic)
- group item by document.Id into itemsByDocumentId
- select MakeCreatedArgs(session, errorId, solution.Workspace, solution, projectId, itemsByDocumentId.Key, ImmutableArray.CreateRange(itemsByDocumentId)));
-
- foreach (var args in argsByDocument)
- {
- RaiseDiagnosticsUpdated(args);
- }
+ Debug.Assert(errorId != null);
+ Debug.Assert(solution != null);
+ Debug.Assert(projectId != null);
- return argsByDocument.SelectAsArray(args => args.DocumentId);
- }
+ var updateEvent = DiagnosticsUpdated;
+ var documentIds = ArrayBuilder.GetInstance();
+ var documentDiagnosticData = ArrayBuilder.GetInstance();
+ var projectDiagnosticData = ArrayBuilder.GetInstance();
+ var project = solution.GetProject(projectId);
- private static DiagnosticData MakeDiagnosticData(ProjectId projectId, Document document, Solution solution, Diagnostic d)
- {
- if (document != null)
+ foreach (var diagnostic in diagnostics)
{
- return DiagnosticData.Create(document, d);
+ var documentOpt = solution.GetDocument(diagnostic.Location.SourceTree, projectId);
+
+ if (documentOpt != null)
+ {
+ if (updateEvent != null)
+ {
+ documentDiagnosticData.Add(DiagnosticData.Create(documentOpt, diagnostic));
+ }
+
+ documentIds.Add(documentOpt.Id);
+ }
+ else if (updateEvent != null)
+ {
+ projectDiagnosticData.Add(DiagnosticData.Create(project, diagnostic));
+ }
}
- else
+
+ foreach (var documentDiagnostics in documentDiagnosticData.ToDictionary(data => data.DocumentId))
{
- var project = solution.GetProject(projectId);
- Debug.Assert(project != null);
- return DiagnosticData.Create(project, d);
+ updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
+ errorId,
+ solution.Workspace,
+ solution,
+ projectId,
+ documentId: documentDiagnostics.Key,
+ diagnostics: documentDiagnostics.Value));
}
- }
- private DiagnosticsUpdatedArgs MakeCreatedArgs(
- DebuggingSession session, Workspace workspace, object errorId, ProjectId projectId, DocumentId documentId, ImmutableArray items)
- {
- return MakeCreatedArgs(session, errorId, workspace, solution: null, projectId: projectId, documentId: documentId, items: items);
- }
-
- private DiagnosticsUpdatedArgs MakeRemovedArgs(
- DebuggingSession session, Workspace workspace, object errorId, ProjectId projectId, DocumentId documentId)
- {
- return MakeRemovedArgs(session, errorId, workspace, solution: null, projectId: projectId, documentId: documentId);
- }
+ if (projectDiagnosticData.Count > 0)
+ {
+ updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
+ errorId,
+ solution.Workspace,
+ solution,
+ projectId,
+ documentId: null,
+ diagnostics: projectDiagnosticData.ToImmutable()));
+ }
- private DiagnosticsUpdatedArgs MakeCreatedArgs(
- DebuggingSession session, object errorId, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray items)
- {
- return DiagnosticsUpdatedArgs.DiagnosticsCreated(
- CreateId(session, errorId), workspace, solution, projectId, documentId, items);
+ documentDiagnosticData.Free();
+ projectDiagnosticData.Free();
+ return documentIds.ToImmutableAndFree();
}
- private DiagnosticsUpdatedArgs MakeRemovedArgs(
- DebuggingSession session, object errorId, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId)
+ internal ImmutableArray ReportDiagnostics(DebuggingSession session, object errorId, ProjectId projectId, Solution solution, IEnumerable diagnostics)
{
- return DiagnosticsUpdatedArgs.DiagnosticsRemoved(
- CreateId(session, errorId), workspace, solution, projectId, documentId);
+ return ReportDiagnostics(new EncErrorId(session, errorId), solution, projectId, diagnostics);
}
- private static EnCId CreateId(DebuggingSession session, object errorId) => new EnCId(session, errorId);
-
- private void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args)
+ internal void ClearDiagnostics(DebuggingSession session, Workspace workspace, object errorId, ProjectId projectId, ImmutableArray documentIds)
{
- this.DiagnosticsUpdated?.Invoke(this, args);
- }
-
- private class EnCId : BuildToolId.Base
- {
- public EnCId(DebuggingSession session, object errorId) :
- base(session, errorId)
- {
- }
-
- public override string BuildTool
- {
- get { return PredefinedBuildTools.EnC; }
- }
+ ClearDiagnostics(new EncErrorId(session, errorId), workspace.CurrentSolution, projectId, documentIds);
}
}
}
diff --git a/src/EditorFeatures/Test/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs b/src/EditorFeatures/Test/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs
index 9a0749ce131e4..a098a3f7e8d67 100644
--- a/src/EditorFeatures/Test/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs
+++ b/src/EditorFeatures/Test/Workspaces/NoCompilationDocumentDiagnosticAnalyzer.cs
@@ -6,6 +6,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
{
@@ -17,16 +18,15 @@ internal class NoCompilationDocumentDiagnosticAnalyzer : DocumentDiagnosticAnaly
public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor);
- public override Task AnalyzeSemanticsAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken)
+ public override Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken)
{
- return Task.FromResult(true);
+ return SpecializedTasks.EmptyImmutableArray();
}
- public override Task AnalyzeSyntaxAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken)
+ public override Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
{
- addDiagnostic(Diagnostic.Create(Descriptor,
- Location.Create(document.FilePath, default(TextSpan), default(LinePositionSpan))));
- return Task.FromResult(true);
+ return Task.FromResult(ImmutableArray.Create(
+ Diagnostic.Create(Descriptor, Location.Create(document.FilePath, default(TextSpan), default(LinePositionSpan)))));
}
}
}
diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/IDocumentDiagnosticAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/IDocumentDiagnosticAnalyzer.cs
index b1e24468ded7a..c3a0ec5d608fe 100644
--- a/src/Features/Core/Portable/Diagnostics/Analyzers/IDocumentDiagnosticAnalyzer.cs
+++ b/src/Features/Core/Portable/Diagnostics/Analyzers/IDocumentDiagnosticAnalyzer.cs
@@ -1,8 +1,10 @@
// 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.Immutable;
using System.Threading;
using System.Threading.Tasks;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
{
@@ -12,8 +14,33 @@ namespace Microsoft.CodeAnalysis.Diagnostics
internal abstract class DocumentDiagnosticAnalyzer : DiagnosticAnalyzer
{
// REVIEW: why DocumentDiagnosticAnalyzer doesn't have span based analysis?
- public abstract Task AnalyzeSyntaxAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken);
- public abstract Task AnalyzeSemanticsAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken);
+ // TODO: Make abstract once TypeScript and F# move over to the overloads above
+ public async virtual Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
+ {
+ var builder = ArrayBuilder.GetInstance();
+ await AnalyzeSyntaxAsync(document, builder.Add, cancellationToken).ConfigureAwait(false);
+ return builder.ToImmutableAndFree();
+ }
+
+ // TODO: Make abstract once TypeScript and F# move over to the overloads above
+ public async virtual Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken)
+ {
+ var builder = ArrayBuilder.GetInstance();
+ await AnalyzeSemanticsAsync(document, builder.Add, cancellationToken).ConfigureAwait(false);
+ return builder.ToImmutableAndFree();
+ }
+
+ // TODO: Remove once TypeScript and F# move over to the overloads above
+ public virtual Task AnalyzeSyntaxAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken)
+ {
+ throw ExceptionUtilities.Unreachable;
+ }
+
+ // TODO: Remove once TypeScript and F# move over to the overloads above
+ public virtual Task AnalyzeSemanticsAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken)
+ {
+ throw ExceptionUtilities.Unreachable;
+ }
///
/// it is not allowed one to implement both DocumentDiagnosticAnalzyer and DiagnosticAnalyzer
diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/RudeEditUserDiagnosticAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/RudeEditUserDiagnosticAnalyzer.cs
index 19e975c1d3bc4..1b47abb0db7d8 100644
--- a/src/Features/Core/Portable/Diagnostics/Analyzers/RudeEditUserDiagnosticAnalyzer.cs
+++ b/src/Features/Core/Portable/Diagnostics/Analyzers/RudeEditUserDiagnosticAnalyzer.cs
@@ -21,20 +21,20 @@ public override ImmutableArray SupportedDiagnostics
}
}
- public override Task AnalyzeSyntaxAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken)
+ public override Task> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
{
// No syntax diagnostics produced by the EnC engine.
- return SpecializedTasks.EmptyTask;
+ return SpecializedTasks.EmptyImmutableArray();
}
- public override async Task AnalyzeSemanticsAsync(Document document, Action addDiagnostic, CancellationToken cancellationToken)
+ public override async Task> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken)
{
try
{
var encService = document.Project.Solution.Workspace.Services.GetService();
if (encService == null)
{
- return;
+ return ImmutableArray.Empty;
}
EditSession session = encService.EditSession;
@@ -42,20 +42,18 @@ public override async Task AnalyzeSemanticsAsync(Document document, Action.Empty;
}
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var analysis = await session.GetDocumentAnalysis(document).GetValueAsync(cancellationToken).ConfigureAwait(false);
- if (!analysis.RudeEditErrors.IsDefault)
+ if (analysis.RudeEditErrors.IsDefault)
{
- session.LogRudeEditErrors(analysis.RudeEditErrors);
-
- foreach (var error in analysis.RudeEditErrors)
- {
- addDiagnostic(error.ToDiagnostic(tree));
- }
+ return ImmutableArray.Empty;
}
+
+ session.LogRudeEditErrors(analysis.RudeEditErrors);
+ return analysis.RudeEditErrors.SelectAsArray((e, t) => e.ToDiagnostic(t), tree);
}
catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
{
diff --git a/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticAnalyzerDriver.cs b/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticAnalyzerDriver.cs
index 66ad5d2eed075..96e3dba336951 100644
--- a/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticAnalyzerDriver.cs
+++ b/src/Features/Core/Portable/Diagnostics/EngineV1/DiagnosticAnalyzerDriver.cs
@@ -171,21 +171,17 @@ public async Task> GetSyntaxDiagnosticsAsync(Diagnost
var documentAnalyzer = analyzer as DocumentDiagnosticAnalyzer;
if (documentAnalyzer != null)
{
- using (var pooledObject = SharedPools.Default>().GetPooledObject())
+ _cancellationToken.ThrowIfCancellationRequested();
+
+ try
+ {
+ var diagnostics = await documentAnalyzer.AnalyzeSyntaxAsync(_document, _cancellationToken).ConfigureAwait(false);
+ return GetFilteredDocumentDiagnostics(diagnostics, compilation);
+ }
+ catch (Exception e) when (!IsCanceled(e, _cancellationToken))
{
- var diagnostics = pooledObject.Object;
- _cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- await documentAnalyzer.AnalyzeSyntaxAsync(_document, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
- return GetFilteredDocumentDiagnostics(diagnostics, compilation).ToImmutableArray();
- }
- catch (Exception e) when (!IsCanceled(e, _cancellationToken))
- {
- OnAnalyzerException(e, analyzer, compilation);
- return ImmutableArray.Empty;
- }
+ OnAnalyzerException(e, analyzer, compilation);
+ return ImmutableArray.Empty;
}
}
@@ -197,7 +193,7 @@ public async Task> GetSyntaxDiagnosticsAsync(Diagnost
var compilationWithAnalyzers = GetCompilationWithAnalyzers(compilation);
var syntaxDiagnostics = await compilationWithAnalyzers.GetAnalyzerSyntaxDiagnosticsAsync(_root.SyntaxTree, ImmutableArray.Create(analyzer), _cancellationToken).ConfigureAwait(false);
await UpdateAnalyzerTelemetryDataAsync(analyzer, compilationWithAnalyzers).ConfigureAwait(false);
- return GetFilteredDocumentDiagnostics(syntaxDiagnostics, compilation, onlyLocationFiltering: true).ToImmutableArray();
+ return syntaxDiagnostics.WhereAsArray(IsLocalDiagnostic);
}
catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
{
@@ -205,25 +201,25 @@ public async Task> GetSyntaxDiagnosticsAsync(Diagnost
}
}
- private IEnumerable GetFilteredDocumentDiagnostics(IEnumerable diagnostics, Compilation compilation, bool onlyLocationFiltering = false)
+ private ImmutableArray GetFilteredDocumentDiagnostics(ImmutableArray diagnostics, Compilation compilationOpt)
{
if (_root == null)
{
return diagnostics;
}
- return GetFilteredDocumentDiagnosticsCore(diagnostics, compilation, onlyLocationFiltering);
+ if (compilationOpt == null)
+ {
+ return diagnostics.WhereAsArray(IsLocalDiagnostic);
+ }
+
+ return CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics.Where(IsLocalDiagnostic), compilationOpt).ToImmutableArray();
}
- private IEnumerable GetFilteredDocumentDiagnosticsCore(IEnumerable diagnostics, Compilation compilation, bool onlyLocationFiltering)
+ private bool IsLocalDiagnostic(Diagnostic diagnostic)
{
- var diagsFilteredByLocation = diagnostics.Where(diagnostic => (diagnostic.Location == Location.None) ||
- (diagnostic.Location.SourceTree == _root.SyntaxTree &&
- (_span == null || diagnostic.Location.SourceSpan.IntersectsWith(_span.Value))));
-
- return compilation == null || onlyLocationFiltering
- ? diagsFilteredByLocation
- : CompilationWithAnalyzers.GetEffectiveDiagnostics(diagsFilteredByLocation, compilation);
+ return diagnostic.Location == Location.None ||
+ diagnostic.Location.SourceTree == _root.SyntaxTree && (_span == null || diagnostic.Location.SourceSpan.IntersectsWith(_span.Value));
}
internal void OnAnalyzerException(Exception ex, DiagnosticAnalyzer analyzer, Compilation compilation)
@@ -251,23 +247,20 @@ public async Task> GetSemanticDiagnosticsAsync(Diagno
var documentAnalyzer = analyzer as DocumentDiagnosticAnalyzer;
if (documentAnalyzer != null)
{
- using (var pooledObject = SharedPools.Default>().GetPooledObject())
+ _cancellationToken.ThrowIfCancellationRequested();
+
+ ImmutableArray diagnostics;
+ try
{
- var diagnostics = pooledObject.Object;
- _cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- await documentAnalyzer.AnalyzeSemanticsAsync(_document, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
- }
- catch (Exception e) when (!IsCanceled(e, _cancellationToken))
- {
- OnAnalyzerException(e, analyzer, compilation);
- return ImmutableArray.Empty;
- }
-
- return GetFilteredDocumentDiagnostics(diagnostics, compilation).ToImmutableArray();
+ diagnostics = await documentAnalyzer.AnalyzeSemanticsAsync(_document, _cancellationToken).ConfigureAwait(false);
}
+ catch (Exception e) when (!IsCanceled(e, _cancellationToken))
+ {
+ OnAnalyzerException(e, analyzer, compilation);
+ return ImmutableArray.Empty;
+ }
+
+ return GetFilteredDocumentDiagnostics(diagnostics, compilation);
}
if (!_document.SupportsSyntaxTree || compilation == null)
diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs
index d97a6125b81cb..ad30f1de894d1 100644
--- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs
+++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs
@@ -323,30 +323,38 @@ private async Task> ComputeProjectDiagnosticAnalyzerDiag
private async Task> ComputeDocumentDiagnosticAnalyzerDiagnosticsAsync(
Document document, DocumentDiagnosticAnalyzer analyzer, AnalysisKind kind, Compilation compilationOpt, CancellationToken cancellationToken)
{
- using (var pooledObject = SharedPools.Default>().GetPooledObject())
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
{
- var diagnostics = pooledObject.Object;
- cancellationToken.ThrowIfCancellationRequested();
+ Task> analyzeAsync;
- try
+ switch (kind)
{
- switch (kind)
- {
- case AnalysisKind.Syntax:
- await analyzer.AnalyzeSyntaxAsync(document, diagnostics.Add, cancellationToken).ConfigureAwait(false);
- return compilationOpt == null ? diagnostics.ToImmutableArrayOrEmpty() : CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt);
- case AnalysisKind.Semantic:
- await analyzer.AnalyzeSemanticsAsync(document, diagnostics.Add, cancellationToken).ConfigureAwait(false);
- return compilationOpt == null ? diagnostics.ToImmutableArrayOrEmpty() : CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt);
- default:
- return Contract.FailWithReturn>("shouldn't reach here");
- }
+ case AnalysisKind.Syntax:
+ analyzeAsync = analyzer.AnalyzeSyntaxAsync(document, cancellationToken);
+ break;
+
+ case AnalysisKind.Semantic:
+ analyzeAsync = analyzer.AnalyzeSemanticsAsync(document, cancellationToken);
+ break;
+
+ default:
+ throw ExceptionUtilities.UnexpectedValue(kind);
}
- catch (Exception e) when (!IsCanceled(e, cancellationToken))
+
+ var diagnostics = (await analyzeAsync.ConfigureAwait(false)).NullToEmpty();
+ if (compilationOpt != null)
{
- OnAnalyzerException(analyzer, document.Project.Id, compilationOpt, e);
- return ImmutableArray.Empty;
+ return CompilationWithAnalyzers.GetEffectiveDiagnostics(diagnostics, compilationOpt);
}
+
+ return diagnostics;
+ }
+ catch (Exception e) when (!IsCanceled(e, cancellationToken))
+ {
+ OnAnalyzerException(analyzer, document.Project.Id, compilationOpt, e);
+ return ImmutableArray.Empty;
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/EditAndContinue/VsENCRebuildableProjectImpl.cs b/src/VisualStudio/Core/Def/Implementation/EditAndContinue/VsENCRebuildableProjectImpl.cs
index d4694fc61e648..64b40e516582b 100644
--- a/src/VisualStudio/Core/Def/Implementation/EditAndContinue/VsENCRebuildableProjectImpl.cs
+++ b/src/VisualStudio/Core/Def/Implementation/EditAndContinue/VsENCRebuildableProjectImpl.cs
@@ -79,7 +79,7 @@ internal sealed class VsENCRebuildableProjectImpl
private EmitBaseline _pendingBaseline;
private Project _projectBeingEmitted;
- private ImmutableArray _documentsWithEmitError;
+ private ImmutableArray _documentsWithEmitError = ImmutableArray.Empty;
///
/// Initialized when the project switches to debug state.
@@ -251,11 +251,11 @@ public int StartDebuggingPE()
var descriptor = new DiagnosticDescriptor("Metadata", "Metadata", ServicesVSResources.ErrorWhileReading, DiagnosticCategory.EditAndContinue, DiagnosticSeverity.Error, isEnabledByDefault: true, customTags: DiagnosticCustomTags.EditAndContinue);
- _diagnosticProvider.ReportDiagnostics(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.DebuggerErrorId, _vsProject.Id, _encService.DebuggingSession.InitialSolution,
- new[]
- {
- Diagnostic.Create(descriptor, Location.None, outputPath, e.Message)
- });
+ _diagnosticProvider.ReportDiagnostics(
+ new EncErrorId(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.DebuggerErrorId),
+ _encService.DebuggingSession.InitialSolution,
+ _vsProject.Id,
+ new[] { Diagnostic.Create(descriptor, Location.None, outputPath, e.Message) });
}
}
else
@@ -322,7 +322,8 @@ public int StopDebuggingPE()
else
{
// an error might have been reported:
- _diagnosticProvider.ClearDiagnostics(_encService.DebuggingSession, _vsProject.Workspace, EditAndContinueDiagnosticUpdateSource.DebuggerErrorId, _vsProject.Id, documentId: null);
+ var errorId = new EncErrorId(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.DebuggerErrorId);
+ _diagnosticProvider.ClearDiagnostics(errorId, _vsProject.Workspace.CurrentSolution, _vsProject.Id, documentIdOpt: null);
}
_activeMethods = null;
@@ -908,8 +909,14 @@ public int ExitBreakStateOnPE()
Debug.Assert(s_breakStateProjectCount >= 0);
_changesApplied = false;
- _diagnosticProvider.ClearDiagnostics(_encService.DebuggingSession, _vsProject.Workspace, EditAndContinueDiagnosticUpdateSource.EmitErrorId, _vsProject.Id, _documentsWithEmitError);
- _documentsWithEmitError = default(ImmutableArray);
+
+ _diagnosticProvider.ClearDiagnostics(
+ new EncErrorId(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.EmitErrorId),
+ _vsProject.Workspace.CurrentSolution,
+ _vsProject.Id,
+ _documentsWithEmitError);
+
+ _documentsWithEmitError = ImmutableArray.Empty;
}
// HResult ignored by the debugger
@@ -971,25 +978,21 @@ public unsafe int BuildForEnc(object pUpdatePE)
delta = emitTask.Result;
}
+ var errorId = new EncErrorId(_encService.DebuggingSession, EditAndContinueDiagnosticUpdateSource.EmitErrorId);
+
// Clear diagnostics, in case the project was built before and failed due to errors.
- _diagnosticProvider.ClearDiagnostics(_encService.DebuggingSession, _vsProject.Workspace, EditAndContinueDiagnosticUpdateSource.EmitErrorId, _vsProject.Id, _documentsWithEmitError);
+ _diagnosticProvider.ClearDiagnostics(errorId, _projectBeingEmitted.Solution, _vsProject.Id, _documentsWithEmitError);
if (!delta.EmitResult.Success)
{
var errors = delta.EmitResult.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error);
- _documentsWithEmitError = _diagnosticProvider.ReportDiagnostics(
- _encService.DebuggingSession,
- EditAndContinueDiagnosticUpdateSource.EmitErrorId,
- _vsProject.Id,
- _projectBeingEmitted.Solution,
- errors);
-
+ _documentsWithEmitError = _diagnosticProvider.ReportDiagnostics(errorId, _projectBeingEmitted.Solution, _vsProject.Id, errors);
_encService.EditSession.LogEmitProjectDeltaErrors(errors.Select(e => e.Id));
return VSConstants.E_FAIL;
}
- _documentsWithEmitError = default(ImmutableArray);
+ _documentsWithEmitError = ImmutableArray.Empty;
SetFileUpdates(updater, delta.LineEdits);
updater.SetDeltaIL(delta.IL.Value, (uint)delta.IL.Value.Length);