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

Commit 227430f

Browse files
authored
Merge pull request #80 from amis92/feature/rich-generators
Rich generators
2 parents 06d31db + a956836 commit 227430f

14 files changed

+670
-78
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Andrew Arnott. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
3+
4+
namespace CodeGeneration.Roslyn.Tests.Generators
5+
{
6+
7+
using System;
8+
using System.Diagnostics;
9+
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.CSharp;
11+
12+
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
13+
[CodeGenerationAttribute(typeof(AddGeneratedAttributeGenerator))]
14+
[Conditional("CodeGeneration")]
15+
public class AddGeneratedAttributeAttribute : Attribute
16+
{
17+
public AddGeneratedAttributeAttribute(string attribute)
18+
{
19+
Attribute = attribute;
20+
}
21+
22+
public string Attribute { get; }
23+
}
24+
25+
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
26+
public class GeneratedAttribute : Attribute
27+
{ }
28+
29+
public class AddGeneratedAttributeGenerator : RichBaseGenerator
30+
{
31+
32+
public AddGeneratedAttributeGenerator(AttributeData attributeData) : base(attributeData)
33+
{
34+
Attribute = (string)AttributeData.ConstructorArguments[0].Value;
35+
}
36+
37+
public string Attribute { get; }
38+
39+
protected override void Generate(RichGenerationContext context)
40+
{
41+
var attribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName(Attribute));
42+
context.AddAttribute(attribute);
43+
}
44+
}
45+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Andrew Arnott. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
3+
4+
namespace CodeGeneration.Roslyn.Tests.Generators
5+
{
6+
7+
using System;
8+
using System.Diagnostics;
9+
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.CSharp;
11+
12+
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
13+
[CodeGenerationAttribute(typeof(AddGeneratedExternGenerator))]
14+
[Conditional("CodeGeneration")]
15+
public class AddGeneratedExternAttribute : Attribute
16+
{
17+
public AddGeneratedExternAttribute(string @extern)
18+
{
19+
Extern = @extern;
20+
}
21+
22+
public string Extern { get; }
23+
}
24+
25+
public class AddGeneratedExternGenerator : RichBaseGenerator
26+
{
27+
28+
public AddGeneratedExternGenerator(AttributeData attributeData) : base(attributeData)
29+
{
30+
Extern = (string)AttributeData.ConstructorArguments[0].Value;
31+
}
32+
33+
public string Extern { get; }
34+
35+
protected override void Generate(RichGenerationContext context)
36+
{
37+
var externAlias = SyntaxFactory.ExternAliasDirective(Extern);
38+
context.AddExtern(externAlias);
39+
}
40+
}
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Andrew Arnott. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
3+
4+
using System.Diagnostics;
5+
6+
namespace CodeGeneration.Roslyn.Tests.Generators
7+
{
8+
using System;
9+
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.CSharp;
11+
12+
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
13+
[CodeGenerationAttribute(typeof(AddGeneratedUsingGenerator))]
14+
[Conditional("CodeGeneration")]
15+
public class AddGeneratedUsingAttribute : Attribute
16+
{
17+
public AddGeneratedUsingAttribute(string @using)
18+
{
19+
Using = @using;
20+
}
21+
22+
public string Using { get; }
23+
}
24+
25+
public class AddGeneratedUsingGenerator : RichBaseGenerator
26+
{
27+
28+
public AddGeneratedUsingGenerator(AttributeData attributeData) : base(attributeData)
29+
{
30+
Using = (string)AttributeData.ConstructorArguments[0].Value;
31+
}
32+
33+
public string Using { get; }
34+
35+
protected override void Generate(RichGenerationContext context)
36+
{
37+
var usingSyntax = SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(Using));
38+
context.AddUsing(usingSyntax);
39+
}
40+
}
41+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) Andrew Arnott. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
3+
4+
namespace CodeGeneration.Roslyn.Tests.Generators
5+
{
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using Microsoft.CodeAnalysis;
11+
using Microsoft.CodeAnalysis.CSharp;
12+
using Microsoft.CodeAnalysis.CSharp.Syntax;
13+
14+
public abstract class BaseGenerator : ICodeGenerator
15+
{
16+
public AttributeData AttributeData { get; }
17+
18+
protected BaseGenerator(AttributeData attributeData)
19+
{
20+
AttributeData = attributeData;
21+
}
22+
23+
Task<SyntaxList<MemberDeclarationSyntax>> ICodeGenerator.GenerateAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
24+
{
25+
var richGenerationContext = new GenerationContext(context, progress, cancellationToken);
26+
Generate(richGenerationContext);
27+
var result = richGenerationContext.CreateResult();
28+
return Task.FromResult(result);
29+
}
30+
31+
protected abstract void Generate(GenerationContext context);
32+
33+
protected class GenerationContext
34+
{
35+
public GenerationContext(TransformationContext transformationContext, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
36+
{
37+
TransformationContext = transformationContext;
38+
Progress = progress;
39+
CancellationToken = cancellationToken;
40+
}
41+
42+
public TransformationContext TransformationContext { get; }
43+
public IProgress<Diagnostic> Progress { get; }
44+
public CancellationToken CancellationToken { get; }
45+
public List<MemberDeclarationSyntax> Members { get; } = new List<MemberDeclarationSyntax>();
46+
47+
public GenerationContext AddMember(MemberDeclarationSyntax memberDeclaration)
48+
{
49+
Members.Add(memberDeclaration);
50+
return this;
51+
}
52+
53+
public SyntaxList<MemberDeclarationSyntax> CreateResult()
54+
{
55+
return SyntaxFactory.List(Members);
56+
}
57+
}
58+
}
59+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Andrew Arnott. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
3+
4+
namespace CodeGeneration.Roslyn.Tests.Generators
5+
{
6+
using System;
7+
using System.Diagnostics;
8+
9+
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
10+
[CodeGenerationAttribute(typeof(DuplicateInOtherNamespaceGenerator))]
11+
[Conditional("CodeGeneration")]
12+
public class DuplicateInOtherNamespaceAttribute : Attribute
13+
{
14+
public DuplicateInOtherNamespaceAttribute(string @namespace)
15+
{
16+
Namespace = @namespace;
17+
}
18+
19+
public string Namespace { get; }
20+
}
21+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Andrew Arnott. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
3+
4+
namespace CodeGeneration.Roslyn.Tests.Generators
5+
{
6+
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CSharp;
8+
using Microsoft.CodeAnalysis.CSharp.Syntax;
9+
10+
public class DuplicateInOtherNamespaceGenerator : RichBaseGenerator
11+
{
12+
13+
public DuplicateInOtherNamespaceGenerator(AttributeData attributeData) : base(attributeData)
14+
{
15+
Namespace = (string)AttributeData.ConstructorArguments[0].Value;
16+
}
17+
18+
public string Namespace { get; }
19+
20+
protected override void Generate(RichGenerationContext context)
21+
{
22+
if (!(context.TransformationContext.ProcessingNode is ClassDeclarationSyntax classDeclaration))
23+
{
24+
return;
25+
}
26+
var partial = SyntaxFactory.ClassDeclaration(classDeclaration.Identifier);
27+
var namespaceSyntax =
28+
SyntaxFactory.NamespaceDeclaration(
29+
SyntaxFactory.ParseName(Namespace))
30+
.AddMembers(partial);
31+
32+
context.AddMember(namespaceSyntax);
33+
}
34+
}
35+
}

src/CodeGeneration.Roslyn.Tests.Generators/EmptyPartialGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,4 @@ private static MemberDeclarationSyntax StructPartial(StructDeclarationSyntax dec
4545
.WithModifiers(SyntaxTokenList.Create(SyntaxFactory.Token(SyntaxKind.PartialKeyword)));
4646
}
4747
}
48-
}
48+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) Andrew Arnott. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
3+
4+
namespace CodeGeneration.Roslyn.Tests.Generators
5+
{
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using Microsoft.CodeAnalysis;
11+
using Microsoft.CodeAnalysis.CSharp;
12+
using Microsoft.CodeAnalysis.CSharp.Syntax;
13+
14+
public abstract class RichBaseGenerator : IRichCodeGenerator
15+
{
16+
public AttributeData AttributeData { get; }
17+
18+
protected RichBaseGenerator(AttributeData attributeData)
19+
{
20+
AttributeData = attributeData;
21+
}
22+
23+
Task<SyntaxList<MemberDeclarationSyntax>> ICodeGenerator.GenerateAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
24+
{
25+
throw new NotImplementedException();
26+
}
27+
28+
Task<RichGenerationResult> IRichCodeGenerator.GenerateRichAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
29+
{
30+
var richGenerationContext = new RichGenerationContext(context, progress, cancellationToken);
31+
Generate(richGenerationContext);
32+
var result = richGenerationContext.CreateResult();
33+
return Task.FromResult(result);
34+
}
35+
36+
protected abstract void Generate(RichGenerationContext context);
37+
38+
protected class RichGenerationContext
39+
{
40+
public RichGenerationContext(TransformationContext transformationContext, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
41+
{
42+
TransformationContext = transformationContext;
43+
Progress = progress;
44+
CancellationToken = cancellationToken;
45+
}
46+
47+
public TransformationContext TransformationContext { get; }
48+
public IProgress<Diagnostic> Progress { get; }
49+
public CancellationToken CancellationToken { get; }
50+
51+
public List<UsingDirectiveSyntax> Usings { get; } = new List<UsingDirectiveSyntax>();
52+
public List<ExternAliasDirectiveSyntax> Externs { get; } = new List<ExternAliasDirectiveSyntax>();
53+
public List<AttributeListSyntax> AttributeLists { get; } = new List<AttributeListSyntax>();
54+
public List<MemberDeclarationSyntax> Members { get; } = new List<MemberDeclarationSyntax>();
55+
56+
public RichGenerationContext AddUsing(UsingDirectiveSyntax usingDirective)
57+
{
58+
Usings.Add(usingDirective);
59+
return this;
60+
}
61+
62+
public RichGenerationContext AddExtern(ExternAliasDirectiveSyntax externAliasDirective)
63+
{
64+
Externs.Add(externAliasDirective);
65+
return this;
66+
}
67+
68+
public RichGenerationContext AddAttribute(AttributeSyntax attribute)
69+
{
70+
var list = SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(attribute));
71+
return AddAttributeList(list);
72+
}
73+
74+
public RichGenerationContext AddAttributeList(AttributeListSyntax attributeList)
75+
{
76+
AttributeLists.Add(attributeList);
77+
return this;
78+
}
79+
80+
public RichGenerationContext AddMember(MemberDeclarationSyntax memberDeclaration)
81+
{
82+
Members.Add(memberDeclaration);
83+
return this;
84+
}
85+
86+
public RichGenerationResult CreateResult()
87+
{
88+
return new RichGenerationResult
89+
{
90+
Members = SyntaxFactory.List(Members),
91+
Usings = SyntaxFactory.List(Usings),
92+
AttributeLists = SyntaxFactory.List(AttributeLists),
93+
Externs = SyntaxFactory.List(Externs),
94+
};
95+
}
96+
}
97+
}
98+
}

0 commit comments

Comments
 (0)