diff --git a/AGENTS.md b/AGENTS.md index 06e33c132..4af0e6205 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -55,7 +55,7 @@ The analyzer must use `IOperation` or `ISymbol` to analyze the content. Only fal ### Generated code -The analyzers analyze generated code, so they must call `context.ConfigureAnalysisOfGeneratedCode(...)` in `Initialize` instead of `ConfigureGeneratedCodeAnalysis`, which `BannedSymbols.txt` makes a compilation error: the flags passed to it are the minimum, and `Analyze | ReportDiagnostics` is added to them unless the `MEZIANTOU_ANALYZER_GENERATED_CODE` environment variable opts out, as analyzing generated code has a cost. Pass `GeneratedCodeAnalysisFlags.None` unless the rule needs generated code to be correct even when a user opts out (`Analyze`), or reports in generated code by default (`Analyze | ReportDiagnostics`). The diagnostics located in generated code are filtered when they are reported. The filtering is done by `GeneratedCodeReporting`, which sets the `DiagnosticReporter.CanReportDiagnostic` filter of `Meziantou.Framework.Roslyn` from a module initializer, so the rules must report their diagnostics with the `ReportDiagnostic` extension methods of the analysis contexts or with a `DiagnosticReporter`; `BannedSymbols.txt` makes reporting directly on a Roslyn context a compilation error, as it would bypass the filter. Add `customTags: [GeneratedCodeReporting.ReportInGeneratedCodeTag]` to the descriptor of the rules that must report in generated code by default, such as the rules whose subject is the generated file itself, use `GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics` in their analyzer, and run `dotnet run --project src/DocumentationGenerator` to update the list in [`docs/generated-code.md`](/docs/generated-code.md). +The analyzers skip generated code, so they must call `context.ConfigureAnalysisOfGeneratedCode(...)` in `Initialize` instead of `ConfigureGeneratedCodeAnalysis`, which `BannedSymbols.txt` makes a compilation error: the flags passed to it are the minimum, and `Analyze | ReportDiagnostics` is added to them only when the `MEZIANTOU_ANALYZER_GENERATED_CODE` environment variable opts in, as analyzing generated code has a cost. Pass `GeneratedCodeAnalysisFlags.None` unless the rule needs generated code to be correct even when nobody opts in (`Analyze`), or reports in generated code by default (`Analyze | ReportDiagnostics`). The diagnostics located in generated code are filtered when they are reported. The filtering is done by `GeneratedCodeReporting`, which sets the `DiagnosticReporter.CanReportDiagnostic` filter of `Meziantou.Framework.Roslyn` from a module initializer, so the rules must report their diagnostics with the `ReportDiagnostic` extension methods of the analysis contexts or with a `DiagnosticReporter`; `BannedSymbols.txt` makes reporting directly on a Roslyn context a compilation error, as it would bypass the filter. Add `customTags: [GeneratedCodeReporting.ReportInGeneratedCodeTag]` to the descriptor of the rules that must report in generated code by default, such as the rules whose subject is the generated file itself, use `GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics` in their analyzer, and run `dotnet run --project src/DocumentationGenerator` to update the list in [`docs/generated-code.md`](/docs/generated-code.md). Code snippets in tests must use raw string literals (`"""`) and must be minimized to only include the necessary code to reproduce the issue. Avoid including unnecessary code that does not contribute to the test case. When reporting a diagnostic, the snippet must use the `[|code|]` syntax or `{|id:code|}` syntax. Do not explicitly indicates lines or columns. diff --git a/README.md b/README.md index bb35c6e35..04d1d4db9 100755 --- a/README.md +++ b/README.md @@ -298,8 +298,19 @@ Supported values are: ## Analyzing generated code -The rules analyze generated code, but most of them do not report the diagnostics located in generated code. Set -`report_generated_code` in the `.editorconfig` file to change it, for a single rule or for all of them at once: +The rules skip generated code, as analyzing it costs build time and you cannot fix code you do not own. Set the +`MEZIANTOU_ANALYZER_GENERATED_CODE` environment variable to `true` (or `1`) to opt in, which makes the rules analyze +generated code: + +```bash +MEZIANTOU_ANALYZER_GENERATED_CODE=true +``` + +Note that the analyzers run in a long-lived process. After changing the variable, run `dotnet build-server shutdown` +and rebuild, or restart your IDE. + +Opting in does not report anything by itself: `report_generated_code` decides whether a rule reports the diagnostics +located in the generated code it analyzes, for a single rule or for all of them at once: ```ini [*.cs] @@ -310,18 +321,8 @@ MA.report_generated_code = true MA0051.report_generated_code = false ``` -A few rules report in generated code by default, such as the Blazor rules that work on the code generated from the -`.razor` files. - -Analyzing generated code costs build time. Set the `MEZIANTOU_ANALYZER_GENERATED_CODE` environment variable to -`false` (or `0`) to opt out, which makes the rules skip generated code entirely, except the few that need it: - -```bash -MEZIANTOU_ANALYZER_GENERATED_CODE=false -``` - -Note that the analyzers run in a long-lived process. After changing the variable, run `dotnet build-server shutdown` -and rebuild, or restart your IDE. +A few rules analyze generated code without the variable, and report in it by default, such as the Blazor rules that +work on the code generated from the `.razor` files. See [Analyzing generated code](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/generated-code.md) for the list of those rules and for the detection of the generated files. diff --git a/docs/generated-code.md b/docs/generated-code.md index 048759cf6..ba79e018d 100644 --- a/docs/generated-code.md +++ b/docs/generated-code.md @@ -1,14 +1,15 @@ # Analyzing generated code -The rules analyze generated code, so they see the whole compilation, but most of them do not report the diagnostics -located in generated code, which is the expected behavior for the vast majority of projects: you cannot fix code you -do not own. Some rules are the exception and report in generated code by default, as the generated file is the -subject of the rule, such as the Blazor rules that work on the code generated from the `.razor` files. +The rules skip generated code, which is the expected behavior for the vast majority of projects: you cannot fix code +you do not own, and analyzing code nobody looks at costs build time. Some rules are the exception and analyze it +anyway: the ones whose subject is the generated file itself, such as the Blazor rules that work on the code generated +from the `.razor` files, and the ones that need to see the whole compilation to be correct. Set the +`MEZIANTOU_ANALYZER_GENERATED_CODE` environment variable to opt in to analyzing generated code with every rule. ## Configuration -The `report_generated_code` option indicates whether a rule reports the diagnostics located in generated code. It can -be set for a single rule, or for all of them at once with the `MA` prefix: +The `report_generated_code` option indicates whether a rule reports the diagnostics located in the generated code it +analyzes. It can be set for a single rule, or for all of them at once with the `MA` prefix: ```ini [*.cs] @@ -35,24 +36,23 @@ MA0051.report_generated_code = true When neither is set, each rule uses its own default, which is to not report in generated code, except for the rules below. To turn off a rule entirely, set its severity to `none` instead. -## Opting out with the environment variable +This option only decides what a rule reports, not what it analyzes, so `report_generated_code = true` has no effect on +a rule that does not analyze generated code: it needs the environment variable below. Setting it to `false` always +works, as a rule can only report what it is allowed to report. -Analyzing generated code costs build time, and a project where nothing reports in generated code pays it for nothing. -Set the `MEZIANTOU_ANALYZER_GENERATED_CODE` environment variable to skip generated code entirely: +## Opting in with the environment variable + +Set the `MEZIANTOU_ANALYZER_GENERATED_CODE` environment variable to analyze generated code with every rule: | Value | Behavior | |-------|----------| -| not set, empty, or any other value | The rules analyze generated code, and `report_generated_code` decides what they report | -| `false` (case-insensitive) or `0` | The rules skip generated code, except the ones that need it | - -The variable can only remove analysis from the rules that do not need it. Two kinds of rules are unaffected: the ones -that report in generated code by default, listed below, and the ones that need to see the whole compilation to be -correct, such as MA0053, which reports a class that no other class inherits from and would report a false positive if -the deriving class were declared in a generated file. +| `true` (case-insensitive) or `1` | The rules analyze generated code, and `report_generated_code` decides what they report | +| not set, empty, or any other value | The rules skip generated code, except the ones that need it | -The option above only decides what the rules report, not what they analyze, so `report_generated_code = true` has no -effect on a rule that skips generated code because of the variable. Setting it to `false` always works, as a rule can -only report what it is allowed to report. +Two kinds of rules analyze generated code without the variable: the ones that report in generated code by default, +listed below, and the ones that need to see the whole compilation to be correct, such as MA0053, which reports a class +that no other class inherits from and would report a false positive if the deriving class were declared in a generated +file. `report_generated_code` works on those rules whether the variable is set or not. ## Rules reporting in generated code by default @@ -99,8 +99,9 @@ written file does not make the code generated, and a partial type declared in a one reports only in the hand written file. Use the `generated_code` option below for the files the detection does not recognize. -The rules that skip generated code because of the environment variable never see it, so they follow the detection of -Roslyn instead, which also considers the symbols marked with `[GeneratedCode]` or `[DebuggerNonUserCode]` generated. +The rules that do not analyze generated code never see it, so they follow the detection of Roslyn instead, which also +considers the symbols marked with `[GeneratedCode]` or `[DebuggerNonUserCode]` generated. The two detections only +differ for a rule the variable opted in. ## Using the `generated_code` option @@ -121,7 +122,7 @@ generated, and `generated_code` when you want all the analyzers to treat a speci An analyzer must declare how it handles generated code from `Initialize(AnalysisContext)`, and the options of the `.editorconfig` files are not available at that point: they can only be read from the analysis callbacks, which run later. An environment variable is the only configuration that can be read early enough, which is why the global -opt-out is not an `.editorconfig` option. +opt-in is not an `.editorconfig` option. This has consequences that are worth knowing: diff --git a/src/Meziantou.Analyzer/BannedSymbols.txt b/src/Meziantou.Analyzer/BannedSymbols.txt index 3ba2cee74..d3e53c5c7 100644 --- a/src/Meziantou.Analyzer/BannedSymbols.txt +++ b/src/Meziantou.Analyzer/BannedSymbols.txt @@ -1,5 +1,5 @@ M:Microsoft.CodeAnalysis.Compilation.GetTypeByMetadataName(System.String); Use GetBestTypeByMetadataName instead -M:Microsoft.CodeAnalysis.Diagnostics.AnalysisContext.ConfigureGeneratedCodeAnalysis(Microsoft.CodeAnalysis.Diagnostics.GeneratedCodeAnalysisFlags); Use ConfigureAnalysisOfGeneratedCode instead, so users can opt out of analyzing generated code +M:Microsoft.CodeAnalysis.Diagnostics.AnalysisContext.ConfigureGeneratedCodeAnalysis(Microsoft.CodeAnalysis.Diagnostics.GeneratedCodeAnalysisFlags); Use ConfigureAnalysisOfGeneratedCode instead, so users can opt in to analyzing generated code M:Microsoft.CodeAnalysis.Diagnostics.SymbolAnalysisContext.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic); Use the ReportDiagnostic methods of ContextExtensions instead, so the diagnostics located in generated code are filtered by GeneratedCodeReporting M:Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic); Use the ReportDiagnostic methods of ContextExtensions instead, so the diagnostics located in generated code are filtered by GeneratedCodeReporting M:Microsoft.CodeAnalysis.Diagnostics.OperationBlockAnalysisContext.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic); Use the ReportDiagnostic methods of ContextExtensions instead, so the diagnostics located in generated code are filtered by GeneratedCodeReporting diff --git a/src/Meziantou.Analyzer/Internals/AnalysisContextExtensions.cs b/src/Meziantou.Analyzer/Internals/AnalysisContextExtensions.cs index c0ac95169..b31e72228 100644 --- a/src/Meziantou.Analyzer/Internals/AnalysisContextExtensions.cs +++ b/src/Meziantou.Analyzer/Internals/AnalysisContextExtensions.cs @@ -14,11 +14,11 @@ internal static class AnalysisContextExtensions private static readonly GeneratedCodeAnalysisFlags AdditionalFlags = GetAdditionalFlags(ReadEnvironmentVariable()); /// - /// Configures how the analyzer handles generated code. The rules analyze generated code and report the - /// diagnostics located in it, which then filters, unless the - /// MEZIANTOU_ANALYZER_GENERATED_CODE environment variable opts out, as analyzing generated code has a - /// cost. is the minimum, which opting out cannot remove: it is what the rule - /// needs to be correct, or to report in generated code by default. + /// Configures how the analyzer handles generated code. The rules skip generated code, as analyzing it has a + /// cost, unless the MEZIANTOU_ANALYZER_GENERATED_CODE environment variable opts in, in which case they + /// analyze it and report the diagnostics located in it, which then + /// filters. is the minimum, which not opting in cannot remove: it is what the + /// rule needs to be correct, or to report in generated code by default. /// public static void ConfigureAnalysisOfGeneratedCode(this AnalysisContext context, GeneratedCodeAnalysisFlags defaultFlags) { @@ -29,9 +29,9 @@ public static void ConfigureAnalysisOfGeneratedCode(this AnalysisContext context internal static GeneratedCodeAnalysisFlags GetAdditionalFlags(string? value) => value?.Trim() switch { - "0" => GeneratedCodeAnalysisFlags.None, - var trimmed when string.Equals(trimmed, "false", StringComparison.OrdinalIgnoreCase) => GeneratedCodeAnalysisFlags.None, - _ => GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics, + "1" => GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics, + var trimmed when string.Equals(trimmed, "true", StringComparison.OrdinalIgnoreCase) => GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics, + _ => GeneratedCodeAnalysisFlags.None, }; private static string? ReadEnvironmentVariable() diff --git a/src/Meziantou.Analyzer/Internals/GeneratedCodeReporting.cs b/src/Meziantou.Analyzer/Internals/GeneratedCodeReporting.cs index b9984bf41..74d2f6875 100644 --- a/src/Meziantou.Analyzer/Internals/GeneratedCodeReporting.cs +++ b/src/Meziantou.Analyzer/Internals/GeneratedCodeReporting.cs @@ -4,12 +4,12 @@ namespace Meziantou.Analyzer.Internals; /// -/// Decides whether a rule reports the diagnostics located in generated code. The analyzers configure Roslyn to -/// analyze generated code and to report the diagnostics located in it, as ConfigureGeneratedCodeAnalysis +/// Decides whether a rule reports the diagnostics located in generated code. The analyzers that analyze generated +/// code also configure Roslyn to report the diagnostics located in it, as ConfigureGeneratedCodeAnalysis /// cannot read the .editorconfig options, so the decision is taken when a diagnostic is reported. The -/// options below only apply to what the analyzers actually analyze: a rule stops reporting in generated code when -/// the MEZIANTOU_ANALYZER_GENERATED_CODE environment variable opts out of analyzing it, unless the rule -/// needs it (see ). +/// options below only apply to what the analyzers actually analyze: a rule only reports in generated code when the +/// MEZIANTOU_ANALYZER_GENERATED_CODE environment variable opts in to analyzing it, unless the rule analyzes +/// it anyway (see ). /// internal static class GeneratedCodeReporting { diff --git a/tests/Meziantou.Analyzer.Test/Internals/AnalysisContextExtensionsTests.cs b/tests/Meziantou.Analyzer.Test/Internals/AnalysisContextExtensionsTests.cs index 906847ea9..e56a6d3d3 100644 --- a/tests/Meziantou.Analyzer.Test/Internals/AnalysisContextExtensionsTests.cs +++ b/tests/Meziantou.Analyzer.Test/Internals/AnalysisContextExtensionsTests.cs @@ -6,28 +6,28 @@ namespace Meziantou.Analyzer.Test.Internals; public sealed class AnalysisContextExtensionsTests { [Theory] - [InlineData("0")] - [InlineData(" 0 ")] - [InlineData("false")] - [InlineData("False")] - [InlineData("FALSE")] - [InlineData(" false ")] - public void GetAdditionalFlags_OptedOut(string value) + [InlineData("1")] + [InlineData(" 1 ")] + [InlineData("true")] + [InlineData("True")] + [InlineData("TRUE")] + [InlineData(" true ")] + public void GetAdditionalFlags_OptedIn(string value) { - Assert.Equal(GeneratedCodeAnalysisFlags.None, AnalysisContextExtensions.GetAdditionalFlags(value)); + Assert.Equal(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics, AnalysisContextExtensions.GetAdditionalFlags(value)); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] - [InlineData("1")] - [InlineData("true")] - [InlineData("True")] + [InlineData("0")] + [InlineData("false")] + [InlineData("False")] [InlineData("dummy")] - [InlineData("falsy")] - public void GetAdditionalFlags_NotOptedOut(string? value) + [InlineData("truthy")] + public void GetAdditionalFlags_NotOptedIn(string? value) { - Assert.Equal(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics, AnalysisContextExtensions.GetAdditionalFlags(value)); + Assert.Equal(GeneratedCodeAnalysisFlags.None, AnalysisContextExtensions.GetAdditionalFlags(value)); } } diff --git a/tests/Meziantou.Analyzer.Test/Rules/GeneratedCodeAnalysisTests.cs b/tests/Meziantou.Analyzer.Test/Rules/GeneratedCodeAnalysisTests.cs index 52a70d9fc..af4247e63 100644 --- a/tests/Meziantou.Analyzer.Test/Rules/GeneratedCodeAnalysisTests.cs +++ b/tests/Meziantou.Analyzer.Test/Rules/GeneratedCodeAnalysisTests.cs @@ -14,14 +14,15 @@ namespace Meziantou.Analyzer.Test.Rules; /// -/// The analyzers analyze generated code, but only the rules configured with report_generated_code, or -/// whose default is to report in generated code such as MA0070, report the diagnostics located in it. The -/// MEZIANTOU_ANALYZER_GENERATED_CODE environment variable opts out of analyzing generated code, which the -/// tests simulate by setting GeneratedCodeAnalysisFlags to the flags of the rule, as the rules read the -/// variable once per process. +/// The analyzers skip generated code, except the rules that need it to be correct and the rules that report in it +/// by default such as MA0070. The MEZIANTOU_ANALYZER_GENERATED_CODE environment variable opts in to +/// analyzing it, and report_generated_code then decides what the rules report, which the tests simulate by +/// setting GeneratedCodeAnalysisFlags, as the rules read the variable once per process. /// public sealed class GeneratedCodeAnalysisTests { + private const GeneratedCodeAnalysisFlags OptedIn = GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics; + private const string GeneratedCodeWithDiagnostic = """ // abstract class Test @@ -47,10 +48,33 @@ public Task AutoGeneratedHeader_NoDiagnosticByDefault() return test.RunAsync(); } + [Fact] + public Task AutoGeneratedHeader_NoDiagnosticWhenTheRuleIsConfiguredButNotOptedIn() + { + // MA0017 does not analyze generated code, so configuring it to report in generated code is not enough + var test = new AbstractTypesTest(); + test.TestState.SetConfiguration("MA0017.report_generated_code", "true"); + test.TestCode = GeneratedCodeWithDiagnostic; + + return test.RunAsync(); + } + + [Fact] + public Task AutoGeneratedHeader_NoDiagnosticWhenOptedInWithoutConfiguration() + { + // Opting in makes the rule analyze generated code, but its default is still to not report in it + var test = new AbstractTypesTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; + test.TestCode = GeneratedCodeWithDiagnostic; + + return test.RunAsync(); + } + [Fact] public Task AutoGeneratedHeader_DiagnosticWhenTheRuleIsConfigured() { var test = new AbstractTypesTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; test.TestState.SetConfiguration("MA0017.report_generated_code", "true"); test.TestCode = GeneratedCodeWithDiagnosticReported; @@ -61,6 +85,7 @@ public Task AutoGeneratedHeader_DiagnosticWhenTheRuleIsConfigured() public Task AutoGeneratedHeader_DiagnosticWhenAllTheRulesAreConfigured() { var test = new AbstractTypesTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; test.TestState.SetConfiguration("MA.report_generated_code", "true"); test.TestCode = GeneratedCodeWithDiagnosticReported; @@ -71,6 +96,7 @@ public Task AutoGeneratedHeader_DiagnosticWhenAllTheRulesAreConfigured() public Task AutoGeneratedHeader_RuleConfigurationWinsOverTheGlobalOne() { var test = new AbstractTypesTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; test.TestState.SetConfiguration(("MA.report_generated_code", "true"), ("MA0017.report_generated_code", "false")); test.TestCode = GeneratedCodeWithDiagnostic; @@ -81,24 +107,13 @@ public Task AutoGeneratedHeader_RuleConfigurationWinsOverTheGlobalOne() public Task AutoGeneratedHeader_GlobalConfigurationDoesNotApplyToAnotherRule() { var test = new AbstractTypesTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; test.TestState.SetConfiguration(("MA.report_generated_code", "false"), ("MA0053.report_generated_code", "true")); test.TestCode = GeneratedCodeWithDiagnostic; return test.RunAsync(); } - [Fact] - public Task AutoGeneratedHeader_NoDiagnosticWhenTheRuleIsConfiguredButOptedOut() - { - // MA0017 does not need generated code, so opting out prevents it from reporting in it - var test = new AbstractTypesTest(); - test.GeneratedCodeAnalysisFlags = GeneratedCodeAnalysisFlags.None; - test.TestState.SetConfiguration("MA0017.report_generated_code", "true"); - test.TestCode = GeneratedCodeWithDiagnostic; - - return test.RunAsync(); - } - [Fact] public Task GeneratedFileName_NoDiagnosticByDefault() { @@ -117,6 +132,7 @@ public Test() { } public Task GeneratedFileName_DiagnosticWhenTheRuleIsConfigured() { var test = new AbstractTypesTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; test.TestState.SetConfiguration("MA0017.report_generated_code", "true"); test.TestState.Sources.Add(("/0/Test.g.cs", """ abstract class Test @@ -129,10 +145,12 @@ abstract class Test } [Fact] - public Task GeneratedCodeAttribute_TheFileIsWhatMatters() + public Task GeneratedCodeAttribute_TheFileIsWhatMattersWhenOptedIn() { // Only the file of the diagnostic is considered, so the attribute does not hide the code of a hand written file var test = new AbstractTypesTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; + test.TestState.SetConfiguration("MA0017.report_generated_code", "true"); test.TestCode = """ [System.CodeDom.Compiler.GeneratedCode("tool", "1.0")] abstract class Test @@ -144,6 +162,23 @@ abstract class Test return test.RunAsync(); } + [Fact] + public Task GeneratedCodeAttribute_NoDiagnosticWhenNotOptedIn() + { + // A rule that does not analyze generated code follows the detection of Roslyn, which also considers the + // symbols marked with [GeneratedCode] generated + var test = new AbstractTypesTest(); + test.TestCode = """ + [System.CodeDom.Compiler.GeneratedCode("tool", "1.0")] + abstract class Test + { + public Test() { } + } + """; + + return test.RunAsync(); + } + [Fact] public Task GeneratedCodeOption_TheFileIsNotGeneratedCode() { @@ -223,6 +258,7 @@ public Task SyntaxTreeRule_NoDiagnosticByDefault() public Task SyntaxTreeRule_DiagnosticWhenTheRuleIsConfigured() { var test = new FixToDoTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; test.TestState.SetConfiguration("MA0026.report_generated_code", "true"); test.TestCode = """ // @@ -234,11 +270,10 @@ public Task SyntaxTreeRule_DiagnosticWhenTheRuleIsConfigured() } [Fact] - public Task GeneratedCodeIsAnalyzedWhenOptedOut() + public Task GeneratedCodeIsAnalyzedWhenNotOptedIn() { - // MA0053 needs generated code to be correct, so opting out cannot stop it from analyzing it + // MA0053 needs generated code to be correct, so it analyzes it even when nobody opts in var test = new ClassMustBeSealedTest(); - test.GeneratedCodeAnalysisFlags = GeneratedCodeAnalysisFlags.Analyze; test.TestState.Sources.Add(("/0/Test.cs", """ class Test { @@ -254,10 +289,11 @@ class Test2 : Test } [Fact] - public Task GeneratedCodeIsAnalyzed() + public Task GeneratedCodeIsAnalyzedWhenOptedIn() { // The class declared in the generated file inherits from the other one, which cannot be sealed var test = new ClassMustBeSealedTest(); + test.GeneratedCodeAnalysisFlags = OptedIn; test.TestState.Sources.Add(("/0/Test.cs", """ class Test {