From 011ab8a51b1c7376879a3099215bf4129b9a82bd Mon Sep 17 00:00:00 2001 From: lindexi Date: Fri, 16 Jun 2023 14:25:03 +0800 Subject: [PATCH 01/48] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E9=9B=86=E9=87=8C=E9=9D=A2=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=85=B6=E4=BB=96=E7=9A=84=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeIncrementalGenerator.cs | 84 ++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs index dd26f0a..c9a1da9 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs @@ -4,7 +4,9 @@ using System.Diagnostics; using System.Linq; using System.Threading; + using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -19,10 +21,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) #if DEBUG Debugger.Launch(); #endif - // 先读取程序集特性,接着遍历整个程序集的所有代码文件,看看哪些是符合需求的,收集起来 // 读取程序集特性 - var assemblyAttributeSyntaxContextIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider ( @@ -58,7 +58,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax); // 如果可以获取到语义的类型,则尝试获取其标记的特性 - if (namedTypeSymbol is not null + if (namedTypeSymbol is not null // 抽象类不应该被加入创建 && !namedTypeSymbol.IsAbstract) { @@ -202,6 +202,25 @@ static bool IsInherit(ITypeSymbol currentType, ITypeSymbol requiredType) } } + class F : SymbolVisitor + { + public override int Visit(ISymbol? symbol) + { + return base.Visit(symbol); + } + + public override int DefaultVisit(ISymbol symbol) + { + + return base.DefaultVisit(symbol); + } + + public override int VisitNamedType(INamedTypeSymbol symbol) + { + return base.VisitNamedType(symbol); + } + } + /// /// 解析出定义在程序集里面的特性 /// @@ -218,6 +237,65 @@ private MarkExportAttributeParseResult ParseMarkExportAttribute(GeneratorSyntaxC foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) { + var sourceModuleReferencedAssemblySymbols = generatorSyntaxContext.SemanticModel.Compilation.SourceModule.ReferencedAssemblySymbols; + foreach (IAssemblySymbol? sourceModuleReferencedAssemblySymbol in sourceModuleReferencedAssemblySymbols) + { + sourceModuleReferencedAssemblySymbol.Accept(new F()); + + var namedTypeSymbols = sourceModuleReferencedAssemblySymbol.GlobalNamespace.GetTypeMembers(); + foreach (var namedTypeSymbol in namedTypeSymbols) + { + + } + + foreach (var namespaceMember in sourceModuleReferencedAssemblySymbol.GlobalNamespace.GetNamespaceMembers()) + { + GetAllType(namespaceMember); + + var members = namespaceMember.GetTypeMembers(); + foreach (var namedTypeSymbol in members) + { + } + } + + void GetAllType(INamespaceSymbol namespaceSymbol) + { + var members = namespaceSymbol.GetTypeMembers(); + foreach (var namedTypeSymbol in members) + { + + } + + var list = namespaceSymbol.GetNamespaceMembers().ToList(); + foreach (var subNamespaceSymbol in list) + { + GetAllType(subNamespaceSymbol); + } + } + + foreach (var moduleSymbol in sourceModuleReferencedAssemblySymbol.Modules) + { + } + + foreach (var namedTypeSymbol in sourceModuleReferencedAssemblySymbol.GetForwardedTypes()) + { + + } + + foreach (var typeName in sourceModuleReferencedAssemblySymbol.TypeNames) + { + } + } + + foreach (var compilationDirectiveReference in generatorSyntaxContext.SemanticModel.Compilation.DirectiveReferences) + { + } + var metadataReferences = generatorSyntaxContext.SemanticModel.Compilation.References.ToList(); + foreach (var metadataReference in metadataReferences) + { + } + + // [assembly: MarkExport(typeof(Base), typeof(FooAttribute))] // attributeSyntax:拿到 MarkExport 符号 // 由于只是拿到 MarkExport 符号,不等于是 `dotnetCampus.Telescope.MarkExportAttribute` 特性,需要走语义分析 From 70e7c500366e4e11a8ff146350d34775a77ccaec Mon Sep 17 00:00:00 2001 From: lindexi Date: Fri, 16 Jun 2023 14:25:11 +0800 Subject: [PATCH 02/48] =?UTF-8?q?Revert=20"=E6=B5=8B=E8=AF=95=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E7=A8=8B=E5=BA=8F=E9=9B=86=E9=87=8C=E9=9D=A2=E6=89=80?= =?UTF-8?q?=E6=9C=89=E5=85=B6=E4=BB=96=E7=9A=84=E5=86=85=E5=AE=B9"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 011ab8a51b1c7376879a3099215bf4129b9a82bd. --- .../TelescopeIncrementalGenerator.cs | 84 +------------------ 1 file changed, 3 insertions(+), 81 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs index c9a1da9..dd26f0a 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs @@ -4,9 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; - using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -21,8 +19,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) #if DEBUG Debugger.Launch(); #endif + // 先读取程序集特性,接着遍历整个程序集的所有代码文件,看看哪些是符合需求的,收集起来 // 读取程序集特性 + var assemblyAttributeSyntaxContextIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider ( @@ -58,7 +58,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax); // 如果可以获取到语义的类型,则尝试获取其标记的特性 - if (namedTypeSymbol is not null + if (namedTypeSymbol is not null // 抽象类不应该被加入创建 && !namedTypeSymbol.IsAbstract) { @@ -202,25 +202,6 @@ static bool IsInherit(ITypeSymbol currentType, ITypeSymbol requiredType) } } - class F : SymbolVisitor - { - public override int Visit(ISymbol? symbol) - { - return base.Visit(symbol); - } - - public override int DefaultVisit(ISymbol symbol) - { - - return base.DefaultVisit(symbol); - } - - public override int VisitNamedType(INamedTypeSymbol symbol) - { - return base.VisitNamedType(symbol); - } - } - /// /// 解析出定义在程序集里面的特性 /// @@ -237,65 +218,6 @@ private MarkExportAttributeParseResult ParseMarkExportAttribute(GeneratorSyntaxC foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) { - var sourceModuleReferencedAssemblySymbols = generatorSyntaxContext.SemanticModel.Compilation.SourceModule.ReferencedAssemblySymbols; - foreach (IAssemblySymbol? sourceModuleReferencedAssemblySymbol in sourceModuleReferencedAssemblySymbols) - { - sourceModuleReferencedAssemblySymbol.Accept(new F()); - - var namedTypeSymbols = sourceModuleReferencedAssemblySymbol.GlobalNamespace.GetTypeMembers(); - foreach (var namedTypeSymbol in namedTypeSymbols) - { - - } - - foreach (var namespaceMember in sourceModuleReferencedAssemblySymbol.GlobalNamespace.GetNamespaceMembers()) - { - GetAllType(namespaceMember); - - var members = namespaceMember.GetTypeMembers(); - foreach (var namedTypeSymbol in members) - { - } - } - - void GetAllType(INamespaceSymbol namespaceSymbol) - { - var members = namespaceSymbol.GetTypeMembers(); - foreach (var namedTypeSymbol in members) - { - - } - - var list = namespaceSymbol.GetNamespaceMembers().ToList(); - foreach (var subNamespaceSymbol in list) - { - GetAllType(subNamespaceSymbol); - } - } - - foreach (var moduleSymbol in sourceModuleReferencedAssemblySymbol.Modules) - { - } - - foreach (var namedTypeSymbol in sourceModuleReferencedAssemblySymbol.GetForwardedTypes()) - { - - } - - foreach (var typeName in sourceModuleReferencedAssemblySymbol.TypeNames) - { - } - } - - foreach (var compilationDirectiveReference in generatorSyntaxContext.SemanticModel.Compilation.DirectiveReferences) - { - } - var metadataReferences = generatorSyntaxContext.SemanticModel.Compilation.References.ToList(); - foreach (var metadataReference in metadataReferences) - { - } - - // [assembly: MarkExport(typeof(Base), typeof(FooAttribute))] // attributeSyntax:拿到 MarkExport 符号 // 由于只是拿到 MarkExport 符号,不等于是 `dotnetCampus.Telescope.MarkExportAttribute` 特性,需要走语义分析 From bf051cbf490d7c5a948e7d3b2b400667e980bfea Mon Sep 17 00:00:00 2001 From: lindexi Date: Fri, 16 Jun 2023 14:52:10 +0800 Subject: [PATCH 03/48] =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E5=AF=B9=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=AF=BC=E5=87=BA=E7=9A=84=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportAttribute.cs | 8 +++++ ...eExportTypeToMethodIncrementalGenerator.cs | 36 +++++++++++++++++++ ....Telescope.SourceGeneratorAnalyzers.csproj | 4 +++ ...ourceGeneratorAnalyzers.csproj.DotSettings | 4 ++- .../TelescopeSourceGeneratorDemo/Program.cs | 2 ++ 5 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs b/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs new file mode 100644 index 0000000..b935ade --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs @@ -0,0 +1,8 @@ +// ReSharper disable once CheckNamespace 这个代码将会被编到用户的代码里面,请不要随意改动 +namespace dotnetCampus.Telescope +{ + [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + sealed class TelescopeExportAttribute : global::System.Attribute + { + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs new file mode 100644 index 0000000..0a80151 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -0,0 +1,36 @@ +using System.Diagnostics; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 从标记的方法导出类型 +/// +[Generator(LanguageNames.CSharp)] +public class TelescopeExportTypeToMethodIncrementalGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { +#if DEBUG + Debugger.Launch(); +#endif + // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 + // 这里可以用来存放具体实现的代码,将不影响用户代码的语义,而不是用来做定义的代码 + //context.RegisterImplementationSourceOutput(); + + // 在所有逻辑执行之前将会开始跑的代码,参与到用户代码里面,影响用户代码的语义 + // 一般是用来输出一些定义的代码 + context.RegisterPostInitializationOutput(static context => + { + var assembly = typeof(TelescopeExportTypeToMethodIncrementalGenerator).Assembly; + var telescopeExportAttributeCodeStream = assembly.GetManifestResourceStream("dotnetCampus.Telescope.SourceGeneratorAnalyzers.EmbeddedResourceCode.TelescopeExportAttribute.cs")!; + var sourceText = SourceText.From(telescopeExportAttributeCodeStream, + // error : Unhandled exception. System.ArgumentException: SourceText cannot be embedded. Provide encoding or canBeEmbedded = true at construction. (Parameter 'text') + canBeEmbedded: true); + context.AddSource("TelescopeExportAttribute", sourceText); + }); + + + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj index e05efec..73dbf8e 100644 --- a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj +++ b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj @@ -10,6 +10,10 @@ false + + + + diff --git a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings index 8616cc0..8ee19e4 100644 --- a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings +++ b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings @@ -1,2 +1,4 @@  - True \ No newline at end of file + True + True + True \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 31eda76..41b160d 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -12,6 +12,8 @@ static void Main(string[] args) Console.WriteLine(exportedTypeMetadata.RealType.FullName); } } + + } [Foo(0, FooEnum.N1, typeof(Foo), null)] From 65fbd6902576fb76fdef4463e0f9b7d43decaccc Mon Sep 17 00:00:00 2001 From: lindexi Date: Sat, 1 Jul 2023 11:34:59 +0800 Subject: [PATCH 04/48] =?UTF-8?q?=E6=94=B6=E9=9B=86=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 73 ++++++++++++++++++- .../TelescopeIncrementalGenerator.cs | 4 +- .../TelescopeSourceGeneratorDemo/Program.cs | 21 +++--- 3 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index 0a80151..738cb21 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -1,5 +1,9 @@ using System.Diagnostics; +using System.Linq; + using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; @@ -15,9 +19,64 @@ public void Initialize(IncrementalGeneratorInitializationContext context) #if DEBUG Debugger.Launch(); #endif + // 先找到定义 + IncrementalValuesProvider collectionExportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, token) => + { + // 先要求是分部的方法,分部的方法必定在分部类里面,这部分判断分部类里面还可以省略 + if (syntaxNode is MethodDeclarationSyntax methodDeclarationSyntax && methodDeclarationSyntax.AttributeLists.Any()) + { + // 同时满足以下条件: + // 1. 是方法 + // 2. 方法带特性 + // 3. 是分部方法 + if (methodDeclarationSyntax.Modifiers.Any(t => t.IsKind(SyntaxKind.PartialKeyword))) + { + return true; + } + } + + return false; + }, (generatorSyntaxContext, token) => + { + // 语义分析,判断方法是否标记了 TelescopeExportAttribute 特性 + + var methodDeclarationSyntax = (MethodDeclarationSyntax) generatorSyntaxContext.Node; + + // 从语法转换为语义,用于后续判断是否标记了特性 + IMethodSymbol? methodSymbol = + generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(methodDeclarationSyntax, token); + + if (methodSymbol is null) + { + return default; + } + + var attributeDataArray = methodSymbol.GetAttributes(); + foreach (var attributeData in attributeDataArray) + { + token.ThrowIfCancellationRequested(); + + var attributeName = attributeData.AttributeClass?.ToDisplayString(new SymbolDisplayFormat(globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included)); + if (attributeName == "global::dotnetCampus.Telescope.TelescopeExportAttribute") + { + + return new CollectionExportTypeResult(methodSymbol, generatorSyntaxContext); + } + } + + return null; + }) + // 过滤不满足条件的 + .Where(t => t is not null) + .Select((t, _) => t!); + // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 // 这里可以用来存放具体实现的代码,将不影响用户代码的语义,而不是用来做定义的代码 - //context.RegisterImplementationSourceOutput(); + context.RegisterImplementationSourceOutput(collectionExportMethodIncrementalValuesProvider, + (productionContext, result) => + { + + }); // 在所有逻辑执行之前将会开始跑的代码,参与到用户代码里面,影响用户代码的语义 // 一般是用来输出一些定义的代码 @@ -33,4 +92,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context) } + + class CollectionExportTypeResult + { + public CollectionExportTypeResult(IMethodSymbol methodSymbol, GeneratorSyntaxContext generatorSyntaxContext) + { + MethodSymbol = methodSymbol; + GeneratorSyntaxContext = generatorSyntaxContext; + } + + public IMethodSymbol MethodSymbol { get; } + public GeneratorSyntaxContext GeneratorSyntaxContext { get; } + } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs index dd26f0a..2749c6b 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs @@ -17,7 +17,9 @@ public class TelescopeIncrementalGenerator : IIncrementalGenerator public void Initialize(IncrementalGeneratorInitializationContext context) { #if DEBUG - Debugger.Launch(); + //Debugger.Launch(); + // 先注释掉,不要打扰 + return; #endif // 先读取程序集特性,接着遍历整个程序集的所有代码文件,看看哪些是符合需求的,收集起来 diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 41b160d..6ebc3ea 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -1,19 +1,22 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo; -internal class Program +internal partial class Program { static void Main(string[] args) { - var attributedTypesExport = new __AttributedTypesExport__(); - ICompileTimeAttributedTypesExporter exporter = attributedTypesExport; - foreach (var exportedTypeMetadata in exporter.ExportAttributeTypes()) - { - // 输出导出的类型 - Console.WriteLine(exportedTypeMetadata.RealType.FullName); - } + //var attributedTypesExport = new __AttributedTypesExport__(); + //ICompileTimeAttributedTypesExporter exporter = attributedTypesExport; + //foreach (var exportedTypeMetadata in exporter.ExportAttributeTypes()) + //{ + // // 输出导出的类型 + // Console.WriteLine(exportedTypeMetadata.RealType.FullName); + //} } - + [dotnetCampus.Telescope.TelescopeExportAttribute] + private static partial Base[] ExportFoo(); + //private static partial IEnumerable ExportFooEnumerable(); + //private static partial Func[] ExportFooCreator(); } [Foo(0, FooEnum.N1, typeof(Foo), null)] From 32e9c59e51dd268b55123a5c137dfe93cecc657e Mon Sep 17 00:00:00 2001 From: lindexi Date: Sat, 1 Jul 2023 17:21:19 +0800 Subject: [PATCH 05/48] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=94=B6=E9=9B=86?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=9A=84=E6=89=80=E6=9C=89=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 167 ++++++++++++++++-- 1 file changed, 157 insertions(+), 10 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index 738cb21..2a14460 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -1,4 +1,6 @@ -using System.Diagnostics; +using System; +using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; @@ -20,7 +22,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) Debugger.Launch(); #endif // 先找到定义 - IncrementalValuesProvider collectionExportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, token) => + IncrementalValuesProvider exportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, token) => { // 先要求是分部的方法,分部的方法必定在分部类里面,这部分判断分部类里面还可以省略 if (syntaxNode is MethodDeclarationSyntax methodDeclarationSyntax && methodDeclarationSyntax.AttributeLists.Any()) @@ -56,11 +58,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { token.ThrowIfCancellationRequested(); - var attributeName = attributeData.AttributeClass?.ToDisplayString(new SymbolDisplayFormat(globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included)); + var attributeName = attributeData.AttributeClass?.ToDisplayString(new SymbolDisplayFormat(globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); if (attributeName == "global::dotnetCampus.Telescope.TelescopeExportAttribute") { - - return new CollectionExportTypeResult(methodSymbol, generatorSyntaxContext); + return new ExportTypeCollectionResult(methodSymbol, generatorSyntaxContext); } } @@ -70,9 +71,75 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Where(t => t is not null) .Select((t, _) => t!); + // 获取方法返回值导出类型 + var exportMethodReturnTypeCollectionResultIncrementalValuesProvider = exportMethodIncrementalValuesProvider.Select((exportTypeCollectionResult, token) => + { + ITypeSymbol methodSymbolReturnType = exportTypeCollectionResult.MethodSymbol.ReturnType; + + if (methodSymbolReturnType is IArrayTypeSymbol arrayTypeSymbol) + { + // 如果是如 partial Base[] ExportFoo() 这样的,收集起来 + ITypeSymbol elementType = arrayTypeSymbol.ElementType; + return new ExportMethodReturnTypeCollectionResult(elementType, null, exportTypeCollectionResult.MethodSymbol) as IExportMethodReturnTypeCollectionResult; + } + else if (methodSymbolReturnType is INamedTypeSymbol namedTypeSymbol) + { + if (namedTypeSymbol.IsGenericType) + { + } + } + + // 其他不认识的,要告诉开发者不能这样写哦 + return new ExportMethodReturnTypeCollectionDiagnostic(); + }); + + // 这是有定义出错的,需要反馈给到开发者的 + var diagnosticIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider.Select((t, _) => t as ExportMethodReturnTypeCollectionDiagnostic).Where(t => t is not null); + + //context.RegisterSourceOutput(diagnosticIncrementalValuesProvider , (productionContext, diagnostic) => + //{ + // productionContext.ReportDiagnostic(); + //}); + + // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 + IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider + .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) + .Where(t => t is not null) + .Select((t, _) => t!) + .Collect(); + + // 收集到了期望收集的内容,将开始进行整个项目的类型收集 + + // 先收集整个项目里面所有的类型 + var assemblyClassIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => + { + return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); + }, (generatorSyntaxContext, token) => + { + var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; + // 从语法转换为语义,用于后续判断是否标记了特性 + INamedTypeSymbol? assemblyClassTypeSymbol = + generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); + if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) + { + return new AssemblyClassCollectionResult(assemblyClassTypeSymbol, classDeclarationSyntax); + } + + return null; + }); + + var candidateClassCollectionResultIncrementalValuesProvider = assemblyClassIncrementalValuesProvider + .Combine(returnTypeCollectionIncrementalValuesProvider) + .Select((tuple, token) => + { + + return new CandidateClassCollectionResult(); + }) + .Where(t => t is not null); + // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 // 这里可以用来存放具体实现的代码,将不影响用户代码的语义,而不是用来做定义的代码 - context.RegisterImplementationSourceOutput(collectionExportMethodIncrementalValuesProvider, + context.RegisterImplementationSourceOutput(candidateClassCollectionResultIncrementalValuesProvider, (productionContext, result) => { @@ -89,13 +156,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context) canBeEmbedded: true); context.AddSource("TelescopeExportAttribute", sourceText); }); - - } - class CollectionExportTypeResult + class ExportTypeCollectionResult : IEquatable { - public CollectionExportTypeResult(IMethodSymbol methodSymbol, GeneratorSyntaxContext generatorSyntaxContext) + public ExportTypeCollectionResult(IMethodSymbol methodSymbol, GeneratorSyntaxContext generatorSyntaxContext) { MethodSymbol = methodSymbol; GeneratorSyntaxContext = generatorSyntaxContext; @@ -103,5 +168,87 @@ public CollectionExportTypeResult(IMethodSymbol methodSymbol, GeneratorSyntaxCon public IMethodSymbol MethodSymbol { get; } public GeneratorSyntaxContext GeneratorSyntaxContext { get; } + + public bool Equals(ExportTypeCollectionResult? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return GeneratorSyntaxContext.Equals(other.GeneratorSyntaxContext) && SymbolEqualityComparer.Default.Equals(MethodSymbol, other.MethodSymbol); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((ExportTypeCollectionResult) obj); + } + + public override int GetHashCode() + { + unchecked + { + return (MethodSymbol.GetHashCode() * 397) ^ GeneratorSyntaxContext.GetHashCode(); + } + } + } + + /// + /// 收集导出方法返回值类型 + /// + /// 可以是收集到了,也可以是返回开发者定义错误代码 + interface IExportMethodReturnTypeCollectionResult + { + } + + class ExportMethodReturnTypeCollectionResult : IExportMethodReturnTypeCollectionResult + { + public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, IMethodSymbol exportPartialMethodSymbol) + { + ExpectedClassBaseType = expectedClassBaseType; + ExpectedClassAttributeType = expectedClassAttributeType; + ExportPartialMethodSymbol = exportPartialMethodSymbol; + } + + /// + /// 期望收集的类型所继承的基础类型 + /// + public ITypeSymbol ExpectedClassBaseType { get; } + + /// + /// 期望类型标记的特性,可选 + /// + public ITypeSymbol? ExpectedClassAttributeType { get; } + + /// + /// 程序集里面标记了导出的分部方法,将用来生成代码 + /// + public IMethodSymbol ExportPartialMethodSymbol { get; } + } + + class ExportMethodReturnTypeCollectionDiagnostic : IExportMethodReturnTypeCollectionResult + { + + } + + /// + /// 程序集里面的类型收集结果 + /// + class AssemblyClassCollectionResult + { + public AssemblyClassCollectionResult(INamedTypeSymbol assemblyClassTypeSymbol, ClassDeclarationSyntax classDeclarationSyntax) + { + AssemblyClassTypeSymbol = assemblyClassTypeSymbol; + ClassDeclarationSyntax = classDeclarationSyntax; + } + + public INamedTypeSymbol AssemblyClassTypeSymbol { get; } + public ClassDeclarationSyntax ClassDeclarationSyntax { get; } + } + + class CandidateClassCollectionResult + { + } } \ No newline at end of file From 605cdd97aafe6c90b9b001939557edb5a813f0e6 Mon Sep 17 00:00:00 2001 From: lindexi Date: Sun, 2 Jul 2023 10:31:19 +0800 Subject: [PATCH 06/48] =?UTF-8?q?=E5=88=A4=E6=96=AD=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E9=87=8C=E9=9D=A2=E7=9A=84=E7=B1=BB=E5=9E=8B=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E7=AC=A6=E5=90=88=E9=A2=84=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index 2a14460..f4eb951 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -3,6 +3,8 @@ using System.Diagnostics; using System.Linq; +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -58,7 +60,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { token.ThrowIfCancellationRequested(); - var attributeName = attributeData.AttributeClass?.ToDisplayString(new SymbolDisplayFormat(globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included, SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces)); + if(attributeData.AttributeClass is null) continue; + + var attributeName = TypeSymbolHelper.TypeSymbolToFullName(attributeData.AttributeClass); if (attributeName == "global::dotnetCampus.Telescope.TelescopeExportAttribute") { return new ExportTypeCollectionResult(methodSymbol, generatorSyntaxContext); @@ -112,26 +116,41 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 先收集整个项目里面所有的类型 var assemblyClassIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => - { - return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); - }, (generatorSyntaxContext, token) => - { - var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; - // 从语法转换为语义,用于后续判断是否标记了特性 - INamedTypeSymbol? assemblyClassTypeSymbol = - generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); - if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) { - return new AssemblyClassCollectionResult(assemblyClassTypeSymbol, classDeclarationSyntax); - } + return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); + }, (generatorSyntaxContext, token) => + { + var classDeclarationSyntax = (ClassDeclarationSyntax)generatorSyntaxContext.Node; + // 从语法转换为语义,用于后续判断是否标记了特性 + INamedTypeSymbol? assemblyClassTypeSymbol = + generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); + if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) + { + return new AssemblyClassCollectionResult(assemblyClassTypeSymbol, classDeclarationSyntax); + } - return null; - }); + return null; + }) + .Where(t => t != null) + .Select((t,_)=>t!); var candidateClassCollectionResultIncrementalValuesProvider = assemblyClassIncrementalValuesProvider .Combine(returnTypeCollectionIncrementalValuesProvider) .Select((tuple, token) => { + var assemblyClassCollectionResult = tuple.Left; + var exportMethodReturnTypeCollectionResultArray = tuple.Right; + + foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResultArray) + { + if (SymbolEqualityComparer.Default.Equals(exportMethodReturnTypeCollectionResult.ExpectedClassBaseType, assemblyClassCollectionResult.AssemblyClassTypeSymbol)) + { + if (exportMethodReturnTypeCollectionResult.ExpectedClassAttributeType is null) + { + // 没有 Attribute 的要求 + } + } + } return new CandidateClassCollectionResult(); }) From 3563746b4684cb81faa2496a8bdff11bd1e8c47a Mon Sep 17 00:00:00 2001 From: lindexi Date: Sun, 2 Jul 2023 11:26:15 +0800 Subject: [PATCH 07/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/TypeSymbolHelper.cs | 33 +++++++++++++++++++ ...eExportTypeToMethodIncrementalGenerator.cs | 2 +- .../TelescopeIncrementalGenerator.cs | 30 +---------------- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/TypeSymbolHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/TypeSymbolHelper.cs index 0efa05d..62e4234 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/TypeSymbolHelper.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/TypeSymbolHelper.cs @@ -21,4 +21,37 @@ public static string TypeSymbolToFullName(ITypeSymbol typeSymbol) return typeSymbol.ToDisplayString(symbolDisplayFormat); } + + /// + /// 判断类型继承关系 + /// + /// 当前的类型 + /// 需要继承的类型 + /// + public static bool IsInherit(ITypeSymbol currentType, ITypeSymbol requiredType) + { + var baseType = currentType.BaseType; + while (baseType is not null) + { + if (SymbolEqualityComparer.Default.Equals(baseType, requiredType)) + { + // 如果基类型是的话 + return true; + } + + // 否则继续找基类型 + baseType = baseType.BaseType; + } + + foreach (var currentInheritInterfaceType in currentType.AllInterfaces) + { + if (SymbolEqualityComparer.Default.Equals(currentInheritInterfaceType, requiredType)) + { + // 如果继承的类型是的话 + return true; + } + } + + return false; + } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index f4eb951..a2f839e 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -143,7 +143,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResultArray) { - if (SymbolEqualityComparer.Default.Equals(exportMethodReturnTypeCollectionResult.ExpectedClassBaseType, assemblyClassCollectionResult.AssemblyClassTypeSymbol)) + if (TypeSymbolHelper.IsInherit(assemblyClassCollectionResult.AssemblyClassTypeSymbol, exportMethodReturnTypeCollectionResult.ExpectedClassBaseType)) { if (exportMethodReturnTypeCollectionResult.ExpectedClassAttributeType is null) { diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs index 2749c6b..e93e7d3 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs @@ -166,7 +166,7 @@ private List ParseMarkClassList(AssemblyCandidateClassPars // 再判断继承类型 var requiredBaseClassOrInterfaceType = markExportAttributeParseResult.BaseClassOrInterfaceTypeInfo; - if (IsInherit(classParseResult.ExportedTypeSymbol, requiredBaseClassOrInterfaceType)) + if (TypeSymbolHelper.IsInherit(classParseResult.ExportedTypeSymbol, requiredBaseClassOrInterfaceType)) { return new MarkClassParseResult(classParseResult.ExportedTypeSymbol, classParseResult.ExportedTypeClassDeclarationSyntax, matchAssemblyMarkAttributeData, markAttributeSyntax, @@ -174,34 +174,6 @@ private List ParseMarkClassList(AssemblyCandidateClassPars } return null; - - // 判断类型继承关系 - static bool IsInherit(ITypeSymbol currentType, ITypeSymbol requiredType) - { - var baseType = currentType.BaseType; - while (baseType is not null) - { - if (SymbolEqualityComparer.Default.Equals(baseType, requiredType)) - { - // 如果基类型是的话 - return true; - } - - // 否则继续找基类型 - baseType = baseType.BaseType; - } - - foreach (var currentInheritInterfaceType in currentType.AllInterfaces) - { - if (SymbolEqualityComparer.Default.Equals(currentInheritInterfaceType, requiredType)) - { - // 如果继承的类型是的话 - return true; - } - } - - return false; - } } /// From 342abc7d96d44b3814c72bdff1bee39c9f92ad44 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 21 Aug 2023 16:53:34 +0800 Subject: [PATCH 08/48] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 32 ++++++++++++++++++- .../TelescopeSourceGeneratorDemo/Program.cs | 5 +-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index 0a80151..6209b11 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -1,5 +1,10 @@ -using System.Diagnostics; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; @@ -31,6 +36,31 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.AddSource("TelescopeExportAttribute", sourceText); }); + var incrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((node, token) => + { + if (node is MethodDeclarationSyntax methodDeclarationSyntax) + { + // 标记 TelescopeExportAttribute 特性 + if (methodDeclarationSyntax.AttributeLists.SelectMany(t => t.Attributes).Any(t => t.ToString().Contains("TelescopeExport"))) + { + // 方法是 Partial 的 + if (methodDeclarationSyntax.Modifiers.Any(SyntaxKind.PartialKeyword)) + { + return true; + } + } + } + + return false; + }, + (syntaxContext, token) => + { + return syntaxContext; + }); + context.RegisterImplementationSourceOutput(incrementalValuesProvider, (productionContext, syntaxContext) => + { + + }); } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 41b160d..cb3b6ae 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -1,6 +1,6 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo; -internal class Program +internal partial class Program { static void Main(string[] args) { @@ -13,7 +13,8 @@ static void Main(string[] args) } } - + [TelescopeExport] + private static partial IEnumerable Export(); } [Foo(0, FooEnum.N1, typeof(Foo), null)] From e9eec0568cf79a4ca11e13a394961e1ddcf4f22c Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 21 Aug 2023 16:55:57 +0800 Subject: [PATCH 09/48] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index 036bb16..9af1e1c 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -1,4 +1,6 @@ -using System.Diagnostics; +using System; +using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; @@ -58,7 +60,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { token.ThrowIfCancellationRequested(); - if(attributeData.AttributeClass is null) continue; + if (attributeData.AttributeClass is null) continue; var attributeName = TypeSymbolHelper.TypeSymbolToFullName(attributeData.AttributeClass); if (attributeName == "global::dotnetCampus.Telescope.TelescopeExportAttribute") @@ -118,7 +120,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); }, (generatorSyntaxContext, token) => { - var classDeclarationSyntax = (ClassDeclarationSyntax)generatorSyntaxContext.Node; + var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; // 从语法转换为语义,用于后续判断是否标记了特性 INamedTypeSymbol? assemblyClassTypeSymbol = generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); @@ -130,7 +132,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return null; }) .Where(t => t != null) - .Select((t,_)=>t!); + .Select((t, _) => t!); var candidateClassCollectionResultIncrementalValuesProvider = assemblyClassIncrementalValuesProvider .Combine(returnTypeCollectionIncrementalValuesProvider) @@ -264,31 +266,8 @@ public AssemblyClassCollectionResult(INamedTypeSymbol assemblyClassTypeSymbol, C public ClassDeclarationSyntax ClassDeclarationSyntax { get; } } - var incrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((node, token) => - { - if (node is MethodDeclarationSyntax methodDeclarationSyntax) - { - // 标记 TelescopeExportAttribute 特性 - if (methodDeclarationSyntax.AttributeLists.SelectMany(t => t.Attributes).Any(t => t.ToString().Contains("TelescopeExport"))) - { - // 方法是 Partial 的 - if (methodDeclarationSyntax.Modifiers.Any(SyntaxKind.PartialKeyword)) - { - return true; - } - } - } - - return false; - }, - (syntaxContext, token) => - { - - return syntaxContext; - }); - context.RegisterImplementationSourceOutput(incrementalValuesProvider, (productionContext, syntaxContext) => - { + class CandidateClassCollectionResult + { - }); } } \ No newline at end of file From 5ad0a3aefd09cff60569cc717d6d4c2f40bfd204 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 21 Aug 2023 17:30:40 +0800 Subject: [PATCH 10/48] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9A=84=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportAttribute.cs | 4 +++ ...eExportTypeToMethodIncrementalGenerator.cs | 33 ++++++++++++++----- .../TelescopeSourceGeneratorDemo/Program.cs | 6 ++-- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs b/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs index b935ade..0d83cc3 100644 --- a/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs +++ b/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs @@ -4,5 +4,9 @@ namespace dotnetCampus.Telescope [global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false, AllowMultiple = false)] sealed class TelescopeExportAttribute : global::System.Attribute { + /// + /// 是否包含引用的程序集和 DLL 里面的类型导出。默认只导出当前程序集 + /// + public bool IncludeReference { set; get; } } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index 9af1e1c..db15f8a 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -65,7 +65,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var attributeName = TypeSymbolHelper.TypeSymbolToFullName(attributeData.AttributeClass); if (attributeName == "global::dotnetCampus.Telescope.TelescopeExportAttribute") { - return new ExportTypeCollectionResult(methodSymbol, generatorSyntaxContext); + var attributeDataNamedArguments = attributeData.NamedArguments; + var includeReference = + attributeDataNamedArguments + .FirstOrDefault(t => t.Key == nameof(TelescopeExportAttribute.IncludeReference)).Value + .Value is true; + + return new ExportTypeCollectionResult(methodSymbol, generatorSyntaxContext) + { + IncludeReference = includeReference + }; } } @@ -80,17 +89,20 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { ITypeSymbol methodSymbolReturnType = exportTypeCollectionResult.MethodSymbol.ReturnType; - if (methodSymbolReturnType is IArrayTypeSymbol arrayTypeSymbol) - { - // 如果是如 partial Base[] ExportFoo() 这样的,收集起来 - ITypeSymbol elementType = arrayTypeSymbol.ElementType; - return new ExportMethodReturnTypeCollectionResult(elementType, null, exportTypeCollectionResult.MethodSymbol) as IExportMethodReturnTypeCollectionResult; - } - else if (methodSymbolReturnType is INamedTypeSymbol namedTypeSymbol) + //if (methodSymbolReturnType is IArrayTypeSymbol arrayTypeSymbol) + //{ + // // 如果是如 partial Base[] ExportFoo() 这样的,收集起来 + // ITypeSymbol elementType = arrayTypeSymbol.ElementType; + // return new ExportMethodReturnTypeCollectionResult(elementType, null, exportTypeCollectionResult.MethodSymbol) as IExportMethodReturnTypeCollectionResult; + //} + //else + if (methodSymbolReturnType is INamedTypeSymbol namedTypeSymbol) { if (namedTypeSymbol.IsGenericType) { } + + return new ExportMethodReturnTypeCollectionResult(namedTypeSymbol, null, exportTypeCollectionResult.MethodSymbol) as IExportMethodReturnTypeCollectionResult; } // 其他不认识的,要告诉开发者不能这样写哦 @@ -185,6 +197,11 @@ public ExportTypeCollectionResult(IMethodSymbol methodSymbol, GeneratorSyntaxCon GeneratorSyntaxContext = generatorSyntaxContext; } + /// + /// 是否包含引用的程序集和 DLL 里面的类型导出。默认只导出当前程序集 + /// + public bool IncludeReference { set; get; } + public IMethodSymbol MethodSymbol { get; } public GeneratorSyntaxContext GeneratorSyntaxContext { get; } diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 6ebc3ea..0a95c03 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -13,9 +13,9 @@ static void Main(string[] args) //} } - [dotnetCampus.Telescope.TelescopeExportAttribute] - private static partial Base[] ExportFoo(); - //private static partial IEnumerable ExportFooEnumerable(); + [dotnetCampus.Telescope.TelescopeExportAttribute(IncludeReference = true)] + //private static partial Base[] ExportFoo(); + private static partial IEnumerable<(Type, FooAttribute, Func)> ExportFooEnumerable(); //private static partial Func[] ExportFooCreator(); } From 10977ce45ab94c95157682326c1f97845ac82151 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 22 Aug 2023 16:59:07 +0800 Subject: [PATCH 11/48] =?UTF-8?q?=E5=AE=9A=E4=B9=89=20ValueTuple=20?= =?UTF-8?q?=E7=9A=84=E8=BD=AC=E6=8D=A2=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/ValueTuple_/ValueTupleInfo.cs | 16 +++++++ .../Core/ValueTuple_/ValueTupleInfoParser.cs | 46 +++++++++++++++++++ .../ValueTupleItemSyntaxAndSymbolInfo.cs | 25 ++++++++++ 3 files changed, 87 insertions(+) create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfo.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleItemSyntaxAndSymbolInfo.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfo.cs b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfo.cs new file mode 100644 index 0000000..c125e69 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfo.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +/// +/// 表示 ValueTuple 的信息 +/// +public class ValueTupleInfo +{ + public ValueTupleInfo(IReadOnlyList itemList) + { + ItemList = itemList; + } + + public IReadOnlyList ItemList { get; } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs new file mode 100644 index 0000000..cc42804 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +public static class ValueTupleInfoParser +{ + public static bool TryParse(ITypeSymbol type, out ValueTupleInfo valueTupleInfo) + { + valueTupleInfo = null!; + + if (type is not INamedTypeSymbol typeArgument) + { + return false; + } + + // 尝试判断是 ValueTuple 的情况 + // (Type type, FooAttribute xx, Func xxx) + if (type.IsValueType && typeArgument.TupleElements.Length > 0 && typeArgument.DeclaringSyntaxReferences[0].GetSyntax() is TupleTypeSyntax + valueTupleSyntaxNode) + { + Debug.Assert(typeArgument.TupleElements.Length == valueTupleSyntaxNode.Elements.Count); + + var list = new List(typeArgument.TupleElements.Length); + + for (var i = 0; i < valueTupleSyntaxNode.Elements.Count; i++) + { + var tupleItemTypeSymbol = typeArgument.TupleElements[i]; + ITypeSymbol typeSymbol = tupleItemTypeSymbol.Type; + // 这个是不对的,在开发者没有设置命名时,拿到的是 Item1 Item2 这样的命名 + //var name = tupleItemTypeSymbol.Name; + var tupleItemSyntax = valueTupleSyntaxNode.Elements[i]; + var name = tupleItemSyntax.Identifier.Text; + + list.Add(new ValueTupleItemSyntaxAndSymbolInfo(typeSymbol, name)); + } + + valueTupleInfo = new ValueTupleInfo(list); + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleItemSyntaxAndSymbolInfo.cs b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleItemSyntaxAndSymbolInfo.cs new file mode 100644 index 0000000..9197e70 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleItemSyntaxAndSymbolInfo.cs @@ -0,0 +1,25 @@ +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +/// +/// 表示 ValueTuple 的每一项的定义内容 +/// +public class ValueTupleItemSyntaxAndSymbolInfo +{ + public ValueTupleItemSyntaxAndSymbolInfo(ITypeSymbol itemType, string itemName) + { + ItemType = itemType; + ItemName = itemName; + } + + /// + /// 类型 + /// + public ITypeSymbol ItemType { get; } + + /// + /// 命名。如果没有命名,那就是空字符串 + /// + public string ItemName { get; } +} \ No newline at end of file From 85bba4c409559048232e9bcb131ec898f33c29bc Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 22 Aug 2023 16:59:35 +0800 Subject: [PATCH 12/48] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 62 ++++++++++++++++++- ...ourceGeneratorAnalyzers.csproj.DotSettings | 1 + .../TelescopeSourceGeneratorDemo/Program.cs | 9 ++- 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs index db15f8a..64c1929 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -10,6 +10,8 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; +using static dotnetCampus.Telescope.SourceGeneratorAnalyzers.TelescopeExportTypeToMethodIncrementalGenerator; + namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; /// @@ -98,11 +100,42 @@ public void Initialize(IncrementalGeneratorInitializationContext context) //else if (methodSymbolReturnType is INamedTypeSymbol namedTypeSymbol) { - if (namedTypeSymbol.IsGenericType) + if (namedTypeSymbol.IsGenericType && TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol) == + "global::System.Collections.Generic.IEnumerable") { + if (namedTypeSymbol.TypeArguments.Length == 1) + { + // 尝试判断是 ValueTuple 的情况 + if (namedTypeSymbol.TypeArguments[0] is INamedTypeSymbol typeArgument && + typeArgument.IsValueType) + { + if (typeArgument.TypeArguments.Length == 3 && typeArgument.TupleElements.Length == 3) + { + //var attributeData = typeArgument.GetAttributes(); // 0 + + //var memberNames = typeArgument.MemberNames; + //var namedTypeSymbols = typeArgument.GetTypeMembers(); // 0 + // static partial IEnumerable<(Type type, FooAttribute xx, Func xxx)> ExportFooEnumerable(); + var type = typeArgument.TupleElements[0]; + ITypeSymbol typeSymbol = type.Type; + var typeName = type.Name; + if (typeArgument.DeclaringSyntaxReferences[0].GetSyntax() is TupleTypeSyntax valueTupleSyntaxNode) + { + if (valueTupleSyntaxNode.Elements.Count == 3) + { + foreach (var tupleElementSyntax in valueTupleSyntaxNode.Elements) + { + var tupleName = tupleElementSyntax.Identifier.Text; + } + } + } + } + } + } } - return new ExportMethodReturnTypeCollectionResult(namedTypeSymbol, null, exportTypeCollectionResult.MethodSymbol) as IExportMethodReturnTypeCollectionResult; + return new ExportMethodReturnTypeCollectionResult(namedTypeSymbol, null, + exportTypeCollectionResult.MethodSymbol, null!) as IExportMethodReturnTypeCollectionResult; } // 其他不认识的,要告诉开发者不能这样写哦 @@ -238,13 +271,17 @@ interface IExportMethodReturnTypeCollectionResult { } + /// + /// 导出的方法的导出类型返回值结果 + /// class ExportMethodReturnTypeCollectionResult : IExportMethodReturnTypeCollectionResult { - public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, IMethodSymbol exportPartialMethodSymbol) + public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, IMethodSymbol exportPartialMethodSymbol, IExportMethodReturnTypeInfo exportMethodReturnTypeInfo) { ExpectedClassBaseType = expectedClassBaseType; ExpectedClassAttributeType = expectedClassAttributeType; ExportPartialMethodSymbol = exportPartialMethodSymbol; + ExportMethodReturnTypeInfo = exportMethodReturnTypeInfo; } /// @@ -261,13 +298,32 @@ public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, /// 程序集里面标记了导出的分部方法,将用来生成代码 /// public IMethodSymbol ExportPartialMethodSymbol { get; } + + /// + /// 导出类型的返回类型信息 + /// + public IExportMethodReturnTypeInfo ExportMethodReturnTypeInfo { get; } } + class ExportMethodReturnTypeCollectionDiagnostic : IExportMethodReturnTypeCollectionResult { } + public interface IExportMethodReturnTypeInfo + { + } + + /// + /// 导出类型的返回类型信息 + /// + public class ValueTupleExportMethodReturnTypeInfo : IExportMethodReturnTypeInfo + { + + } + + /// /// 程序集里面的类型收集结果 /// diff --git a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings index 8ee19e4..61496b5 100644 --- a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings +++ b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings @@ -1,4 +1,5 @@  True True + True True \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 0a95c03..f6eecae 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -15,10 +15,17 @@ static void Main(string[] args) [dotnetCampus.Telescope.TelescopeExportAttribute(IncludeReference = true)] //private static partial Base[] ExportFoo(); - private static partial IEnumerable<(Type, FooAttribute, Func)> ExportFooEnumerable(); + private static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable(); //private static partial Func[] ExportFooCreator(); } +//internal partial class Program +//{ +// private static partial IEnumerable<(Type , FooAttribute xx, Func xxx)> ExportFooEnumerable() +// { +// } +//} + [Foo(0, FooEnum.N1, typeof(Foo), null)] abstract class F1 : Base { From cd661f9ba8294909fbc78142083cbf968062b55a Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 22 Aug 2023 17:03:29 +0800 Subject: [PATCH 13/48] =?UTF-8?q?=E6=95=B4=E7=90=86=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 32 +++---------------- ...ourceGeneratorAnalyzers.csproj.DotSettings | 3 +- 2 files changed, 7 insertions(+), 28 deletions(-) rename src/TelescopeSourceGenerator/Analyzers/{ => ExportTypeToMethod_}/TelescopeExportTypeToMethodIncrementalGenerator.cs (88%) diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs similarity index 88% rename from src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs rename to src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 64c1929..7166877 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -103,34 +103,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context) if (namedTypeSymbol.IsGenericType && TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol) == "global::System.Collections.Generic.IEnumerable") { - if (namedTypeSymbol.TypeArguments.Length == 1) + // 尝试判断是 ValueTuple 的情况 + // 要求符合以下定义 + // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() + if (namedTypeSymbol.TypeArguments.Length == 1 && ValueTupleInfoParser.TryParse(namedTypeSymbol.TypeArguments[0], out var valueTupleInfo) && valueTupleInfo.ItemList.Count == 3) { - // 尝试判断是 ValueTuple 的情况 - if (namedTypeSymbol.TypeArguments[0] is INamedTypeSymbol typeArgument && - typeArgument.IsValueType) - { - if (typeArgument.TypeArguments.Length == 3 && typeArgument.TupleElements.Length == 3) - { - //var attributeData = typeArgument.GetAttributes(); // 0 - - //var memberNames = typeArgument.MemberNames; - //var namedTypeSymbols = typeArgument.GetTypeMembers(); // 0 - // static partial IEnumerable<(Type type, FooAttribute xx, Func xxx)> ExportFooEnumerable(); - var type = typeArgument.TupleElements[0]; - ITypeSymbol typeSymbol = type.Type; - var typeName = type.Name; - if (typeArgument.DeclaringSyntaxReferences[0].GetSyntax() is TupleTypeSyntax valueTupleSyntaxNode) - { - if (valueTupleSyntaxNode.Elements.Count == 3) - { - foreach (var tupleElementSyntax in valueTupleSyntaxNode.Elements) - { - var tupleName = tupleElementSyntax.Identifier.Text; - } - } - } - } - } + } } diff --git a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings index 61496b5..3b3ee1e 100644 --- a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings +++ b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj.DotSettings @@ -2,4 +2,5 @@ True True True - True \ No newline at end of file + True + True \ No newline at end of file From 12c0a0a3c39339f89074cec2dae3fed1e5b060bb Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 22 Aug 2023 17:03:56 +0800 Subject: [PATCH 14/48] =?UTF-8?q?=E6=8B=86=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IExportMethodReturnTypeInfo.cs | 5 +++++ ...elescopeExportTypeToMethodIncrementalGenerator.cs | 12 +----------- .../ValueTupleExportMethodReturnTypeInfo.cs | 9 +++++++++ 3 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs new file mode 100644 index 0000000..0825ee9 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs @@ -0,0 +1,5 @@ +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +public interface IExportMethodReturnTypeInfo +{ +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 7166877..637e8b2 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -289,17 +289,7 @@ class ExportMethodReturnTypeCollectionDiagnostic : IExportMethodReturnTypeCollec } - public interface IExportMethodReturnTypeInfo - { - } - - /// - /// 导出类型的返回类型信息 - /// - public class ValueTupleExportMethodReturnTypeInfo : IExportMethodReturnTypeInfo - { - - } + /// diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs new file mode 100644 index 0000000..1497d1c --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs @@ -0,0 +1,9 @@ +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 导出类型的返回类型信息 +/// +public class ValueTupleExportMethodReturnTypeInfo : IExportMethodReturnTypeInfo +{ + +} \ No newline at end of file From 956cfc0808608eaa901efebbc6e4cf86f80ef306 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 23 Aug 2023 10:15:35 +0800 Subject: [PATCH 15/48] =?UTF-8?q?=E5=B0=81=E8=A3=85=E8=BE=85=E5=8A=A9?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AssemblySymbolHelper.cs | 79 ++++++++++++++ ...eExportTypeToMethodIncrementalGenerator.cs | 103 +++++++++++++++--- .../ValueTupleExportMethodReturnTypeInfo.cs | 9 +- 3 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs new file mode 100644 index 0000000..2ff04b5 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs @@ -0,0 +1,79 @@ +using Microsoft.CodeAnalysis; + +using System.Collections.Generic; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +static class AssemblySymbolHelper +{ + public static IEnumerable GetAllTypeSymbol(IAssemblySymbol assemblySymbol) => GetAllTypeSymbol(assemblySymbol.GlobalNamespace); + + public static IEnumerable GetAllTypeSymbol(INamespaceSymbol namespaceSymbol) + { + var typeMemberList = namespaceSymbol.GetTypeMembers(); + + foreach (var typeSymbol in typeMemberList) + { + yield return typeSymbol; + } + + foreach (var namespaceMember in namespaceSymbol.GetNamespaceMembers()) + { + foreach (var typeSymbol in GetAllTypeSymbol(namespaceMember)) + { + yield return typeSymbol; + } + } + } + + public static bool IsReference(IAssemblySymbol currentAssemblySymbol, IAssemblySymbol requiredAssemblySymbol) + { + var visited = new Dictionary(SymbolEqualityComparer.Default); + return IsReference(currentAssemblySymbol, requiredAssemblySymbol, visited); + } + + public static bool IsReference(IAssemblySymbol currentAssemblySymbol, IAssemblySymbol requiredAssemblySymbol, + Dictionary visited) + { + if (SymbolEqualityComparer.Default.Equals(currentAssemblySymbol, requiredAssemblySymbol)) + { + // 这个就看业务了,如果两个程序集是相同的,是否判断为引用关系 + return true; + } + + foreach (var moduleSymbol in currentAssemblySymbol.Modules) + { + foreach (var referencedAssemblySymbol in moduleSymbol.ReferencedAssemblySymbols) + { + if (SymbolEqualityComparer.Default.Equals(referencedAssemblySymbol, requiredAssemblySymbol)) + { + // 记录当前程序集存在引用关系 + visited[currentAssemblySymbol] = true; + return true; + } + else + { + if (visited.TryGetValue(referencedAssemblySymbol, out var isReference)) + { + // 这个是访问过的,那就从字典获取缓存,不需要再访问一次 + // 同时也能解决程序集循环引用问题 + } + else + { + // 没有访问过的,获取引用的程序集是否存在引用关系 + isReference = IsReference(referencedAssemblySymbol, requiredAssemblySymbol, visited); + visited[referencedAssemblySymbol] = isReference; + } + + if (isReference) + { + // 如果这个程序集有引用,那也算上 + return true; + } + } + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 637e8b2..fb36557 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; @@ -89,7 +90,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 获取方法返回值导出类型 var exportMethodReturnTypeCollectionResultIncrementalValuesProvider = exportMethodIncrementalValuesProvider.Select((exportTypeCollectionResult, token) => { - ITypeSymbol methodSymbolReturnType = exportTypeCollectionResult.MethodSymbol.ReturnType; + ITypeSymbol methodSymbolReturnType = exportTypeCollectionResult.ExportPartialMethodSymbol.ReturnType; //if (methodSymbolReturnType is IArrayTypeSymbol arrayTypeSymbol) //{ @@ -106,18 +107,21 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 尝试判断是 ValueTuple 的情况 // 要求符合以下定义 // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() - if (namedTypeSymbol.TypeArguments.Length == 1 && ValueTupleInfoParser.TryParse(namedTypeSymbol.TypeArguments[0], out var valueTupleInfo) && valueTupleInfo.ItemList.Count == 3) + if (namedTypeSymbol.TypeArguments.Length == 1 && ValueTupleInfoParser.TryParse(namedTypeSymbol.TypeArguments[0], out ValueTupleInfo valueTupleInfo) && valueTupleInfo.ItemList.Count == 3) { - + // 准备导出的类型的基类型 + var expectedClassBaseType = valueTupleInfo.ItemList[0].ItemType; + // 表示的特性 + var expectedClassAttributeType = valueTupleInfo.ItemList[1].ItemType; + + return new ExportMethodReturnTypeCollectionResult(expectedClassBaseType, expectedClassAttributeType, + exportTypeCollectionResult, new ValueTupleExportMethodReturnTypeInfo(valueTupleInfo)); } } - - return new ExportMethodReturnTypeCollectionResult(namedTypeSymbol, null, - exportTypeCollectionResult.MethodSymbol, null!) as IExportMethodReturnTypeCollectionResult; } // 其他不认识的,要告诉开发者不能这样写哦 - return new ExportMethodReturnTypeCollectionDiagnostic(); + return new ExportMethodReturnTypeCollectionDiagnostic() as IExportMethodReturnTypeCollectionResult; }); // 这是有定义出错的,需要反馈给到开发者的 @@ -157,6 +161,71 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Where(t => t != null) .Select((t, _) => t!); + // 将这些需要包含引用程序集的加进来返回值类型。因为标记导出支持带引用程序集的 + var assemblyReferenceExportReturnTypeProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider + .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) + // 只有非空且包含引用程序集的,才加入 + .Where(t => t is not null && t.ExportTypeCollectionResult.IncludeReference) + .Select((t, _) => t!) + .Collect(); + + // 收集引用的程序集的类型 + var referenceAssemblyTypeIncrementalValueProvider = context.CompilationProvider.Combine(assemblyReferenceExportReturnTypeProvider).Select((tuple, token) => + { + var compilation = tuple.Left; + var returnTypeCollectionResults = tuple.Right; + + // 所有导出类型的定义逻辑 + var exportMethodReturnTypeCollectionResults = tuple.Right; + + // 获取到所有引用程序集 + var referencedAssemblySymbols = compilation.SourceModule.ReferencedAssemblySymbols; + + foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResults) + { + + } + + foreach (IAssemblySymbol referencedAssemblySymbol in referencedAssemblySymbols) + { + var containingAssembly = exportMethodReturnTypeCollectionResults[0].ExpectedClassBaseType.ContainingAssembly; + + if (referencedAssemblySymbol.Modules.Any(t=>t.ReferencedAssemblySymbols.Any(x=>SymbolEqualityComparer.Default.Equals(x,containingAssembly)))) + { + + } + + //// 获取所有的类型 + //// 这里 ToList 只是为了方便调试 + //var allTypeSymbol = GetAllTypeSymbol(referencedAssemblySymbol.GlobalNamespace); + + //foreach (var namedTypeSymbol in allTypeSymbol) + //{ + + //} + } + + return 2; + + static IEnumerable GetAllTypeSymbol(INamespaceSymbol namespaceSymbol) + { + var typeMemberList = namespaceSymbol.GetTypeMembers(); + + foreach (var typeSymbol in typeMemberList) + { + yield return typeSymbol; + } + + foreach (var namespaceMember in namespaceSymbol.GetNamespaceMembers()) + { + foreach (var typeSymbol in GetAllTypeSymbol(namespaceMember)) + { + yield return typeSymbol; + } + } + } + }); + var candidateClassCollectionResultIncrementalValuesProvider = assemblyClassIncrementalValuesProvider .Combine(returnTypeCollectionIncrementalValuesProvider) .Select((tuple, token) => @@ -204,7 +273,7 @@ class ExportTypeCollectionResult : IEquatable { public ExportTypeCollectionResult(IMethodSymbol methodSymbol, GeneratorSyntaxContext generatorSyntaxContext) { - MethodSymbol = methodSymbol; + ExportPartialMethodSymbol = methodSymbol; GeneratorSyntaxContext = generatorSyntaxContext; } @@ -212,8 +281,10 @@ public ExportTypeCollectionResult(IMethodSymbol methodSymbol, GeneratorSyntaxCon /// 是否包含引用的程序集和 DLL 里面的类型导出。默认只导出当前程序集 /// public bool IncludeReference { set; get; } - - public IMethodSymbol MethodSymbol { get; } + /// + /// 程序集里面标记了导出的分部方法,将用来生成代码 + /// + public IMethodSymbol ExportPartialMethodSymbol { get; } public GeneratorSyntaxContext GeneratorSyntaxContext { get; } public bool Equals(ExportTypeCollectionResult? other) @@ -221,7 +292,7 @@ public bool Equals(ExportTypeCollectionResult? other) if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return GeneratorSyntaxContext.Equals(other.GeneratorSyntaxContext) && SymbolEqualityComparer.Default.Equals(MethodSymbol, other.MethodSymbol); + return GeneratorSyntaxContext.Equals(other.GeneratorSyntaxContext) && SymbolEqualityComparer.Default.Equals(ExportPartialMethodSymbol, other.ExportPartialMethodSymbol); } public override bool Equals(object? obj) @@ -236,7 +307,7 @@ public override int GetHashCode() { unchecked { - return (MethodSymbol.GetHashCode() * 397) ^ GeneratorSyntaxContext.GetHashCode(); + return (ExportPartialMethodSymbol.GetHashCode() * 397) ^ GeneratorSyntaxContext.GetHashCode(); } } } @@ -254,11 +325,11 @@ interface IExportMethodReturnTypeCollectionResult /// class ExportMethodReturnTypeCollectionResult : IExportMethodReturnTypeCollectionResult { - public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, IMethodSymbol exportPartialMethodSymbol, IExportMethodReturnTypeInfo exportMethodReturnTypeInfo) + public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, ExportTypeCollectionResult exportTypeCollectionResult, IExportMethodReturnTypeInfo exportMethodReturnTypeInfo) { ExpectedClassBaseType = expectedClassBaseType; ExpectedClassAttributeType = expectedClassAttributeType; - ExportPartialMethodSymbol = exportPartialMethodSymbol; + ExportTypeCollectionResult = exportTypeCollectionResult; ExportMethodReturnTypeInfo = exportMethodReturnTypeInfo; } @@ -272,10 +343,12 @@ public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, /// public ITypeSymbol? ExpectedClassAttributeType { get; } + public ExportTypeCollectionResult ExportTypeCollectionResult { get; } + /// /// 程序集里面标记了导出的分部方法,将用来生成代码 /// - public IMethodSymbol ExportPartialMethodSymbol { get; } + public IMethodSymbol ExportPartialMethodSymbol => ExportTypeCollectionResult.ExportPartialMethodSymbol; /// /// 导出类型的返回类型信息 diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs index 1497d1c..e8fb2bd 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs @@ -1,9 +1,16 @@ -namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; /// /// 导出类型的返回类型信息 /// public class ValueTupleExportMethodReturnTypeInfo : IExportMethodReturnTypeInfo { + public ValueTupleExportMethodReturnTypeInfo(ValueTupleInfo valueTupleInfo) + { + ValueTupleInfo = valueTupleInfo; + } + public ValueTupleInfo ValueTupleInfo { get; } } \ No newline at end of file From bc4d8f19aa63a8742f9610ebf81d1fad8fd6ab36 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 23 Aug 2023 12:11:39 +0800 Subject: [PATCH 16/48] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E6=95=B4=E4=B8=AA=E7=A8=8B=E5=BA=8F=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 158 +++++++++++------- 1 file changed, 96 insertions(+), 62 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index fb36557..b8506d0 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Data; using System.Diagnostics; using System.Linq; @@ -132,35 +133,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // productionContext.ReportDiagnostic(); //}); - // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 - IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider - .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) - .Where(t => t is not null) - .Select((t, _) => t!) - .Collect(); - // 收集到了期望收集的内容,将开始进行整个项目的类型收集 - // 先收集整个项目里面所有的类型 - var assemblyClassIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => - { - return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); - }, (generatorSyntaxContext, token) => - { - var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; - // 从语法转换为语义,用于后续判断是否标记了特性 - INamedTypeSymbol? assemblyClassTypeSymbol = - generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); - if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) - { - return new AssemblyClassCollectionResult(assemblyClassTypeSymbol, classDeclarationSyntax); - } - - return null; - }) - .Where(t => t != null) - .Select((t, _) => t!); - // 将这些需要包含引用程序集的加进来返回值类型。因为标记导出支持带引用程序集的 var assemblyReferenceExportReturnTypeProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) @@ -173,7 +147,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var referenceAssemblyTypeIncrementalValueProvider = context.CompilationProvider.Combine(assemblyReferenceExportReturnTypeProvider).Select((tuple, token) => { var compilation = tuple.Left; - var returnTypeCollectionResults = tuple.Right; // 所有导出类型的定义逻辑 var exportMethodReturnTypeCollectionResults = tuple.Right; @@ -181,50 +154,68 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 获取到所有引用程序集 var referencedAssemblySymbols = compilation.SourceModule.ReferencedAssemblySymbols; + var candidateClassList = new List(); + foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResults) { - - } + var assemblyClassTypeSymbolList = new List(); + var candidateClassTypeResult = new CandidateClassTypeResult(exportMethodReturnTypeCollectionResult, assemblyClassTypeSymbolList); + candidateClassList.Add(candidateClassTypeResult); - foreach (IAssemblySymbol referencedAssemblySymbol in referencedAssemblySymbols) - { - var containingAssembly = exportMethodReturnTypeCollectionResults[0].ExpectedClassBaseType.ContainingAssembly; + // 期望继承的基础类型 + var expectedClassBaseType = exportMethodReturnTypeCollectionResult.ExpectedClassBaseType; + // 过滤程序集,只有引用了期望继承的基础类型所在程序集的,才可以被收集到。如果没有引用,那自然写不出继承基础类型的代码 - if (referencedAssemblySymbol.Modules.Any(t=>t.ReferencedAssemblySymbols.Any(x=>SymbolEqualityComparer.Default.Equals(x,containingAssembly)))) - { - - } + var visited = new Dictionary(SymbolEqualityComparer.Default); - //// 获取所有的类型 - //// 这里 ToList 只是为了方便调试 - //var allTypeSymbol = GetAllTypeSymbol(referencedAssemblySymbol.GlobalNamespace); + foreach (var referencedAssemblySymbol in referencedAssemblySymbols) + { + if (!AssemblySymbolHelper.IsReference(referencedAssemblySymbol, expectedClassBaseType.ContainingAssembly, visited)) + { + // 如果当前程序集没有直接或间接继承期望继承的基础类型所在程序集,那就证明当前程序集一定不存在任何可能被收集的类型 + continue; + } - //foreach (var namedTypeSymbol in allTypeSymbol) - //{ - - //} + foreach (var assemblyClassTypeSymbol in AssemblySymbolHelper.GetAllTypeSymbol(referencedAssemblySymbol)) + { + if (exportMethodReturnTypeCollectionResult.IsMatch(assemblyClassTypeSymbol)) + { + assemblyClassTypeSymbolList.Add(assemblyClassTypeSymbol); + } + } + } } - return 2; + return new CandidateClassCollectionResult(candidateClassList); + }); - static IEnumerable GetAllTypeSymbol(INamespaceSymbol namespaceSymbol) + // 收集当前分析器所分析项目的类型 + // 先收集整个项目里面所有的类型 + var assemblyClassIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => { - var typeMemberList = namespaceSymbol.GetTypeMembers(); - - foreach (var typeSymbol in typeMemberList) + return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); + }, (generatorSyntaxContext, token) => + { + var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; + // 从语法转换为语义,用于后续判断是否标记了特性 + INamedTypeSymbol? assemblyClassTypeSymbol = + generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); + if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) { - yield return typeSymbol; + return new AssemblyClassCollectionResult(assemblyClassTypeSymbol, classDeclarationSyntax); } - foreach (var namespaceMember in namespaceSymbol.GetNamespaceMembers()) - { - foreach (var typeSymbol in GetAllTypeSymbol(namespaceMember)) - { - yield return typeSymbol; - } - } - } - }); + return null; + }) + .Where(t => t != null) + .Select((t, _) => t!); + + // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 + IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider + .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) + .Where(t => t is not null) + .Select((t, _) => t!) + .Collect(); var candidateClassCollectionResultIncrementalValuesProvider = assemblyClassIncrementalValuesProvider .Combine(returnTypeCollectionIncrementalValuesProvider) @@ -244,16 +235,28 @@ static IEnumerable GetAllTypeSymbol(INamespaceSymbol namespace } } - return new CandidateClassCollectionResult(); + return new CandidateClassCollectionResult(null!); }) .Where(t => t is not null); + var collectionResultIncrementalValueProvider = referenceAssemblyTypeIncrementalValueProvider.Combine(candidateClassCollectionResultIncrementalValuesProvider.Collect()) + .SelectMany((tuple, _) => { return tuple.Right.Add(tuple.Left); }) + .Collect() + .Select((array, _) => + { + // 去重 + return array.Distinct().ToList(); + }); + // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 // 这里可以用来存放具体实现的代码,将不影响用户代码的语义,而不是用来做定义的代码 - context.RegisterImplementationSourceOutput(candidateClassCollectionResultIncrementalValuesProvider, + context.RegisterImplementationSourceOutput(collectionResultIncrementalValueProvider, (productionContext, result) => { - + foreach (var candidateClassCollectionResult in result) + { + + } }); // 在所有逻辑执行之前将会开始跑的代码,参与到用户代码里面,影响用户代码的语义 @@ -354,6 +357,16 @@ public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, /// 导出类型的返回类型信息 /// public IExportMethodReturnTypeInfo ExportMethodReturnTypeInfo { get; } + + /// + /// 判断传入的程序集类型满足当前的要求条件 + /// + /// + /// + public bool IsMatch(INamedTypeSymbol assemblyClassTypeSymbol) + { + return true; + } } @@ -380,8 +393,29 @@ public AssemblyClassCollectionResult(INamedTypeSymbol assemblyClassTypeSymbol, C public ClassDeclarationSyntax ClassDeclarationSyntax { get; } } + /// + /// 候选收集的结果 + /// class CandidateClassCollectionResult { + public CandidateClassCollectionResult(IReadOnlyList candidateClassTypeResultList) + { + CandidateClassTypeResultList = candidateClassTypeResultList; + } + + public IReadOnlyList CandidateClassTypeResultList { get; } + } + + class CandidateClassTypeResult + { + public CandidateClassTypeResult(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, IReadOnlyList assemblyClassTypeSymbolList) + { + ExportMethodReturnTypeCollectionResult = exportMethodReturnTypeCollectionResult; + AssemblyClassTypeSymbolList = assemblyClassTypeSymbolList; + } + + public ExportMethodReturnTypeCollectionResult ExportMethodReturnTypeCollectionResult { get; } + public IReadOnlyList AssemblyClassTypeSymbolList { get; } } } \ No newline at end of file From fa12b861c82835666116aeea45bda0592b1228c4 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 23 Aug 2023 14:35:42 +0800 Subject: [PATCH 17/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=96=E9=94=99?= =?UTF-8?q?=E6=9C=9F=E6=9C=9B=E7=BB=A7=E6=89=BF=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportTypeToMethodIncrementalGenerator.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index b8506d0..c75d7cc 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -110,8 +110,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() if (namedTypeSymbol.TypeArguments.Length == 1 && ValueTupleInfoParser.TryParse(namedTypeSymbol.TypeArguments[0], out ValueTupleInfo valueTupleInfo) && valueTupleInfo.ItemList.Count == 3) { + if (TypeSymbolHelper.TypeSymbolToFullName(valueTupleInfo.ItemList[0].ItemType) != "global::System.Type") + { + // 这就是错误的 + } + + var funcTypeSymbol = (INamedTypeSymbol) valueTupleInfo.ItemList[2].ItemType; // 准备导出的类型的基类型 - var expectedClassBaseType = valueTupleInfo.ItemList[0].ItemType; + var expectedClassBaseType = funcTypeSymbol.TypeArguments[0]; + // 表示的特性 var expectedClassAttributeType = valueTupleInfo.ItemList[1].ItemType; From fd882bf274f486d9e8ccf7085fa0493972b46959 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 23 Aug 2023 14:43:34 +0800 Subject: [PATCH 18/48] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SourceFusion.sln | 21 +++++++++++++++++++ .../Demo/DemoLib1/F1.cs | 13 ++++++++++++ ...e.SourceGeneratorAnalyzers.DemoLib1.csproj | 13 ++++++++++++ .../Demo/DemoLib2/F2.cs | 14 +++++++++++++ ...e.SourceGeneratorAnalyzers.DemoLib2.csproj | 13 ++++++++++++ .../Demo/DemoLib3/F3.cs | 14 +++++++++++++ ...e.SourceGeneratorAnalyzers.DemoLib3.csproj | 13 ++++++++++++ .../TelescopeSourceGeneratorDemo/Program.cs | 6 ++++-- ...scope.SourceGeneratorAnalyzers.Demo.csproj | 1 + 9 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Demo/DemoLib1/F1.cs create mode 100644 src/TelescopeSourceGenerator/Demo/DemoLib1/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1.csproj create mode 100644 src/TelescopeSourceGenerator/Demo/DemoLib2/F2.cs create mode 100644 src/TelescopeSourceGenerator/Demo/DemoLib2/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib2.csproj create mode 100644 src/TelescopeSourceGenerator/Demo/DemoLib3/F3.cs create mode 100644 src/TelescopeSourceGenerator/Demo/DemoLib3/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib3.csproj diff --git a/SourceFusion.sln b/SourceFusion.sln index ca55f44..f2117d9 100644 --- a/SourceFusion.sln +++ b/SourceFusion.sln @@ -52,6 +52,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Actions", "GitHub Ac ..\Ipc\.github\workflows\nuget-tag-publish.yml = ..\Ipc\.github\workflows\nuget-tag-publish.yml EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1", "src\TelescopeSourceGenerator\Demo\DemoLib1\dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1.csproj", "{D9EA5A56-A4E4-4994-B634-8C1B1256D393}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib2", "src\TelescopeSourceGenerator\Demo\DemoLib2\dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib2.csproj", "{804D6902-6885-42A7-9EC3-BB0E09AAD3F2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib3", "src\TelescopeSourceGenerator\Demo\DemoLib3\dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib3.csproj", "{F1E050D2-E840-4793-8E97-024FBAD8908A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,6 +104,18 @@ Global {F1E2D63D-A05A-4647-ADB3-750A9F651D22}.Debug|Any CPU.Build.0 = Debug|Any CPU {F1E2D63D-A05A-4647-ADB3-750A9F651D22}.Release|Any CPU.ActiveCfg = Release|Any CPU {F1E2D63D-A05A-4647-ADB3-750A9F651D22}.Release|Any CPU.Build.0 = Release|Any CPU + {D9EA5A56-A4E4-4994-B634-8C1B1256D393}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9EA5A56-A4E4-4994-B634-8C1B1256D393}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9EA5A56-A4E4-4994-B634-8C1B1256D393}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9EA5A56-A4E4-4994-B634-8C1B1256D393}.Release|Any CPU.Build.0 = Release|Any CPU + {804D6902-6885-42A7-9EC3-BB0E09AAD3F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {804D6902-6885-42A7-9EC3-BB0E09AAD3F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {804D6902-6885-42A7-9EC3-BB0E09AAD3F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {804D6902-6885-42A7-9EC3-BB0E09AAD3F2}.Release|Any CPU.Build.0 = Release|Any CPU + {F1E050D2-E840-4793-8E97-024FBAD8908A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1E050D2-E840-4793-8E97-024FBAD8908A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1E050D2-E840-4793-8E97-024FBAD8908A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1E050D2-E840-4793-8E97-024FBAD8908A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -108,6 +126,9 @@ Global {C8BB3F7F-344C-40B4-BF00-005575C8C91A} = {A9879CB9-D164-4A0F-9F7A-D4B86C66BD68} {350C2DAF-7AD8-4285-9C8F-737D4D078B65} = {A9879CB9-D164-4A0F-9F7A-D4B86C66BD68} {F1E2D63D-A05A-4647-ADB3-750A9F651D22} = {A9879CB9-D164-4A0F-9F7A-D4B86C66BD68} + {D9EA5A56-A4E4-4994-B634-8C1B1256D393} = {A9879CB9-D164-4A0F-9F7A-D4B86C66BD68} + {804D6902-6885-42A7-9EC3-BB0E09AAD3F2} = {A9879CB9-D164-4A0F-9F7A-D4B86C66BD68} + {F1E050D2-E840-4793-8E97-024FBAD8908A} = {A9879CB9-D164-4A0F-9F7A-D4B86C66BD68} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {22702A10-22E1-4670-8FCA-9581202E6CAB} diff --git a/src/TelescopeSourceGenerator/Demo/DemoLib1/F1.cs b/src/TelescopeSourceGenerator/Demo/DemoLib1/F1.cs new file mode 100644 index 0000000..a3dd43e --- /dev/null +++ b/src/TelescopeSourceGenerator/Demo/DemoLib1/F1.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1; + +public class F1 +{ +} + +public class F1Attribute : Attribute{} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Demo/DemoLib1/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1.csproj b/src/TelescopeSourceGenerator/Demo/DemoLib1/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1.csproj new file mode 100644 index 0000000..d5b4d08 --- /dev/null +++ b/src/TelescopeSourceGenerator/Demo/DemoLib1/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + false + + + + + + diff --git a/src/TelescopeSourceGenerator/Demo/DemoLib2/F2.cs b/src/TelescopeSourceGenerator/Demo/DemoLib2/F2.cs new file mode 100644 index 0000000..5c85c34 --- /dev/null +++ b/src/TelescopeSourceGenerator/Demo/DemoLib2/F2.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib2; + +[F1] +public class F2 : F1 +{ +} diff --git a/src/TelescopeSourceGenerator/Demo/DemoLib2/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib2.csproj b/src/TelescopeSourceGenerator/Demo/DemoLib2/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib2.csproj new file mode 100644 index 0000000..6d4439c --- /dev/null +++ b/src/TelescopeSourceGenerator/Demo/DemoLib2/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib2.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + false + + + + + + diff --git a/src/TelescopeSourceGenerator/Demo/DemoLib3/F3.cs b/src/TelescopeSourceGenerator/Demo/DemoLib3/F3.cs new file mode 100644 index 0000000..41a7d3a --- /dev/null +++ b/src/TelescopeSourceGenerator/Demo/DemoLib3/F3.cs @@ -0,0 +1,14 @@ +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib3; + +[F1] +public class F3 : F1 +{ +} diff --git a/src/TelescopeSourceGenerator/Demo/DemoLib3/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib3.csproj b/src/TelescopeSourceGenerator/Demo/DemoLib3/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib3.csproj new file mode 100644 index 0000000..10f7c00 --- /dev/null +++ b/src/TelescopeSourceGenerator/Demo/DemoLib3/dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib3.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + false + + + + + + diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index f6eecae..5d1aace 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -1,4 +1,6 @@ -namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo; +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.DemoLib1; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo; internal partial class Program { @@ -15,7 +17,7 @@ static void Main(string[] args) [dotnetCampus.Telescope.TelescopeExportAttribute(IncludeReference = true)] //private static partial Base[] ExportFoo(); - private static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable(); + private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable(); //private static partial Func[] ExportFooCreator(); } diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo.csproj b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo.csproj index 122fd0f..17a567b 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo.csproj +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/dotnetCampus.Telescope.SourceGeneratorAnalyzers.Demo.csproj @@ -11,6 +11,7 @@ + From 423ce81c305d72c204b80a30b598ac3948ceda6d Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 23 Aug 2023 15:25:22 +0800 Subject: [PATCH 19/48] =?UTF-8?q?=E5=87=8F=E5=B0=91=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=A4=A7=E9=87=8F=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 85 ++++++++++--------- .../TelescopeSourceGeneratorDemo/Program.cs | 5 ++ 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index c75d7cc..4583790 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -197,8 +197,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context) }); // 收集当前分析器所分析项目的类型 + // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 + IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider + .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) + .Where(t => t is not null) + .Select((t, _) => t!) + .Collect(); + // 先收集整个项目里面所有的类型 - var assemblyClassIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => + var candidateClassCollectionResultIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => { return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); }, (generatorSyntaxContext, token) => @@ -209,40 +216,38 @@ public void Initialize(IncrementalGeneratorInitializationContext context) generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) { - return new AssemblyClassCollectionResult(assemblyClassTypeSymbol, classDeclarationSyntax); + return assemblyClassTypeSymbol; } return null; }) .Where(t => t != null) - .Select((t, _) => t!); - - // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 - IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider - .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) - .Where(t => t is not null) .Select((t, _) => t!) - .Collect(); - - var candidateClassCollectionResultIncrementalValuesProvider = assemblyClassIncrementalValuesProvider .Combine(returnTypeCollectionIncrementalValuesProvider) - .Select((tuple, token) => + .Select((tuple, _) => { - var assemblyClassCollectionResult = tuple.Left; + var assemblyClassTypeSymbol = tuple.Left; var exportMethodReturnTypeCollectionResultArray = tuple.Right; + var result = new List(); + foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResultArray) { - if (TypeSymbolHelper.IsInherit(assemblyClassCollectionResult.AssemblyClassTypeSymbol, exportMethodReturnTypeCollectionResult.ExpectedClassBaseType)) + if (exportMethodReturnTypeCollectionResult.IsMatch(assemblyClassTypeSymbol)) { - if (exportMethodReturnTypeCollectionResult.ExpectedClassAttributeType is null) - { - // 没有 Attribute 的要求 - } + result.Add(new CandidateClassTypeResult(exportMethodReturnTypeCollectionResult, + new[] { assemblyClassTypeSymbol})); } } - return new CandidateClassCollectionResult(null!); + if (result.Count > 0) + { + return new CandidateClassCollectionResult(result); + } + else + { + return null; + } }) .Where(t => t is not null); @@ -251,7 +256,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Collect() .Select((array, _) => { - // 去重 + // 去重 return array.Distinct().ToList(); }); @@ -372,37 +377,33 @@ public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, /// public bool IsMatch(INamedTypeSymbol assemblyClassTypeSymbol) { + // 先判断是否继承,再判断是否标记特性 + if (!TypeSymbolHelper.IsInherit(assemblyClassTypeSymbol, ExpectedClassBaseType)) + { + // 没有继承基类,那就是不符合了 + return false; + } + + foreach (var attributeData in assemblyClassTypeSymbol.GetAttributes()) + { + if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, ExpectedClassAttributeType)) + { + return true; + } + } + return true; } } - class ExportMethodReturnTypeCollectionDiagnostic : IExportMethodReturnTypeCollectionResult { - - } - - - - - /// - /// 程序集里面的类型收集结果 - /// - class AssemblyClassCollectionResult - { - public AssemblyClassCollectionResult(INamedTypeSymbol assemblyClassTypeSymbol, ClassDeclarationSyntax classDeclarationSyntax) - { - AssemblyClassTypeSymbol = assemblyClassTypeSymbol; - ClassDeclarationSyntax = classDeclarationSyntax; - } - - public INamedTypeSymbol AssemblyClassTypeSymbol { get; } - public ClassDeclarationSyntax ClassDeclarationSyntax { get; } } /// /// 候选收集的结果 /// + /// 包含所有的导出结果。比如项目里面有多个导出方法,每一个导出方法就是一个 CandidateClassTypeResult 对象 class CandidateClassCollectionResult { public CandidateClassCollectionResult(IReadOnlyList candidateClassTypeResultList) @@ -413,6 +414,10 @@ public CandidateClassCollectionResult(IReadOnlyList ca public IReadOnlyList CandidateClassTypeResultList { get; } } + /// + /// 候选的导出类型结果 + /// + /// 包含标记导出的方法信息,以及程序集里面导出的类型 class CandidateClassTypeResult { public CandidateClassTypeResult(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, IReadOnlyList assemblyClassTypeSymbolList) diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 5d1aace..9046cdc 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -21,6 +21,11 @@ static void Main(string[] args) //private static partial Func[] ExportFooCreator(); } +[F1] +public class CurrentFoo : DemoLib1.F1 +{ +} + //internal partial class Program //{ // private static partial IEnumerable<(Type , FooAttribute xx, Func xxx)> ExportFooEnumerable() From a35a4d06301bd2d39219c1a4d840a18b52aed5bb Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 15:43:47 +0800 Subject: [PATCH 20/48] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=94=9F=E6=88=90?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eExportTypeToMethodIncrementalGenerator.cs | 286 ++++++++++++++++-- .../ValueTupleExportMethodReturnTypeInfo.cs | 6 + 2 files changed, 270 insertions(+), 22 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 4583790..4b62056 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -3,7 +3,9 @@ using System.Collections.Immutable; using System.Data; using System.Diagnostics; +using System.IO; using System.Linq; +using System.Text; using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; @@ -118,12 +120,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var funcTypeSymbol = (INamedTypeSymbol) valueTupleInfo.ItemList[2].ItemType; // 准备导出的类型的基类型 var expectedClassBaseType = funcTypeSymbol.TypeArguments[0]; - + // 表示的特性 var expectedClassAttributeType = valueTupleInfo.ItemList[1].ItemType; return new ExportMethodReturnTypeCollectionResult(expectedClassBaseType, expectedClassAttributeType, - exportTypeCollectionResult, new ValueTupleExportMethodReturnTypeInfo(valueTupleInfo)); + exportTypeCollectionResult, new ValueTupleExportMethodReturnTypeInfo(valueTupleInfo) + { + IsIEnumerable = true + }); } } } @@ -205,22 +210,23 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Collect(); // 先收集整个项目里面所有的类型 - var candidateClassCollectionResultIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => - { - return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); - }, (generatorSyntaxContext, token) => - { - var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; - // 从语法转换为语义,用于后续判断是否标记了特性 - INamedTypeSymbol? assemblyClassTypeSymbol = - generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); - if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) + var candidateClassCollectionResultIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider( + (syntaxNode, _) => { - return assemblyClassTypeSymbol; - } + return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); + }, (generatorSyntaxContext, token) => + { + var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; + // 从语法转换为语义,用于后续判断是否标记了特性 + INamedTypeSymbol? assemblyClassTypeSymbol = + generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); + if (assemblyClassTypeSymbol is not null && !assemblyClassTypeSymbol.IsAbstract) + { + return assemblyClassTypeSymbol; + } - return null; - }) + return null; + }) .Where(t => t != null) .Select((t, _) => t!) .Combine(returnTypeCollectionIncrementalValuesProvider) @@ -236,7 +242,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) if (exportMethodReturnTypeCollectionResult.IsMatch(assemblyClassTypeSymbol)) { result.Add(new CandidateClassTypeResult(exportMethodReturnTypeCollectionResult, - new[] { assemblyClassTypeSymbol})); + new[] { assemblyClassTypeSymbol })); } } @@ -249,15 +255,33 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return null; } }) - .Where(t => t is not null); + .Where(t => t is not null) + .Select((t, _) => t!); var collectionResultIncrementalValueProvider = referenceAssemblyTypeIncrementalValueProvider.Combine(candidateClassCollectionResultIncrementalValuesProvider.Collect()) .SelectMany((tuple, _) => { return tuple.Right.Add(tuple.Left); }) .Collect() .Select((array, _) => { - // 去重 - return array.Distinct().ToList(); + var dictionary = new Dictionary>(); + + foreach (var candidateClassCollectionResult in array) + { + foreach (var candidateClassTypeResult in candidateClassCollectionResult.CandidateClassTypeResultList) + { + var result = candidateClassTypeResult.ExportMethodReturnTypeCollectionResult; + + if (!dictionary.TryGetValue(result, out var list)) + { + list = new List(); + dictionary.Add(result, list); + } + + list.AddRange(candidateClassTypeResult.AssemblyClassTypeSymbolList); + } + } + + return dictionary; }); // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 @@ -265,9 +289,163 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterImplementationSourceOutput(collectionResultIncrementalValueProvider, (productionContext, result) => { - foreach (var candidateClassCollectionResult in result) + foreach (var item in result) { - + /* + private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable() + { + yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + } + */ + var exportMethodReturnTypeCollectionResult = item.Key; + var list = item.Value; + + var methodSource = new StringBuilder(); + + if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo valueTupleExportMethodReturnTypeInfo) + { + var exportPartialMethodSymbol = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol; + + var accessibilityCode = + exportPartialMethodSymbol.DeclaredAccessibility switch + { + Accessibility.Public=>"public", + Accessibility.Private=>"private", + Accessibility.Internal=>"internal", + Accessibility.Protected=>"protected", + Accessibility.ProtectedAndInternal=>"private protected", + _ => string.Empty + }; + methodSource.Append(accessibilityCode).Append(' '); + + if (exportPartialMethodSymbol.IsStatic) + { + methodSource.Append("static "); + } + + methodSource.Append("partial "); + + if (!valueTupleExportMethodReturnTypeInfo.IsIEnumerable) + { + // 还没支持其他返回值的情况 + throw new NotSupportedException(); + } + + methodSource.Append("global::System.Collections.Generic.IEnumerable<"); + methodSource.Append('('); + var valueTupleInfo = valueTupleExportMethodReturnTypeInfo.ValueTupleInfo; + for (var i = 0; i < valueTupleInfo.ItemList.Count; i++) + { + var info = valueTupleInfo.ItemList[i]; + + if (i != valueTupleInfo.ItemList.Count - 1) + { + var type = TypeSymbolHelper.TypeSymbolToFullName(info.ItemType); + methodSource.Append(type).Append(' '); + methodSource.Append(info.ItemName); + + methodSource.Append(','); + } + else + { + var type = TypeSymbolHelper.TypeSymbolToFullName(exportMethodReturnTypeCollectionResult + .ExpectedClassBaseType); + methodSource.Append($"global::System.Func<{type}> {info.ItemName}"); + } + } + + methodSource.Append(')'); + methodSource.Append('>'); + methodSource.Append(' '); + methodSource.Append(exportPartialMethodSymbol.Name); + methodSource.AppendLine("()"); + methodSource.AppendLine("{"); + + foreach (var namedTypeSymbol in list) + { + // yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + + var attribute = namedTypeSymbol.GetAttributes().First(t => + SymbolEqualityComparer.Default.Equals(t.AttributeClass, + exportMethodReturnTypeCollectionResult + .ExpectedClassAttributeType)); + var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); + + var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); + methodSource.Append($"yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());"); + } + methodSource.AppendLine("}"); + } + + var source = methodSource.ToString(); + + var partialClassType = (INamedTypeSymbol) exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.ReceiverType!; + + var symbolDisplayFormat = new SymbolDisplayFormat + ( + // 带上命名空间和类型名 + SymbolDisplayGlobalNamespaceStyle.Omitted, + // 命名空间之前加上 global 防止冲突 + SymbolDisplayTypeQualificationStyle + .NameAndContainingTypesAndNamespaces + ); + var @namespace = partialClassType.ContainingNamespace?.ToDisplayString(symbolDisplayFormat); + + if (TryGetClassDeclarationList(partialClassType, out var declarationList)) + { + int declarationCount = declarationList!.Count; + /* 以下代码用来解决嵌套类型 + for (int i = 0; i < declarationCount - 1; i++) + { + string declarationSource = $@" + {declarationList[declarationCount - 1 - i]} + {{"; + sb.Append($@" + {IndentSource(declarationSource, numIndentations: i + 1)} + "); + } + */ + + var isIncludeNamespace = !string.IsNullOrEmpty(@namespace); + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("// "); + + if (isIncludeNamespace) + { + stringBuilder.Append(@$" + +namespace {@namespace} +{{"); + } + + var generatedCodeAttributeSource = + "[global::System.CodeDom.Compiler.GeneratedCode(\"Telescope\", \"1.0.0\")]"; + + // Add the core implementation for the derived context class. + string partialContextImplementation = $@" +{generatedCodeAttributeSource}{declarationList[0]} +{{ + {IndentSource(source, Math.Max(1, declarationCount - 1))} +}}"; + stringBuilder.AppendLine(IndentSource(partialContextImplementation, numIndentations: declarationCount)); + + if (!isIncludeNamespace) + { + stringBuilder.AppendLine("}"); + } + + var fileName = $"{partialClassType.Name}-{exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.Name}"; + productionContext.AddSource(fileName,stringBuilder.ToString()); + +//#if DEBUG +// var debugFolder = @"F:\temp"; +// if (Directory.Exists(debugFolder)) +// { +// var debugFile = Path.Combine(debugFolder, fileName); +// File.WriteAllText(debugFile, stringBuilder.ToString()); +// } +//#endif + } } }); @@ -284,6 +462,64 @@ public void Initialize(IncrementalGeneratorInitializationContext context) }); } + + + private static string IndentSource(string source, int numIndentations) + { + Debug.Assert(numIndentations >= 1); + return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); + //return source.Replace(Environment.NewLine, $"{Environment.NewLine}{new string(' ', 4 * numIndentations)}"); // 4 spaces per indentation. + } + + private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, out List? classDeclarationList) + { + INamedTypeSymbol currentSymbol = typeSymbol; + classDeclarationList = null; + + while (currentSymbol != null) + { + ClassDeclarationSyntax? classDeclarationSyntax = currentSymbol.DeclaringSyntaxReferences.First().GetSyntax() as ClassDeclarationSyntax; + + if (classDeclarationSyntax != null) + { + SyntaxTokenList tokenList = classDeclarationSyntax.Modifiers; + int tokenCount = tokenList.Count; + + bool isPartial = false; + + string[] declarationElements = new string[tokenCount + 2]; + + for (int i = 0; i < tokenCount; i++) + { + SyntaxToken token = tokenList[i]; + declarationElements[i] = token.Text; + + if (token.IsKind(SyntaxKind.PartialKeyword)) + { + isPartial = true; + } + } + + if (!isPartial) + { + classDeclarationList = null; + return false; + } + + declarationElements[tokenCount] = "class"; + declarationElements[tokenCount + 1] = currentSymbol.Name; + + (classDeclarationList ??= new List()).Add(string.Join(" ", declarationElements)); + } + + currentSymbol = currentSymbol.ContainingType; + } + + Debug.Assert(classDeclarationList != null); + Debug.Assert(classDeclarationList!.Count > 0); + return true; + } + class ExportTypeCollectionResult : IEquatable { public ExportTypeCollectionResult(IMethodSymbol methodSymbol, GeneratorSyntaxContext generatorSyntaxContext) @@ -377,6 +613,12 @@ public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, /// public bool IsMatch(INamedTypeSymbol assemblyClassTypeSymbol) { + if (assemblyClassTypeSymbol.IsAbstract) + { + // 抽象类不能提供 + return false; + } + // 先判断是否继承,再判断是否标记特性 if (!TypeSymbolHelper.IsInherit(assemblyClassTypeSymbol, ExpectedClassBaseType)) { diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs index e8fb2bd..a44de77 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs @@ -13,4 +13,10 @@ public ValueTupleExportMethodReturnTypeInfo(ValueTupleInfo valueTupleInfo) } public ValueTupleInfo ValueTupleInfo { get; } + + /// + /// 是否采用 global::System.Collections.Generic.IEnumerable 返回值 + /// IEnumerable<(Type, F1Attribute xx, Func<DemoLib1.F1> xxx)> + /// + public bool IsIEnumerable { set; get; } } \ No newline at end of file From e601998e2ba4ba2db97b234355cc0f0f4363fb75 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 15:45:36 +0800 Subject: [PATCH 21/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportTypeToMethodIncrementalGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 4b62056..902c309 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -429,7 +429,7 @@ namespace {@namespace} }}"; stringBuilder.AppendLine(IndentSource(partialContextImplementation, numIndentations: declarationCount)); - if (!isIncludeNamespace) + if (isIncludeNamespace) { stringBuilder.AppendLine("}"); } From 8ac604d575c07921bf66fb9f41faa2f74e7c35b8 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 15:48:01 +0800 Subject: [PATCH 22/48] =?UTF-8?q?=E6=95=B4=E7=90=86=E8=BE=85=E5=8A=A9?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AccessibilityHelper.cs | 17 +++++++++++++++++ ...opeExportTypeToMethodIncrementalGenerator.cs | 10 +--------- .../TelescopeSourceGeneratorDemo/Program.cs | 5 +++++ 3 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs new file mode 100644 index 0000000..246c000 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs @@ -0,0 +1,17 @@ +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +static class AccessibilityHelper +{ + public static string ToCSharpCode(this Accessibility accessibility) + => accessibility switch + { + Accessibility.Public => "public", + Accessibility.Private => "private", + Accessibility.Internal => "internal", + Accessibility.Protected => "protected", + Accessibility.ProtectedAndInternal => "private protected", + _ => string.Empty + }; +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 902c309..bd004ff 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -307,15 +307,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var exportPartialMethodSymbol = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol; var accessibilityCode = - exportPartialMethodSymbol.DeclaredAccessibility switch - { - Accessibility.Public=>"public", - Accessibility.Private=>"private", - Accessibility.Internal=>"internal", - Accessibility.Protected=>"protected", - Accessibility.ProtectedAndInternal=>"private protected", - _ => string.Empty - }; + exportPartialMethodSymbol.DeclaredAccessibility.ToCSharpCode(); methodSource.Append(accessibilityCode).Append(' '); if (exportPartialMethodSymbol.IsStatic) diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 9046cdc..0ead03c 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -6,6 +6,11 @@ internal partial class Program { static void Main(string[] args) { + foreach (var (_, xx, xxx) in ExportFooEnumerable()) + { + + } + //var attributedTypesExport = new __AttributedTypesExport__(); //ICompileTimeAttributedTypesExporter exporter = attributedTypesExport; //foreach (var exportedTypeMetadata in exporter.ExportAttributeTypes()) From 00f469daebc20881112bb0c7b309a723ae86c70e Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 16:09:53 +0800 Subject: [PATCH 23/48] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AccessibilityHelper.cs | 1 + .../Analyzers/Core/AssemblyInfo.cs | 36 +++++++++++++++++++ ...eExportTypeToMethodIncrementalGenerator.cs | 34 +++++++++--------- 3 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/AssemblyInfo.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs index 246c000..b69caa2 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AccessibilityHelper.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis; +using System; namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AssemblyInfo.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblyInfo.cs new file mode 100644 index 0000000..2a41196 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +internal static class AssemblyInfo +{ + public static string ToolName => + Assembly.GetExecutingAssembly().GetCustomAttribute().Product; + + public static string ToolVersion => + Assembly.GetExecutingAssembly().GetCustomAttribute() + .InformationalVersion; + + /// + /// 如果需要为类加上 ,则使用此字符串。 + /// + public static string GeneratedCodeAttribute => + $@"[global::System.CodeDom.Compiler.GeneratedCode(""{ToolName}"", ""{ToolVersion}"")]"; + + /// + /// 获取可以为每一个生成的文件都增加的文件头。 + /// + public const string GeneratedCodeComment = + $@"//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +#define GENERATED_CODE + +"; +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index bd004ff..13d633a 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -336,7 +336,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) methodSource.Append(type).Append(' '); methodSource.Append(info.ItemName); - methodSource.Append(','); + methodSource.Append(',').Append(' '); } else { @@ -364,7 +364,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); - methodSource.Append($"yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());"); + methodSource.AppendLine(IndentSource($"yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", + numIndentations: 1)); } methodSource.AppendLine("}"); } @@ -387,20 +388,19 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { int declarationCount = declarationList!.Count; /* 以下代码用来解决嵌套类型 - for (int i = 0; i < declarationCount - 1; i++) - { - string declarationSource = $@" - {declarationList[declarationCount - 1 - i]} - {{"; - sb.Append($@" - {IndentSource(declarationSource, numIndentations: i + 1)} - "); - } - */ + for (int i = 0; i < declarationCount - 1; i++) + { + string declarationSource = $@" + {declarationList[declarationCount - 1 - i]} + {{"; + sb.Append($@" + {IndentSource(declarationSource, numIndentations: i + 1)} + "); + } + */ var isIncludeNamespace = !string.IsNullOrEmpty(@namespace); - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("// "); + var stringBuilder = new StringBuilder(AssemblyInfo.GeneratedCodeComment); if (isIncludeNamespace) { @@ -410,12 +410,12 @@ namespace {@namespace} {{"); } - var generatedCodeAttributeSource = - "[global::System.CodeDom.Compiler.GeneratedCode(\"Telescope\", \"1.0.0\")]"; + var generatedCodeAttributeSource = AssemblyInfo.GeneratedCodeAttribute; // Add the core implementation for the derived context class. string partialContextImplementation = $@" -{generatedCodeAttributeSource}{declarationList[0]} +{generatedCodeAttributeSource} +{declarationList[0]} {{ {IndentSource(source, Math.Max(1, declarationCount - 1))} }}"; From 66825b14c81079e105ca1b19f9d1aed8d6227de2 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 16:12:01 +0800 Subject: [PATCH 24/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BA=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportTypeToMethodIncrementalGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 13d633a..4d6cfe9 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -364,7 +364,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); - methodSource.AppendLine(IndentSource($"yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", + methodSource.AppendLine(IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", numIndentations: 1)); } methodSource.AppendLine("}"); From e0e3c289bf24a104c6e80736ee26f96d064d9f08 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 16:50:56 +0800 Subject: [PATCH 25/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AssemblySymbolHelper.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs index 2ff04b5..0c2ba2e 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs @@ -51,6 +51,11 @@ public static bool IsReference(IAssemblySymbol currentAssemblySymbol, IAssemblyS visited[currentAssemblySymbol] = true; return true; } + else if (SymbolEqualityComparer.Default.Equals(referencedAssemblySymbol, currentAssemblySymbol)) + { + // 循环引用,跳过 + continue; + } else { if (visited.TryGetValue(referencedAssemblySymbol, out var isReference)) @@ -60,6 +65,9 @@ public static bool IsReference(IAssemblySymbol currentAssemblySymbol, IAssemblyS } else { + // 进入递归之前,先将自身设置到字典,先设置为没有引用。防止循环引用炸掉 + visited[referencedAssemblySymbol] = false; + // 没有访问过的,获取引用的程序集是否存在引用关系 isReference = IsReference(referencedAssemblySymbol, requiredAssemblySymbol, visited); visited[referencedAssemblySymbol] = isReference; From f464e1d026b12012319c690491b455eefc483414 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 17:00:02 +0800 Subject: [PATCH 26/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=89=B9=E6=80=A7?= =?UTF-8?q?=E4=B8=A2=E5=A4=B1=E5=AD=97=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AttributeCodeReWriter.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs index 4208e8a..f61722e 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs @@ -69,6 +69,19 @@ static string TypedConstantToCodeString(TypedConstant typedConstant) break; } + case TypedConstantKind.Primitive: + { + if (typedConstant.Value is string text) + { + constructorArgumentCode = "\"" + text + "\""; + } + else + { + constructorArgumentCode = typedConstant.Value?.ToString() ?? "null"; + } + + break; + } default: { constructorArgumentCode = typedConstant.Value?.ToString() ?? "null"; From 31d8a81a9696221afb56852a867b99607171814d Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 17:07:34 +0800 Subject: [PATCH 27/48] =?UTF-8?q?=E9=98=B2=E6=AD=A2=E5=8A=A0=E4=B8=8A?= =?UTF-8?q?=E4=B8=8D=E5=8F=AF=E8=A7=81=E7=9A=84=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportTypeToMethodIncrementalGenerator.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 4d6cfe9..9ec6f92 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -188,8 +188,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context) continue; } + var isInternalsVisibleTo = referencedAssemblySymbol.GivesAccessTo(compilation.Assembly); + foreach (var assemblyClassTypeSymbol in AssemblySymbolHelper.GetAllTypeSymbol(referencedAssemblySymbol)) { + if (!isInternalsVisibleTo && + assemblyClassTypeSymbol.DeclaredAccessibility != Accessibility.Public) + { + // 如果设置不可见的,那就不要加入了 + continue; + } + if (exportMethodReturnTypeCollectionResult.IsMatch(assemblyClassTypeSymbol)) { assemblyClassTypeSymbolList.Add(assemblyClassTypeSymbol); From fb32ef03a57d1b645cb41d4b489e473f76001009 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 17:32:33 +0800 Subject: [PATCH 28/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如果类型没有标记特性,那就不能判断符合 --- .../TelescopeExportTypeToMethodIncrementalGenerator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 9ec6f92..6f453fe 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -627,6 +627,12 @@ public bool IsMatch(INamedTypeSymbol assemblyClassTypeSymbol) return false; } + if (ExpectedClassAttributeType is null) + { + // 如果没有特性要求,那就返回符合 + return true; + } + foreach (var attributeData in assemblyClassTypeSymbol.GetAttributes()) { if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, ExpectedClassAttributeType)) @@ -635,7 +641,7 @@ public bool IsMatch(INamedTypeSymbol assemblyClassTypeSymbol) } } - return true; + return false; } } From 5539984d33157e65f5cc9c30decbb3b019cd46fb Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 17:46:48 +0800 Subject: [PATCH 29/48] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B8=83=E5=B0=94?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AttributeCodeReWriter.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs index f61722e..b42fc79 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs @@ -75,6 +75,14 @@ static string TypedConstantToCodeString(TypedConstant typedConstant) { constructorArgumentCode = "\"" + text + "\""; } + else if (typedConstant.Value is true) + { + constructorArgumentCode = "true"; + } + else if (typedConstant.Value is false) + { + constructorArgumentCode = "false"; + } else { constructorArgumentCode = typedConstant.Value?.ToString() ?? "null"; From 44990163f2beda2157bd54214dbb9c396f436175 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 18:15:26 +0800 Subject: [PATCH 30/48] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AttributeCodeReWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs index b42fc79..498f41b 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs @@ -37,7 +37,7 @@ public static string GetAttributeCreatedCode(AttributeData attributeData) $@"new {TypeSymbolHelper.TypeSymbolToFullName(attributeData.AttributeClass!)}({string.Join(",", constructorArgumentCodeList)}) {{ {string.Join(@", - ", namedArgumentCodeList.Select(x => $"{x.propertyName} = {x.valueCode}"))} + ", namedArgumentCodeList.Select(x => $"{x.propertyName} = {x.valueCode}"))} }}"; static string TypedConstantToCodeString(TypedConstant typedConstant) From 4517a8125984bbd41b21f03a55b2d24dcbea1d8e Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 18:20:36 +0800 Subject: [PATCH 31/48] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=8D=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AttributeCodeReWriter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs index 498f41b..f0a86be 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AttributeCodeReWriter.cs @@ -42,7 +42,6 @@ public static string GetAttributeCreatedCode(AttributeData attributeData) static string TypedConstantToCodeString(TypedConstant typedConstant) { - var constructorArgumentType = typedConstant.Type; var constructorArgumentValue = typedConstant.Value; string constructorArgumentCode; From 40139360449a28d2a98452987ead60f20e090630 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 18:22:26 +0800 Subject: [PATCH 32/48] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportTypeToMethodIncrementalGenerator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 6f453fe..36ce7e6 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -272,6 +272,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Collect() .Select((array, _) => { + // 去掉重复的定义 var dictionary = new Dictionary>(); foreach (var candidateClassCollectionResult in array) From bd816303b21d2a013da7d903d8f470fab6637226 Mon Sep 17 00:00:00 2001 From: lindexi Date: Mon, 28 Aug 2023 18:26:55 +0800 Subject: [PATCH 33/48] =?UTF-8?q?=E6=8F=90=E4=BE=9B=E8=BE=85=E5=8A=A9?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/IncrementalValuesProviderHelper.cs | 17 ++++++++++ ...eExportTypeToMethodIncrementalGenerator.cs | 32 +++++++++++-------- 2 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs new file mode 100644 index 0000000..1e04284 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs @@ -0,0 +1,17 @@ +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +static class IncrementalValuesProviderHelper +{ + /// + /// 过滤掉空的值 + /// + /// + /// + /// + public static IncrementalValuesProvider FilterNull(this IncrementalValuesProvider provider) + { + return provider.Where(t => t != null).Select((t, _) => t!); + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 36ce7e6..c21ffb8 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -87,8 +87,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return null; }) // 过滤不满足条件的 - .Where(t => t is not null) - .Select((t, _) => t!); + .FilterNull(); // 获取方法返回值导出类型 var exportMethodReturnTypeCollectionResultIncrementalValuesProvider = exportMethodIncrementalValuesProvider.Select((exportTypeCollectionResult, token) => @@ -214,18 +213,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) - .Where(t => t is not null) - .Select((t, _) => t!) + .FilterNull() .Collect(); - // 先收集整个项目里面所有的类型 + // 收集整个项目里面所有的类型 var candidateClassCollectionResultIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider( (syntaxNode, _) => { return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); }, (generatorSyntaxContext, token) => { - var classDeclarationSyntax = (ClassDeclarationSyntax) generatorSyntaxContext.Node; + var classDeclarationSyntax = (ClassDeclarationSyntax)generatorSyntaxContext.Node; // 从语法转换为语义,用于后续判断是否标记了特性 INamedTypeSymbol? assemblyClassTypeSymbol = generatorSyntaxContext.SemanticModel.GetDeclaredSymbol(classDeclarationSyntax, token); @@ -236,8 +234,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return null; }) - .Where(t => t != null) - .Select((t, _) => t!) + .FilterNull() .Combine(returnTypeCollectionIncrementalValuesProvider) .Select((tuple, _) => { @@ -264,8 +261,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return null; } }) - .Where(t => t is not null) - .Select((t, _) => t!); + .FilterNull(); var collectionResultIncrementalValueProvider = referenceAssemblyTypeIncrementalValueProvider.Combine(candidateClassCollectionResultIncrementalValuesProvider.Collect()) .SelectMany((tuple, _) => { return tuple.Right.Add(tuple.Left); }) @@ -464,8 +460,12 @@ namespace {@namespace} }); } - - + /// + /// 提供缩进的方法 + /// + /// + /// + /// private static string IndentSource(string source, int numIndentations) { Debug.Assert(numIndentations >= 1); @@ -473,6 +473,12 @@ private static string IndentSource(string source, int numIndentations) //return source.Replace(Environment.NewLine, $"{Environment.NewLine}{new string(' ', 4 * numIndentations)}"); // 4 spaces per indentation. } + /// + /// 尝试获取类型的定义 + /// + /// + /// 嵌套类的定义 + /// private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, out List? classDeclarationList) { INamedTypeSymbol currentSymbol = typeSymbol; @@ -560,7 +566,7 @@ public override int GetHashCode() { unchecked { - return (ExportPartialMethodSymbol.GetHashCode() * 397) ^ GeneratorSyntaxContext.GetHashCode(); + return (SymbolEqualityComparer.Default.GetHashCode(ExportPartialMethodSymbol) * 397) ^ GeneratorSyntaxContext.GetHashCode(); } } } From 12ff43005c2d88e270b47a9e02cbe1a53c44a40d Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 10:35:56 +0800 Subject: [PATCH 34/48] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=89=93=E5=8C=85?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/nuget publish.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/nuget publish.yml b/.github/workflows/nuget publish.yml index 5018982..af2c6f2 100644 --- a/.github/workflows/nuget publish.yml +++ b/.github/workflows/nuget publish.yml @@ -27,6 +27,9 @@ jobs: run: dotnet build --configuration Release -v n shell: pwsh + - name: Pack with dotnet + run: dotnet pack --configuration Release --no-build + - name: Install Nuget uses: nuget/setup-nuget@v1 with: From b015756c0baf2dfc20f6f48892830c5eaf8d6e3c Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 10:42:37 +0800 Subject: [PATCH 35/48] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=89=93=E5=8C=85?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...dotnetCampus.Telescope.SourceGeneratorAnalyzers.NuGet.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TelescopeSourceGenerator/NuGet/dotnetCampus.Telescope.SourceGeneratorAnalyzers.NuGet.csproj b/src/TelescopeSourceGenerator/NuGet/dotnetCampus.Telescope.SourceGeneratorAnalyzers.NuGet.csproj index 072d909..8ae2bf1 100644 --- a/src/TelescopeSourceGenerator/NuGet/dotnetCampus.Telescope.SourceGeneratorAnalyzers.NuGet.csproj +++ b/src/TelescopeSourceGenerator/NuGet/dotnetCampus.Telescope.SourceGeneratorAnalyzers.NuGet.csproj @@ -15,7 +15,7 @@ - + From 9e402aaa3a8a7b6389f5cbb7647e82f33fdfe54a Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 11:12:38 +0800 Subject: [PATCH 36/48] =?UTF-8?q?=E6=8F=90=E5=8D=87=20VisualStudio=20?= =?UTF-8?q?=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/ValueTuple_/ValueTupleInfoParser.cs | 5 +- ...eExportTypeToMethodIncrementalGenerator.cs | 271 ++++++++++-------- 2 files changed, 150 insertions(+), 126 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs index cc42804..0977cef 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/ValueTuple_/ValueTupleInfoParser.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -7,7 +8,7 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; public static class ValueTupleInfoParser { - public static bool TryParse(ITypeSymbol type, out ValueTupleInfo valueTupleInfo) + public static bool TryParse(ITypeSymbol type, CancellationToken token, out ValueTupleInfo valueTupleInfo) { valueTupleInfo = null!; @@ -18,7 +19,7 @@ public static bool TryParse(ITypeSymbol type, out ValueTupleInfo valueTupleInfo) // 尝试判断是 ValueTuple 的情况 // (Type type, FooAttribute xx, Func xxx) - if (type.IsValueType && typeArgument.TupleElements.Length > 0 && typeArgument.DeclaringSyntaxReferences[0].GetSyntax() is TupleTypeSyntax + if (type.IsValueType && typeArgument.TupleElements.Length > 0 && typeArgument.DeclaringSyntaxReferences[0].GetSyntax(token) is TupleTypeSyntax valueTupleSyntaxNode) { Debug.Assert(typeArgument.TupleElements.Length == valueTupleSyntaxNode.Elements.Count); diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index c21ffb8..361a0bf 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -30,7 +30,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) Debugger.Launch(); #endif // 先找到定义 - IncrementalValuesProvider exportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, token) => + IncrementalValuesProvider exportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => { // 先要求是分部的方法,分部的方法必定在分部类里面,这部分判断分部类里面还可以省略 if (syntaxNode is MethodDeclarationSyntax methodDeclarationSyntax && methodDeclarationSyntax.AttributeLists.Any()) @@ -109,7 +109,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 尝试判断是 ValueTuple 的情况 // 要求符合以下定义 // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() - if (namedTypeSymbol.TypeArguments.Length == 1 && ValueTupleInfoParser.TryParse(namedTypeSymbol.TypeArguments[0], out ValueTupleInfo valueTupleInfo) && valueTupleInfo.ItemList.Count == 3) + if (namedTypeSymbol.TypeArguments.Length == 1 && ValueTupleInfoParser.TryParse(namedTypeSymbol.TypeArguments[0], token, out ValueTupleInfo valueTupleInfo) && valueTupleInfo.ItemList.Count == 3) { if (TypeSymbolHelper.TypeSymbolToFullName(valueTupleInfo.ItemList[0].ItemType) != "global::System.Type") { @@ -169,6 +169,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResults) { + token.ThrowIfCancellationRequested(); + var assemblyClassTypeSymbolList = new List(); var candidateClassTypeResult = new CandidateClassTypeResult(exportMethodReturnTypeCollectionResult, assemblyClassTypeSymbolList); candidateClassList.Add(candidateClassTypeResult); @@ -181,6 +183,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) foreach (var referencedAssemblySymbol in referencedAssemblySymbols) { + token.ThrowIfCancellationRequested(); if (!AssemblySymbolHelper.IsReference(referencedAssemblySymbol, expectedClassBaseType.ContainingAssembly, visited)) { // 如果当前程序集没有直接或间接继承期望继承的基础类型所在程序集,那就证明当前程序集一定不存在任何可能被收集的类型 @@ -236,7 +239,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) }) .FilterNull() .Combine(returnTypeCollectionIncrementalValuesProvider) - .Select((tuple, _) => + .Select((tuple, token) => { var assemblyClassTypeSymbol = tuple.Left; var exportMethodReturnTypeCollectionResultArray = tuple.Right; @@ -245,6 +248,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResultArray) { + token.ThrowIfCancellationRequested(); if (exportMethodReturnTypeCollectionResult.IsMatch(assemblyClassTypeSymbol)) { result.Add(new CandidateClassTypeResult(exportMethodReturnTypeCollectionResult, @@ -266,15 +270,17 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var collectionResultIncrementalValueProvider = referenceAssemblyTypeIncrementalValueProvider.Combine(candidateClassCollectionResultIncrementalValuesProvider.Collect()) .SelectMany((tuple, _) => { return tuple.Right.Add(tuple.Left); }) .Collect() - .Select((array, _) => + .Select((array, token) => { // 去掉重复的定义 var dictionary = new Dictionary>(); foreach (var candidateClassCollectionResult in array) { + token.ThrowIfCancellationRequested(); foreach (var candidateClassTypeResult in candidateClassCollectionResult.CandidateClassTypeResultList) { + token.ThrowIfCancellationRequested(); var result = candidateClassTypeResult.ExportMethodReturnTypeCollectionResult; if (!dictionary.TryGetValue(result, out var list)) @@ -290,160 +296,177 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return dictionary; }); - // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 - // 这里可以用来存放具体实现的代码,将不影响用户代码的语义,而不是用来做定义的代码 - context.RegisterImplementationSourceOutput(collectionResultIncrementalValueProvider, - (productionContext, result) => + // 转换为源代码输出 + // 源代码输出放在 Select 可以随时打断,实际 VisualStudio 性能会比放在 RegisterImplementationSourceOutput 高很多 + var sourceCodeProvider = collectionResultIncrementalValueProvider.Select((result, token) => + { + var codeList = new List<(string /*FileName*/, string /*SourceCode*/)>(result.Count); + foreach (var item in result) { - foreach (var item in result) + token.ThrowIfCancellationRequested(); + + /* + private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable() + { + yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + } + */ + var exportMethodReturnTypeCollectionResult = item.Key; + var list = item.Value; + + var methodSource = new StringBuilder(); + + if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo valueTupleExportMethodReturnTypeInfo) { - /* - private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable() - { - yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); - } - */ - var exportMethodReturnTypeCollectionResult = item.Key; - var list = item.Value; + var exportPartialMethodSymbol = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol; - var methodSource = new StringBuilder(); + var accessibilityCode = + exportPartialMethodSymbol.DeclaredAccessibility.ToCSharpCode(); + methodSource.Append(accessibilityCode).Append(' '); - if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo valueTupleExportMethodReturnTypeInfo) + if (exportPartialMethodSymbol.IsStatic) { - var exportPartialMethodSymbol = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol; + methodSource.Append("static "); + } - var accessibilityCode = - exportPartialMethodSymbol.DeclaredAccessibility.ToCSharpCode(); - methodSource.Append(accessibilityCode).Append(' '); + methodSource.Append("partial "); - if (exportPartialMethodSymbol.IsStatic) - { - methodSource.Append("static "); - } + if (!valueTupleExportMethodReturnTypeInfo.IsIEnumerable) + { + // 还没支持其他返回值的情况 + throw new NotSupportedException(); + } - methodSource.Append("partial "); + methodSource.Append("global::System.Collections.Generic.IEnumerable<"); + methodSource.Append('('); + var valueTupleInfo = valueTupleExportMethodReturnTypeInfo.ValueTupleInfo; + for (var i = 0; i < valueTupleInfo.ItemList.Count; i++) + { + var info = valueTupleInfo.ItemList[i]; - if (!valueTupleExportMethodReturnTypeInfo.IsIEnumerable) + if (i != valueTupleInfo.ItemList.Count - 1) { - // 还没支持其他返回值的情况 - throw new NotSupportedException(); - } + var type = TypeSymbolHelper.TypeSymbolToFullName(info.ItemType); + methodSource.Append(type).Append(' '); + methodSource.Append(info.ItemName); - methodSource.Append("global::System.Collections.Generic.IEnumerable<"); - methodSource.Append('('); - var valueTupleInfo = valueTupleExportMethodReturnTypeInfo.ValueTupleInfo; - for (var i = 0; i < valueTupleInfo.ItemList.Count; i++) + methodSource.Append(',').Append(' '); + } + else { - var info = valueTupleInfo.ItemList[i]; - - if (i != valueTupleInfo.ItemList.Count - 1) - { - var type = TypeSymbolHelper.TypeSymbolToFullName(info.ItemType); - methodSource.Append(type).Append(' '); - methodSource.Append(info.ItemName); - - methodSource.Append(',').Append(' '); - } - else - { - var type = TypeSymbolHelper.TypeSymbolToFullName(exportMethodReturnTypeCollectionResult - .ExpectedClassBaseType); - methodSource.Append($"global::System.Func<{type}> {info.ItemName}"); - } + var type = TypeSymbolHelper.TypeSymbolToFullName(exportMethodReturnTypeCollectionResult + .ExpectedClassBaseType); + methodSource.Append($"global::System.Func<{type}> {info.ItemName}"); } + } - methodSource.Append(')'); - methodSource.Append('>'); - methodSource.Append(' '); - methodSource.Append(exportPartialMethodSymbol.Name); - methodSource.AppendLine("()"); - methodSource.AppendLine("{"); + methodSource.Append(')'); + methodSource.Append('>'); + methodSource.Append(' '); + methodSource.Append(exportPartialMethodSymbol.Name); + methodSource.AppendLine("()"); + methodSource.AppendLine("{"); - foreach (var namedTypeSymbol in list) - { - // yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + foreach (var namedTypeSymbol in list) + { + token.ThrowIfCancellationRequested(); + // yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + + var attribute = namedTypeSymbol.GetAttributes().First(t => + SymbolEqualityComparer.Default.Equals(t.AttributeClass, + exportMethodReturnTypeCollectionResult + .ExpectedClassAttributeType)); + var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); + + var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); + methodSource.AppendLine(IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", + numIndentations: 1)); + } + methodSource.AppendLine("}"); + } - var attribute = namedTypeSymbol.GetAttributes().First(t => - SymbolEqualityComparer.Default.Equals(t.AttributeClass, - exportMethodReturnTypeCollectionResult - .ExpectedClassAttributeType)); - var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); + var source = methodSource.ToString(); - var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); - methodSource.AppendLine(IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", - numIndentations: 1)); - } - methodSource.AppendLine("}"); - } + var partialClassType = (INamedTypeSymbol) exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.ReceiverType!; - var source = methodSource.ToString(); + var symbolDisplayFormat = new SymbolDisplayFormat + ( + // 带上命名空间和类型名 + SymbolDisplayGlobalNamespaceStyle.Omitted, + // 命名空间之前加上 global 防止冲突 + SymbolDisplayTypeQualificationStyle + .NameAndContainingTypesAndNamespaces + ); + var @namespace = partialClassType.ContainingNamespace?.ToDisplayString(symbolDisplayFormat); - var partialClassType = (INamedTypeSymbol) exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.ReceiverType!; + if (TryGetClassDeclarationList(partialClassType, out var declarationList)) + { + int declarationCount = declarationList!.Count; + /* 以下代码用来解决嵌套类型 + for (int i = 0; i < declarationCount - 1; i++) + { + string declarationSource = $@" + {declarationList[declarationCount - 1 - i]} + {{"; + sb.Append($@" + {IndentSource(declarationSource, numIndentations: i + 1)} + "); + } + */ - var symbolDisplayFormat = new SymbolDisplayFormat - ( - // 带上命名空间和类型名 - SymbolDisplayGlobalNamespaceStyle.Omitted, - // 命名空间之前加上 global 防止冲突 - SymbolDisplayTypeQualificationStyle - .NameAndContainingTypesAndNamespaces - ); - var @namespace = partialClassType.ContainingNamespace?.ToDisplayString(symbolDisplayFormat); + var isIncludeNamespace = !string.IsNullOrEmpty(@namespace); + var stringBuilder = new StringBuilder(AssemblyInfo.GeneratedCodeComment); - if (TryGetClassDeclarationList(partialClassType, out var declarationList)) + if (isIncludeNamespace) { - int declarationCount = declarationList!.Count; - /* 以下代码用来解决嵌套类型 - for (int i = 0; i < declarationCount - 1; i++) - { - string declarationSource = $@" - {declarationList[declarationCount - 1 - i]} - {{"; - sb.Append($@" - {IndentSource(declarationSource, numIndentations: i + 1)} - "); - } - */ - - var isIncludeNamespace = !string.IsNullOrEmpty(@namespace); - var stringBuilder = new StringBuilder(AssemblyInfo.GeneratedCodeComment); - - if (isIncludeNamespace) - { - stringBuilder.Append(@$" + stringBuilder.Append(@$" namespace {@namespace} {{"); - } + } - var generatedCodeAttributeSource = AssemblyInfo.GeneratedCodeAttribute; + var generatedCodeAttributeSource = AssemblyInfo.GeneratedCodeAttribute; - // Add the core implementation for the derived context class. - string partialContextImplementation = $@" + // Add the core implementation for the derived context class. + string partialContextImplementation = $@" {generatedCodeAttributeSource} {declarationList[0]} {{ {IndentSource(source, Math.Max(1, declarationCount - 1))} }}"; - stringBuilder.AppendLine(IndentSource(partialContextImplementation, numIndentations: declarationCount)); - - if (isIncludeNamespace) - { - stringBuilder.AppendLine("}"); - } + stringBuilder.AppendLine(IndentSource(partialContextImplementation, numIndentations: declarationCount)); - var fileName = $"{partialClassType.Name}-{exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.Name}"; - productionContext.AddSource(fileName,stringBuilder.ToString()); - -//#if DEBUG -// var debugFolder = @"F:\temp"; -// if (Directory.Exists(debugFolder)) -// { -// var debugFile = Path.Combine(debugFolder, fileName); -// File.WriteAllText(debugFile, stringBuilder.ToString()); -// } -//#endif + if (isIncludeNamespace) + { + stringBuilder.AppendLine("}"); } + + var fileName = $"{partialClassType.Name}-{exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.Name}"; + + codeList.Add((fileName, stringBuilder.ToString())); + + //#if DEBUG + // var debugFolder = @"F:\temp"; + // if (Directory.Exists(debugFolder)) + // { + // var debugFile = Path.Combine(debugFolder, fileName); + // File.WriteAllText(debugFile, stringBuilder.ToString()); + // } + //#endif + } + } + + return codeList; + }); + + // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 + // 这里可以用来存放具体实现的代码,将不影响用户代码的语义,而不是用来做定义的代码 + context.RegisterImplementationSourceOutput(sourceCodeProvider, + (productionContext, result) => + { + foreach (var (fileName, code) in result) + { + productionContext.AddSource(fileName, code); } }); From 659c3f60ffbee19e71e894c214793c07736c11e2 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 14:44:45 +0800 Subject: [PATCH 37/48] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TelescopeExportTypeToMethodIncrementalGenerator.cs | 10 ---------- .../Analyzers/TelescopeIncrementalGenerator.cs | 6 ------ 2 files changed, 16 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 361a0bf..0340c0a 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -444,15 +444,6 @@ namespace {@namespace} var fileName = $"{partialClassType.Name}-{exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.Name}"; codeList.Add((fileName, stringBuilder.ToString())); - - //#if DEBUG - // var debugFolder = @"F:\temp"; - // if (Directory.Exists(debugFolder)) - // { - // var debugFile = Path.Combine(debugFolder, fileName); - // File.WriteAllText(debugFile, stringBuilder.ToString()); - // } - //#endif } } @@ -493,7 +484,6 @@ private static string IndentSource(string source, int numIndentations) { Debug.Assert(numIndentations >= 1); return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); - //return source.Replace(Environment.NewLine, $"{Environment.NewLine}{new string(' ', 4 * numIndentations)}"); // 4 spaces per indentation. } /// diff --git a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs index e93e7d3..e737bdf 100644 --- a/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/TelescopeIncrementalGenerator.cs @@ -16,12 +16,6 @@ public class TelescopeIncrementalGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { -#if DEBUG - //Debugger.Launch(); - // 先注释掉,不要打扰 - return; -#endif - // 先读取程序集特性,接着遍历整个程序集的所有代码文件,看看哪些是符合需求的,收集起来 // 读取程序集特性 From 3a88719953c8f8e5648e8f280bd49e2f5d8f4ba7 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 17:34:38 +0800 Subject: [PATCH 38/48] =?UTF-8?q?=E6=8B=86=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CandidateClassCollectionResult.cs | 17 ++ .../CandidateClassTypeResult.cs | 21 +++ ...ortMethodReturnTypeCollectionDiagnostic.cs | 5 + .../ExportMethodReturnTypeCollectionResult.cs | 77 ++++++++ .../ExportTypeCollectionResult.cs | 47 +++++ ...IExportMethodReturnTypeCollectionResult.cs | 9 + ...eExportTypeToMethodIncrementalGenerator.cs | 164 +----------------- 7 files changed, 180 insertions(+), 160 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassCollectionResult.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassTypeResult.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportTypeCollectionResult.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeCollectionResult.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassCollectionResult.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassCollectionResult.cs new file mode 100644 index 0000000..ca702cc --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassCollectionResult.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 候选收集的结果 +/// +/// 包含所有的导出结果。比如项目里面有多个导出方法,每一个导出方法就是一个 CandidateClassTypeResult 对象 +class CandidateClassCollectionResult +{ + public CandidateClassCollectionResult(IReadOnlyList candidateClassTypeResultList) + { + CandidateClassTypeResultList = candidateClassTypeResultList; + } + + public IReadOnlyList CandidateClassTypeResultList { get; } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassTypeResult.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassTypeResult.cs new file mode 100644 index 0000000..6e595db --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/CandidateClassTypeResult.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 候选的导出类型结果 +/// +/// 包含标记导出的方法信息,以及程序集里面导出的类型 +class CandidateClassTypeResult +{ + public CandidateClassTypeResult(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, IReadOnlyList assemblyClassTypeSymbolList) + { + ExportMethodReturnTypeCollectionResult = exportMethodReturnTypeCollectionResult; + AssemblyClassTypeSymbolList = assemblyClassTypeSymbolList; + } + + public ExportMethodReturnTypeCollectionResult ExportMethodReturnTypeCollectionResult { get; } + + public IReadOnlyList AssemblyClassTypeSymbolList { get; } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs new file mode 100644 index 0000000..4e65285 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs @@ -0,0 +1,5 @@ +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +class ExportMethodReturnTypeCollectionDiagnostic : IExportMethodReturnTypeCollectionResult +{ +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs new file mode 100644 index 0000000..043d790 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs @@ -0,0 +1,77 @@ +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 导出的方法的导出类型返回值结果 +/// +class ExportMethodReturnTypeCollectionResult : IExportMethodReturnTypeCollectionResult +{ + public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, ExportTypeCollectionResult exportTypeCollectionResult, IExportMethodReturnTypeInfo exportMethodReturnTypeInfo) + { + ExpectedClassBaseType = expectedClassBaseType; + ExpectedClassAttributeType = expectedClassAttributeType; + ExportTypeCollectionResult = exportTypeCollectionResult; + ExportMethodReturnTypeInfo = exportMethodReturnTypeInfo; + } + + /// + /// 期望收集的类型所继承的基础类型 + /// + public ITypeSymbol ExpectedClassBaseType { get; } + + /// + /// 期望类型标记的特性,可选 + /// + public ITypeSymbol? ExpectedClassAttributeType { get; } + + public ExportTypeCollectionResult ExportTypeCollectionResult { get; } + + /// + /// 程序集里面标记了导出的分部方法,将用来生成代码 + /// + public IMethodSymbol ExportPartialMethodSymbol => ExportTypeCollectionResult.ExportPartialMethodSymbol; + + /// + /// 导出类型的返回类型信息 + /// + public IExportMethodReturnTypeInfo ExportMethodReturnTypeInfo { get; } + + /// + /// 判断传入的程序集类型满足当前的要求条件 + /// + /// + /// + public bool IsMatch(INamedTypeSymbol assemblyClassTypeSymbol) + { + if (assemblyClassTypeSymbol.IsAbstract) + { + // 抽象类不能提供 + return false; + } + + // 先判断是否继承,再判断是否标记特性 + if (!TypeSymbolHelper.IsInherit(assemblyClassTypeSymbol, ExpectedClassBaseType)) + { + // 没有继承基类,那就是不符合了 + return false; + } + + if (ExpectedClassAttributeType is null) + { + // 如果没有特性要求,那就返回符合 + return true; + } + + foreach (var attributeData in assemblyClassTypeSymbol.GetAttributes()) + { + if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, ExpectedClassAttributeType)) + { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportTypeCollectionResult.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportTypeCollectionResult.cs new file mode 100644 index 0000000..da73e12 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportTypeCollectionResult.cs @@ -0,0 +1,47 @@ +using System; +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +class ExportTypeCollectionResult : IEquatable +{ + public ExportTypeCollectionResult(IMethodSymbol methodSymbol, GeneratorSyntaxContext generatorSyntaxContext) + { + ExportPartialMethodSymbol = methodSymbol; + GeneratorSyntaxContext = generatorSyntaxContext; + } + + /// + /// 是否包含引用的程序集和 DLL 里面的类型导出。默认只导出当前程序集 + /// + public bool IncludeReference { set; get; } + /// + /// 程序集里面标记了导出的分部方法,将用来生成代码 + /// + public IMethodSymbol ExportPartialMethodSymbol { get; } + public GeneratorSyntaxContext GeneratorSyntaxContext { get; } + + public bool Equals(ExportTypeCollectionResult? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return GeneratorSyntaxContext.Equals(other.GeneratorSyntaxContext) && SymbolEqualityComparer.Default.Equals(ExportPartialMethodSymbol, other.ExportPartialMethodSymbol); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((ExportTypeCollectionResult) obj); + } + + public override int GetHashCode() + { + unchecked + { + return (SymbolEqualityComparer.Default.GetHashCode(ExportPartialMethodSymbol) * 397) ^ GeneratorSyntaxContext.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeCollectionResult.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeCollectionResult.cs new file mode 100644 index 0000000..5930a2a --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeCollectionResult.cs @@ -0,0 +1,9 @@ +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 收集导出方法返回值类型 +/// +/// 可以是收集到了,也可以是返回开发者定义错误代码 +interface IExportMethodReturnTypeCollectionResult +{ +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 0340c0a..cb8ae96 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -27,7 +27,10 @@ public class TelescopeExportTypeToMethodIncrementalGenerator : IIncrementalGener public void Initialize(IncrementalGeneratorInitializationContext context) { #if DEBUG - Debugger.Launch(); + if (!Debugger.IsAttached) + { + Debugger.Launch(); + } #endif // 先找到定义 IncrementalValuesProvider exportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => @@ -540,163 +543,4 @@ private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, out Debug.Assert(classDeclarationList!.Count > 0); return true; } - - class ExportTypeCollectionResult : IEquatable - { - public ExportTypeCollectionResult(IMethodSymbol methodSymbol, GeneratorSyntaxContext generatorSyntaxContext) - { - ExportPartialMethodSymbol = methodSymbol; - GeneratorSyntaxContext = generatorSyntaxContext; - } - - /// - /// 是否包含引用的程序集和 DLL 里面的类型导出。默认只导出当前程序集 - /// - public bool IncludeReference { set; get; } - /// - /// 程序集里面标记了导出的分部方法,将用来生成代码 - /// - public IMethodSymbol ExportPartialMethodSymbol { get; } - public GeneratorSyntaxContext GeneratorSyntaxContext { get; } - - public bool Equals(ExportTypeCollectionResult? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return GeneratorSyntaxContext.Equals(other.GeneratorSyntaxContext) && SymbolEqualityComparer.Default.Equals(ExportPartialMethodSymbol, other.ExportPartialMethodSymbol); - } - - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((ExportTypeCollectionResult) obj); - } - - public override int GetHashCode() - { - unchecked - { - return (SymbolEqualityComparer.Default.GetHashCode(ExportPartialMethodSymbol) * 397) ^ GeneratorSyntaxContext.GetHashCode(); - } - } - } - - /// - /// 收集导出方法返回值类型 - /// - /// 可以是收集到了,也可以是返回开发者定义错误代码 - interface IExportMethodReturnTypeCollectionResult - { - } - - /// - /// 导出的方法的导出类型返回值结果 - /// - class ExportMethodReturnTypeCollectionResult : IExportMethodReturnTypeCollectionResult - { - public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, ExportTypeCollectionResult exportTypeCollectionResult, IExportMethodReturnTypeInfo exportMethodReturnTypeInfo) - { - ExpectedClassBaseType = expectedClassBaseType; - ExpectedClassAttributeType = expectedClassAttributeType; - ExportTypeCollectionResult = exportTypeCollectionResult; - ExportMethodReturnTypeInfo = exportMethodReturnTypeInfo; - } - - /// - /// 期望收集的类型所继承的基础类型 - /// - public ITypeSymbol ExpectedClassBaseType { get; } - - /// - /// 期望类型标记的特性,可选 - /// - public ITypeSymbol? ExpectedClassAttributeType { get; } - - public ExportTypeCollectionResult ExportTypeCollectionResult { get; } - - /// - /// 程序集里面标记了导出的分部方法,将用来生成代码 - /// - public IMethodSymbol ExportPartialMethodSymbol => ExportTypeCollectionResult.ExportPartialMethodSymbol; - - /// - /// 导出类型的返回类型信息 - /// - public IExportMethodReturnTypeInfo ExportMethodReturnTypeInfo { get; } - - /// - /// 判断传入的程序集类型满足当前的要求条件 - /// - /// - /// - public bool IsMatch(INamedTypeSymbol assemblyClassTypeSymbol) - { - if (assemblyClassTypeSymbol.IsAbstract) - { - // 抽象类不能提供 - return false; - } - - // 先判断是否继承,再判断是否标记特性 - if (!TypeSymbolHelper.IsInherit(assemblyClassTypeSymbol, ExpectedClassBaseType)) - { - // 没有继承基类,那就是不符合了 - return false; - } - - if (ExpectedClassAttributeType is null) - { - // 如果没有特性要求,那就返回符合 - return true; - } - - foreach (var attributeData in assemblyClassTypeSymbol.GetAttributes()) - { - if (SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, ExpectedClassAttributeType)) - { - return true; - } - } - - return false; - } - } - - class ExportMethodReturnTypeCollectionDiagnostic : IExportMethodReturnTypeCollectionResult - { - } - - /// - /// 候选收集的结果 - /// - /// 包含所有的导出结果。比如项目里面有多个导出方法,每一个导出方法就是一个 CandidateClassTypeResult 对象 - class CandidateClassCollectionResult - { - public CandidateClassCollectionResult(IReadOnlyList candidateClassTypeResultList) - { - CandidateClassTypeResultList = candidateClassTypeResultList; - } - - public IReadOnlyList CandidateClassTypeResultList { get; } - } - - /// - /// 候选的导出类型结果 - /// - /// 包含标记导出的方法信息,以及程序集里面导出的类型 - class CandidateClassTypeResult - { - public CandidateClassTypeResult(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, IReadOnlyList assemblyClassTypeSymbolList) - { - ExportMethodReturnTypeCollectionResult = exportMethodReturnTypeCollectionResult; - AssemblyClassTypeSymbolList = assemblyClassTypeSymbolList; - } - - public ExportMethodReturnTypeCollectionResult ExportMethodReturnTypeCollectionResult { get; } - - public IReadOnlyList AssemblyClassTypeSymbolList { get; } - } } \ No newline at end of file From fb91d7ac24d1a105bd0ae604d3a1948877d50db2 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 17:55:17 +0800 Subject: [PATCH 39/48] =?UTF-8?q?=E6=8B=86=E5=88=86=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=80=BC=E5=AE=9E=E7=8E=B0=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...upleExportMethodReturnTypeCodeGenerator.cs | 98 +++++++++++++++++++ .../ExportMethodCodeGenerator.cs | 57 +++++++++++ .../IExportMethodCodeGenerator.cs | 11 +++ .../IExportMethodReturnTypeInfo.cs | 5 + ...eExportTypeToMethodIncrementalGenerator.cs | 79 +-------------- 5 files changed, 175 insertions(+), 75 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs new file mode 100644 index 0000000..0d3f744 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs @@ -0,0 +1,98 @@ +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +using Microsoft.CodeAnalysis; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 采用 IEnumerable 的 ValueTuple 返回值类型的生成方法 +/// +class EnumerableValueTupleExportMethodReturnTypeCodeGenerator : IExportMethodCodeGenerator +{ + public string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, List list, + CancellationToken token) + { + var methodSource = new StringBuilder(); + + if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo valueTupleExportMethodReturnTypeInfo) + { + var exportPartialMethodSymbol = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol; + + var accessibilityCode = + exportPartialMethodSymbol.DeclaredAccessibility.ToCSharpCode(); + methodSource.Append(accessibilityCode).Append(' '); + + if (exportPartialMethodSymbol.IsStatic) + { + methodSource.Append("static "); + } + + methodSource.Append("partial "); + + if (!valueTupleExportMethodReturnTypeInfo.IsIEnumerable) + { + // 还没支持其他返回值的情况 + throw new NotSupportedException(); + } + + methodSource.Append("global::System.Collections.Generic.IEnumerable<"); + methodSource.Append('('); + var valueTupleInfo = valueTupleExportMethodReturnTypeInfo.ValueTupleInfo; + for (var i = 0; i < valueTupleInfo.ItemList.Count; i++) + { + var info = valueTupleInfo.ItemList[i]; + + if (i != valueTupleInfo.ItemList.Count - 1) + { + var type = TypeSymbolHelper.TypeSymbolToFullName(info.ItemType); + methodSource.Append(type).Append(' '); + methodSource.Append(info.ItemName); + + methodSource.Append(',').Append(' '); + } + else + { + var type = TypeSymbolHelper.TypeSymbolToFullName(exportMethodReturnTypeCollectionResult + .ExpectedClassBaseType); + methodSource.Append($"global::System.Func<{type}> {info.ItemName}"); + } + } + + methodSource.Append(')'); + methodSource.Append('>'); + methodSource.Append(' '); + methodSource.Append(exportPartialMethodSymbol.Name); + methodSource.AppendLine("()"); + methodSource.AppendLine("{"); + + foreach (var namedTypeSymbol in list) + { + token.ThrowIfCancellationRequested(); + // yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + + var attribute = namedTypeSymbol.GetAttributes().First(t => + SymbolEqualityComparer.Default.Equals(t.AttributeClass, + exportMethodReturnTypeCollectionResult + .ExpectedClassAttributeType)); + var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); + + var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); + methodSource.AppendLine(ExportMethodCodeGenerator.IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", + numIndentations: 1)); + } + methodSource.AppendLine("}"); + } + else + { + throw new ArgumentException($"调用错误,其他返回值类型不应该调用"); + } + + return methodSource.ToString(); + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs new file mode 100644 index 0000000..073ed7f --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; + +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 生成导出类型方法的代码 +/// +/// 这个类型只是一个分发工厂,由于存在不同的返回值等需要支持,于是拆分为不同的实现方法 +static class ExportMethodCodeGenerator +{ + public static string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, List list, CancellationToken token) + { + IExportMethodCodeGenerator codeGenerator; + + if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo + valueTupleExportMethodReturnTypeInfo) + { + if (valueTupleExportMethodReturnTypeInfo.IsIEnumerable) + { + codeGenerator = new EnumerableValueTupleExportMethodReturnTypeCodeGenerator(); + } + else + { + // 还没支持其他返回值的情况 + throw new NotSupportedException(); + } + } + else + { + // 还没支持其他返回值的情况 + throw new NotSupportedException(); + } + + return codeGenerator.GenerateSourceCode(exportMethodReturnTypeCollectionResult, list, token); + } + + /// + /// 提供缩进的方法 + /// + /// + /// + /// + public static string IndentSource(string source, int numIndentations) + { + Debug.Assert(numIndentations >= 1); + return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs new file mode 100644 index 0000000..a756288 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading; +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +interface IExportMethodCodeGenerator +{ + string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, + List list, CancellationToken token); +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs index 0825ee9..8c1da9c 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs @@ -1,5 +1,10 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; +/// +/// 导出方法返回值类型信息 +/// +/// 比如属于枚举的 ValueTuple 返回值类型的 +/// 比如属于数组返回值类型的 public interface IExportMethodReturnTypeInfo { } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index cb8ae96..8d677e3 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -317,78 +317,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var exportMethodReturnTypeCollectionResult = item.Key; var list = item.Value; - var methodSource = new StringBuilder(); - - if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo valueTupleExportMethodReturnTypeInfo) - { - var exportPartialMethodSymbol = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol; - - var accessibilityCode = - exportPartialMethodSymbol.DeclaredAccessibility.ToCSharpCode(); - methodSource.Append(accessibilityCode).Append(' '); - - if (exportPartialMethodSymbol.IsStatic) - { - methodSource.Append("static "); - } - - methodSource.Append("partial "); - - if (!valueTupleExportMethodReturnTypeInfo.IsIEnumerable) - { - // 还没支持其他返回值的情况 - throw new NotSupportedException(); - } - - methodSource.Append("global::System.Collections.Generic.IEnumerable<"); - methodSource.Append('('); - var valueTupleInfo = valueTupleExportMethodReturnTypeInfo.ValueTupleInfo; - for (var i = 0; i < valueTupleInfo.ItemList.Count; i++) - { - var info = valueTupleInfo.ItemList[i]; - - if (i != valueTupleInfo.ItemList.Count - 1) - { - var type = TypeSymbolHelper.TypeSymbolToFullName(info.ItemType); - methodSource.Append(type).Append(' '); - methodSource.Append(info.ItemName); - - methodSource.Append(',').Append(' '); - } - else - { - var type = TypeSymbolHelper.TypeSymbolToFullName(exportMethodReturnTypeCollectionResult - .ExpectedClassBaseType); - methodSource.Append($"global::System.Func<{type}> {info.ItemName}"); - } - } - - methodSource.Append(')'); - methodSource.Append('>'); - methodSource.Append(' '); - methodSource.Append(exportPartialMethodSymbol.Name); - methodSource.AppendLine("()"); - methodSource.AppendLine("{"); - - foreach (var namedTypeSymbol in list) - { - token.ThrowIfCancellationRequested(); - // yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); - - var attribute = namedTypeSymbol.GetAttributes().First(t => - SymbolEqualityComparer.Default.Equals(t.AttributeClass, - exportMethodReturnTypeCollectionResult - .ExpectedClassAttributeType)); - var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); - - var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); - methodSource.AppendLine(IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", - numIndentations: 1)); - } - methodSource.AppendLine("}"); - } - - var source = methodSource.ToString(); + var methodCode = + ExportMethodCodeGenerator.GenerateSourceCode(exportMethodReturnTypeCollectionResult, list, token); var partialClassType = (INamedTypeSymbol) exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.ReceiverType!; @@ -435,7 +365,7 @@ namespace {@namespace} {generatedCodeAttributeSource} {declarationList[0]} {{ - {IndentSource(source, Math.Max(1, declarationCount - 1))} + {IndentSource(methodCode, Math.Max(1, declarationCount - 1))} }}"; stringBuilder.AppendLine(IndentSource(partialContextImplementation, numIndentations: declarationCount)); @@ -485,8 +415,7 @@ namespace {@namespace} /// private static string IndentSource(string source, int numIndentations) { - Debug.Assert(numIndentations >= 1); - return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); + return ExportMethodCodeGenerator.IndentSource(source, numIndentations); } /// From 16800d88a3bf23e49f991ea398cea1172a6a4171 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 17:59:02 +0800 Subject: [PATCH 40/48] =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=BA=90=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=94=9F=E6=88=90=E9=9D=99=E6=80=81=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...TupleExportMethodReturnTypeCodeGenerator.cs | 8 +++++++- .../ExportMethodCodeGenerator.cs | 13 ------------- .../IExportMethodCodeGenerator.cs | 3 +++ .../SourceCodeGeneratorHelper.cs | 18 ++++++++++++++++++ ...peExportTypeToMethodIncrementalGenerator.cs | 8 +------- 5 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs index 0d3f744..13a3e6f 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs @@ -18,6 +18,12 @@ class EnumerableValueTupleExportMethodReturnTypeCodeGenerator : IExportMethodCod public string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, List list, CancellationToken token) { + /* + private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable() + { + yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + } + */ var methodSource = new StringBuilder(); if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo valueTupleExportMethodReturnTypeInfo) @@ -83,7 +89,7 @@ public string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMe var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); - methodSource.AppendLine(ExportMethodCodeGenerator.IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", + methodSource.AppendLine(SourceCodeGeneratorHelper.IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", numIndentations: 1)); } methodSource.AppendLine("}"); diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs index 073ed7f..cceaa7f 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; @@ -42,16 +41,4 @@ public static string GenerateSourceCode(ExportMethodReturnTypeCollectionResult e return codeGenerator.GenerateSourceCode(exportMethodReturnTypeCollectionResult, list, token); } - - /// - /// 提供缩进的方法 - /// - /// - /// - /// - public static string IndentSource(string source, int numIndentations) - { - Debug.Assert(numIndentations >= 1); - return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); - } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs index a756288..ffb10e0 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodCodeGenerator.cs @@ -4,6 +4,9 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; +/// +/// 导入方法的生成器 +/// interface IExportMethodCodeGenerator { string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs new file mode 100644 index 0000000..c9167c1 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs @@ -0,0 +1,18 @@ +using System.Diagnostics; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +static class SourceCodeGeneratorHelper +{ + /// + /// 提供缩进的方法 + /// + /// + /// + /// + public static string IndentSource(string source, int numIndentations) + { + Debug.Assert(numIndentations >= 1); + return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 8d677e3..2456537 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -308,12 +308,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { token.ThrowIfCancellationRequested(); - /* - private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable() - { - yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); - } - */ var exportMethodReturnTypeCollectionResult = item.Key; var list = item.Value; @@ -415,7 +409,7 @@ namespace {@namespace} /// private static string IndentSource(string source, int numIndentations) { - return ExportMethodCodeGenerator.IndentSource(source, numIndentations); + return SourceCodeGeneratorHelper.IndentSource(source, numIndentations); } /// From 592aafdd7231a01462233748af35517b2360fed2 Mon Sep 17 00:00:00 2001 From: lindexi Date: Tue, 29 Aug 2023 18:08:20 +0800 Subject: [PATCH 41/48] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E7=9A=84=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/SourceCodeGeneratorHelper.cs | 147 ++++++++++++++++++ .../SourceCodeGeneratorHelper.cs | 18 --- ...eExportTypeToMethodIncrementalGenerator.cs | 113 +------------- 3 files changed, 151 insertions(+), 127 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs delete mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs new file mode 100644 index 0000000..ca8e475 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; + +static class SourceCodeGeneratorHelper +{ + /// + /// 创建 partial 类型的代码 + /// + /// + /// 放在类型里面的代码 + /// + public static string GeneratePartialClassCode(INamedTypeSymbol partialClassType, string memberCode) + { + var symbolDisplayFormat = new SymbolDisplayFormat + ( + // 带上命名空间和类型名 + SymbolDisplayGlobalNamespaceStyle.Omitted, + // 命名空间之前加上 global 防止冲突 + SymbolDisplayTypeQualificationStyle + .NameAndContainingTypesAndNamespaces + ); + var @namespace = partialClassType.ContainingNamespace?.ToDisplayString(symbolDisplayFormat); + + if (TryGetClassDeclarationList(partialClassType, out var declarationList)) + { + int declarationCount = declarationList!.Count; + /* 以下代码用来解决嵌套类型 + for (int i = 0; i < declarationCount - 1; i++) + { + string declarationSource = $@" + {declarationList[declarationCount - 1 - i]} + {{"; + sb.Append($@" + {IndentSource(declarationSource, numIndentations: i + 1)} + "); + } + */ + + var isIncludeNamespace = !string.IsNullOrEmpty(@namespace); + var stringBuilder = new StringBuilder(AssemblyInfo.GeneratedCodeComment); + + if (isIncludeNamespace) + { + stringBuilder.Append(@$" + +namespace {@namespace} +{{"); + } + + var generatedCodeAttributeSource = AssemblyInfo.GeneratedCodeAttribute; + + // Add the core implementation for the derived context class. + string partialContextImplementation = $@" +{generatedCodeAttributeSource} +{declarationList[0]} +{{ + {IndentSource(memberCode, Math.Max(1, declarationCount - 1))} +}}"; + stringBuilder.AppendLine(IndentSource(partialContextImplementation, numIndentations: declarationCount)); + if (isIncludeNamespace) + { + stringBuilder.AppendLine("}"); + } + + return stringBuilder.ToString(); + } + else + { + throw new ArgumentException($"无法为 {partialClassType} 创建代码"); + } + } + + /// + /// 尝试获取类型的定义 + /// + /// + /// 嵌套类的定义 + /// + private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, out List? classDeclarationList) + { + INamedTypeSymbol currentSymbol = typeSymbol; + classDeclarationList = null; + + while (currentSymbol != null) + { + ClassDeclarationSyntax? classDeclarationSyntax = currentSymbol.DeclaringSyntaxReferences.First().GetSyntax() as ClassDeclarationSyntax; + + if (classDeclarationSyntax != null) + { + SyntaxTokenList tokenList = classDeclarationSyntax.Modifiers; + int tokenCount = tokenList.Count; + + bool isPartial = false; + + string[] declarationElements = new string[tokenCount + 2]; + + for (int i = 0; i < tokenCount; i++) + { + SyntaxToken token = tokenList[i]; + declarationElements[i] = token.Text; + + if (token.IsKind(SyntaxKind.PartialKeyword)) + { + isPartial = true; + } + } + + if (!isPartial) + { + classDeclarationList = null; + return false; + } + + declarationElements[tokenCount] = "class"; + declarationElements[tokenCount + 1] = currentSymbol.Name; + + (classDeclarationList ??= new List()).Add(string.Join(" ", declarationElements)); + } + + currentSymbol = currentSymbol.ContainingType; + } + + Debug.Assert(classDeclarationList != null); + Debug.Assert(classDeclarationList!.Count > 0); + return true; + } + + /// + /// 提供缩进的方法 + /// + /// + /// + /// + public static string IndentSource(string source, int numIndentations) + { + Debug.Assert(numIndentations >= 1); + return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); + } +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs deleted file mode 100644 index c9167c1..0000000 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/SourceCodeGeneratorHelper.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Diagnostics; - -namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; - -static class SourceCodeGeneratorHelper -{ - /// - /// 提供缩进的方法 - /// - /// - /// - /// - public static string IndentSource(string source, int numIndentations) - { - Debug.Assert(numIndentations >= 1); - return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); - } -} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 2456537..17f25fa 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -316,62 +316,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var partialClassType = (INamedTypeSymbol) exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.ReceiverType!; - var symbolDisplayFormat = new SymbolDisplayFormat - ( - // 带上命名空间和类型名 - SymbolDisplayGlobalNamespaceStyle.Omitted, - // 命名空间之前加上 global 防止冲突 - SymbolDisplayTypeQualificationStyle - .NameAndContainingTypesAndNamespaces - ); - var @namespace = partialClassType.ContainingNamespace?.ToDisplayString(symbolDisplayFormat); - - if (TryGetClassDeclarationList(partialClassType, out var declarationList)) - { - int declarationCount = declarationList!.Count; - /* 以下代码用来解决嵌套类型 - for (int i = 0; i < declarationCount - 1; i++) - { - string declarationSource = $@" - {declarationList[declarationCount - 1 - i]} - {{"; - sb.Append($@" - {IndentSource(declarationSource, numIndentations: i + 1)} - "); - } - */ - - var isIncludeNamespace = !string.IsNullOrEmpty(@namespace); - var stringBuilder = new StringBuilder(AssemblyInfo.GeneratedCodeComment); - - if (isIncludeNamespace) - { - stringBuilder.Append(@$" - -namespace {@namespace} -{{"); - } - - var generatedCodeAttributeSource = AssemblyInfo.GeneratedCodeAttribute; - - // Add the core implementation for the derived context class. - string partialContextImplementation = $@" -{generatedCodeAttributeSource} -{declarationList[0]} -{{ - {IndentSource(methodCode, Math.Max(1, declarationCount - 1))} -}}"; - stringBuilder.AppendLine(IndentSource(partialContextImplementation, numIndentations: declarationCount)); - - if (isIncludeNamespace) - { - stringBuilder.AppendLine("}"); - } + var code = SourceCodeGeneratorHelper.GeneratePartialClassCode(partialClassType, methodCode); - var fileName = $"{partialClassType.Name}-{exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.Name}"; + var fileName = + $"{partialClassType.Name}-{exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.Name}"; - codeList.Add((fileName, stringBuilder.ToString())); - } + codeList.Add((fileName, code)); } return codeList; @@ -411,59 +361,4 @@ private static string IndentSource(string source, int numIndentations) { return SourceCodeGeneratorHelper.IndentSource(source, numIndentations); } - - /// - /// 尝试获取类型的定义 - /// - /// - /// 嵌套类的定义 - /// - private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, out List? classDeclarationList) - { - INamedTypeSymbol currentSymbol = typeSymbol; - classDeclarationList = null; - - while (currentSymbol != null) - { - ClassDeclarationSyntax? classDeclarationSyntax = currentSymbol.DeclaringSyntaxReferences.First().GetSyntax() as ClassDeclarationSyntax; - - if (classDeclarationSyntax != null) - { - SyntaxTokenList tokenList = classDeclarationSyntax.Modifiers; - int tokenCount = tokenList.Count; - - bool isPartial = false; - - string[] declarationElements = new string[tokenCount + 2]; - - for (int i = 0; i < tokenCount; i++) - { - SyntaxToken token = tokenList[i]; - declarationElements[i] = token.Text; - - if (token.IsKind(SyntaxKind.PartialKeyword)) - { - isPartial = true; - } - } - - if (!isPartial) - { - classDeclarationList = null; - return false; - } - - declarationElements[tokenCount] = "class"; - declarationElements[tokenCount + 1] = currentSymbol.Name; - - (classDeclarationList ??= new List()).Add(string.Join(" ", declarationElements)); - } - - currentSymbol = currentSymbol.ContainingType; - } - - Debug.Assert(classDeclarationList != null); - Debug.Assert(classDeclarationList!.Count > 0); - return true; - } } \ No newline at end of file From 30dca58501f56ebcdb8b9ff53b6eaaaa09568bdb Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 30 Aug 2023 11:28:38 +0800 Subject: [PATCH 42/48] =?UTF-8?q?=E6=8B=86=E5=88=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/SourceCodeGeneratorHelper.cs | 108 +++++++++++++++++- ...upleExportMethodReturnTypeCodeGenerator.cs | 93 ++++----------- .../ExportMethodCodeGenerator.cs | 34 ++---- .../ExportMethodReturnType.cs | 13 +++ .../ExportMethodReturnTypeCollectionResult.cs | 6 +- ...eExportTypeToMethodIncrementalGenerator.cs | 31 ++--- 6 files changed, 173 insertions(+), 112 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnType.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs index ca8e475..896ed2a 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/SourceCodeGeneratorHelper.cs @@ -3,6 +3,8 @@ using System.Diagnostics; using System.Linq; using System.Text; +using System.Threading; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -11,6 +13,100 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; static class SourceCodeGeneratorHelper { + /// + /// 创建分部方法的代码 + /// + /// + /// 放在方法内的代码 + /// + /// + public static string GeneratePartialMethodCode(IMethodSymbol partialMethodSymbol, string methodCode, CancellationToken token) + { + var methodSource = new StringBuilder(); + + var accessibilityCode = + partialMethodSymbol.DeclaredAccessibility.ToCSharpCode(); + methodSource.Append(accessibilityCode).Append(' '); + + if (partialMethodSymbol.IsStatic) + { + methodSource.Append("static "); + } + + if (partialMethodSymbol.IsPartialDefinition) + { + methodSource.Append("partial "); + } + + var returnType = partialMethodSymbol.ReturnType; + GenerateTypeCode(returnType, methodSource, token); + + methodSource.Append(' '); + methodSource.Append(partialMethodSymbol.Name); + methodSource.AppendLine("()"); // 暂时只支持无参函数 + methodSource.AppendLine("{"); + methodSource.AppendLine(IndentSource(methodCode, 1, shouldFirstLine: true)); + methodSource.Append('}'); + + return methodSource.ToString(); + } + + /// + /// 根据传入的类型创建代码 + /// + /// + public static void GenerateTypeCode(ITypeSymbol typeSymbol, StringBuilder output, CancellationToken token) + { + var returnTypeCode = TypeSymbolHelper.TypeSymbolToFullName(typeSymbol); + output.Append(returnTypeCode); + if (typeSymbol is INamedTypeSymbol returnTypeNamedTypeSymbol && returnTypeNamedTypeSymbol.IsGenericType) + { + output.Append('<'); + for (var i = 0; i < returnTypeNamedTypeSymbol.TypeArguments.Length; i++) + { + token.ThrowIfCancellationRequested(); + + var typeArgument = returnTypeNamedTypeSymbol.TypeArguments[i]; + + if (typeArgument.IsTupleType && + ValueTupleInfoParser.TryParse(typeArgument, token, out var valueTupleInfo)) + { + output.Append('('); + for (var index = 0; index < valueTupleInfo.ItemList.Count; index++) + { + var info = valueTupleInfo.ItemList[index]; + + GenerateTypeCode(info.ItemType, output, token); + + if (!string.IsNullOrEmpty(info.ItemName)) + { + output.Append(' ') + .Append(info.ItemName); + } + + if (index != valueTupleInfo.ItemList.Count - 1) + { + output.Append(',').Append(' '); + } + } + + output.Append(')'); + } + else + { + GenerateTypeCode(typeArgument, output, token); + } + + if (i != returnTypeNamedTypeSymbol.TypeArguments.Length - 1) + { + output.Append(','); + } + } + + output.Append('>'); + } + } + /// /// 创建 partial 类型的代码 /// @@ -138,10 +234,18 @@ private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, out /// /// /// + /// /// - public static string IndentSource(string source, int numIndentations) + public static string IndentSource(string source, int numIndentations, bool shouldFirstLine = false) { Debug.Assert(numIndentations >= 1); - return source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); + var result = source.Replace("\r", "").Replace("\n", $"\r\n{new string(' ', 4 * numIndentations)}"); + + if (shouldFirstLine) + { + result = new string(' ', 4 * numIndentations) + result; + } + + return result; } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs index 13a3e6f..a138ba7 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/EnumerableValueTupleExportMethodReturnTypeCodeGenerator.cs @@ -24,81 +24,34 @@ public string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMe yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); } */ - var methodSource = new StringBuilder(); - - if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo valueTupleExportMethodReturnTypeInfo) + if (exportMethodReturnTypeCollectionResult.ExportMethodReturnType != + ExportMethodReturnType.EnumerableValueTupleWithTypeAttributeCreator) { - var exportPartialMethodSymbol = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol; - - var accessibilityCode = - exportPartialMethodSymbol.DeclaredAccessibility.ToCSharpCode(); - methodSource.Append(accessibilityCode).Append(' '); - - if (exportPartialMethodSymbol.IsStatic) - { - methodSource.Append("static "); - } - - methodSource.Append("partial "); - - if (!valueTupleExportMethodReturnTypeInfo.IsIEnumerable) - { - // 还没支持其他返回值的情况 - throw new NotSupportedException(); - } - - methodSource.Append("global::System.Collections.Generic.IEnumerable<"); - methodSource.Append('('); - var valueTupleInfo = valueTupleExportMethodReturnTypeInfo.ValueTupleInfo; - for (var i = 0; i < valueTupleInfo.ItemList.Count; i++) - { - var info = valueTupleInfo.ItemList[i]; - - if (i != valueTupleInfo.ItemList.Count - 1) - { - var type = TypeSymbolHelper.TypeSymbolToFullName(info.ItemType); - methodSource.Append(type).Append(' '); - methodSource.Append(info.ItemName); - - methodSource.Append(',').Append(' '); - } - else - { - var type = TypeSymbolHelper.TypeSymbolToFullName(exportMethodReturnTypeCollectionResult - .ExpectedClassBaseType); - methodSource.Append($"global::System.Func<{type}> {info.ItemName}"); - } - } - - methodSource.Append(')'); - methodSource.Append('>'); - methodSource.Append(' '); - methodSource.Append(exportPartialMethodSymbol.Name); - methodSource.AppendLine("()"); - methodSource.AppendLine("{"); - - foreach (var namedTypeSymbol in list) - { - token.ThrowIfCancellationRequested(); - // yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + throw new ArgumentException($"调用错误,其他返回值类型不应该调用"); + } - var attribute = namedTypeSymbol.GetAttributes().First(t => - SymbolEqualityComparer.Default.Equals(t.AttributeClass, - exportMethodReturnTypeCollectionResult - .ExpectedClassAttributeType)); - var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); + var methodCode = new StringBuilder(); - var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); - methodSource.AppendLine(SourceCodeGeneratorHelper.IndentSource($" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", - numIndentations: 1)); - } - methodSource.AppendLine("}"); - } - else + foreach (var namedTypeSymbol in list) { - throw new ArgumentException($"调用错误,其他返回值类型不应该调用"); + token.ThrowIfCancellationRequested(); + // yield return (typeof(CurrentFoo), new F1Attribute(), () => new CurrentFoo()); + + var attribute = namedTypeSymbol.GetAttributes().First(t => + SymbolEqualityComparer.Default.Equals(t.AttributeClass, + exportMethodReturnTypeCollectionResult + .ExpectedClassAttributeType)); + var attributeCreatedCode = AttributeCodeReWriter.GetAttributeCreatedCode(attribute); + + var typeName = TypeSymbolHelper.TypeSymbolToFullName(namedTypeSymbol); + methodCode.AppendLine(SourceCodeGeneratorHelper.IndentSource( + $" yield return (typeof({typeName}), {attributeCreatedCode}, () => new {typeName}());", + numIndentations: 1)); } - return methodSource.ToString(); + var methodSource = SourceCodeGeneratorHelper.GeneratePartialMethodCode( + exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol, methodCode.ToString(), token); + + return methodSource; } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs index cceaa7f..a9799b4 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodCodeGenerator.cs @@ -1,11 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; -using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; - using Microsoft.CodeAnalysis; namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; @@ -16,28 +12,20 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; /// 这个类型只是一个分发工厂,由于存在不同的返回值等需要支持,于是拆分为不同的实现方法 static class ExportMethodCodeGenerator { - public static string GenerateSourceCode(ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, List list, CancellationToken token) + public static string GenerateSourceCode( + ExportMethodReturnTypeCollectionResult exportMethodReturnTypeCollectionResult, List list, + CancellationToken token) { - IExportMethodCodeGenerator codeGenerator; - - if (exportMethodReturnTypeCollectionResult.ExportMethodReturnTypeInfo is ValueTupleExportMethodReturnTypeInfo - valueTupleExportMethodReturnTypeInfo) - { - if (valueTupleExportMethodReturnTypeInfo.IsIEnumerable) - { - codeGenerator = new EnumerableValueTupleExportMethodReturnTypeCodeGenerator(); - } - else + IExportMethodCodeGenerator codeGenerator = + exportMethodReturnTypeCollectionResult.ExportMethodReturnType switch { + ExportMethodReturnType + .EnumerableValueTupleWithTypeAttributeCreator + => + new EnumerableValueTupleExportMethodReturnTypeCodeGenerator(), // 还没支持其他返回值的情况 - throw new NotSupportedException(); - } - } - else - { - // 还没支持其他返回值的情况 - throw new NotSupportedException(); - } + _ => throw new NotSupportedException() + }; return codeGenerator.GenerateSourceCode(exportMethodReturnTypeCollectionResult, list, token); } diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnType.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnType.cs new file mode 100644 index 0000000..72694ef --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnType.cs @@ -0,0 +1,13 @@ +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; + +/// +/// 导出方法的返回类型 +/// +public enum ExportMethodReturnType +{ + /// + /// 采用 IEnumerable 导出 ValueTuple 包含 Type Attribute 和 Creator 三个参数 + /// + // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() + EnumerableValueTupleWithTypeAttributeCreator, +} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs index 043d790..d667e2f 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionResult.cs @@ -8,12 +8,12 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; /// class ExportMethodReturnTypeCollectionResult : IExportMethodReturnTypeCollectionResult { - public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, ExportTypeCollectionResult exportTypeCollectionResult, IExportMethodReturnTypeInfo exportMethodReturnTypeInfo) + public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, ITypeSymbol? expectedClassAttributeType, ExportTypeCollectionResult exportTypeCollectionResult, ExportMethodReturnType exportMethodReturnType) { ExpectedClassBaseType = expectedClassBaseType; ExpectedClassAttributeType = expectedClassAttributeType; ExportTypeCollectionResult = exportTypeCollectionResult; - ExportMethodReturnTypeInfo = exportMethodReturnTypeInfo; + ExportMethodReturnType= exportMethodReturnType; } /// @@ -36,7 +36,7 @@ public ExportMethodReturnTypeCollectionResult(ITypeSymbol expectedClassBaseType, /// /// 导出类型的返回类型信息 /// - public IExportMethodReturnTypeInfo ExportMethodReturnTypeInfo { get; } + public ExportMethodReturnType ExportMethodReturnType { get; } /// /// 判断传入的程序集类型满足当前的要求条件 diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 17f25fa..bf4a811 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -112,25 +112,28 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 尝试判断是 ValueTuple 的情况 // 要求符合以下定义 // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() - if (namedTypeSymbol.TypeArguments.Length == 1 && ValueTupleInfoParser.TryParse(namedTypeSymbol.TypeArguments[0], token, out ValueTupleInfo valueTupleInfo) && valueTupleInfo.ItemList.Count == 3) + if (namedTypeSymbol.TypeArguments.Length == 1 && namedTypeSymbol.TypeArguments[0] is INamedTypeSymbol tupleType && tupleType.IsTupleType && tupleType.TupleElements.Length>0) { - if (TypeSymbolHelper.TypeSymbolToFullName(valueTupleInfo.ItemList[0].ItemType) != "global::System.Type") + if (tupleType.TupleElements.Length == 3) { - // 这就是错误的 - } + // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() - var funcTypeSymbol = (INamedTypeSymbol) valueTupleInfo.ItemList[2].ItemType; - // 准备导出的类型的基类型 - var expectedClassBaseType = funcTypeSymbol.TypeArguments[0]; + if (TypeSymbolHelper.TypeSymbolToFullName(tupleType.TupleElements[0].Type) != "global::System.Type") + { + // 这就是错误的 + } - // 表示的特性 - var expectedClassAttributeType = valueTupleInfo.ItemList[1].ItemType; + // 表示的特性 + var expectedClassAttributeType = tupleType.TupleElements[1].Type; - return new ExportMethodReturnTypeCollectionResult(expectedClassBaseType, expectedClassAttributeType, - exportTypeCollectionResult, new ValueTupleExportMethodReturnTypeInfo(valueTupleInfo) - { - IsIEnumerable = true - }); + // Func + var funcTypeSymbol = (INamedTypeSymbol) tupleType.TupleElements[2].Type; + // 准备导出的类型的基类型 + var expectedClassBaseType = funcTypeSymbol.TypeArguments[0]; + + return new ExportMethodReturnTypeCollectionResult(expectedClassBaseType, expectedClassAttributeType, + exportTypeCollectionResult, ExportMethodReturnType.EnumerableValueTupleWithTypeAttributeCreator); + } } } } From 2db8be607b0c0b26025b45dc3819d4fafbbb777c Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 30 Aug 2023 11:46:29 +0800 Subject: [PATCH 43/48] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=8D=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IExportMethodReturnTypeInfo.cs | 10 --------- .../ValueTupleExportMethodReturnTypeInfo.cs | 22 ------------------- 2 files changed, 32 deletions(-) delete mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs delete mode 100644 src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs deleted file mode 100644 index 8c1da9c..0000000 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/IExportMethodReturnTypeInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; - -/// -/// 导出方法返回值类型信息 -/// -/// 比如属于枚举的 ValueTuple 返回值类型的 -/// 比如属于数组返回值类型的 -public interface IExportMethodReturnTypeInfo -{ -} \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs deleted file mode 100644 index a44de77..0000000 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ValueTupleExportMethodReturnTypeInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; - -namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; - -/// -/// 导出类型的返回类型信息 -/// -public class ValueTupleExportMethodReturnTypeInfo : IExportMethodReturnTypeInfo -{ - public ValueTupleExportMethodReturnTypeInfo(ValueTupleInfo valueTupleInfo) - { - ValueTupleInfo = valueTupleInfo; - } - - public ValueTupleInfo ValueTupleInfo { get; } - - /// - /// 是否采用 global::System.Collections.Generic.IEnumerable 返回值 - /// IEnumerable<(Type, F1Attribute xx, Func<DemoLib1.F1> xxx)> - /// - public bool IsIEnumerable { set; get; } -} \ No newline at end of file From 6aa457bc11c10b2c4113f7b473f3edfbf94d6b0d Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 30 Aug 2023 14:39:12 +0800 Subject: [PATCH 44/48] =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Diagnostics/TesDiagnostics.cs | 79 ++++++++++ ...ortMethodReturnTypeCollectionDiagnostic.cs | 17 ++- ...eExportTypeToMethodIncrementalGenerator.cs | 44 ++++-- .../Analyzers/Properties/Resource.Designer.cs | 63 ++++++++ .../Properties/Resources.Designer.cs | 108 ++++++++++++++ .../Analyzers/Properties/Resources.resx | 135 ++++++++++++++++++ ....Telescope.SourceGeneratorAnalyzers.csproj | 12 ++ 7 files changed, 449 insertions(+), 9 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/Diagnostics/TesDiagnostics.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/Properties/Resource.Designer.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/Properties/Resources.Designer.cs create mode 100644 src/TelescopeSourceGenerator/Analyzers/Properties/Resources.resx diff --git a/src/TelescopeSourceGenerator/Analyzers/Diagnostics/TesDiagnostics.cs b/src/TelescopeSourceGenerator/Analyzers/Diagnostics/TesDiagnostics.cs new file mode 100644 index 0000000..09d3d31 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Diagnostics/TesDiagnostics.cs @@ -0,0 +1,79 @@ +using Microsoft.CodeAnalysis; + +using System; +using System.Collections.Generic; +using System.Resources; +using System.Text; +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties; +using static dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties.Resources; + +using static Microsoft.CodeAnalysis.WellKnownDiagnosticTags; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Diagnostics; + +static class TesDiagnostics +{ + // ReSharper disable InconsistentNaming + public static DiagnosticDescriptor Tes000_UnknownError => new DiagnosticDescriptor + ( + nameof(Tes000), + Localize(nameof(Tes000)), + Localize(nameof(Tes000_Message)), + Categories.Compiler, + DiagnosticSeverity.Error, + true, + customTags: new[] { AnalyzerException, NotConfigurable } + ); + + public static DiagnosticDescriptor Tes001_MethodReturnTypeError => new DiagnosticDescriptor + ( + nameof(Tes001), + Localize(nameof(Tes001)), + Localize(nameof(Tes001_Message)), + Categories.Compiler, + DiagnosticSeverity.Error, + true, + customTags: new[] { AnalyzerException, NotConfigurable } + ); + + + private static class Categories + { + /// + /// 可能产生 bug,则报告此诊断。 + /// + public const string AvoidBugs = "dotnetCampus.AvoidBugs"; + + /// + /// 为了提供代码生成能力,则报告此诊断。 + /// + public const string CodeFixOnly = "dotnetCampus.CodeFixOnly"; + + /// + /// 因编译要求而必须满足的条件没有满足,则报告此诊断。 + /// + public const string Compiler = "dotnetCampus.Compiler"; + + /// + /// 因 Telescope 库内的机制限制,必须满足此要求 Telescope 才可正常工作,则报告此诊断。 + /// + public const string Mechanism = "dotnetCampus.Mechanism"; + + /// + /// 为了代码可读性,使之更易于理解、方便调试,则报告此诊断。 + /// + public const string Readable = "dotnetCampus.Readable"; + + /// + /// 能写得出来正常编译,但会引发运行时异常,则报告此诊断。 + /// + public const string RuntimeException = "dotnetCampus.RuntimeException"; + + /// + /// 编写了无法生效的代码,则报告此诊断。 + /// + public const string Useless = "dotnetCampus.Useless"; + } + + public static LocalizableString Localize(string key) => new LocalizableResourceString(key, dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties.Resources.ResourceManager, typeof(Resources)); +} diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs index 4e65285..3120036 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/ExportMethodReturnTypeCollectionDiagnostic.cs @@ -1,5 +1,20 @@ -namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; +using Microsoft.CodeAnalysis; + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; class ExportMethodReturnTypeCollectionDiagnostic : IExportMethodReturnTypeCollectionResult { + public ExportMethodReturnTypeCollectionDiagnostic(DiagnosticDescriptor diagnosticDescriptor, + Location? location = null, params object[]? messageArgs) + { + DiagnosticDescriptor = diagnosticDescriptor; + Location = location; + MessageArgs = messageArgs; + } + + public Location? Location { get; set; } + public DiagnosticDescriptor DiagnosticDescriptor { get; } + public object[]? MessageArgs { set; get; } + + public Diagnostic ToDiagnostic() => Diagnostic.Create(DiagnosticDescriptor, Location, MessageArgs); } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index bf4a811..6ef5e6d 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -8,13 +8,14 @@ using System.Text; using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; +using dotnetCampus.Telescope.SourceGeneratorAnalyzers.Diagnostics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; -using static dotnetCampus.Telescope.SourceGeneratorAnalyzers.TelescopeExportTypeToMethodIncrementalGenerator; +using static dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties.Resources; namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers; @@ -112,7 +113,9 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // 尝试判断是 ValueTuple 的情况 // 要求符合以下定义 // static partial IEnumerable<(Type, FooAttribute xx, Func xxx)> ExportFooEnumerable() - if (namedTypeSymbol.TypeArguments.Length == 1 && namedTypeSymbol.TypeArguments[0] is INamedTypeSymbol tupleType && tupleType.IsTupleType && tupleType.TupleElements.Length>0) + if (namedTypeSymbol.TypeArguments.Length == 1 && + namedTypeSymbol.TypeArguments[0] is INamedTypeSymbol tupleType && tupleType.IsTupleType && + tupleType.TupleElements.Length > 0) { if (tupleType.TupleElements.Length == 3) { @@ -121,6 +124,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) if (TypeSymbolHelper.TypeSymbolToFullName(tupleType.TupleElements[0].Type) != "global::System.Type") { // 这就是错误的 + return ReturnTypeError(nameof(Tes001_Message_EnumerableValueTupleWithTypeAttributeCreator)); } // 表示的特性 @@ -128,6 +132,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Func var funcTypeSymbol = (INamedTypeSymbol) tupleType.TupleElements[2].Type; + if (!funcTypeSymbol.IsGenericType || TypeSymbolHelper.TypeSymbolToFullName(funcTypeSymbol) != "global::System.Func") + { + // 不是 Func 的 + return ReturnTypeError(nameof(Tes001_Message_EnumerableValueTupleWithTypeAttributeCreator)); + } + // 准备导出的类型的基类型 var expectedClassBaseType = funcTypeSymbol.TypeArguments[0]; @@ -139,16 +149,34 @@ public void Initialize(IncrementalGeneratorInitializationContext context) } // 其他不认识的,要告诉开发者不能这样写哦 - return new ExportMethodReturnTypeCollectionDiagnostic() as IExportMethodReturnTypeCollectionResult; + return new ExportMethodReturnTypeCollectionDiagnostic(TesDiagnostics.Tes000_UnknownError) as IExportMethodReturnTypeCollectionResult; + + Location GetLocation() + { + var syntaxNode = exportTypeCollectionResult.GeneratorSyntaxContext.Node; + var location = Location.Create(syntaxNode.SyntaxTree, syntaxNode.Span); + return location; + } + + ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) + { + return new ExportMethodReturnTypeCollectionDiagnostic + ( + TesDiagnostics.Tes001_MethodReturnTypeError, + GetLocation(), + TesDiagnostics.Localize(messageKey) + ); + } }); // 这是有定义出错的,需要反馈给到开发者的 - var diagnosticIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider.Select((t, _) => t as ExportMethodReturnTypeCollectionDiagnostic).Where(t => t is not null); + var diagnosticIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider.Select((t, _) => t as ExportMethodReturnTypeCollectionDiagnostic) + .FilterNull(); - //context.RegisterSourceOutput(diagnosticIncrementalValuesProvider , (productionContext, diagnostic) => - //{ - // productionContext.ReportDiagnostic(); - //}); + context.RegisterSourceOutput(diagnosticIncrementalValuesProvider, (productionContext, diagnostic) => + { + productionContext.ReportDiagnostic(diagnostic.ToDiagnostic()); + }); // 收集到了期望收集的内容,将开始进行整个项目的类型收集 diff --git a/src/TelescopeSourceGenerator/Analyzers/Properties/Resource.Designer.cs b/src/TelescopeSourceGenerator/Analyzers/Properties/Resource.Designer.cs new file mode 100644 index 0000000..3bd3e2c --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Properties/Resource.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/src/TelescopeSourceGenerator/Analyzers/Properties/Resources.Designer.cs b/src/TelescopeSourceGenerator/Analyzers/Properties/Resources.Designer.cs new file mode 100644 index 0000000..c7aa698 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Properties/Resources.Designer.cs @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("dotnetCampus.Telescope.SourceGeneratorAnalyzers.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 Telescope unknown error 的本地化字符串。 + /// + internal static string Tes000 { + get { + return ResourceManager.GetString("Tes000", resourceCulture); + } + } + + /// + /// 查找类似 An unknown error occurred when generating. 的本地化字符串。 + /// + internal static string Tes000_Message { + get { + return ResourceManager.GetString("Tes000_Message", resourceCulture); + } + } + + /// + /// 查找类似 Return type error 的本地化字符串。 + /// + internal static string Tes001 { + get { + return ResourceManager.GetString("Tes001", resourceCulture); + } + } + + /// + /// 查找类似 The method return type not match Telescope rule. {0} 的本地化字符串。 + /// + internal static string Tes001_Message { + get { + return ResourceManager.GetString("Tes001_Message", resourceCulture); + } + } + + /// + /// 查找类似 The format that complies with the rules is: IEnumerable<(Type type, FooAttribute attribute, Func<Base> creator) 的本地化字符串。 + /// + internal static string Tes001_Message_EnumerableValueTupleWithTypeAttributeCreator { + get { + return ResourceManager.GetString("Tes001_Message_EnumerableValueTupleWithTypeAttributeCreator", resourceCulture); + } + } + } +} diff --git a/src/TelescopeSourceGenerator/Analyzers/Properties/Resources.resx b/src/TelescopeSourceGenerator/Analyzers/Properties/Resources.resx new file mode 100644 index 0000000..02e3b9f --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/Properties/Resources.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Telescope unknown error + + + An unknown error occurred when generating. + + + Return type error + + + The method return type not match Telescope rule. {0} + + + The format that complies with the rules is: IEnumerable<(Type type, FooAttribute attribute, Func<Base> creator) + + \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj index 73dbf8e..08d6622 100644 --- a/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj +++ b/src/TelescopeSourceGenerator/Analyzers/dotnetCampus.Telescope.SourceGeneratorAnalyzers.csproj @@ -23,4 +23,16 @@ + + + True + True + Resources.resx + + + ResXFileCodeGenerator + Resources.Designer.cs + + + \ No newline at end of file From 61aba68cd9787ba037421b257b90384044032f08 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 30 Aug 2023 15:14:40 +0800 Subject: [PATCH 45/48] =?UTF-8?q?=E6=94=AF=E6=8C=81=E9=9D=99=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/IncrementalValuesProviderHelper.cs | 2 +- ...eExportTypeToMethodIncrementalGenerator.cs | 34 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs index 1e04284..6ae60dd 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs @@ -12,6 +12,6 @@ static class IncrementalValuesProviderHelper /// public static IncrementalValuesProvider FilterNull(this IncrementalValuesProvider provider) { - return provider.Where(t => t != null).Select((t, _) => t!); + return provider.Where(static t => t != null).Select(static (t, _) => t!); } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 6ef5e6d..866ed7b 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -34,7 +34,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) } #endif // 先找到定义 - IncrementalValuesProvider exportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((syntaxNode, _) => + IncrementalValuesProvider exportMethodIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider(static (syntaxNode, _) => { // 先要求是分部的方法,分部的方法必定在分部类里面,这部分判断分部类里面还可以省略 if (syntaxNode is MethodDeclarationSyntax methodDeclarationSyntax && methodDeclarationSyntax.AttributeLists.Any()) @@ -50,7 +50,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) } return false; - }, (generatorSyntaxContext, token) => + }, static (generatorSyntaxContext, token) => { // 语义分析,判断方法是否标记了 TelescopeExportAttribute 特性 @@ -94,7 +94,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .FilterNull(); // 获取方法返回值导出类型 - var exportMethodReturnTypeCollectionResultIncrementalValuesProvider = exportMethodIncrementalValuesProvider.Select((exportTypeCollectionResult, token) => + var exportMethodReturnTypeCollectionResultIncrementalValuesProvider = exportMethodIncrementalValuesProvider.Select(static (exportTypeCollectionResult, token) => { ITypeSymbol methodSymbolReturnType = exportTypeCollectionResult.ExportPartialMethodSymbol.ReturnType; @@ -170,10 +170,10 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) }); // 这是有定义出错的,需要反馈给到开发者的 - var diagnosticIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider.Select((t, _) => t as ExportMethodReturnTypeCollectionDiagnostic) + var diagnosticIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider.Select(static (t, _) => t as ExportMethodReturnTypeCollectionDiagnostic) .FilterNull(); - context.RegisterSourceOutput(diagnosticIncrementalValuesProvider, (productionContext, diagnostic) => + context.RegisterSourceOutput(diagnosticIncrementalValuesProvider, static (productionContext, diagnostic) => { productionContext.ReportDiagnostic(diagnostic.ToDiagnostic()); }); @@ -182,14 +182,14 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 将这些需要包含引用程序集的加进来返回值类型。因为标记导出支持带引用程序集的 var assemblyReferenceExportReturnTypeProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider - .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) + .Select(static (t, _) => t as ExportMethodReturnTypeCollectionResult) // 只有非空且包含引用程序集的,才加入 - .Where(t => t is not null && t.ExportTypeCollectionResult.IncludeReference) - .Select((t, _) => t!) + .Where(static t => t is not null && t.ExportTypeCollectionResult.IncludeReference) + .Select(static (t, _) => t!) .Collect(); // 收集引用的程序集的类型 - var referenceAssemblyTypeIncrementalValueProvider = context.CompilationProvider.Combine(assemblyReferenceExportReturnTypeProvider).Select((tuple, token) => + var referenceAssemblyTypeIncrementalValueProvider = context.CompilationProvider.Combine(assemblyReferenceExportReturnTypeProvider).Select(static (tuple, token) => { var compilation = tuple.Left; @@ -249,16 +249,16 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 收集当前分析器所分析项目的类型 // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider - .Select((t, _) => t as ExportMethodReturnTypeCollectionResult) + .Select(static (t, _) => t as ExportMethodReturnTypeCollectionResult) .FilterNull() .Collect(); // 收集整个项目里面所有的类型 var candidateClassCollectionResultIncrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider( - (syntaxNode, _) => + static (syntaxNode, _) => { return syntaxNode.IsKind(SyntaxKind.ClassDeclaration); - }, (generatorSyntaxContext, token) => + }, static (generatorSyntaxContext, token) => { var classDeclarationSyntax = (ClassDeclarationSyntax)generatorSyntaxContext.Node; // 从语法转换为语义,用于后续判断是否标记了特性 @@ -273,7 +273,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) }) .FilterNull() .Combine(returnTypeCollectionIncrementalValuesProvider) - .Select((tuple, token) => + .Select(static (tuple, token) => { var assemblyClassTypeSymbol = tuple.Left; var exportMethodReturnTypeCollectionResultArray = tuple.Right; @@ -302,9 +302,9 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) .FilterNull(); var collectionResultIncrementalValueProvider = referenceAssemblyTypeIncrementalValueProvider.Combine(candidateClassCollectionResultIncrementalValuesProvider.Collect()) - .SelectMany((tuple, _) => { return tuple.Right.Add(tuple.Left); }) + .SelectMany(static (tuple, _) => { return tuple.Right.Add(tuple.Left); }) .Collect() - .Select((array, token) => + .Select(static (array, token) => { // 去掉重复的定义 var dictionary = new Dictionary>(); @@ -332,7 +332,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 转换为源代码输出 // 源代码输出放在 Select 可以随时打断,实际 VisualStudio 性能会比放在 RegisterImplementationSourceOutput 高很多 - var sourceCodeProvider = collectionResultIncrementalValueProvider.Select((result, token) => + var sourceCodeProvider = collectionResultIncrementalValueProvider.Select(static (result, token) => { var codeList = new List<(string /*FileName*/, string /*SourceCode*/)>(result.Count); foreach (var item in result) @@ -361,7 +361,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 可以被 IDE 选择不生成的代码,但是在完全生成输出时将会跑 // 这里可以用来存放具体实现的代码,将不影响用户代码的语义,而不是用来做定义的代码 context.RegisterImplementationSourceOutput(sourceCodeProvider, - (productionContext, result) => + static (productionContext, result) => { foreach (var (fileName, code) in result) { From b9804d1d7e203641ef7443070d399740c2d3fd6f Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 30 Aug 2023 15:23:58 +0800 Subject: [PATCH 46/48] =?UTF-8?q?=E5=87=86=E5=A4=87=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/README.md | 79 +++++++++++++++++++ .../TelescopeSourceGeneratorDemo/Program.cs | 24 ++---- 2 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 src/TelescopeSourceGenerator/Analyzers/README.md diff --git a/src/TelescopeSourceGenerator/Analyzers/README.md b/src/TelescopeSourceGenerator/Analyzers/README.md new file mode 100644 index 0000000..82fb178 --- /dev/null +++ b/src/TelescopeSourceGenerator/Analyzers/README.md @@ -0,0 +1,79 @@ +# Telescope.SourceGeneratorAnalyzers + +使用 SourceGenerator 源代码生成器的 Telescope 版本 + +可以用来导出指定类型 + +## 用法 + +支持多个不同的导出写法 + +### 分部方法式 + +这是推荐的方法 + +在分部类里定义分部方法,分部方法标记 `dotnetCampus.Telescope.TelescopeExportAttribute` 特性,且返回值包括导出条件,如以下写法 + +```csharp +internal partial class Program +{ + [dotnetCampus.Telescope.TelescopeExportAttribute()] + private static partial IEnumerable<(Type type, F1Attribute attribute, Func creator)> ExportFooEnumerable(); +} +``` + +以上代码将导出当前项目标记了 `F1Attribute` 且继承 `Base` 的所有类型。经过 Telescope 源代码生成器即可生成大概如下的代码 + +```csharp + [global::System.CodeDom.Compiler.GeneratedCode("dotnetCampus.Telescope.SourceGeneratorAnalyzers", "1.0.0")] + internal partial class Program + { + private static partial IEnumerable<(Type type, F1Attribute attribute, Func creator)> ExportFooEnumerable() + { + yield return (typeof(F2), new F1Attribute() + { + + }, () => new F2()); + yield return (typeof(F3), new F1Attribute() + { + + }, () => new F3()); + } + } +``` + +高级用法: + +可以在 TelescopeExportAttribute 加上 IncludeReference 属性用来导出所有引用程序集的满足条件的类型,如以下代码 + +```csharp +internal partial class Program +{ + [dotnetCampus.Telescope.TelescopeExportAttribute(IncludeReference = true)] + private static partial IEnumerable<(Type type, F1Attribute attribute, Func creator)> ExportFooEnumerable(); +} +``` + +仅推荐在入口程序集加上 `IncludeReference = true` 属性,因为一旦加入此属性,任何引用程序集的变更都可能导致源代码生成器重复执行,降低 VisualStudio 性能 + +### 程序集标记 + +这是传统的 Telescope 实现方法,在需要导出类型的项目里标记 `dotnetCampus.Telescope.MarkExportAttribute` 特性,如以下代码 + +```csharp +[assembly: dotnetCampus.Telescope.MarkExportAttribute(typeof(Base), typeof(FooAttribute))] +``` + +标记之后将会自动生成 `dotnetCampus.Telescope.__AttributedTypesExport__` 类型,即可在代码里面直接使用,如以下代码 + +```csharp + var attributedTypesExport = new __AttributedTypesExport__(); + ICompileTimeAttributedTypesExporter exporter = attributedTypesExport; + foreach (var exportedTypeMetadata in exporter.ExportAttributeTypes()) + { + // 输出导出的类型 + Console.WriteLine(exportedTypeMetadata.RealType.FullName); + } +``` + +也可以使用 `dotnetCampus.Telescope.AttributedTypes` 辅助类获取所有导出类型 \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 0ead03c..28fc092 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -8,22 +8,19 @@ static void Main(string[] args) { foreach (var (_, xx, xxx) in ExportFooEnumerable()) { - } - //var attributedTypesExport = new __AttributedTypesExport__(); - //ICompileTimeAttributedTypesExporter exporter = attributedTypesExport; - //foreach (var exportedTypeMetadata in exporter.ExportAttributeTypes()) - //{ - // // 输出导出的类型 - // Console.WriteLine(exportedTypeMetadata.RealType.FullName); - //} + var attributedTypesExport = new __AttributedTypesExport__(); + ICompileTimeAttributedTypesExporter exporter = attributedTypesExport; + foreach (var exportedTypeMetadata in exporter.ExportAttributeTypes()) + { + // 输出导出的类型 + Console.WriteLine(exportedTypeMetadata.RealType.FullName); + } } [dotnetCampus.Telescope.TelescopeExportAttribute(IncludeReference = true)] - //private static partial Base[] ExportFoo(); private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable(); - //private static partial Func[] ExportFooCreator(); } [F1] @@ -31,13 +28,6 @@ public class CurrentFoo : DemoLib1.F1 { } -//internal partial class Program -//{ -// private static partial IEnumerable<(Type , FooAttribute xx, Func xxx)> ExportFooEnumerable() -// { -// } -//} - [Foo(0, FooEnum.N1, typeof(Foo), null)] abstract class F1 : Base { From a347ab73125a37261a3bc77865bd46387a587aa1 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 30 Aug 2023 15:49:52 +0800 Subject: [PATCH 47/48] =?UTF-8?q?=E6=8F=90=E5=8D=87=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...peExportTypeToMethodIncrementalGenerator.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index 866ed7b..e6e7df6 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -189,16 +189,16 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) .Collect(); // 收集引用的程序集的类型 - var referenceAssemblyTypeIncrementalValueProvider = context.CompilationProvider.Combine(assemblyReferenceExportReturnTypeProvider).Select(static (tuple, token) => + var referenceAssemblyTypeIncrementalValueProvider = context.CompilationProvider + .Select(static (compilation, _) => compilation.SourceModule.ReferencedAssemblySymbols) + .Combine(assemblyReferenceExportReturnTypeProvider).Select(static (tuple, token) => { - var compilation = tuple.Left; + // 获取到所有引用程序集 + var referencedAssemblySymbols = tuple.Left; // 所有导出类型的定义逻辑 var exportMethodReturnTypeCollectionResults = tuple.Right; - // 获取到所有引用程序集 - var referencedAssemblySymbols = compilation.SourceModule.ReferencedAssemblySymbols; - var candidateClassList = new List(); foreach (var exportMethodReturnTypeCollectionResult in exportMethodReturnTypeCollectionResults) @@ -211,12 +211,15 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 期望继承的基础类型 var expectedClassBaseType = exportMethodReturnTypeCollectionResult.ExpectedClassBaseType; - // 过滤程序集,只有引用了期望继承的基础类型所在程序集的,才可以被收集到。如果没有引用,那自然写不出继承基础类型的代码 + + // 当前项目的程序集,用来判断 internal 可见性 + var currentAssembly = exportMethodReturnTypeCollectionResult.ExportPartialMethodSymbol.ContainingAssembly; var visited = new Dictionary(SymbolEqualityComparer.Default); foreach (var referencedAssemblySymbol in referencedAssemblySymbols) { + // 过滤程序集,只有引用了期望继承的基础类型所在程序集的,才可以被收集到。如果没有引用,那自然写不出继承基础类型的代码 token.ThrowIfCancellationRequested(); if (!AssemblySymbolHelper.IsReference(referencedAssemblySymbol, expectedClassBaseType.ContainingAssembly, visited)) { @@ -224,7 +227,8 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) continue; } - var isInternalsVisibleTo = referencedAssemblySymbol.GivesAccessTo(compilation.Assembly); + // 判断 referencedAssemblySymbol 是否设置 internal 可见 + var isInternalsVisibleTo = referencedAssemblySymbol.GivesAccessTo(currentAssembly); foreach (var assemblyClassTypeSymbol in AssemblySymbolHelper.GetAllTypeSymbol(referencedAssemblySymbol)) { From dde58761e4169bc693f0350a24bf97dcbb678957 Mon Sep 17 00:00:00 2001 From: lindexi Date: Sat, 2 Sep 2023 17:56:24 +0800 Subject: [PATCH 48/48] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Analyzers/Core/AssemblySymbolHelper.cs | 11 ++++++++--- .../Core/IncrementalValuesProviderHelper.cs | 2 +- .../TelescopeExportAttribute.cs | 2 +- ...escopeExportTypeToMethodIncrementalGenerator.cs | 14 +++++++------- .../Demo/TelescopeSourceGeneratorDemo/Program.cs | 2 +- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs index 0c2ba2e..a1d4c2b 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/AssemblySymbolHelper.cs @@ -6,9 +6,14 @@ namespace dotnetCampus.Telescope.SourceGeneratorAnalyzers.Core; static class AssemblySymbolHelper { - public static IEnumerable GetAllTypeSymbol(IAssemblySymbol assemblySymbol) => GetAllTypeSymbol(assemblySymbol.GlobalNamespace); + /// + /// 获取当前程序集里面的所有类型 + /// + /// + /// + public static IEnumerable GetAllTypeSymbols(IAssemblySymbol assemblySymbol) => GetAllTypeSymbols(assemblySymbol.GlobalNamespace); - public static IEnumerable GetAllTypeSymbol(INamespaceSymbol namespaceSymbol) + public static IEnumerable GetAllTypeSymbols(INamespaceSymbol namespaceSymbol) { var typeMemberList = namespaceSymbol.GetTypeMembers(); @@ -19,7 +24,7 @@ public static IEnumerable GetAllTypeSymbol(INamespaceSymbol na foreach (var namespaceMember in namespaceSymbol.GetNamespaceMembers()) { - foreach (var typeSymbol in GetAllTypeSymbol(namespaceMember)) + foreach (var typeSymbol in GetAllTypeSymbols(namespaceMember)) { yield return typeSymbol; } diff --git a/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs b/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs index 6ae60dd..5fcaea9 100644 --- a/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs +++ b/src/TelescopeSourceGenerator/Analyzers/Core/IncrementalValuesProviderHelper.cs @@ -10,7 +10,7 @@ static class IncrementalValuesProviderHelper /// /// /// - public static IncrementalValuesProvider FilterNull(this IncrementalValuesProvider provider) + public static IncrementalValuesProvider ExcludeNulls(this IncrementalValuesProvider provider) { return provider.Where(static t => t != null).Select(static (t, _) => t!); } diff --git a/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs b/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs index 0d83cc3..f6a49ba 100644 --- a/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs +++ b/src/TelescopeSourceGenerator/Analyzers/EmbeddedResourceCode/TelescopeExportAttribute.cs @@ -7,6 +7,6 @@ sealed class TelescopeExportAttribute : global::System.Attribute /// /// 是否包含引用的程序集和 DLL 里面的类型导出。默认只导出当前程序集 /// - public bool IncludeReference { set; get; } + public bool IncludeReferences { set; get; } } } \ No newline at end of file diff --git a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs index e6e7df6..f9598d1 100644 --- a/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs +++ b/src/TelescopeSourceGenerator/Analyzers/ExportTypeToMethod_/TelescopeExportTypeToMethodIncrementalGenerator.cs @@ -78,7 +78,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var attributeDataNamedArguments = attributeData.NamedArguments; var includeReference = attributeDataNamedArguments - .FirstOrDefault(t => t.Key == nameof(TelescopeExportAttribute.IncludeReference)).Value + .FirstOrDefault(t => t.Key == nameof(TelescopeExportAttribute.IncludeReferences)).Value .Value is true; return new ExportTypeCollectionResult(methodSymbol, generatorSyntaxContext) @@ -91,7 +91,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return null; }) // 过滤不满足条件的 - .FilterNull(); + .ExcludeNulls(); // 获取方法返回值导出类型 var exportMethodReturnTypeCollectionResultIncrementalValuesProvider = exportMethodIncrementalValuesProvider.Select(static (exportTypeCollectionResult, token) => @@ -171,7 +171,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 这是有定义出错的,需要反馈给到开发者的 var diagnosticIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider.Select(static (t, _) => t as ExportMethodReturnTypeCollectionDiagnostic) - .FilterNull(); + .ExcludeNulls(); context.RegisterSourceOutput(diagnosticIncrementalValuesProvider, static (productionContext, diagnostic) => { @@ -230,7 +230,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 判断 referencedAssemblySymbol 是否设置 internal 可见 var isInternalsVisibleTo = referencedAssemblySymbol.GivesAccessTo(currentAssembly); - foreach (var assemblyClassTypeSymbol in AssemblySymbolHelper.GetAllTypeSymbol(referencedAssemblySymbol)) + foreach (var assemblyClassTypeSymbol in AssemblySymbolHelper.GetAllTypeSymbols(referencedAssemblySymbol)) { if (!isInternalsVisibleTo && assemblyClassTypeSymbol.DeclaredAccessibility != Accessibility.Public) @@ -254,7 +254,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) // 收集所有的带返回类型,用来进行下一步的收集项目里的所有类型 IncrementalValueProvider> returnTypeCollectionIncrementalValuesProvider = exportMethodReturnTypeCollectionResultIncrementalValuesProvider .Select(static (t, _) => t as ExportMethodReturnTypeCollectionResult) - .FilterNull() + .ExcludeNulls() .Collect(); // 收集整个项目里面所有的类型 @@ -275,7 +275,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) return null; }) - .FilterNull() + .ExcludeNulls() .Combine(returnTypeCollectionIncrementalValuesProvider) .Select(static (tuple, token) => { @@ -303,7 +303,7 @@ ExportMethodReturnTypeCollectionDiagnostic ReturnTypeError(string messageKey) return null; } }) - .FilterNull(); + .ExcludeNulls(); var collectionResultIncrementalValueProvider = referenceAssemblyTypeIncrementalValueProvider.Combine(candidateClassCollectionResultIncrementalValuesProvider.Collect()) .SelectMany(static (tuple, _) => { return tuple.Right.Add(tuple.Left); }) diff --git a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs index 28fc092..3e1a141 100644 --- a/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs +++ b/src/TelescopeSourceGenerator/Demo/TelescopeSourceGeneratorDemo/Program.cs @@ -19,7 +19,7 @@ static void Main(string[] args) } } - [dotnetCampus.Telescope.TelescopeExportAttribute(IncludeReference = true)] + [dotnetCampus.Telescope.TelescopeExportAttribute(IncludeReferences = true)] private static partial IEnumerable<(Type, F1Attribute xx, Func xxx)> ExportFooEnumerable(); }