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

Commit

Permalink
Merge pull request #80 from amis92/feature/rich-generators
Browse files Browse the repository at this point in the history
Rich generators
  • Loading branch information
AArnott authored Aug 20, 2018
2 parents 06d31db + a956836 commit 227430f
Show file tree
Hide file tree
Showing 14 changed files with 670 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace CodeGeneration.Roslyn.Tests.Generators
{

using System;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[CodeGenerationAttribute(typeof(AddGeneratedAttributeGenerator))]
[Conditional("CodeGeneration")]
public class AddGeneratedAttributeAttribute : Attribute
{
public AddGeneratedAttributeAttribute(string attribute)
{
Attribute = attribute;
}

public string Attribute { get; }
}

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public class GeneratedAttribute : Attribute
{ }

public class AddGeneratedAttributeGenerator : RichBaseGenerator
{

public AddGeneratedAttributeGenerator(AttributeData attributeData) : base(attributeData)
{
Attribute = (string)AttributeData.ConstructorArguments[0].Value;
}

public string Attribute { get; }

protected override void Generate(RichGenerationContext context)
{
var attribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName(Attribute));
context.AddAttribute(attribute);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace CodeGeneration.Roslyn.Tests.Generators
{

using System;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[CodeGenerationAttribute(typeof(AddGeneratedExternGenerator))]
[Conditional("CodeGeneration")]
public class AddGeneratedExternAttribute : Attribute
{
public AddGeneratedExternAttribute(string @extern)
{
Extern = @extern;
}

public string Extern { get; }
}

public class AddGeneratedExternGenerator : RichBaseGenerator
{

public AddGeneratedExternGenerator(AttributeData attributeData) : base(attributeData)
{
Extern = (string)AttributeData.ConstructorArguments[0].Value;
}

public string Extern { get; }

protected override void Generate(RichGenerationContext context)
{
var externAlias = SyntaxFactory.ExternAliasDirective(Extern);
context.AddExtern(externAlias);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

using System.Diagnostics;

namespace CodeGeneration.Roslyn.Tests.Generators
{
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[CodeGenerationAttribute(typeof(AddGeneratedUsingGenerator))]
[Conditional("CodeGeneration")]
public class AddGeneratedUsingAttribute : Attribute
{
public AddGeneratedUsingAttribute(string @using)
{
Using = @using;
}

public string Using { get; }
}

public class AddGeneratedUsingGenerator : RichBaseGenerator
{

public AddGeneratedUsingGenerator(AttributeData attributeData) : base(attributeData)
{
Using = (string)AttributeData.ConstructorArguments[0].Value;
}

public string Using { get; }

protected override void Generate(RichGenerationContext context)
{
var usingSyntax = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(Using));
context.AddUsing(usingSyntax);
}
}
}
59 changes: 59 additions & 0 deletions src/CodeGeneration.Roslyn.Tests.Generators/BaseGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace CodeGeneration.Roslyn.Tests.Generators
{
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

public abstract class BaseGenerator : ICodeGenerator
{
public AttributeData AttributeData { get; }

protected BaseGenerator(AttributeData attributeData)
{
AttributeData = attributeData;
}

Task<SyntaxList<MemberDeclarationSyntax>> ICodeGenerator.GenerateAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
{
var richGenerationContext = new GenerationContext(context, progress, cancellationToken);
Generate(richGenerationContext);
var result = richGenerationContext.CreateResult();
return Task.FromResult(result);
}

protected abstract void Generate(GenerationContext context);

protected class GenerationContext
{
public GenerationContext(TransformationContext transformationContext, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
{
TransformationContext = transformationContext;
Progress = progress;
CancellationToken = cancellationToken;
}

public TransformationContext TransformationContext { get; }
public IProgress<Diagnostic> Progress { get; }
public CancellationToken CancellationToken { get; }
public List<MemberDeclarationSyntax> Members { get; } = new List<MemberDeclarationSyntax>();

public GenerationContext AddMember(MemberDeclarationSyntax memberDeclaration)
{
Members.Add(memberDeclaration);
return this;
}

public SyntaxList<MemberDeclarationSyntax> CreateResult()
{
return SyntaxFactory.List(Members);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace CodeGeneration.Roslyn.Tests.Generators
{
using System;
using System.Diagnostics;

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
[CodeGenerationAttribute(typeof(DuplicateInOtherNamespaceGenerator))]
[Conditional("CodeGeneration")]
public class DuplicateInOtherNamespaceAttribute : Attribute
{
public DuplicateInOtherNamespaceAttribute(string @namespace)
{
Namespace = @namespace;
}

public string Namespace { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace CodeGeneration.Roslyn.Tests.Generators
{
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

public class DuplicateInOtherNamespaceGenerator : RichBaseGenerator
{

public DuplicateInOtherNamespaceGenerator(AttributeData attributeData) : base(attributeData)
{
Namespace = (string)AttributeData.ConstructorArguments[0].Value;
}

public string Namespace { get; }

protected override void Generate(RichGenerationContext context)
{
if (!(context.TransformationContext.ProcessingNode is ClassDeclarationSyntax classDeclaration))
{
return;
}
var partial = SyntaxFactory.ClassDeclaration(classDeclaration.Identifier);
var namespaceSyntax =
SyntaxFactory.NamespaceDeclaration(
SyntaxFactory.ParseName(Namespace))
.AddMembers(partial);

context.AddMember(namespaceSyntax);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ private static MemberDeclarationSyntax StructPartial(StructDeclarationSyntax dec
.WithModifiers(SyntaxTokenList.Create(SyntaxFactory.Token(SyntaxKind.PartialKeyword)));
}
}
}
}
98 changes: 98 additions & 0 deletions src/CodeGeneration.Roslyn.Tests.Generators/RichBaseGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.

namespace CodeGeneration.Roslyn.Tests.Generators
{
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

public abstract class RichBaseGenerator : IRichCodeGenerator
{
public AttributeData AttributeData { get; }

protected RichBaseGenerator(AttributeData attributeData)
{
AttributeData = attributeData;
}

Task<SyntaxList<MemberDeclarationSyntax>> ICodeGenerator.GenerateAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}

Task<RichGenerationResult> IRichCodeGenerator.GenerateRichAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
{
var richGenerationContext = new RichGenerationContext(context, progress, cancellationToken);
Generate(richGenerationContext);
var result = richGenerationContext.CreateResult();
return Task.FromResult(result);
}

protected abstract void Generate(RichGenerationContext context);

protected class RichGenerationContext
{
public RichGenerationContext(TransformationContext transformationContext, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
{
TransformationContext = transformationContext;
Progress = progress;
CancellationToken = cancellationToken;
}

public TransformationContext TransformationContext { get; }
public IProgress<Diagnostic> Progress { get; }
public CancellationToken CancellationToken { get; }

public List<UsingDirectiveSyntax> Usings { get; } = new List<UsingDirectiveSyntax>();
public List<ExternAliasDirectiveSyntax> Externs { get; } = new List<ExternAliasDirectiveSyntax>();
public List<AttributeListSyntax> AttributeLists { get; } = new List<AttributeListSyntax>();
public List<MemberDeclarationSyntax> Members { get; } = new List<MemberDeclarationSyntax>();

public RichGenerationContext AddUsing(UsingDirectiveSyntax usingDirective)
{
Usings.Add(usingDirective);
return this;
}

public RichGenerationContext AddExtern(ExternAliasDirectiveSyntax externAliasDirective)
{
Externs.Add(externAliasDirective);
return this;
}

public RichGenerationContext AddAttribute(AttributeSyntax attribute)
{
var list = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(attribute));
return AddAttributeList(list);
}

public RichGenerationContext AddAttributeList(AttributeListSyntax attributeList)
{
AttributeLists.Add(attributeList);
return this;
}

public RichGenerationContext AddMember(MemberDeclarationSyntax memberDeclaration)
{
Members.Add(memberDeclaration);
return this;
}

public RichGenerationResult CreateResult()
{
return new RichGenerationResult
{
Members = SyntaxFactory.List(Members),
Usings = SyntaxFactory.List(Usings),
AttributeLists = SyntaxFactory.List(AttributeLists),
Externs = SyntaxFactory.List(Externs),
};
}
}
}
}
Loading

0 comments on commit 227430f

Please sign in to comment.