Skip to content
This repository has been archived by the owner on Dec 12, 2020. It is now read-only.

Features

Amadeusz Sadowski edited this page Jun 15, 2019 · 7 revisions

Content

Prerequisites

  • An implementation of one of ICodeGenerator/IRichCodeGenerator
    • Any class implementing those interfaces must have a constructor that has single parameter of type Microsoft.CodeAnalysis.AttributeData. Otherwise an error will be raised on consumer build.

Terms

To easier navigate through the convoluted area of multiple levels of builds, runtimes, compilations, code, source and generation, the following expressions are defined:

-CG.R or framework is the CodeGeneration.Roslyn framework in general, including but not limited to the build task, command line tool invoked from it, or the public contract.

  • [Code]Generator is an implementation that performs the actual generation of source code given a compiled project.
  • Consumer is the end-user of the framework and generators
  • [Generator]Provider is the third party that actually provides generator implementation
  • Trigger [Attribute] is the attribute that triggers framework's engine and

ICodeGenerator

This interface offers basic TransformAsync method which will be called by CG.R Engine. Context of the generation location is passed via TransformationContext parameter, and two utility parameters are provided: IProgress will print given diagnostics into MSBuild log, and CancellationToken is provided for cancellation control.

Implementations are the actual generators that will then be used in consumer builds.

Example generator:

// file WorkInProgressGenerator.cs in project Awesome.Generators
using System;
using System.Threading;
using System.Threading.Tasks;
using CodeGeneration.Roslyn;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Awesome.Generators
{
    public class WorkInProgressGenerator : ICodeGenerator
    {
        public WorkInProgressGenerator(AttributeData attributeData) { }

        public async Task<SyntaxList<MemberDeclarationSyntax>> GenerateAsync(
            TransformationContext context,
            IProgress<Diagnostic> progress,
            CancellationToken cancellationToken)
        {
            SyntaxList<MemberDeclarationSyntax> results = await CreateNewMembersAsync();
            return results;
        }

        private async Task<SyntaxList<MemberDeclarationSyntax>> CreateNewMembersAsync()
        {
            // TODO
            throw new NotImplementedException();
        }
    }
}

CodeGenerationAttributeAttribute

When a custom attribute definition is annotated with [CodeGenerationAttribute], it becomes the trigger attribute.

The type of code generator is read from attribute's CodeGenerationAttributeAttribute constructor parameter. This is either:

  • typeof(x) expression which requires code generator to live in the same assembly as the generator, or
  • a string constant containing fully qualified type name, e.g. CodeGeneration.Roslyn.Tests.Generators.EmptyPartialGenerator, CodeGeneration.Roslyn.Tests.Generators. If you omit the assembly name (after comma), it'll resolve to the same assembly as the one in which the attribute itself was declared.

An example:

// file WorkInProgressAttribute.cs in project Awesome.Generators.Attributes
using System;
using CodeGeneration.Roslyn;

[CodeGenerationAttribute("Awesome.Generators.WorkInProgressGenerator, Awesome.Generators")]
public class WorkInProgressAttribute : Attribute
{
}

The custom attribute can annotate any attribute-allowing syntax node, even a whole assembly (e.g. [assembly: WorkInProgress]), there are no constraints on custom attribute's target.

Invocation

The generator is instantiated for every applicable attribute occurrence and appropriate AttributeData is passed into it. Immediately after that the method TransformAsync is called.

TransformationContext

The context consists of:

  • CSharpSyntaxNode ProcessingNode which is the syntax node that is annotated with a trigger attribute, e.g. a type, method, property, or even whole assembly
  • CSharpCompilation Compilation which is the compilation model of all original source files.
  • SemanticModel SemanticModel for the whole CSharpCompilation in use
  • string ProjectDirectory - absolute path of the directory where the project file is located
  • IEnumerable<UsingDirectiveSyntax> CompilationUnitUsings contains usings generated by generators that already ran for some node in a document being processed. These usings will be added at the top of the generated source document.
  • IEnumerable<ExternAliasDirectiveSyntax> CompilationUnitExterns similar as above, but for extern directives.

Processing of ICodeGenerator results

TODO

IRichCodeGenerator

TODO

Processing of IRichCodeGenerator results

TODO

Clone this wiki locally