Skip to content

API Proposal: IncrementalGeneratorPostInitializationContext.AddEmbeddedAttributeDefinition #76584

@333fred

Description

@333fred

Background and Motivation

Generator authors have issues with user-visible marker types (usually used to drive ForAttributeWithMetadataName) being visible in multiple compilations, which causes warnings to be issued. The compiler already has a solution for this for its own generated types: Microsoft.CodeAnalysis.EmbeddedAttribute. In #76523, we allowed this type to be provided by users, so that generator authors will be able to take advantage of the attribute for their own scenarios. However, the definition that must be followed is very specific, and we think it's likely that generator authors may struggle to get it entirely correct, including remembering the partial modifier so that other generators can safely add their own copies. We therefore propose an API to allow generator authors to add the attribute directly, entirely correctly.

Proposed API

namespace Microsoft.CodeAnalysis;

public readonly struct IncrementalGeneratorPostInitializationContext
{
    public CancellationToken CancellationToken { get; }
    public void AddSource(string hintName, string source);
    public void AddSource(string hintName, SourceText sourceText);

+   /// <summary>
+   /// Adds a <see cref="SourceText" /> to the compilation containing the definition of <c>Microsoft.CodeAnalysis.EmbeddedAttribute</c>.
+   /// The source will have a <c>hintName</c> of Microsoft.CodeAnalysis.EmbeddedAttribute. 
+   /// </summary>
+   /// <remarks>
+   /// This attribute can be used to mark a type as being only visible to the current assembly. Most commonly, any types provided during this <see cref="IncrementalGeneratorPostInitializationContext"/>
+   /// should be marked with this attribute to prevent them from being used by other assemblies. The attribute will prevent any downstream assemblies from consuming the type.
+   /// </remarks>
+   public void AddEmbeddedAttributeDefinition();
}

Usage Examples

        context.RegisterPostInitializationOutput(static postInitializationContext =>
            postInitializationContext.AddEmbeddedAttributeDefinition();
            postInitializationContext.AddSource("myGeneratedFile.cs", SourceText.From("""
                using System;
                using Microsoft.CodeAnalysis;
                namespace GeneratedNamespace
                {
                    [AttributeUsage(AttributeTargets.Method), Embedded]
                    internal sealed class GeneratedAttribute : Attribute
                    {
                    }
                }
                """, Encoding.UTF8)));

Alternative Designs

We considered other alternatives, such as moving the warning location to where a generator author could suppress it, but these other approaches were all much more complicated. EmbeddedAttribute is a battle-tested solution that the compiler has used for years, so we think it's the best approach.

Risks

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions