c#-查找语法树和引用符号上都有属性的方法?
发布时间:2022-09-07 22:36:37 454
相关标签: # flask
我有一个引用类库的应用程序,在这两个类库中,有一些类型的某些方法具有我需要收集的特定属性。
我能够涵盖这两种情况,也就是说,在语法树(应用程序)和引用符号(类库)上找到这些具有特定属性的方法。
我唯一的问题是,我发现自己在搜索这些属性方面做了两倍的工作。
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace ClassLibrary1;
[Generator]
public sealed class HelloSourceGenerator : ISourceGenerator
// https://github.com/JoanComasFdz/dotnet-how-to-debug-source-generator-vs2022
{
public void Initialize(GeneratorInitializationContext context)
{
}
public void Execute(GeneratorExecutionContext context)
{
const string assemblyFilter = "ClassLibrary"; // only match assemblies whose name starts with
const string attributeName = "global::ClassLibrary2.TestAttribute"; // the attribute we're looking for in methods
// gather symbols in referenced assemblies
var stack1 = new Stack(); // scratch stack
var stack2 = new Stack(); // output stack
var symbols = context
.Compilation
.SourceModule
.ReferencedAssemblySymbols
.Where(s => s.Name.StartsWith(assemblyFilter)).OrderBy(s => s.Name);
foreach (var assemblySymbol in symbols)
{
var assemblyMembers = assemblySymbol.GlobalNamespace.GetMembers();
foreach (var symbol in assemblyMembers)
{
stack1.Push(symbol);
}
while (stack1.Any())
{
var pop = stack1.Pop();
var members = pop.GetMembers();
foreach (var item in members)
{
if (item is INamespaceOrTypeSymbol namespaceOrTypeSymbol)
{
stack1.Push(namespaceOrTypeSymbol);
}
}
if (pop is ITypeSymbol typeSymbol)
{
stack2.Push(typeSymbol);
}
}
}
// find methods who have the attribute we're looking for
var dictionary = new Dictionary>(SymbolEqualityComparer.Default);
// 1. in referenced assemblies
foreach (var symbol in stack2)
{
var kind = symbol.TypeKind;
if (kind is not (TypeKind.Class or TypeKind.Struct))
continue;
var members = symbol.GetMembers();
foreach (var member in members)
{
if (member.Kind is not SymbolKind.Method)
continue;
var attributes = member.GetAttributes();
foreach (var attribute in attributes)
{
var s = attribute.AttributeClass!.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (!string.Equals(s, attributeName, StringComparison.Ordinal))
continue;
if (dictionary.ContainsKey(symbol))
{
dictionary[symbol].Add(member);
}
else
{
dictionary.Add(symbol, new List { member });
}
}
}
}
// 2. in syntax tree
foreach (var tree in context.Compilation.SyntaxTrees)
{
var model = context.Compilation.GetSemanticModel(tree);
foreach (var descendantNode in tree.GetRoot().DescendantNodes())
{
if (descendantNode is not ClassDeclarationSyntax && descendantNode is not StructDeclarationSyntax)
continue;
var cs = model.GetDeclaredSymbol(descendantNode)!;
foreach (var m in descendantNode.DescendantNodes().OfType())
{
var ms = model.GetDeclaredSymbol(m)!;
foreach (var data in ms.GetAttributes())
{
var s = data.AttributeClass!.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (!string.Equals(s, attributeName, StringComparison.Ordinal))
continue;
if (dictionary.ContainsKey(cs))
{
dictionary[cs].Add(ms);
}
else
{
dictionary.Add(cs, new List { ms });
}
}
}
}
}
// TODO generate some code
var builder = new StringBuilder();
builder.AppendLine(@"
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace PSX.Generated;
public static class Logging
{
public static IReadOnlyDictionary Names { get; }
static Logging()
{
var names = new Dictionary();
");
;
foreach (var pair in dictionary)
{
var key = pair.Key.ToDisplayString();
foreach (var symbol in pair.Value)
{
builder.AppendLine($@"
names.Add(
""{key}"",
""{symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}""
);");
}
}
builder.AppendLine(@"
Names = new ReadOnlyDictionary(names);
}
}");
var source = builder.ToString();
context.AddSource("PSX.Generated.Logging.g.cs", source);
}
}
输出:
这正是我所期望的,所有具有该属性的方法,无论它们是在应用程序中还是在其引用中,都会被找到,并从中生成一个helper类。
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace PSX.Generated;
public static class Logging
{
public static IReadOnlyDictionary Names { get; }
static Logging()
{
var names = new Dictionary();
names.Add(
"ClassLibrary2.ImplementationStruct1",
"Method1"
);
names.Add(
"ClassLibrary2.ImplementationStruct1",
"Method4"
);
names.Add(
"ClassLibrary2.Inner.Implementation1",
"Method1"
);
names.Add(
"ClassLibrary2.Inner.Implementation1",
"Method2"
);
names.Add(
"ConsoleApp1.ImplementationClass2",
"Method1"
);
names.Add(
"ConsoleApp1.ImplementationClass2",
"Method3"
);
names.Add(
"ConsoleApp1.ImplementationStruct2",
"Method1"
);
names.Add(
"ConsoleApp1.ImplementationStruct2",
"Method4"
);
Names = new ReadOnlyDictionary(names);
}
}
问题:
有没有一种方法可以在语法树和引用符号上只搜索一次属性,而不是代码中的两次?
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报