Created
February 9, 2021 17:20
-
-
Save kevingosse/1a9438c5980916dc6c653078f46b2cab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using Microsoft.CodeAnalysis; | |
using Microsoft.CodeAnalysis.CSharp.Syntax; | |
using Microsoft.CodeAnalysis.Text; | |
namespace IsEvenSourceGenerator | |
{ | |
[Generator] | |
public class SourceGenerator : ISourceGenerator | |
{ | |
public void Initialize(GeneratorInitializationContext context) | |
{ | |
context.RegisterForSyntaxNotifications(() => new IsEvenSyntaxReceiver()); | |
} | |
public void Execute(GeneratorExecutionContext context) | |
{ | |
if (!(context.SyntaxReceiver is IsEvenSyntaxReceiver syntaxReceiver)) | |
{ | |
return; | |
} | |
foreach (var kvp in syntaxReceiver.MaxValue) | |
{ | |
GenerateIsEven(kvp.Key, kvp.Value, context); | |
} | |
} | |
private void GenerateIsEven((string @namespace, string type) key, int value, GeneratorExecutionContext context) | |
{ | |
var sourceBuilder = new StringBuilder(@" | |
namespace {namespace} | |
{ | |
partial class {class} | |
{ | |
public static bool IsEven(int number) => (number) switch | |
{ | |
{evens} => true, | |
{odds} => false | |
}; | |
} | |
} | |
"); | |
var evens = string.Join(" or ", Enumerable.Range(0, value + 1).Where(i => i % 2 == 0)); | |
var odds = string.Join(" or ", Enumerable.Range(0, value + 1).Where(i => i % 2 != 0)); | |
var result = sourceBuilder.ToString() | |
.Replace("{namespace}", key.@namespace) | |
.Replace("{class}", key.type) | |
.Replace("{odds}", odds) | |
.Replace("{evens}", evens); | |
context.AddSource($"{key.@namespace}.{key.type}", SourceText.From(result, Encoding.UTF8)); | |
Output.AppendLine(result); | |
} | |
} | |
public class IsEvenSyntaxReceiver : ISyntaxReceiver | |
{ | |
public Dictionary<(string @namespace, string type), int> MaxValue { get; private set; } = new(); | |
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) | |
{ | |
if (syntaxNode is InvocationExpressionSyntax invocationExpression && invocationExpression.Expression.ToString() == "IsEven") | |
{ | |
foreach (var argument in invocationExpression.ArgumentList.Arguments) | |
{ | |
if (argument.Expression.Kind() == Microsoft.CodeAnalysis.CSharp.SyntaxKind.NumericLiteralExpression) | |
{ | |
var value = int.Parse(argument.Expression.ToString()); | |
// Find parent ClassDeclarationSyntax | |
var classDeclaration = syntaxNode.FirstAncestorOrSelf<ClassDeclarationSyntax>(); | |
if (!classDeclaration.Modifiers.ToString().Contains("partial")) | |
{ | |
continue; | |
} | |
var @namespace = classDeclaration.FirstAncestorOrSelf<NamespaceDeclarationSyntax>(); | |
var key = (@namespace.Name.ToString(), classDeclaration.Identifier.ToString()); | |
MaxValue.TryGetValue(key, out var maxValue); | |
if (value >= maxValue) | |
{ | |
MaxValue[key] = value; | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment