-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
Background and Motivation
An extremely common pattern seen in source generators involves inserting an attribute via PostInitialization, then finding all symbols that are marked with that attribute. There are currently several different ways to acheive this, and we often hear from customers that they would like a 'canonical' compiler approved method. While we provide examples in the cookbook, it seems like we have an opportunity to provide a set of APIs to do this directly which will allow customers to fall into the 'pit of success' and allow us to potentially optimize further as we know exactly what they are trying to acheive.
Proposed API
namespace Microsoft.CodeAnalysis
{
public readonly struct SyntaxValueProvider
{
+ /// <summary>
+ /// Creates an <see cref="IncrementalValuesProvider{T}"/> that can provide a transform over all <see cref="SyntaxNode"/>s marked with a specified attribute.
+ /// </summary>
+ /// <param name="attributeFQN">The FullyQualifiedName of the attribute used to search for nodes that are annotated with it.</param>
+ /// <param name="transform">A function that performs the transfomation of the found nodes</param>
+ /// <returns>An <see cref="IncrementalValuesProvider{T}"/> that provides the results of the transformation</returns>
+ public IncrementalValuesProvider<T> FromAttribute<T>(string attributeFQN, Func<GeneratorSyntaxContext, AttributeData attributeData, CancellationToken, T> transform);
}
Usage Examples
// regular post initalization injected attribute
ctx.RegisterPostInitializationOutput((c) => c.AddSource("myAttribute", @"using System;
namespace AutoNotify
{
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
sealed class AutoNotifyAttribute : Attribute
{
public AutoNotifyAttribute()
{
}
public string PropertyName { get; set; }
}
"));
// search by existing / post init injected attribute
var x = ctx.SyntaxProvider.FromAttribute("AutoNotify.AutoNotifyAttribute", (syntaxContext, attribData, ct) => ...);
Error handling / resolution
There are multiple possible resolution strategies to the attribute look up (should it exist in source only? can it exist in a library?) and we'll take an opinionated stance on this, rather than provide overloads that provide these different behaviours. If an author wants full control they can use the exisiting lower level primitives as today.
Open Questions
Should AttributeData be on the Context or passed as another lambda parameter?