diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 6e35ba05afac9..0276f31c75f07 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -4680,6 +4680,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs index 6f38af066cf86..3dbf1fdf79aea 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs @@ -127,6 +127,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar string? runtimeMetadataVersion = null; bool errorEndLocation = false; bool reportAnalyzer = false; + bool skipAnalyzers = false; ArrayBuilder instrumentationKinds = ArrayBuilder.GetInstance(); CultureInfo? preferredUILang = null; string? touchedFilesPath = null; @@ -1179,6 +1180,21 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar reportAnalyzer = true; continue; + case "skipanalyzers": + case "skipanalyzers+": + if (value != null) + break; + + skipAnalyzers = true; + continue; + + case "skipanalyzers-": + if (value != null) + break; + + skipAnalyzers = false; + continue; + case "nostdlib": case "nostdlib+": if (value != null) @@ -1503,6 +1519,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar ShouldIncludeErrorEndLocation = errorEndLocation, PreferredUILang = preferredUILang, ReportAnalyzer = reportAnalyzer, + SkipAnalyzers = skipAnalyzers, EmbeddedFiles = embeddedFiles.AsImmutable() }; } diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs index 743d9fedd6e9c..1bc7ad9b8496d 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCompiler.cs @@ -361,10 +361,11 @@ protected override bool TryGetCompilerDiagnosticCode(string diagnosticId, out ui protected override void ResolveAnalyzersFromArguments( List diagnostics, CommonMessageProvider messageProvider, + bool skipAnalyzers, out ImmutableArray analyzers, out ImmutableArray generators) { - Arguments.ResolveAnalyzersFromArguments(LanguageNames.CSharp, diagnostics, messageProvider, AssemblyLoader, out analyzers, out generators); + Arguments.ResolveAnalyzersFromArguments(LanguageNames.CSharp, diagnostics, messageProvider, AssemblyLoader, skipAnalyzers, out analyzers, out generators); } protected override void ResolveEmbeddedFilesFromExternalSourceDirectives( diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 04249de6bedf9..ae96939ff6aa9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 1996a351256c8..97430eb68ce8b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 74f0519f95da7..0ce045c0c07d3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index f606678c3ae57..d6922fa6d755a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 36ad6c93f3d14..7601491e2ccc4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index f287bb374e8f1..e8e1ab5cc9ac3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index d86934dcca3bb..54370f59cb5f5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index c1a419f934cd3..946a525c1c38a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index a4bc18e2ffae4..c14b0879180e5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 45a12515a5951..b201d10c08375 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 3cf885532a4c1..b679651f1a5a8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 8220b7f143adc..ad1d5639ff738 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index a308b27a26ebc..9e45c477929fb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1016,6 +1016,7 @@ both mean SARIF version 2.1.0. -reportanalyzer Report additional analyzer information, such as execution time. +-skipanalyzers[+|-] Skip execution of diagnostic analyzers. - LANGUAGE - -checked[+|-] Generate overflow checks diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index 37cc427d8de26..f705a1f6caed2 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -9129,6 +9129,66 @@ public void ReportAnalyzerOutput() CleanupAllGeneratedFiles(srcFile.Path); } + [Fact] + [WorkItem(40926, "https://github.com/dotnet/roslyn/issues/40926")] + public void SkipAnalyzersParse() + { + var parsedArgs = DefaultParse(new[] { "a.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.False(parsedArgs.SkipAnalyzers); + + parsedArgs = DefaultParse(new[] { "/skipanalyzers+", "a.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.True(parsedArgs.SkipAnalyzers); + + parsedArgs = DefaultParse(new[] { "/skipanalyzers", "a.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.True(parsedArgs.SkipAnalyzers); + + parsedArgs = DefaultParse(new[] { "/SKIPANALYZERS+", "a.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.True(parsedArgs.SkipAnalyzers); + + parsedArgs = DefaultParse(new[] { "/skipanalyzers-", "a.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.False(parsedArgs.SkipAnalyzers); + + parsedArgs = DefaultParse(new[] { "/skipanalyzers-", "/skipanalyzers+", "a.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.True(parsedArgs.SkipAnalyzers); + + parsedArgs = DefaultParse(new[] { "/skipanalyzers", "/skipanalyzers-", "a.cs" }, WorkingDirectory); + parsedArgs.Errors.Verify(); + Assert.False(parsedArgs.SkipAnalyzers); + } + + [Theory, CombinatorialData] + [WorkItem(40926, "https://github.com/dotnet/roslyn/issues/40926")] + public void SkipAnalyzersSemantics(bool skipAnalyzers) + { + var srcFile = Temp.CreateFile().WriteAllText(@"class C {}"); + var srcDirectory = Path.GetDirectoryName(srcFile.Path); + + var outWriter = new StringWriter(CultureInfo.InvariantCulture); + var skipAnalyzersFlag = "/skipanalyzers" + (skipAnalyzers ? "+" : "-"); + var csc = CreateCSharpCompiler(null, srcDirectory, new[] { skipAnalyzersFlag, "/reportanalyzer", "/t:library", "/a:" + Assembly.GetExecutingAssembly().Location, srcFile.Path }); + var exitCode = csc.Run(outWriter); + Assert.Equal(0, exitCode); + var output = outWriter.ToString(); + if (skipAnalyzers) + { + Assert.DoesNotContain(CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader, output, StringComparison.Ordinal); + Assert.DoesNotContain(new WarningDiagnosticAnalyzer().ToString(), output, StringComparison.Ordinal); + } + else + { + Assert.Contains(CodeAnalysisResources.AnalyzerExecutionTimeColumnHeader, output, StringComparison.Ordinal); + Assert.Contains(new WarningDiagnosticAnalyzer().ToString(), output, StringComparison.Ordinal); + } + + CleanupAllGeneratedFiles(srcFile.Path); + } + [Fact] [WorkItem(24835, "https://github.com/dotnet/roslyn/issues/24835")] public void TestCompilationSuccessIfOnlySuppressedDiagnostics() @@ -12249,6 +12309,55 @@ class C CleanupAllGeneratedFiles(src.Path); } + [Theory, CombinatorialData] + [WorkItem(40926, "https://github.com/dotnet/roslyn/issues/40926")] + public void TestSourceGeneratorsWithAnalyzers(bool includeCurrentAssemblyAsAnalyzerReference, bool skipAnalyzers) + { + var dir = Temp.CreateDirectory(); + var src = dir.CreateFile("temp.cs").WriteAllText(@" +class C +{ +}"); + + var generatedSource = "public class D { }"; + var generator = new SingleFileTestGenerator(generatedSource, "generatedSource.cs"); + + // 'skipAnalyzers' should have no impact on source generator execution, but should prevent analyzer execution. + var skipAnalyzersFlag = "/skipAnalyzers" + (skipAnalyzers ? "+" : "-"); + + // Verify analyzers were executed only if both the following conditions were satisfied: + // 1. Current assembly was added as an analyzer reference, i.e. "includeCurrentAssemblyAsAnalyzerReference = true" and + // 2. We did not explicitly request skipping analyzers, i.e. "skipAnalyzers = false". + var expectedAnalayzerExecution = includeCurrentAssemblyAsAnalyzerReference && !skipAnalyzers; + + // 'WarningDiagnosticAnalyzer' generates a warning for each named type. + // We expect two warnings for this test: type "C" defined in source and the source generator defined type. + // Additionally, we also have an analyzer that generates "warning CS8032: An instance of analyzer cannot be created" + var expectedWarningCount = expectedAnalayzerExecution ? 3 : 0; + + var output = VerifyOutput(dir, src, includeCurrentAssemblyAsAnalyzerReference, + expectedWarningCount: expectedWarningCount, + additionalFlags: new[] { "/langversion:preview", "/debug:embedded", "/out:embed.exe", skipAnalyzersFlag }, + generators: new[] { generator }); + + // Verify source generator was executed, regardless of the value of 'skipAnalyzers'. + var generatorPrefix = $"{generator.GetType().Module.ModuleVersionId}_{generator.GetType().FullName}"; + ValidateEmbeddedSources_Portable(new Dictionary { { Path.Combine(dir.Path, $"{generatorPrefix}_generatedSource.cs"), generatedSource } }, dir, true); + + if (expectedAnalayzerExecution) + { + Assert.Contains("warning Warning01", output, StringComparison.Ordinal); + Assert.Contains("warning CS8032", output, StringComparison.Ordinal); + } + else + { + Assert.Empty(output); + } + + // Clean up temp files + CleanupAllGeneratedFiles(src.Path); + } + [Theory] [InlineData("partial class D {}", "file1.cs", "partial class E {}", "file2.cs")] // different files, different names [InlineData("partial class D {}", "file1.cs", "partial class E {}", "file1.cs")] // different files, same names diff --git a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs index 73eac0a28b6f9..96fc7cd9f8382 100644 --- a/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs +++ b/src/Compilers/Core/MSBuildTask/ManagedCompiler.cs @@ -316,6 +316,12 @@ public string? SharedCompilationId get { return (string?)_store[nameof(SharedCompilationId)]; } } + public bool SkipAnalyzers + { + set { _store[nameof(SkipAnalyzers)] = value; } + get { return _store.GetOrDefault(nameof(SkipAnalyzers), false); } + } + public bool SkipCompilerExecution { set { _store[nameof(SkipCompilerExecution)] = value; } @@ -830,6 +836,7 @@ internal void AddResponseFileCommandsForSwitchesSinceInitialReleaseThatAreNeeded commandLine.AppendSwitchWithSplitting("/instrument:", Instrument, ",", ';', ','); commandLine.AppendSwitchIfNotNull("/sourcelink:", SourceLink); commandLine.AppendSwitchIfNotNull("/langversion:", LangVersion); + commandLine.AppendPlusOrMinusSwitch("/skipanalyzers", _store, nameof(SkipAnalyzers)); AddFeatures(commandLine, Features); AddEmbeddedFilesToCommandLine(commandLine); diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets index fd58376a7e958..76f3f1d7f54bc 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.CSharp.Core.targets @@ -126,6 +126,7 @@ ResponseFiles="$(CompilerResponseFile)" RuntimeMetadataVersion="$(RuntimeMetadataVersion)" SharedCompilationId="$(SharedCompilationId)" + SkipAnalyzers="$(_SkipAnalyzers)" SkipCompilerExecution="$(SkipCompilerExecution)" Sources="@(Compile)" SubsystemVersion="$(SubsystemVersion)" diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets b/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets index 5949476b91651..15c9229883e72 100644 --- a/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets +++ b/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets @@ -50,6 +50,28 @@ + + + + <_SkipAnalyzers> + + + + + <_SkipAnalyzers>true + + +