Skip to content

Commit 1ad248d

Browse files
authored
Merge pull request #69750 from mavasani/OpenFileDiagnosticsRefresh
Update "Current Document" background analysis semantics and fix Full Solution analysis with project config changes
2 parents 280e223 + 15a2ff3 commit 1ad248d

File tree

14 files changed

+234
-78
lines changed

14 files changed

+234
-78
lines changed

src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool
668668
switch (analysisScope)
669669
{
670670
case BackgroundAnalysisScope.None:
671-
case BackgroundAnalysisScope.ActiveFile:
671+
case BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics:
672672
case BackgroundAnalysisScope.OpenFiles:
673673
workspace.OpenAdditionalDocument(firstAdditionalDocument.Id);
674674
await incrementalAnalyzer.AnalyzeNonSourceDocumentAsync(firstAdditionalDocument, InvocationReasons.SyntaxChanged, CancellationToken.None);
@@ -686,7 +686,7 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool
686686

687687
var expectedCount = (analysisScope, testMultiple) switch
688688
{
689-
(BackgroundAnalysisScope.ActiveFile or BackgroundAnalysisScope.None, _) => 0,
689+
(BackgroundAnalysisScope.None or BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics, _) => 0,
690690
(BackgroundAnalysisScope.OpenFiles or BackgroundAnalysisScope.FullSolution, false) => 1,
691691
(BackgroundAnalysisScope.OpenFiles, true) => 2,
692692
(BackgroundAnalysisScope.FullSolution, true) => 4,
@@ -704,7 +704,7 @@ internal async Task TestAdditionalFileAnalyzer(bool registerFromInitialize, bool
704704
d => d.Id == analyzer.Descriptor.Id && d.DataLocation.UnmappedFileSpan.Path == additionalDoc.FilePath);
705705

706706
var text = await additionalDoc.GetTextAsync();
707-
if (analysisScope is BackgroundAnalysisScope.ActiveFile or BackgroundAnalysisScope.None)
707+
if (analysisScope is BackgroundAnalysisScope.None or BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics)
708708
{
709709
Assert.Empty(applicableDiagnostics);
710710
}
@@ -779,7 +779,7 @@ internal async Task TestDiagnosticSuppressor(bool includeAnalyzer, bool includeS
779779
switch (analysisScope)
780780
{
781781
case BackgroundAnalysisScope.None:
782-
case BackgroundAnalysisScope.ActiveFile:
782+
case BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics:
783783
workspace.OpenDocument(document.Id);
784784
var documentTrackingService = (TestDocumentTrackingService)workspace.Services.GetService<IDocumentTrackingService>();
785785
documentTrackingService.SetActiveDocument(document.Id);
@@ -910,7 +910,7 @@ void M()
910910
switch (analysisScope)
911911
{
912912
case BackgroundAnalysisScope.None:
913-
case BackgroundAnalysisScope.ActiveFile:
913+
case BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics:
914914
if (isSourceGenerated)
915915
workspace.OpenSourceGeneratedDocument(document.Id);
916916
else

src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs

Lines changed: 49 additions & 49 deletions
Large diffs are not rendered by default.

src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ static bool IsAnalyzerEnabledForDocument(
9393
CompilerDiagnosticsScope.None => false,
9494

9595
// Compiler diagnostics are enabled for visible documents and open documents which had errors/warnings in prior snapshot.
96-
CompilerDiagnosticsScope.VisibleFilesAndFilesWithPreviouslyReportedDiagnostics => isVisibleDocument || (isOpenDocument && !previousData.Items.IsEmpty),
96+
CompilerDiagnosticsScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics => IsVisibleDocumentOrOpenDocumentWithPriorReportedVisibleDiagnostics(isVisibleDocument, isOpenDocument, previousData),
9797

9898
// Compiler diagnostics are enabled for all open documents.
9999
CompilerDiagnosticsScope.OpenFiles => isOpenDocument,
@@ -111,8 +111,8 @@ static bool IsAnalyzerEnabledForDocument(
111111
// Analyzers are disabled for all documents.
112112
BackgroundAnalysisScope.None => false,
113113

114-
// Analyzers are enabled for active document.
115-
BackgroundAnalysisScope.ActiveFile => isActiveDocument,
114+
// Analyzers are enabled for visible documents and open documents which had errors/warnings in prior snapshot.
115+
BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics => IsVisibleDocumentOrOpenDocumentWithPriorReportedVisibleDiagnostics(isVisibleDocument, isOpenDocument, previousData),
116116

117117
// Analyzers are enabled for all open documents.
118118
BackgroundAnalysisScope.OpenFiles => isOpenDocument,
@@ -124,6 +124,18 @@ static bool IsAnalyzerEnabledForDocument(
124124
};
125125
}
126126
}
127+
128+
static bool IsVisibleDocumentOrOpenDocumentWithPriorReportedVisibleDiagnostics(
129+
bool isVisibleDocument,
130+
bool isOpenDocument,
131+
DocumentAnalysisData previousData)
132+
{
133+
if (isVisibleDocument)
134+
return true;
135+
136+
return isOpenDocument
137+
&& previousData.Items.Any(static d => d.Severity is DiagnosticSeverity.Error or DiagnosticSeverity.Warning or DiagnosticSeverity.Info);
138+
}
127139
}
128140

129141
/// <summary>

src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.ProjectState.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading.Tasks;
1010
using Microsoft.CodeAnalysis.Host;
1111
using Microsoft.CodeAnalysis.Options;
12+
using Microsoft.CodeAnalysis.PooledObjects;
1213
using Microsoft.CodeAnalysis.Shared.Extensions;
1314
using Microsoft.CodeAnalysis.Simplification;
1415
using Microsoft.CodeAnalysis.SolutionCrawler;
@@ -199,12 +200,17 @@ public async ValueTask SaveToInMemoryStorageAsync(Project project, DiagnosticAna
199200

200201
RemoveInMemoryCache(_lastResult);
201202

203+
using var _ = PooledHashSet<DocumentId>.GetInstance(out var documentIdsToProcess);
204+
documentIdsToProcess.AddRange(_lastResult.DocumentIdsOrEmpty);
205+
documentIdsToProcess.AddRange(result.DocumentIdsOrEmpty);
206+
202207
// save last aggregated form of analysis result
203208
_lastResult = result.ToAggregatedForm();
204209

205210
// serialization can't be canceled.
206211
var serializerVersion = result.Version;
207-
foreach (var documentId in result.DocumentIds)
212+
213+
foreach (var documentId in documentIdsToProcess)
208214
{
209215
var document = project.GetTextDocument(documentId);
210216

src/Features/LanguageServer/Protocol/Features/Options/SolutionCrawlerOptionsStorage.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ public static CompilerDiagnosticsScope GetBackgroundCompilerAnalysisScope(this I
7373
{
7474
if (LowMemoryForcedMinimalBackgroundAnalysis)
7575
{
76-
return CompilerDiagnosticsScope.VisibleFilesAndFilesWithPreviouslyReportedDiagnostics;
76+
return CompilerDiagnosticsScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics;
7777
}
7878

7979
return globalOptions.GetOption(SolutionBackgroundAnalysisScopeOption) switch
8080
{
81-
BackgroundAnalysisScope.ActiveFile => CompilerDiagnosticsScope.VisibleFilesAndFilesWithPreviouslyReportedDiagnostics,
81+
BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics => CompilerDiagnosticsScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics,
8282
BackgroundAnalysisScope.OpenFiles => CompilerDiagnosticsScope.OpenFiles,
8383
BackgroundAnalysisScope.FullSolution => CompilerDiagnosticsScope.FullSolution,
8484
BackgroundAnalysisScope.None => CompilerDiagnosticsScope.None,

src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ private protected static InitializationOptions GetInitializationOptions(
324324
compilerDiagnosticsScope ??= analyzerDiagnosticsScope switch
325325
{
326326
BackgroundAnalysisScope.None => CompilerDiagnosticsScope.None,
327-
BackgroundAnalysisScope.ActiveFile => CompilerDiagnosticsScope.VisibleFilesAndFilesWithPreviouslyReportedDiagnostics,
327+
BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics => CompilerDiagnosticsScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics,
328328
BackgroundAnalysisScope.OpenFiles => CompilerDiagnosticsScope.OpenFiles,
329329
BackgroundAnalysisScope.FullSolution => CompilerDiagnosticsScope.FullSolution,
330330
_ => throw ExceptionUtilities.UnexpectedValue(analyzerDiagnosticsScope),

src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static BackgroundAnalysisScope Option_Background_Analysis_Scope_None_Tag
3131
=> BackgroundAnalysisScope.None;
3232

3333
public static BackgroundAnalysisScope Option_Background_Analysis_Scope_Active_File_Tag
34-
=> BackgroundAnalysisScope.ActiveFile;
34+
=> BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics;
3535

3636
public static BackgroundAnalysisScope Option_Background_Analysis_Scope_Open_Files_Tag
3737
=> BackgroundAnalysisScope.OpenFiles;
@@ -58,7 +58,7 @@ public static CompilerDiagnosticsScope Option_Compiler_Diagnostics_Scope_None_Ta
5858
=> CompilerDiagnosticsScope.None;
5959

6060
public static CompilerDiagnosticsScope Option_Compiler_Diagnostics_Scope_Visible_Files_Tag
61-
=> CompilerDiagnosticsScope.VisibleFilesAndFilesWithPreviouslyReportedDiagnostics;
61+
=> CompilerDiagnosticsScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics;
6262

6363
public static CompilerDiagnosticsScope Option_Compiler_Diagnostics_Scope_Open_Files_Tag
6464
=> CompilerDiagnosticsScope.OpenFiles;

src/VisualStudio/Core/Def/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ private void OnSetAnalysisScopeDefaultStatus(object sender, EventArgs e)
154154
=> OnSetAnalysisScopeStatus((OleMenuCommand)sender, scope: null);
155155

156156
private void OnSetAnalysisScopeCurrentDocumentStatus(object sender, EventArgs e)
157-
=> OnSetAnalysisScopeStatus((OleMenuCommand)sender, BackgroundAnalysisScope.ActiveFile);
157+
=> OnSetAnalysisScopeStatus((OleMenuCommand)sender, BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics);
158158

159159
private void OnSetAnalysisScopeOpenDocumentsStatus(object sender, EventArgs e)
160160
=> OnSetAnalysisScopeStatus((OleMenuCommand)sender, BackgroundAnalysisScope.OpenFiles);
@@ -195,7 +195,7 @@ private void OnSetAnalysisScopeStatus(OleMenuCommand command, BackgroundAnalysis
195195
{
196196
command.Text = GetBackgroundAnalysisScope(_workspace.CurrentSolution, _globalOptions) switch
197197
{
198-
BackgroundAnalysisScope.ActiveFile => ServicesVSResources.Default_Current_Document,
198+
BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics => ServicesVSResources.Default_Current_Document,
199199
BackgroundAnalysisScope.OpenFiles => ServicesVSResources.Default_Open_Documents,
200200
BackgroundAnalysisScope.FullSolution => ServicesVSResources.Default_Entire_Solution,
201201
BackgroundAnalysisScope.None => ServicesVSResources.Default_None,
@@ -235,7 +235,7 @@ private void OnSetAnalysisScopeDefault(object sender, EventArgs args)
235235
=> OnSetAnalysisScope(scope: null);
236236

237237
private void OnSetAnalysisScopeCurrentDocument(object sender, EventArgs args)
238-
=> OnSetAnalysisScope(BackgroundAnalysisScope.ActiveFile);
238+
=> OnSetAnalysisScope(BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics);
239239

240240
private void OnSetAnalysisScopeOpenDocuments(object sender, EventArgs args)
241241
=> OnSetAnalysisScope(BackgroundAnalysisScope.OpenFiles);

src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpCodeActions.cs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313
using Microsoft.CodeAnalysis.CodeFixes;
1414
using Microsoft.CodeAnalysis.CodeRefactorings;
1515
using Microsoft.CodeAnalysis.Host.Mef;
16+
using Microsoft.CodeAnalysis.PooledObjects;
1617
using Microsoft.CodeAnalysis.Shared.TestHooks;
18+
using Microsoft.CodeAnalysis.SolutionCrawler;
1719
using Microsoft.CodeAnalysis.Test.Utilities;
1820
using Microsoft.CodeAnalysis.Text;
1921
using Microsoft.VisualStudio.Extensibility.Testing;
22+
using Microsoft.VisualStudio.Shell.TableManager;
2023
using Roslyn.Test.Utilities;
2124
using Roslyn.VisualStudio.IntegrationTests;
2225
using Roslyn.VisualStudio.IntegrationTests.InProcess;
@@ -914,6 +917,127 @@ static async Task VerifyDiagnosticInErrorListAsync(string expectedSeverity, Test
914917
}
915918
}
916919

920+
[IdeTheory, Trait(Traits.Feature, Traits.Features.CodeActionsConfiguration)]
921+
[InlineData(BackgroundAnalysisScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics, CompilerDiagnosticsScope.VisibleFilesAndOpenFilesWithPreviouslyReportedDiagnostics)]
922+
[InlineData(BackgroundAnalysisScope.FullSolution, CompilerDiagnosticsScope.FullSolution)]
923+
internal async Task ConfigureSeverityWithManualEditsToEditorconfig_CurrentDocumentScope(BackgroundAnalysisScope analyzerScope, CompilerDiagnosticsScope compilerScope)
924+
{
925+
var markup1 = @"
926+
class C
927+
{
928+
public static void Main()
929+
{
930+
// CS0219: The variable 'x' is assigned but its value is never used
931+
// IDE0059: Unnecessary assignment of a value to 'x'
932+
int x = 0;
933+
}
934+
}";
935+
936+
var markup2 = @"
937+
class C2
938+
{
939+
public static void M()
940+
{
941+
// CS0219: The variable 'y' is assigned but its value is never used
942+
// IDE0059: Unnecessary assignment of a value to 'y'
943+
int $$y = 0;
944+
}
945+
}";
946+
await TestServices.Workspace.SetBackgroundAnalysisOptionsAsync(analyzerScope, compilerScope, HangMitigatingCancellationToken);
947+
948+
await SetUpEditorAsync(markup2, HangMitigatingCancellationToken);
949+
950+
await TestServices.Workspace.WaitForAllAsyncOperationsAsync(
951+
new[]
952+
{
953+
FeatureAttribute.Workspace,
954+
FeatureAttribute.SolutionCrawlerLegacy,
955+
FeatureAttribute.DiagnosticService,
956+
FeatureAttribute.ErrorSquiggles,
957+
},
958+
HangMitigatingCancellationToken);
959+
960+
await TestServices.SolutionExplorer.AddFileAsync(ProjectName, "Class2.cs", markup1, open: true, cancellationToken: HangMitigatingCancellationToken);
961+
962+
await TestServices.Workspace.WaitForAllAsyncOperationsAsync(
963+
new[]
964+
{
965+
FeatureAttribute.Workspace,
966+
FeatureAttribute.SolutionCrawlerLegacy,
967+
FeatureAttribute.DiagnosticService,
968+
FeatureAttribute.ErrorSquiggles,
969+
},
970+
HangMitigatingCancellationToken);
971+
972+
// Verify compiler and analyzer diagnostics in original code.
973+
await VerifyDiagnosticsInErrorListAsync("warning", "info", TestServices, HangMitigatingCancellationToken);
974+
975+
// Add an .editorconfig file to the project to change severities to error.
976+
await TestServices.SolutionExplorer.AddFileAsync(ProjectName, ".editorconfig", open: true, cancellationToken: HangMitigatingCancellationToken);
977+
await TestServices.Editor.SetTextAsync(@"
978+
[*.cs]
979+
dotnet_diagnostic.CS0219.severity = error
980+
dotnet_diagnostic.IDE0059.severity = error", HangMitigatingCancellationToken);
981+
982+
await TestServices.Workspace.WaitForAllAsyncOperationsAsync(
983+
new[]
984+
{
985+
FeatureAttribute.Workspace,
986+
FeatureAttribute.SolutionCrawlerLegacy,
987+
FeatureAttribute.DiagnosticService,
988+
FeatureAttribute.ErrorSquiggles,
989+
},
990+
HangMitigatingCancellationToken);
991+
992+
// Verify compiler and analyzer diagnostics are now reported as errors.
993+
await VerifyDiagnosticsInErrorListAsync("error", "error", TestServices, HangMitigatingCancellationToken);
994+
995+
// Edit editorconfig file to disable both compiler and analyzer diagnostics.
996+
await TestServices.Editor.SetTextAsync(@"
997+
[*.cs]
998+
dotnet_diagnostic.CS0219.severity = none
999+
dotnet_diagnostic.IDE0059.severity = none", HangMitigatingCancellationToken);
1000+
1001+
await TestServices.Workspace.WaitForAllAsyncOperationsAsync(
1002+
new[]
1003+
{
1004+
FeatureAttribute.Workspace,
1005+
FeatureAttribute.SolutionCrawlerLegacy,
1006+
FeatureAttribute.DiagnosticService,
1007+
FeatureAttribute.ErrorSquiggles,
1008+
},
1009+
HangMitigatingCancellationToken);
1010+
1011+
// Verify compiler and analyzer diagnostics are now cleared.
1012+
await VerifyDiagnosticsInErrorListAsync("none", "none", TestServices, HangMitigatingCancellationToken);
1013+
1014+
static async Task VerifyDiagnosticsInErrorListAsync(string expectedCompilerDiagnosticSeverity, string expectedAnalyzerDiagnosticSeverity, TestServices testServices, CancellationToken cancellationToken)
1015+
{
1016+
await testServices.ErrorList.ShowErrorListAsync(cancellationToken);
1017+
1018+
using var _ = ArrayBuilder<string>.GetInstance(out var expectedContentsBuilder);
1019+
1020+
if (expectedCompilerDiagnosticSeverity != "none")
1021+
{
1022+
expectedContentsBuilder.Add($"(Compiler) Class1.cs(8, 13): {expectedCompilerDiagnosticSeverity} CS0219: The variable 'y' is assigned but its value is never used");
1023+
expectedContentsBuilder.Add($"(Compiler) Class2.cs(8, 13): {expectedCompilerDiagnosticSeverity} CS0219: The variable 'x' is assigned but its value is never used");
1024+
}
1025+
1026+
if (expectedAnalyzerDiagnosticSeverity != "none")
1027+
{
1028+
expectedContentsBuilder.Add($"(Compiler) Class1.cs(8, 13): {expectedAnalyzerDiagnosticSeverity} IDE0059: Unnecessary assignment of a value to 'y'");
1029+
expectedContentsBuilder.Add($"(Compiler) Class2.cs(8, 13): {expectedAnalyzerDiagnosticSeverity} IDE0059: Unnecessary assignment of a value to 'x'");
1030+
}
1031+
1032+
var expectedContents = expectedContentsBuilder.ToImmutable().Sort();
1033+
var actualContents = await testServices.ErrorList.GetErrorsAsync(ErrorSource.Other, Microsoft.VisualStudio.Shell.Interop.__VSERRORCATEGORY.EC_MESSAGE, cancellationToken);
1034+
1035+
AssertEx.EqualOrDiff(
1036+
string.Join(Environment.NewLine, expectedContents),
1037+
string.Join(Environment.NewLine, actualContents));
1038+
}
1039+
}
1040+
9171041
[IdeFact]
9181042
[Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)]
9191043
public async Task TestFixAllOccurrences_CodeFix_ContainingMember()

0 commit comments

Comments
 (0)