Generated code

edit

Roslyn recognizes generated code in two independent ways, and the package exposes both.

Generated files

SyntaxTree.IsGeneratedCode looks at the file. In order, it uses:

  1. the generated_code option of .editorconfig, when it is set;
  2. the well-known file names: .g.cs, .g.i.cs, .designer.cs, .generated.cs and TemporaryGeneratedFile_*;
  3. an <auto-generated> comment at the start of the file.

Pass the AnalyzerOptions of an analysis context, or the AnalyzerConfigOptionsProvider of a source generator, to read the .editorconfig option: the overload that only takes a CancellationToken applies the last two rules. GeneratedCodeExtensions.IsGeneratedCodeFile(path) applies the file name rule alone.

Generated symbols

ISymbol.IsGeneratedCodeSymbol looks at the symbol: it walks the symbol and the symbols that contain it, up to the assembly, looking for [System.CodeDom.Compiler.GeneratedCode]. A symbol declared in several files, such as a partial type, is never generated code, and the walk stops there:

var compilation = CSharpCompilation.Create(
    "Sample",
    [CSharpSyntaxTree.ParseText("""
        [System.CodeDom.Compiler.GeneratedCode("Tool", "1.0")]
        public class Generated
        {
            public void Method() { }
        }

        public class Handwritten { }
        """)],
    [MetadataReference.CreateFromFile(typeof(object).Assembly.Location)]);

// Resolve the attribute once, then test the symbols
var generatedCodeAttribute = compilation.GetTypeByMetadataName("System.CodeDom.Compiler.GeneratedCodeAttribute");
var symbol = compilation.GetTypeByMetadataName("Generated")!.GetMembers("Method").Single();
Assert.True(symbol.IsGeneratedCodeSymbol(generatedCodeAttribute));
Assert.False(compilation.GetTypeByMetadataName("Handwritten")!.IsGeneratedCodeSymbol(generatedCodeAttribute));

Resolve the attribute type once per compilation and pass it, rather than the Compilation overload, when you test many symbols.

Match the analyzer driver

With GeneratedCodeAnalysisFlags.None, the analyzer driver skips a location when either check matches, for symbol, syntax and operation actions alike. The symbol check covers the declaration of the symbol that carries the attribute: another type of the same file without the attribute is still analyzed. Use both checks to make the same decision in your own code, for instance in a diagnostic filter.

A source generator gets no special treatment: Roslyn does not flag the trees it adds to the compilation. When the hint name of a generated file has no well-known suffix, its content has no <auto-generated> comment and its types have no [GeneratedCode] attribute, every analyzer runs on it, including those that opted out of generated code. Name the generated files *.g.cs, or start them with // <auto-generated/>.