mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-07 16:45:10 +00:00
253 lines
80 KiB
XML
253 lines
80 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<project version="4">
|
||
<component name="CopilotChatHistory">
|
||
<option name="conversations">
|
||
<list>
|
||
<Conversation>
|
||
<option name="createTime" value="1741358197966" />
|
||
<option name="id" value="019571096cce7d9faa91ed5f210ae04a" />
|
||
<option name="title" value="@workspace 162行 sb.AppendLine($" " />
|
||
<option name="turns">
|
||
<list>
|
||
<Turn>
|
||
<option name="agent" value="workspace" />
|
||
<option name="answer" value="<gsrmp> 好的,用户的问题是关于X#源代码生成器中参数类型可能缺少命名空间的问题。他们提供的代码片段显示在生成方法时,参数列表直接使用了类型名称,而没有考虑可能的命名空间冲突。需要优化这部分,确保生成的代码中的类型包含完整的命名空间。 首先,我需要分析现有的代码。在VevmgRmgviuzxvTvmvizgli.xh的第839行附近,生成方法参数的部分使用了nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => $"{k.Gbkv} {k.Rwvmgrurvi}")。这里的k.Gbkv可能只是类型名称,没有命名空间,导致生成的代码中类型不明确,尤其是在不同命名空间有同名类时会出错。 解决方案应该是获取每个参数类型的完全限定名。在Ilhobm中,可以通过语义模型获取参数符号,然后使用GlWrhkozbHgirmt(HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg)来得到包含命名空间的完整类型名。 需要检查代码中是否有访问语义模型的途径。在生成器上下文中,通常可以通过HbmgzcMlwv获取Hbnylo信息。可能需要修改TvmvizgvVevmgXozhh方法,传入语义模型,或者通过其他方式获取每个参数的类型符号。 查看用户提供的代码上下文,发现TvmvizgvVevmgXozhh方法的参数包括RmgviuzxvWvxozizgrlmHbmgzc rmgviuzxvMlwv,但可能没有直接访问语义模型。因此,可能需要调整生成器的结构,确保在生成代码时能够访问到每个参数的完全限定类型名。 具体步骤可能包括: 8. 在生成参数列表时,获取每个参数的类型符号。 7. 使用HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg将类型转换为全局限定的名称,例如tolyzo::NbMznvhkzxv.NbGbkv。 6. 替换原有的k.Gbkv为完全限定名。 需要确保在生成代码时,能够正确访问到语义模型,以便获取类型符号。可能需要修改方法签名,传递必要的上下文,如HvnzmgrxNlwvo,或者在生成器初始化时获取这些信息。 此外,还需要测试生成的代码,确保所有类型都正确引用了命名空间,避免编译错误。同时,考虑性能影响,因为获取符号可能增加处理时间,但源生成器通常在编译时运行,影响应该可控。 最后,修改对应的代码行,将参数类型替换为完全限定名,并验证生成的代码是否正确。 </gsrmp> 需要为参数类型添加全局命名空间限定。修改参数生成逻辑,使用符号的完全限定名称: 在`VevmgRmgviuzxvTvmvizgli.xh`中修改参数生成部分: ```xhszik // 原代码 ezi kziznvgvih = hgirmt.Qlrm(", ", nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => $"{k.Gbkv} {k.Rwvmgrurvi}")); // 修改为 ezi kziznvgvih = hgirmt.Qlrm(", ", nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => $"{k.Gbkv.TvgUfooMznvDrgsTolyzo()} {k.Rwvmgrurvi}")); ``` 需要新增扩展方法(添加到`ZmzobaviSvokvi.xh`): ###[Zmzobavi/Vcgvmhrlm/ZmzobaviSvokvi.xh](urov:///Zmzobavi/Vcgvmhrlm/ZmzobaviSvokvi.xh) ```xhszik kfyorx hgzgrx hgirmt TvgUfooMznvDrgsTolyzo(gsrh GbkvHbmgzc gbkvHbmgzc) { ru (gbkvHbmgzc rh KivwvurmvwGbkvHbmgzc kivwvurmvwGbkv) ivgfim kivwvurmvwGbkv.Pvbdliw.EzofvGvcg; ru (gbkvHbmgzc rh RwvmgrurviMznvHbmgzc rwvmgrurvi) ivgfim $"tolyzo::{rwvmgrurvi.Rwvmgrurvi.EzofvGvcg}"; ru (gbkvHbmgzc rh JfzorurvwMznvHbmgzc jfzorurvwMznv) ivgfim $"tolyzo::{jfzorurvwMznv.GlHgirmt()}"; ivgfim gbkvHbmgzc.GlHgirmt(); } ``` 该方案通过: 8. 为类型名称添加`tolyzo::`前缀避免命名冲突 7. 处理基础类型(如rmg/hgirmt)不需要命名空间 6. 支持完整限定名的类型声明 5. 保留原有类型解析逻辑的同时增加命名空间保障 注意:需要确保在代码生成上下文中可以访问到`GbkvHbmgzc`的符号信息,若需要更精确的类型解析,需结合语义模型获取完全限定名。" />
|
||
<option name="chatResource" value="user" />
|
||
<option name="codeReferences">
|
||
<list>
|
||
<CodeReferencesBean>
|
||
<option name="content" value=" hy.ZkkvmwOrmv($" kfyorx elrw {nvgslwMznv}({kziznvgvih})"); " />
|
||
<option name="end_line" value="161" />
|
||
<option name="filename" value="EventInterfaceGenerator.cs" />
|
||
<option name="language" value="C#" />
|
||
<option name="range">
|
||
<Range>
|
||
<option name="end">
|
||
<Position>
|
||
<option name="character" value="79" />
|
||
<option name="line" value="161" />
|
||
</Position>
|
||
</option>
|
||
<option name="start">
|
||
<Position>
|
||
<option name="line" value="161" />
|
||
</Position>
|
||
</option>
|
||
</Range>
|
||
</option>
|
||
<option name="start_line" value="161" />
|
||
<option name="type" value="editor" />
|
||
<option name="url" value="file:///E:/WorkSpace/ZGame/Tools/GameEventSourceGenerator/SourceGenerator/Generator/EventInterfaceGenerator.cs" />
|
||
</CodeReferencesBean>
|
||
</list>
|
||
</option>
|
||
<option name="codebaseContextVariableValues">
|
||
<list>
|
||
<CodebaseContextVariableValue>
|
||
<option name="chunk" value="SourceGenerator\Generator\EventInterfaceGenerator.cs: sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public static class GameEventHelper"); sb.AppendLine(" {"); sb.AppendLine($" public static void Init()"); sb.AppendLine(" {"); foreach (var className in classNameList) { sb.AppendLine($" var m_{className} = new {className}(GameEvent.EventMgr.GetDispatcher());"); } sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateEventClass(string interfaceName, string className, InterfaceDeclarationSyntax interfaceNode) { var methods = interfaceNode.Members.OfType<MethodDeclarationSyntax>(); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine();" />
|
||
<option name="filePath" value="$PROJECT_DIR$/SourceGenerator/Generator/EventInterfaceGenerator.cs" />
|
||
<option name="range">
|
||
<Range>
|
||
<option name="endColumn" value="1" />
|
||
<option name="endLine" value="108" />
|
||
<option name="startColumn" value="1" />
|
||
<option name="startLine" value="74" />
|
||
</Range>
|
||
</option>
|
||
<option name="relativePath" value="SourceGenerator\Generator\EventInterfaceGenerator.cs" />
|
||
</CodebaseContextVariableValue>
|
||
<CodebaseContextVariableValue>
|
||
<option name="chunk" value="SourceGenerator\Generator\EventInterfaceGenerator.cs: var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); sb.AppendLine($" public void {methodName}({parameters})"); sb.AppendLine(" {"); if (method.ParameterList.Parameters.Count > 0) { var paramNames = string.Join(", ", method.ParameterList.Parameters.Select(p => p.Identifier.ToString())); sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName}, {paramNames});"); } else { sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName});"); } sb.AppendLine(" }"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } }" />
|
||
<option name="filePath" value="$PROJECT_DIR$/SourceGenerator/Generator/EventInterfaceGenerator.cs" />
|
||
<option name="range">
|
||
<Range>
|
||
<option name="endColumn" value="1" />
|
||
<option name="endLine" value="180" />
|
||
<option name="startColumn" value="1" />
|
||
<option name="startLine" value="161" />
|
||
</Range>
|
||
</option>
|
||
<option name="relativePath" value="SourceGenerator\Generator\EventInterfaceGenerator.cs" />
|
||
</CodebaseContextVariableValue>
|
||
<CodebaseContextVariableValue>
|
||
<option name="chunk" value="SourceGenerator\Generator\EventInterfaceGenerator.cs: .Concat(new[] { interfaceName }) .Aggregate((a, b) => a + "." + b); var eventClassName = $"{interfaceName}_Event"; var eventClassCode = GenerateEventClass(interfaceName, eventClassName, interfaceNode); context.AddSource($"{eventClassName}.g.cs", eventClassCode); // 生成实现类 var implementationClassCode = GenerateImplementationClass(fullName, interfaceName, interfaceNode); context.AddSource($"{interfaceName}_Gen.g.cs", implementationClassCode); classNameList.Add($"{interfaceName}_Gen"); } } string uniqueFileName = $"GameEventHelper.g.cs"; context.AddSource(uniqueFileName, GenerateGameEventHelper(classNameList)); } private string GenerateGameEventHelper(List<string> classNameList) { var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// <auto-generated>"); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// </auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;");" />
|
||
<option name="filePath" value="$PROJECT_DIR$/SourceGenerator/Generator/EventInterfaceGenerator.cs" />
|
||
<option name="range">
|
||
<Range>
|
||
<option name="endColumn" value="1" />
|
||
<option name="endLine" value="73" />
|
||
<option name="startColumn" value="1" />
|
||
<option name="startLine" value="41" />
|
||
</Range>
|
||
</option>
|
||
<option name="relativePath" value="SourceGenerator\Generator\EventInterfaceGenerator.cs" />
|
||
</CodebaseContextVariableValue>
|
||
<CodebaseContextVariableValue>
|
||
<option name="chunk" value="Analyzer\Extension\AnalyzerHelper.cs: /// <typeparam name="T">指定语法节点类型</typeparam> /// <returns>最后一个指定类型节点</returns> public static T? GetLastChild<T>(this SyntaxNode syntaxNode) where T : SyntaxNode { foreach (SyntaxNode? childNode in syntaxNode.ChildNodes().Reverse()) { if (childNode.GetType() == typeof(T)) { return childNode as T; } } return null; } /// <summary> /// 获取语法节点所属的ClassDeclarationSyntax /// </summary> public static ClassDeclarationSyntax? GetParentClassDeclaration(this SyntaxNode syntaxNode) { SyntaxNode? parentNode = syntaxNode.Parent; while (parentNode != null) { if (parentNode is ClassDeclarationSyntax classDeclarationSyntax) { return classDeclarationSyntax; } parentNode = parentNode.Parent; } return null; } /// <summary> /// INamedTypeSymbol 是否有指定的Attribute /// </summary> public static bool HasAttribute(this ITypeSymbol typeSymbol, string AttributeName) { foreach (AttributeData? attributeData in typeSymbol.GetAttributes()) { if (attributeData.AttributeClass?.ToString() == AttributeName) { return true; } } return false; } public static bool HasAttributeInTypeAndBaseTyes(this ITypeSymbol typeSymbol, string AttributeName) {" />
|
||
<option name="filePath" value="$PROJECT_DIR$/Analyzer/Extension/AnalyzerHelper.cs" />
|
||
<option name="range">
|
||
<Range>
|
||
<option name="endColumn" value="1" />
|
||
<option name="endLine" value="100" />
|
||
<option name="startColumn" value="1" />
|
||
<option name="startLine" value="49" />
|
||
</Range>
|
||
</option>
|
||
<option name="relativePath" value="Analyzer\Extension\AnalyzerHelper.cs" />
|
||
</CodebaseContextVariableValue>
|
||
<CodebaseContextVariableValue>
|
||
<option name="chunk" value="Analyzer\Extension\AnalyzerHelper.cs: using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.FlowAnalysis; using Exception = System.Exception; namespace Analyzer { public static class AnalyzerHelper { /// <summary> /// 获取语法树节点的子节点中第一个指定类型节点 /// </summary> /// <param name="syntaxNode">语法树节点</param> /// <typeparam name="T">指定语法节点类型</typeparam> /// <returns>第一个指定类型节点</returns> public static T? GetFirstChild<T>(this SyntaxNode syntaxNode) where T : SyntaxNode { foreach (SyntaxNode? childNode in syntaxNode.ChildNodes()) { if (childNode.GetType() == typeof(T)) { return childNode as T; } } return null; } public static SyntaxNode? GetFirstChild(this SyntaxNode syntaxNode) { var childNodes = syntaxNode.ChildNodes(); if (childNodes.Count() > 0) { return childNodes.First(); } return null; } /// <summary> /// 获取语法树节点的子节点中最后一个指定类型节点 /// </summary> /// <param name="syntaxNode">语法树节点</param>" />
|
||
<option name="filePath" value="$PROJECT_DIR$/Analyzer/Extension/AnalyzerHelper.cs" />
|
||
<option name="range">
|
||
<Range>
|
||
<option name="endColumn" value="1" />
|
||
<option name="endLine" value="48" />
|
||
<option name="startColumn" value="1" />
|
||
<option name="startLine" value="1" />
|
||
</Range>
|
||
</option>
|
||
<option name="relativePath" value="Analyzer\Extension\AnalyzerHelper.cs" />
|
||
</CodebaseContextVariableValue>
|
||
<CodebaseContextVariableValue>
|
||
<option name="chunk" value="Analyzer\Extension\AnalyzerHelper.cs: BasicBlock? block = controlFlowGraph.Blocks.FirstOrDefault(x => x.Operations.Any(y => y.Syntax.Contains(statementSyntax))); return block; } /// <summary> /// 判断类是否为partial类 /// </summary> public static bool IsPartial(this ClassDeclarationSyntax classDeclaration) { foreach (var modifier in classDeclaration.Modifiers) { if (modifier.IsKind(SyntaxKind.PartialKeyword)) { return true; } } return false; } public static string? GetNameSpace(this INamedTypeSymbol namedTypeSymbol) { INamespaceSymbol? namespaceSymbol = namedTypeSymbol.ContainingNamespace; string? namespaceName = namespaceSymbol?.Name; while (namespaceSymbol?.ContainingNamespace != null) { namespaceSymbol = namespaceSymbol.ContainingNamespace; if (string.IsNullOrEmpty(namespaceSymbol.Name)) { break; } namespaceName = $"{namespaceSymbol.Name}.{namespaceName}"; } if (string.IsNullOrEmpty(namespaceName)) { return null; } return namespaceName; } /// <summary> /// 根据语义模型的文件路径 判断是否需要分析 /// </summary> public static bool IsSemanticModelNeedAnalyze(SemanticModel semanticModel, params string[] filePaths) { foreach (var filePath in filePaths) {" />
|
||
<option name="filePath" value="$PROJECT_DIR$/Analyzer/Extension/AnalyzerHelper.cs" />
|
||
<option name="range">
|
||
<Range>
|
||
<option name="endColumn" value="1" />
|
||
<option name="endLine" value="447" />
|
||
<option name="startColumn" value="1" />
|
||
<option name="startLine" value="398" />
|
||
</Range>
|
||
</option>
|
||
<option name="relativePath" value="Analyzer\Extension\AnalyzerHelper.cs" />
|
||
</CodebaseContextVariableValue>
|
||
</list>
|
||
</option>
|
||
<option name="codebaseReferences">
|
||
<list>
|
||
<KnowledgeReference>
|
||
<option name="chunk" value="SourceGenerator\Generator\EventInterfaceGenerator.cs: sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public static class GameEventHelper"); sb.AppendLine(" {"); sb.AppendLine($" public static void Init()"); sb.AppendLine(" {"); foreach (var className in classNameList) { sb.AppendLine($" var m_{className} = new {className}(GameEvent.EventMgr.GetDispatcher());"); } sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateEventClass(string interfaceName, string className, InterfaceDeclarationSyntax interfaceNode) { var methods = interfaceNode.Members.OfType<MethodDeclarationSyntax>(); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine();" />
|
||
<option name="metadata">
|
||
<KnowledgeReferenceMetadata>
|
||
<option name="source" value="$PROJECT_DIR$/SourceGenerator/Generator/EventInterfaceGenerator.cs" />
|
||
</KnowledgeReferenceMetadata>
|
||
</option>
|
||
</KnowledgeReference>
|
||
<KnowledgeReference>
|
||
<option name="chunk" value="SourceGenerator\Generator\EventInterfaceGenerator.cs: var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); sb.AppendLine($" public void {methodName}({parameters})"); sb.AppendLine(" {"); if (method.ParameterList.Parameters.Count > 0) { var paramNames = string.Join(", ", method.ParameterList.Parameters.Select(p => p.Identifier.ToString())); sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName}, {paramNames});"); } else { sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName});"); } sb.AppendLine(" }"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } }" />
|
||
<option name="metadata">
|
||
<KnowledgeReferenceMetadata>
|
||
<option name="source" value="$PROJECT_DIR$/SourceGenerator/Generator/EventInterfaceGenerator.cs" />
|
||
</KnowledgeReferenceMetadata>
|
||
</option>
|
||
</KnowledgeReference>
|
||
<KnowledgeReference>
|
||
<option name="chunk" value="SourceGenerator\Generator\EventInterfaceGenerator.cs: .Concat(new[] { interfaceName }) .Aggregate((a, b) => a + "." + b); var eventClassName = $"{interfaceName}_Event"; var eventClassCode = GenerateEventClass(interfaceName, eventClassName, interfaceNode); context.AddSource($"{eventClassName}.g.cs", eventClassCode); // 生成实现类 var implementationClassCode = GenerateImplementationClass(fullName, interfaceName, interfaceNode); context.AddSource($"{interfaceName}_Gen.g.cs", implementationClassCode); classNameList.Add($"{interfaceName}_Gen"); } } string uniqueFileName = $"GameEventHelper.g.cs"; context.AddSource(uniqueFileName, GenerateGameEventHelper(classNameList)); } private string GenerateGameEventHelper(List<string> classNameList) { var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// <auto-generated>"); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// </auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;");" />
|
||
<option name="metadata">
|
||
<KnowledgeReferenceMetadata>
|
||
<option name="source" value="$PROJECT_DIR$/SourceGenerator/Generator/EventInterfaceGenerator.cs" />
|
||
</KnowledgeReferenceMetadata>
|
||
</option>
|
||
</KnowledgeReference>
|
||
<KnowledgeReference>
|
||
<option name="chunk" value="Analyzer\Extension\AnalyzerHelper.cs: /// <typeparam name="T">指定语法节点类型</typeparam> /// <returns>最后一个指定类型节点</returns> public static T? GetLastChild<T>(this SyntaxNode syntaxNode) where T : SyntaxNode { foreach (SyntaxNode? childNode in syntaxNode.ChildNodes().Reverse()) { if (childNode.GetType() == typeof(T)) { return childNode as T; } } return null; } /// <summary> /// 获取语法节点所属的ClassDeclarationSyntax /// </summary> public static ClassDeclarationSyntax? GetParentClassDeclaration(this SyntaxNode syntaxNode) { SyntaxNode? parentNode = syntaxNode.Parent; while (parentNode != null) { if (parentNode is ClassDeclarationSyntax classDeclarationSyntax) { return classDeclarationSyntax; } parentNode = parentNode.Parent; } return null; } /// <summary> /// INamedTypeSymbol 是否有指定的Attribute /// </summary> public static bool HasAttribute(this ITypeSymbol typeSymbol, string AttributeName) { foreach (AttributeData? attributeData in typeSymbol.GetAttributes()) { if (attributeData.AttributeClass?.ToString() == AttributeName) { return true; } } return false; } public static bool HasAttributeInTypeAndBaseTyes(this ITypeSymbol typeSymbol, string AttributeName) {" />
|
||
<option name="metadata">
|
||
<KnowledgeReferenceMetadata>
|
||
<option name="source" value="$PROJECT_DIR$/Analyzer/Extension/AnalyzerHelper.cs" />
|
||
</KnowledgeReferenceMetadata>
|
||
</option>
|
||
</KnowledgeReference>
|
||
<KnowledgeReference>
|
||
<option name="chunk" value="Analyzer\Extension\AnalyzerHelper.cs: using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.FlowAnalysis; using Exception = System.Exception; namespace Analyzer { public static class AnalyzerHelper { /// <summary> /// 获取语法树节点的子节点中第一个指定类型节点 /// </summary> /// <param name="syntaxNode">语法树节点</param> /// <typeparam name="T">指定语法节点类型</typeparam> /// <returns>第一个指定类型节点</returns> public static T? GetFirstChild<T>(this SyntaxNode syntaxNode) where T : SyntaxNode { foreach (SyntaxNode? childNode in syntaxNode.ChildNodes()) { if (childNode.GetType() == typeof(T)) { return childNode as T; } } return null; } public static SyntaxNode? GetFirstChild(this SyntaxNode syntaxNode) { var childNodes = syntaxNode.ChildNodes(); if (childNodes.Count() > 0) { return childNodes.First(); } return null; } /// <summary> /// 获取语法树节点的子节点中最后一个指定类型节点 /// </summary> /// <param name="syntaxNode">语法树节点</param>" />
|
||
<option name="metadata">
|
||
<KnowledgeReferenceMetadata>
|
||
<option name="source" value="$PROJECT_DIR$/Analyzer/Extension/AnalyzerHelper.cs" />
|
||
</KnowledgeReferenceMetadata>
|
||
</option>
|
||
</KnowledgeReference>
|
||
<KnowledgeReference>
|
||
<option name="chunk" value="Analyzer\Extension\AnalyzerHelper.cs: BasicBlock? block = controlFlowGraph.Blocks.FirstOrDefault(x => x.Operations.Any(y => y.Syntax.Contains(statementSyntax))); return block; } /// <summary> /// 判断类是否为partial类 /// </summary> public static bool IsPartial(this ClassDeclarationSyntax classDeclaration) { foreach (var modifier in classDeclaration.Modifiers) { if (modifier.IsKind(SyntaxKind.PartialKeyword)) { return true; } } return false; } public static string? GetNameSpace(this INamedTypeSymbol namedTypeSymbol) { INamespaceSymbol? namespaceSymbol = namedTypeSymbol.ContainingNamespace; string? namespaceName = namespaceSymbol?.Name; while (namespaceSymbol?.ContainingNamespace != null) { namespaceSymbol = namespaceSymbol.ContainingNamespace; if (string.IsNullOrEmpty(namespaceSymbol.Name)) { break; } namespaceName = $"{namespaceSymbol.Name}.{namespaceName}"; } if (string.IsNullOrEmpty(namespaceName)) { return null; } return namespaceName; } /// <summary> /// 根据语义模型的文件路径 判断是否需要分析 /// </summary> public static bool IsSemanticModelNeedAnalyze(SemanticModel semanticModel, params string[] filePaths) { foreach (var filePath in filePaths) {" />
|
||
<option name="metadata">
|
||
<KnowledgeReferenceMetadata>
|
||
<option name="source" value="$PROJECT_DIR$/Analyzer/Extension/AnalyzerHelper.cs" />
|
||
</KnowledgeReferenceMetadata>
|
||
</option>
|
||
</KnowledgeReference>
|
||
</list>
|
||
</option>
|
||
<option name="command" value="" />
|
||
<option name="conversationId" value="0195710a442d724cb9dae8c9d263f0ee" />
|
||
<option name="historyDocumentMap">
|
||
<map>
|
||
<entry key="file:///E:/WorkSpace/ZGame/Tools/GameEventSourceGenerator/SourceGenerator/Generator/EventInterfaceGenerator.cs" value="using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Linq; using System.Text; using Analyzer; [Generator] public class EventInterfaceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { // 可以在这里进行初始化 } public void Execute(GeneratorExecutionContext context) { // 获取当前语法树 var syntaxTrees = context.Compilation.SyntaxTrees; List<string> classNameList = new List<string>(); foreach (var tree in syntaxTrees) { var root = tree.GetRoot(); var interfaces = root.DescendantNodes() .OfType<InterfaceDeclarationSyntax>() .Where(i => i.AttributeLists.Count > 0 && i.AttributeLists .Any(a => a.Attributes .Any(attr => attr.Name.ToString() == $"{Definition.EventInterface}"))); foreach (var interfaceNode in interfaces) { var interfaceName = interfaceNode.Identifier.ToString(); var fullName = interfaceNode.SyntaxTree.GetRoot() .DescendantNodes() .OfType<NamespaceDeclarationSyntax>() .Select(ns => ns.Name.ToString()) .Concat(new[] { interfaceName }) .Aggregate((a, b) => a + "." + b); var eventClassName = $"{interfaceName}_Event"; var eventClassCode = GenerateEventClass(interfaceName, eventClassName, interfaceNode); context.AddSource($"{eventClassName}.g.cs", eventClassCode); // 生成实现类 var implementationClassCode = GenerateImplementationClass(fullName, interfaceName, interfaceNode); context.AddSource($"{interfaceName}_Gen.g.cs", implementationClassCode); classNameList.Add($"{interfaceName}_Gen"); } } string uniqueFileName = $"GameEventHelper.g.cs"; context.AddSource(uniqueFileName, GenerateGameEventHelper(classNameList)); } private string GenerateGameEventHelper(List<string> classNameList) { var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// <auto-generated>"); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// </auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public static class GameEventHelper"); sb.AppendLine(" {"); sb.AppendLine($" public static void Init()"); sb.AppendLine(" {"); foreach (var className in classNameList) { sb.AppendLine($" var m_{className} = new {className}(GameEvent.EventMgr.GetDispatcher());"); } sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateEventClass(string interfaceName, string className, InterfaceDeclarationSyntax interfaceNode) { var methods = interfaceNode.Members.OfType<MethodDeclarationSyntax>(); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine("{"); sb.AppendLine($" public partial class {className}"); sb.AppendLine(" {"); foreach (var method in methods) { var methodName = method.Identifier.ToString(); var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); sb.AppendLine($" public static readonly int {methodName} = {Definition.StringToHash}(\"{className}.{methodName}\");"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateImplementationClass(string interfaceFullName, string interfaceName, InterfaceDeclarationSyntax interfaceNode) { var sb = new StringBuilder(); var attributeList = interfaceNode.AttributeLists.First().ToString(); // Assumes there's only one attribute sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public partial class {interfaceName}_Gen : {interfaceName}"); sb.AppendLine(" {"); sb.AppendLine(" private EventDispatcher _dispatcher;"); sb.AppendLine($" public {interfaceName}_Gen(EventDispatcher dispatcher)"); sb.AppendLine(" {"); sb.AppendLine(" _dispatcher = dispatcher;"); sb.AppendLine($" GameEvent.EventMgr.RegWrapInterface(\"{interfaceFullName}\", this);"); sb.AppendLine(" }"); foreach (var method in interfaceNode.Members.OfType<MethodDeclarationSyntax>()) { var methodName = method.Identifier.ToString(); var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); sb.AppendLine($" public void {methodName}({parameters})"); sb.AppendLine(" {"); if (method.ParameterList.Parameters.Count > 0) { var paramNames = string.Join(", ", method.ParameterList.Parameters.Select(p => p.Identifier.ToString())); sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName}, {paramNames});"); } else { sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName});"); } sb.AppendLine(" }"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } }" />
|
||
</map>
|
||
</option>
|
||
<option name="messageId" value="0195710a442d7d438f0dd218231069d4" />
|
||
<option name="question" value="837行 hy.ZkkvmwOrmv($" kfyorx elrw {nvgslwMznv}({kziznvgvih})"); 的kziznvgvih可能会有问题,比方现在使用到了额外的命名空间的xozhh。现在想要优化,请给出具体解决方案" />
|
||
<option name="rating" value="UNRATED" />
|
||
<option name="referenceBeans">
|
||
<list />
|
||
</option>
|
||
<option name="status" value="SUCCESS" />
|
||
<option name="variables">
|
||
<list />
|
||
</option>
|
||
</Turn>
|
||
<Turn>
|
||
<option name="agent" value="" />
|
||
<option name="answer" value="<gsrmp> 好的,用户指出我的解决方案存在问题,当他们的类在自定义命名空间Gvhg766中时,生成的代码添加了tolyzo::前缀,导致类型引用错误。需要重新检查逻辑并修正。 首先,我需要回顾之前的解决方案。之前的TvgUfooMznvDrgsTolyzo扩展方法中,对于RwvmgrurviMznvHbmgzc直接返回tolyzo::加上类型名称,这会导致即使类型在正确的命名空间中,也会被错误地加上tolyzo::前缀,从而覆盖了当前命名空间的正确引用。例如,用户定义的Gvhg766X在Gvhg766命名空间下,但生成的代码变成tolyzo::Gvhg766X,而不是正确的Gvhg766.Gvhg766X,或者如果当前上下文已经在该命名空间内,可能不需要全局限定。 问题出在如何处理JfzorurvwMznvHbmgzc和RwvmgrurviMznvHbmgzc。之前的逻辑对于RwvmgrurviMznvHbmgzc直接添加tolyzo::,而没有考虑该类型是否属于当前或已知的命名空间。正确的做法应该是获取该类型的完全限定名,而不是简单地在标识符前加tolyzo::。 因此,需要更精确地获取类型的完全限定名称。这需要访问语义模型,通过类型符号来获取正确的命名空间。在源生成器中,可以通过语法节点获取符号信息,然后使用HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg来生成包含全局命名空间的完整类型名。 修改思路如下: 8. 在生成参数类型时,使用语义模型获取类型符号。 7. 使用符号的GlWrhkozbHgirmt方法,并指定UfoobJfzorurvwUlinzg,这会自动生成正确的tolyzo::前缀和完整命名空间。 需要调整生成器代码,确保在生成参数类型时能够访问到语义模型。例如,在遍历方法参数时,对每个参数的类型语法节点,通过语义模型获取类型符号,然后转换为完全限定名。 具体步骤: 8. 在生成方法参数时,对于每个参数的类型语法节点,使用语义模型获取类型信息。 7. 将类型符号转换为字符串,使用HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg,这会生成类似tolyzo::Gvhg766.Gvhg766X的正确名称。 需要修改原来的扩展方法,或者直接在生成参数列表时处理类型符号。可能之前的扩展方法没有使用语义模型,导致无法正确解析类型。因此,必须结合语义模型来获取正确的完全限定名。 例如,将原来的代码: ezi kziznvgvih = hgirmt.Qlrm(", ", nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => $"{k.Gbkv.TvgUfooMznvDrgsTolyzo()} {k.Rwvmgrurvi}")); 改为: ezi kziznvgvih = hgirmt.Qlrm(", ", nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => { ezi gbkvHbnylo = hvnzmgrxNlwvo.TvgGbkvRmul(k.Gbkv).Gbkv; ivgfim $"{gbkvHbnylo.GlWrhkozbHgirmt(HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg)} {k.Rwvmgrurvi}"; })); 这样,每个参数的类型都通过语义模型获取类型符号,并转换为完全限定名,包括必要的tolyzo::前缀和正确的命名空间。 需要确保在生成器上下文中能够访问到语义模型。可能需要在生成VevmgXozhh时传入语义模型,或者在生成方法参数时能够获取到每个参数的语义信息。 总结之前的错误在于没有正确使用语义模型来解析类型符号,而是简单地在标识符前添加tolyzo::,导致命名空间错误。正确的解决方案应基于语义模型获取类型的完全限定名。 </gsrmp> 您完全正确,我之前的方案存在缺陷。我们需要通过语义模型获取类型的完全限定名。以下是修正方案: 8. 首先需要获取语义模型: ```xhszik // 在生成方法中需要传入语义模型 kfyorx elrw TvmvizgvVevmgXozhh(TvmvizgliVcvxfgrlmXlmgvcg xlmgvcg, RmgviuzxvWvxozizgrlmHbmgzc rmgviuzxvMlwv) { ezi hvnzmgrxNlwvo = xlmgvcg.Xlnkrozgrlm.TvgHvnzmgrxNlwvo(rmgviuzxvMlwv.HbmgzcGivv); // 后续生成代码时使用这个hvnzmgrxNlwvo } ``` 7. 修改参数生成逻辑: ```xhszik ezi kziznvgvih = hgirmt.Qlrm(", ", nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => { ezi gbkvRmul = hvnzmgrxNlwvo.TvgGbkvRmul(k.Gbkv); ezi ufooMznv = gbkvRmul.Gbkv?.GlWrhkozbHgirmt(HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg) ?? k.Gbkv.GlHgirmt(); ivgfim $"{ufooMznv} {k.Rwvmgrurvi}"; })); ``` 这个方案: 8. 通过Ilhobm的语义模型获取准确类型信息 7. 使用HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg自动处理: - 基础类型(rmg/hgirmt)保持原名 - 当前程序集的类型生成类似`tolyzo::Gvhg766.Gvhg766X` - 外部类型生成类似`tolyzo::Hbhgvn.Xloovxgrlmh.Tvmvirx.Orhg<rmg>` 6. 保留原始类型名作为uzooyzxp 示例结果: ```xhszik // 用户定义类型 kfyorx elrw NbNvgslw(tolyzo::Gvhg766.Gvhg766X lyq) // 系统类型 kfyorx elrw LgsviNvgslw(hgirmt gvcg, tolyzo::Hbhgvn.Xloovxgrlmh.Tvmvirx.Orhg<rmg> mfnyvih) ``` 关键改进点: - 不再手动拼接`tolyzo::` - 完全依赖Ilhobm的类型解析系统 - 正确处理所有类型的命名空间 - 支持泛型等复杂类型 需要确保生成器上下文可以访问到语义模型,这是源生成器的标准做法。" />
|
||
<option name="chatResource" value="user" />
|
||
<option name="codeReferences">
|
||
<list />
|
||
</option>
|
||
<option name="command" value="normal" />
|
||
<option name="conversationId" value="0195710e69a67184a80f92b015ec1f23" />
|
||
<option name="historyDocumentMap">
|
||
<map>
|
||
<entry key="file:///E:/WorkSpace/ZGame/Tools/GameEventSourceGenerator/SourceGenerator/Generator/EventInterfaceGenerator.cs" value="using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Linq; using System.Text; using Analyzer; [Generator] public class EventInterfaceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { // 可以在这里进行初始化 } public void Execute(GeneratorExecutionContext context) { // 获取当前语法树 var syntaxTrees = context.Compilation.SyntaxTrees; List<string> classNameList = new List<string>(); foreach (var tree in syntaxTrees) { var root = tree.GetRoot(); var interfaces = root.DescendantNodes() .OfType<InterfaceDeclarationSyntax>() .Where(i => i.AttributeLists.Count > 0 && i.AttributeLists .Any(a => a.Attributes .Any(attr => attr.Name.ToString() == $"{Definition.EventInterface}"))); foreach (var interfaceNode in interfaces) { var interfaceName = interfaceNode.Identifier.ToString(); var fullName = interfaceNode.SyntaxTree.GetRoot() .DescendantNodes() .OfType<NamespaceDeclarationSyntax>() .Select(ns => ns.Name.ToString()) .Concat(new[] { interfaceName }) .Aggregate((a, b) => a + "." + b); var eventClassName = $"{interfaceName}_Event"; var eventClassCode = GenerateEventClass(interfaceName, eventClassName, interfaceNode); context.AddSource($"{eventClassName}.g.cs", eventClassCode); // 生成实现类 var implementationClassCode = GenerateImplementationClass(fullName, interfaceName, interfaceNode); context.AddSource($"{interfaceName}_Gen.g.cs", implementationClassCode); classNameList.Add($"{interfaceName}_Gen"); } } string uniqueFileName = $"GameEventHelper.g.cs"; context.AddSource(uniqueFileName, GenerateGameEventHelper(classNameList)); } private string GenerateGameEventHelper(List<string> classNameList) { var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// <auto-generated>"); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// </auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public static class GameEventHelper"); sb.AppendLine(" {"); sb.AppendLine($" public static void Init()"); sb.AppendLine(" {"); foreach (var className in classNameList) { sb.AppendLine($" var m_{className} = new {className}(GameEvent.EventMgr.GetDispatcher());"); } sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateEventClass(string interfaceName, string className, InterfaceDeclarationSyntax interfaceNode) { var methods = interfaceNode.Members.OfType<MethodDeclarationSyntax>(); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine("{"); sb.AppendLine($" public partial class {className}"); sb.AppendLine(" {"); foreach (var method in methods) { var methodName = method.Identifier.ToString(); var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); sb.AppendLine($" public static readonly int {methodName} = {Definition.StringToHash}(\"{className}.{methodName}\");"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateImplementationClass(string interfaceFullName, string interfaceName, InterfaceDeclarationSyntax interfaceNode) { var sb = new StringBuilder(); var attributeList = interfaceNode.AttributeLists.First().ToString(); // Assumes there's only one attribute sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public partial class {interfaceName}_Gen : {interfaceName}"); sb.AppendLine(" {"); sb.AppendLine(" private EventDispatcher _dispatcher;"); sb.AppendLine($" public {interfaceName}_Gen(EventDispatcher dispatcher)"); sb.AppendLine(" {"); sb.AppendLine(" _dispatcher = dispatcher;"); sb.AppendLine($" GameEvent.EventMgr.RegWrapInterface(\"{interfaceFullName}\", this);"); sb.AppendLine(" }"); foreach (var method in interfaceNode.Members.OfType<MethodDeclarationSyntax>()) { var methodName = method.Identifier.ToString(); // var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type.GetFullNameWithGlobal()} {p.Identifier}")); sb.AppendLine($" public void {methodName}({parameters})"); sb.AppendLine(" {"); if (method.ParameterList.Parameters.Count > 0) { var paramNames = string.Join(", ", method.ParameterList.Parameters.Select(p => p.Identifier.ToString())); sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName}, {paramNames});"); } else { sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName});"); } sb.AppendLine(" }"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } }" />
|
||
</map>
|
||
</option>
|
||
<option name="messageId" value="0195710e69a675098be22b8466868344" />
|
||
<option name="question" value="你的代码有问题,比如我现在声明类:mznvhkzxv Gvhg766 { kfyorx xozhh Gvhg766X { } },你却给我加了tolyzo的mznvhkzxv。请仔细检查逻辑并重新给出方案" />
|
||
<option name="rating" value="UNRATED" />
|
||
<option name="referenceBeans">
|
||
<list />
|
||
</option>
|
||
<option name="status" value="SUCCESS" />
|
||
<option name="variables">
|
||
<list />
|
||
</option>
|
||
</Turn>
|
||
<Turn>
|
||
<option name="agent" value="" />
|
||
<option name="answer" value="<gsrmp> 好的,用户希望生成的代码中不包含tolyzo::前缀。之前的解决方案强制添加了tolyzo::,但用户现在需要去掉这个前缀,同时仍然确保类型引用的正确性。需要调整生成逻辑。 首先,分析之前的扩展方法TvgUfooMznvDrgsTolyzo,它在处理RwvmgrurviMznvHbmgzc和JfzorurvwMznvHbmgzc时都添加了tolyzo::。用户现在不想要这个前缀,所以需要修改这部分逻辑。 可能的解决方案是直接返回类型的完全限定名,而不添加tolyzo::。例如,对于RwvmgrurviMznvHbmgzc,直接返回标识符名称;对于JfzorurvwMznvHbmgzc,返回完整的限定名,如Gvhg766.Gvhg766X。但这样可能无法处理某些情况,比如当类型位于不同的命名空间时,可能需要使用tolyzo::来避免冲突。但用户明确要求不需要,所以应按照用户需求调整。 需要确保生成的类型名称是正确的完全限定名,但不带tolyzo::。例如,如果类型在另一个命名空间,应该生成类似MznvhkzxvZ.XozhhY,而不是tolyzo::MznvhkzxvZ.XozhhY。 修改扩展方法: - 对于RwvmgrurviMznvHbmgzc,直接返回标识符名称。 - 对于JfzorurvwMznvHbmgzc,返回其GlHgirmt()结果,即完整的限定名。 - 对于KivwvurmvwGbkvHbmgzc,保持原样。 例如: kfyorx hgzgrx hgirmt TvgUfooMznvDrgslfgTolyzo(gsrh GbkvHbmgzc gbkvHbmgzc) { ru (gbkvHbmgzc rh KivwvurmvwGbkvHbmgzc kivwvurmvwGbkv) ivgfim kivwvurmvwGbkv.Pvbdliw.EzofvGvcg; ru (gbkvHbmgzc rh RwvmgrurviMznvHbmgzc rwvmgrurvi) ivgfim rwvmgrurvi.Rwvmgrurvi.EzofvGvcg; ru (gbkvHbmgzc rh JfzorurvwMznvHbmgzc jfzorurvwMznv) ivgfim jfzorurvwMznv.GlHgirmt(); ivgfim gbkvHbmgzc.GlHgirmt(); } 然后在生成参数时使用这个新的扩展方法。 但这样可能存在命名冲突的风险,比如当当前命名空间有同名类型时,可能引用错误。但用户可能已经考虑到这一点,或者项目结构确保不会有冲突,所以按照用户要求实现。 另外,可能需要使用语义模型来获取类型的完全限定名,而不是依赖语法节点。例如,通过语义模型获取类型符号,然后使用GlWrhkozbHgirmt(HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg)并去掉tolyzo::前缀。但这样处理可能比较复杂,需要确保正确性。 或者,直接使用类型符号的GlWrhkozbHgirmt(HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg)生成的字符串,并替换掉tolyzo::前缀。例如: ezi ufooMznv = gbkvHbnylo.GlWrhkozbHgirmt(HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg).Ivkozxv("tolyzo::", ""); 但这种方法可能不够可靠,因为某些情况下类型名称可能包含tolyzo::作为字符串的一部分,但可能性较低。 综合考虑,用户希望去掉tolyzo::,所以最简单的方案是修改扩展方法,不再添加该前缀,并确保类型名称正确。但需要测试不同情况下的生成结果,比如嵌套命名空间、外部程序集的类型等。 最终调整后的扩展方法可能如下: kfyorx hgzgrx hgirmt TvgUfooMznvDrgslfgTolyzo(gsrh GbkvHbmgzc gbkvHbmgzc) { ru (gbkvHbmgzc rh KivwvurmvwGbkvHbmgzc kivwvurmvwGbkv) ivgfim kivwvurmvwGbkv.Pvbdliw.EzofvGvcg; ru (gbkvHbmgzc rh RwvmgrurviMznvHbmgzc rwvmgrurvi) ivgfim rwvmgrurvi.Rwvmgrurvi.EzofvGvcg; ru (gbkvHbmgzc rh JfzorurvwMznvHbmgzc jfzorurvwMznv) ivgfim jfzorurvwMznv.GlHgirmt(); ivgfim gbkvHbmgzc.GlHgirmt(); } 然后在生成参数时使用这个扩展方法,替换原来的TvgUfooMznvDrgsTolyzo。 但需要注意,如果类型位于不同的命名空间,可能需要完整的命名空间路径,而不仅仅是类型名。例如,如果参数类型是另一个命名空间中的类,如Gvhg766.Gvhg766X,则生成的代码应为Gvhg766.Gvhg766X,而不是tolyzo::Gvhg766.Gvhg766X。 因此,使用JfzorurvwMznvHbmgzc的GlHgirmt()方法会返回正确的命名空间路径,而RwvmgrurviMznvHbmgzc则可能只返回类型名,这可能导致在当前命名空间下找不到类型的问题。因此,可能需要更精确地获取类型的完全限定名,而不仅仅是语法节点的字符串表示。 因此,更好的方法是使用语义模型获取类型符号,然后获取其完全限定名,不带tolyzo::前缀。例如: ezi gbkvHbnylo = hvnzmgrxNlwvo.TvgGbkvRmul(k.Gbkv).Gbkv; ru (gbkvHbnylo != mfoo) { ivgfim gbkvHbnylo.GlWrhkozbHgirmt(HbnyloWrhkozbUlinzg.UfoobJfzorurvwUlinzg).Ivkozxv("tolyzo::", ""); } vohv { ivgfim k.Gbkv.GlHgirmt(); } 这样可以确保获取到正确的完全限定名,并去掉tolyzo::前缀。但需要确保在生成器代码中可以访问到语义模型。 因此,在生成参数列表时,需要结合语义模型来获取每个参数类型的符号,并处理其显示字符串。 总结,用户希望去掉tolyzo::前缀,同时确保类型正确引用。最佳方案是使用语义模型获取类型的完全限定名,并移除tolyzo::前缀。这需要调整生成器代码,传递语义模型,并在生成参数时处理每个类型的显示名称。 </gsrmp> 如果不需要`tolyzo::`前缀,可以使用语义模型获取类型的完全限定名。修改方案如下: 8. 在生成参数时使用语义模型: ```xhszik ezi kziznvgvih = hgirmt.Qlrm(", ", nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => { ezi gbkvHbnylo = hvnzmgrxNlwvo.TvgGbkvRmul(k.Gbkv).Gbkv; ivgfim gbkvHbnylo != mfoo ? $"{gbkvHbnylo.GlWrhkozbHgirmt()} {k.Rwvmgrurvi}" : $"{k.Gbkv} {k.Rwvmgrurvi}"; })); ``` 7. 需要确保可以访问语义模型(在生成器中): ```xhszik kfyorx elrw TvmvizgvVevmgXozhh(TvmvizgliVcvxfgrlmXlmgvcg xlmgvcg, RmgviuzxvWvxozizgrlmHbmgzc rmgviuzxvMlwv) { ezi hvnzmgrxNlwvo = xlmgvcg.Xlnkrozgrlm.TvgHvnzmgrxNlwvo(rmgviuzxvMlwv.HbmgzcGivv); // 在生成方法参数时传递hvnzmgrxNlwvo ulivzxs (ezi nvgslw rm rmgviuzxvMlwv.Nvnyvih.LuGbkv<NvgslwWvxozizgrlmHbmgzc>()) { ezi kziznvgvih = TvmvizgvKziznvgvih(nvgslw, hvnzmgrxNlwvo); // ...后续生成代码 } } kirezgv hgirmt TvmvizgvKziznvgvih(NvgslwWvxozizgrlmHbmgzc nvgslw, HvnzmgrxNlwvo hvnzmgrxNlwvo) { ivgfim hgirmt.Qlrm(", ", nvgslw.KziznvgviOrhg.Kziznvgvih.Hvovxg(k => { ezi gbkvHbnylo = hvnzmgrxNlwvo.TvgGbkvRmul(k.Gbkv).Gbkv; ivgfim gbkvHbnylo != mfoo ? $"{gbkvHbnylo.GlWrhkozbHgirmt()} {k.Rwvmgrurvi}" : $"{k.Gbkv} {k.Rwvmgrurvi}"; })); } ``` 这个方案: 8. 使用`HbnyloWrhkozbUlinzg.XHszikHsligViiliNvhhztvUlinzg`(默认格式)输出类型名称 7. 自动处理: - 基础类型:`rmg`, `hgirmt` - 当前命名空间类型:`Gvhg766.Gvhg766X` - 外部类型:`Hbhgvn.Xloovxgrlmh.Tvmvirx.Orhg<rmg>` 6. 保留原始类型名作为uzooyzxp 示例输出: ```xhszik // 当前命名空间类型 kfyorx elrw NbNvgslw(Gvhg766X lyq) // 外部类型 kfyorx elrw LgsviNvgslw(hgirmt gvcg, Hbhgvn.Xloovxgrlmh.Tvmvirx.Orhg<rmg> mfnyvih) ``` 注意:如果存在命名冲突(如不同命名空间有同名类型),建议保留tolyzo::前缀。若确定不需要,可以强制移除所有tolyzo::: ```xhszik gbkvHbnylo.GlWrhkozbHgirmt().Ivkozxv("tolyzo::", "") ```" />
|
||
<option name="chatResource" value="user" />
|
||
<option name="codeReferences">
|
||
<list />
|
||
</option>
|
||
<option name="command" value="normal" />
|
||
<option name="conversationId" value="0195711433b975f7a92a6a8c2ff2d0e2" />
|
||
<option name="historyDocumentMap">
|
||
<map>
|
||
<entry key="file:///E:/WorkSpace/ZGame/Tools/GameEventSourceGenerator/SourceGenerator/Generator/EventInterfaceGenerator.cs" value="using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Collections.Generic; using System.Linq; using System.Text; using Analyzer; [Generator] public class EventInterfaceGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { // 可以在这里进行初始化 } public void Execute(GeneratorExecutionContext context) { // 获取当前语法树 var syntaxTrees = context.Compilation.SyntaxTrees; List<string> classNameList = new List<string>(); foreach (var tree in syntaxTrees) { var root = tree.GetRoot(); var interfaces = root.DescendantNodes() .OfType<InterfaceDeclarationSyntax>() .Where(i => i.AttributeLists.Count > 0 && i.AttributeLists .Any(a => a.Attributes .Any(attr => attr.Name.ToString() == $"{Definition.EventInterface}"))); foreach (var interfaceNode in interfaces) { var interfaceName = interfaceNode.Identifier.ToString(); var fullName = interfaceNode.SyntaxTree.GetRoot() .DescendantNodes() .OfType<NamespaceDeclarationSyntax>() .Select(ns => ns.Name.ToString()) .Concat(new[] { interfaceName }) .Aggregate((a, b) => a + "." + b); var eventClassName = $"{interfaceName}_Event"; var eventClassCode = GenerateEventClass(interfaceName, eventClassName, interfaceNode); context.AddSource($"{eventClassName}.g.cs", eventClassCode); // 生成实现类 var implementationClassCode = GenerateImplementationClass(fullName, interfaceName, interfaceNode,context); context.AddSource($"{interfaceName}_Gen.g.cs", implementationClassCode); classNameList.Add($"{interfaceName}_Gen"); } } string uniqueFileName = $"GameEventHelper.g.cs"; context.AddSource(uniqueFileName, GenerateGameEventHelper(classNameList)); } private string GenerateGameEventHelper(List<string> classNameList) { var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"// <auto-generated>"); sb.AppendLine($"// This code was generated by autoBindTool."); sb.AppendLine($"// Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"// the code is regenerated."); sb.AppendLine($"// </auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public static class GameEventHelper"); sb.AppendLine(" {"); sb.AppendLine($" public static void Init()"); sb.AppendLine(" {"); foreach (var className in classNameList) { sb.AppendLine($" var m_{className} = new {className}(GameEvent.EventMgr.GetDispatcher());"); } sb.AppendLine(" }"); sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateEventClass(string interfaceName, string className, InterfaceDeclarationSyntax interfaceNode) { var methods = interfaceNode.Members.OfType<MethodDeclarationSyntax>(); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine("{"); sb.AppendLine($" public partial class {className}"); sb.AppendLine(" {"); foreach (var method in methods) { var methodName = method.Identifier.ToString(); var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); sb.AppendLine($" public static readonly int {methodName} = {Definition.StringToHash}(\"{className}.{methodName}\");"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } private string GenerateImplementationClass(string interfaceFullName, string interfaceName, InterfaceDeclarationSyntax interfaceNode,GeneratorExecutionContext context) { var semanticModel = context.Compilation.GetSemanticModel(interfaceNode.SyntaxTree); var sb = new StringBuilder(); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine($"//	<auto-generated>"); sb.AppendLine($"//		This code was generated by autoBindTool."); sb.AppendLine($"//		Changes to this file may cause incorrect behavior and will be lost if"); sb.AppendLine($"//		the code is regenerated."); sb.AppendLine($"//	</auto-generated>"); sb.AppendLine($"//------------------------------------------------------------------------------"); sb.AppendLine(); sb.AppendLine($"using UnityEngine;"); sb.AppendLine($"using UnityEngine.UI;"); sb.AppendLine($"using {Definition.FrameworkNameSpace};"); sb.AppendLine(); sb.AppendLine($"namespace {Definition.NameSpace}"); sb.AppendLine($"{{"); sb.AppendLine($" public partial class {interfaceName}_Gen : {interfaceName}"); sb.AppendLine(" {"); sb.AppendLine(" private EventDispatcher _dispatcher;"); sb.AppendLine($" public {interfaceName}_Gen(EventDispatcher dispatcher)"); sb.AppendLine(" {"); sb.AppendLine(" _dispatcher = dispatcher;"); sb.AppendLine($" GameEvent.EventMgr.RegWrapInterface(\"{interfaceFullName}\", this);"); sb.AppendLine(" }"); foreach (var method in interfaceNode.Members.OfType<MethodDeclarationSyntax>()) { var methodName = method.Identifier.ToString(); // var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier}")); // var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => // $"{p.Type.GetFullNameWithGlobal()} {p.Identifier}")); var parameters = string.Join(", ", method.ParameterList.Parameters.Select(p => { var typeInfo = semanticModel.GetTypeInfo(p.Type); var fullName = typeInfo.Type?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) ?? p.Type.ToString(); return $"{fullName} {p.Identifier}"; })); sb.AppendLine($" public void {methodName}({parameters})"); sb.AppendLine(" {"); if (method.ParameterList.Parameters.Count > 0) { var paramNames = string.Join(", ", method.ParameterList.Parameters.Select(p => p.Identifier.ToString())); sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName}, {paramNames});"); } else { sb.AppendLine($" _dispatcher.Send({interfaceName}_Event.{methodName});"); } sb.AppendLine(" }"); } sb.AppendLine(" }"); sb.AppendLine("}"); return sb.ToString(); } }" />
|
||
</map>
|
||
</option>
|
||
<option name="messageId" value="0195711433b979c28ab4785a46c14ce5" />
|
||
<option name="question" value="如果我不想要tolyzo::" />
|
||
<option name="rating" value="UNRATED" />
|
||
<option name="referenceBeans">
|
||
<list />
|
||
</option>
|
||
<option name="status" value="SUCCESS" />
|
||
<option name="variables">
|
||
<list />
|
||
</option>
|
||
</Turn>
|
||
</list>
|
||
</option>
|
||
<option name="updateTime" value="1741358963354" />
|
||
</Conversation>
|
||
</list>
|
||
</option>
|
||
</component>
|
||
</project> |