dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
18.96k stars 4.03k forks source link

Source generators cannot access arbitrary item metadata #60595

Open chsienki opened 2 years ago

chsienki commented 2 years ago

The compiler targets support a mechanism for including item metadata from MSBuild in an analyzer config that can be read by generators (see https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md#consume-msbuild-properties-and-metadata).

For instance a user could write:

<ItemGroup Include="Foo.Bar" Value="baz" />

And when paired with the appropriate targets in the generator

<CompilerVisibleItemMetadata Include="Constant" MetadataName="Comment" />

The generated config looks something like:

[C:/projects/scratch/60532repro/Foo.Bar]
build_metadata.Constant.Value = Baz

Unfortunately this only works when the item has a representation on-disk as either a source file or additional file, because the AnalyzerConfig interface only takes an instance of AdditionalFile or SyntaxTree to perform the lookup (https://sourceroslyn.io/#Microsoft.CodeAnalysis/DiagnosticAnalyzer/AnalyzerConfigOptionsProvider.cs,721ac189c6f5024f).

This means that generators are forced to create 'dummy' additional files that don't really exist, just to given them a key that they can lookup against. Further, even if we had an arbitrary string lookup, the generator wouldn't know what values to lookup (as they are provided by the user as part of the include).

We should design an API that allows for this sort of arbitrary lookup. A couple of options seem possible:

  1. We could make the analyzer config enumerable by item heading. That way a generator can enumerator over each item and check if it has the metadata it is looking for.
    • This is probably the simplest option, but not necessarily particularly efficient or easy to use.
  2. Reverse the lookup: have an option that gets each section if it contains a particular key.
    • Conceptually similar to the above, but perhaps simpler to reason about for the generator authors
  3. We add a new kind of lookup to AnalyzerConfigOptions (string, or opaque key?) and a new API that can return the different kind of 'things' that are contained in the metadata
    • This requires significantly more design thought, but could be 'layered' on top of analyzer config as a distinct API. Would make using metadata and properties potentially simpler, and exposed as top-level inputs to incremental generators.
chsienki commented 2 years ago

Related: https://github.com/devlooped/ThisAssembly/issues/85