Skip to content

Instantly share code, notes, and snippets.

@kevingosse
Created February 9, 2021 17:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevingosse/1a9438c5980916dc6c653078f46b2cab to your computer and use it in GitHub Desktop.
Save kevingosse/1a9438c5980916dc6c653078f46b2cab to your computer and use it in GitHub Desktop.
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