internal static void CheckInvocation(IMethodSymbol sym, IMethodSymbol callerSym) { if (!SymbolTable.EnableTranslationCheck) { return; } if (ClassInfo.HasAttribute(sym, "Cs2Dsl.DontCheckAttribute")) { return; } if (null != callerSym && ClassInfo.HasAttribute(callerSym, "Cs2Dsl.DontCheckAttribute")) { return; } if (null != callerSym && ClassInfo.HasAttribute(callerSym.ContainingType, "Cs2Dsl.DontCheckAttribute")) { return; } if (!SymbolTable.Instance.IsCs2DslSymbol(sym)) { var ckey = ClassInfo.GetFullName(sym.ContainingType); var id = string.Format("{0}.{1}", ckey, sym.Name); if (!SymbolTable.Instance.CheckedInvocations.Contains(id)) { SymbolTable.Instance.CheckedInvocations.Add(id); bool isOverload = false; ClassSymbolInfo info; if (SymbolTable.Instance.ClassSymbols.TryGetValue(ckey, out info)) { info.SymbolOverloadFlags.TryGetValue(sym.Name, out isOverload); } string callerInfo = string.Empty; if (null != callerSym) { var callerClass = ClassInfo.GetFullName(callerSym.ContainingType); var callerMethod = SymbolTable.Instance.NameMangling(callerSym); callerInfo = string.Format(" caller:{0}.{1}", callerClass, callerMethod); } if (sym.IsExtensionMethod && !SymbolTable.Instance.IsLegalExtension(sym.ContainingType)) { //不支持的语法 Logger.Instance.Log("Translation Error", "unsupported extern extension method {0}.{1} !{2}", ckey, sym.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } else { if (SymbolTable.Instance.IsIllegalMethod(sym)) { Logger.Instance.Log("Translation Error", "unsupported extern method {0}.{1} !{2}", ckey, sym.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } if (sym.ContainingType.TypeKind == TypeKind.Delegate || sym.ContainingType.IsGenericType && SymbolTable.Instance.IsLegalGenericType(sym.ContainingType, true) || sym.IsGenericMethod && SymbolTable.Instance.IsLegalGenericMethod(sym)) { //如果是标记为合法的泛型类或委托类型的成员,则不用再进行类型检查 } else { foreach (var param in sym.Parameters) { var type = param.Type as INamedTypeSymbol; if (param.IsParams && isOverload) { Logger.Instance.Log("Translation Warning", "extern overloaded method {0}.{1} parameter {2} is params, please check export api code !{3}", ckey, sym.Name, param.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); continue; } if (null != type && type.TypeKind != TypeKind.Delegate) { if (type.IsGenericType) { if (!SymbolTable.Instance.IsLegalParameterGenericType(type)) { Logger.Instance.Log("Translation Error", "extern method {0}.{1} parameter {2} is generic type, please replace with non generic type !{3}", ckey, sym.Name, param.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } else { if (SymbolTable.Instance.IsIllegalType(type)) { Logger.Instance.Log("Translation Error", "extern method {0}.{1} parameter {2} is unsupported type, please replace with non generic type !{3}", ckey, sym.Name, param.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } } } if (!sym.ReturnsVoid) { var type = sym.ReturnType as INamedTypeSymbol; if (null != type && type.TypeKind != TypeKind.Delegate) { if (type.IsGenericType) { if (!SymbolTable.Instance.IsLegalParameterGenericType(type)) { Logger.Instance.Log("Translation Error", "extern method {0}.{1} return {2} is generic type, please replace with non generic type !{3}", ckey, sym.Name, type.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } else { if (SymbolTable.Instance.IsIllegalType(type)) { Logger.Instance.Log("Translation Error", "extern method {0}.{1} return {2} is unsupported type, please replace with non generic type !{3}", ckey, sym.Name, type.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } } } } } } }
internal void Init(IMethodSymbol sym, SyntaxNode node) { IsAnonymousOrLambdaMethod = node is SimpleLambdaExpressionSyntax || node is ParenthesizedLambdaExpressionSyntax || node is AnonymousMethodExpressionSyntax; TryCatchUsingOrLoopSwitchStack.Clear(); TempReturnAnalysisStack.Clear(); ParamNames.Clear(); ReturnParamNames.Clear(); OriginalParamsName = string.Empty; ExistYield = false; ExistTopLevelReturn = false; ExistTry = false; TryUsingLayer = 0; ReturnVarName = string.Empty; SemanticInfo = sym; SyntaxNode = node; if (!sym.IsExtensionMethod && sym.IsGenericMethod) { //不是扩展方法,泛型参数放在参数表最前面 foreach (var param in sym.TypeParameters) { ParamNames.Add(param.Name); if (param.ConstraintTypes.Length > 0) { ParamTypes.Add(ClassInfo.GetFullName(param.ConstraintTypes[0])); } else if (param.HasReferenceTypeConstraint) { ParamTypes.Add("System.Object"); } else if (param.HasValueTypeConstraint) { ParamTypes.Add("System.ValueType"); } else { ParamTypes.Add("null"); } ParamTypeKinds.Add("TypeKind." + param.TypeKind.ToString()); ParamRefOrOuts.Add(0); ParamIsExterns.Add(false); } } bool first = true; foreach (var param in sym.Parameters) { if (param.IsParams) { var arrTypeSym = param.Type as IArrayTypeSymbol; if (null != arrTypeSym) { string elementType = ClassInfo.GetFullName(arrTypeSym.ElementType); string elementTypeKind = "TypeKind." + arrTypeSym.ElementType.TypeKind.ToString(); ParamsElementInfo = string.Format("{0}, {1}", elementType, elementTypeKind); } ParamNames.Add("..."); ParamTypes.Add(ClassInfo.GetFullName(param.Type)); ParamTypeKinds.Add("TypeKind." + param.Type.TypeKind.ToString()); ParamRefOrOuts.Add(0); ParamIsExterns.Add(!SymbolTable.Instance.IsCs2DslSymbol(param.Type)); OriginalParamsName = param.Name; //遇到变参直接结束(变参set_Item会出现后面带一个value参数的情形,在函数实现里处理) break; } else if (param.RefKind == RefKind.Ref) { //ref参数与out参数在形参处理时机制相同,实参时out参数传入__cs2dsl_out(适应脚本引擎与dotnet反射的调用规则) var fn = ClassInfo.GetFullName(param.Type); ParamNames.Add(param.Name); ParamTypes.Add(fn); ParamTypeKinds.Add("TypeKind." + param.Type.TypeKind.ToString()); ParamRefOrOuts.Add(1); ParamIsExterns.Add(!SymbolTable.Instance.IsCs2DslSymbol(param.Type)); ReturnParamNames.Add(param.Name); ReturnParamTypes.Add(fn); ReturnParamTypeKinds.Add("TypeKind." + param.Type.TypeKind.ToString()); ReturnParamRefOrOuts.Add(1); ReturnParamIsExterns.Add(!SymbolTable.Instance.IsCs2DslSymbol(param.Type)); } else if (param.RefKind == RefKind.Out) { if (param.Type.IsValueType && !SymbolTable.IsBasicType(param.Type) && !CsDslTranslater.IsImplementationOfSys(param.Type, "IEnumerator")) { string ns = ClassInfo.GetNamespaces(param.Type); if (SymbolTable.Instance.IsCs2DslSymbol(param.Type)) { OutValueParams.Add(ParamNames.Count); NeedFuncInfo = true; } else if (ns != "System") { OutExternValueParams.Add(ParamNames.Count); NeedFuncInfo = true; } } //ref参数与out参数在形参处理时机制相同,实参时out参数传入__cs2dsl_out(适应脚本引擎与dotnet反射的调用规则) var fn = ClassInfo.GetFullName(param.Type); ParamNames.Add(param.Name); ParamTypes.Add(fn); ParamTypeKinds.Add("TypeKind." + param.Type.TypeKind.ToString()); ParamRefOrOuts.Add(2); ParamIsExterns.Add(!SymbolTable.Instance.IsCs2DslSymbol(param.Type)); ReturnParamNames.Add(param.Name); ReturnParamTypes.Add(fn); ReturnParamTypeKinds.Add("TypeKind." + param.Type.TypeKind.ToString()); ReturnParamRefOrOuts.Add(2); ReturnParamIsExterns.Add(!SymbolTable.Instance.IsCs2DslSymbol(param.Type)); } else { ParamNames.Add(param.Name); ParamTypes.Add(ClassInfo.GetFullName(param.Type)); ParamTypeKinds.Add("TypeKind." + param.Type.TypeKind.ToString()); ParamRefOrOuts.Add(0); ParamIsExterns.Add(!SymbolTable.Instance.IsCs2DslSymbol(param.Type)); } if (first && sym.IsExtensionMethod && sym.IsGenericMethod) { //扩展方法的泛型参数放在第一个参数后 foreach (var tp in sym.TypeParameters) { ParamNames.Add(tp.Name); if (tp.ConstraintTypes.Length > 0) { ParamTypes.Add(ClassInfo.GetFullName(tp.ConstraintTypes[0])); } else if (tp.HasReferenceTypeConstraint) { ParamTypes.Add("System.Object"); } else if (tp.HasValueTypeConstraint) { ParamTypes.Add("System.ValueType"); } else { ParamTypes.Add("null"); } ParamTypeKinds.Add("TypeKind." + tp.TypeKind.ToString()); ParamRefOrOuts.Add(0); ParamIsExterns.Add(!SymbolTable.Instance.IsCs2DslSymbol(param.Type)); } } first = false; } if (!sym.ReturnsVoid) { string returnType = ClassInfo.GetFullName(sym.ReturnType); if (returnType.StartsWith("System.Collections") && (sym.ReturnType.Name == "IEnumerable" || sym.ReturnType.Name == "IEnumerator")) { var analysis = new YieldAnalysis(); analysis.Visit(node); ExistYield = analysis.YieldCount > 0; } } ReturnValueCount = ReturnParamNames.Count + (sym.ReturnsVoid ? 0 : 1); if (!NeedFuncInfo && ClassInfo.HasAttribute(sym, "Cs2Dsl.NeedFuncInfoAttribute")) { NeedFuncInfo = true; } }
internal void Init(IMethodSymbol sym, SemanticModel model) { MethodSymbol = sym; Model = model; Args.Clear(); DslToObjectArgs.Clear(); ArgConversions.Clear(); DefaultValueArgs.Clear(); DslToObjectDefArgs.Clear(); ReturnArgs.Clear(); ReturnValueArgFlags.Clear(); ReturnArgOperations.Clear(); ReturnArgSymbols.Clear(); GenericTypeArgs.Clear(); ClassKey = ClassInfo.GetFullName(sym.ContainingType); GenericClassKey = ClassInfo.GetFullNameWithTypeParameters(sym.ContainingType); IsEnumClass = sym.ContainingType.TypeKind == TypeKind.Enum || ClassKey == "System.Enum"; IsExtensionMethod = sym.IsExtensionMethod; IsBasicValueMethod = SymbolTable.IsBasicValueMethod(sym); IsArrayStaticMethod = ClassKey == "System.Array" && sym.IsStatic; IsExternMethod = !SymbolTable.Instance.IsCs2DslSymbol(sym); if ((ClassKey == "UnityEngine.GameObject" || ClassKey == "UnityEngine.Component") && (sym.Name.StartsWith("GetComponent") || sym.Name.StartsWith("AddComponent"))) { IsComponentGetOrAdd = true; } NonGenericMethodSymbol = null; PostPositionGenericTypeArgs = false; ExternOverloadedMethodSignature = string.Empty; if (IsExternMethod) { var syms = sym.ContainingType.GetMembers(sym.Name); if (sym.IsGenericMethod) { bool existNonGenericVersion = false; if (null != syms) { //寻找匹配的非泛型版本 foreach (var isym in syms) { var msym = isym as IMethodSymbol; if (null != msym && !msym.IsGenericMethod && msym.Parameters.Length == sym.Parameters.Length + sym.TypeParameters.Length) { existNonGenericVersion = true; for (int i = 0; i < sym.TypeParameters.Length; ++i) { var psym = msym.Parameters[i]; if (psym.Type.Name != "Type") { existNonGenericVersion = false; break; } } for (int i = 0; i < sym.Parameters.Length; ++i) { var psym1 = msym.Parameters[i + sym.TypeParameters.Length]; var psym2 = sym.Parameters[i]; if (psym1.Type.Name != psym2.Type.Name && psym2.OriginalDefinition.Type.TypeKind != TypeKind.TypeParameter) { existNonGenericVersion = false; break; } } if (existNonGenericVersion) { NonGenericMethodSymbol = msym; PostPositionGenericTypeArgs = false; } else { existNonGenericVersion = true; for (int i = 0; i < sym.Parameters.Length; ++i) { var psym1 = msym.Parameters[i]; var psym2 = sym.Parameters[i]; if (psym1.Type.Name != psym2.Type.Name && psym2.OriginalDefinition.Type.TypeKind != TypeKind.TypeParameter) { existNonGenericVersion = false; break; } } for (int i = 0; i < sym.TypeParameters.Length; ++i) { var psym = msym.Parameters[i + sym.Parameters.Length]; if (psym.Type.Name != "Type") { existNonGenericVersion = false; break; } } if (existNonGenericVersion) { NonGenericMethodSymbol = msym; PostPositionGenericTypeArgs = true; } } if (existNonGenericVersion) { break; } } } if (!existNonGenericVersion) { //寻找匹配的变参版本 foreach (var isym in syms) { var msym = isym as IMethodSymbol; if (null != msym && !msym.IsGenericMethod && msym.Parameters.Length > 0 && msym.Parameters.Length <= sym.Parameters.Length) { bool existParamsVersion = true; var lastPsym = msym.Parameters[msym.Parameters.Length - 1]; if (lastPsym.IsParams) { for (int i = 0; i < msym.Parameters.Length; ++i) { var psym1 = msym.Parameters[i]; var psym2 = sym.Parameters[i]; if (i < msym.Parameters.Length - 1 && psym1.Type.Name != psym2.Type.Name) { existParamsVersion = false; break; } } } if (existParamsVersion) { NonGenericMethodSymbol = msym; break; } } } } } if (existNonGenericVersion) { foreach (var arg in sym.TypeArguments) { GenericTypeArgs.Add(arg); } } else { //没有找到参数匹配的非泛型版本,则不传递泛型参数类型 //这样处理可以适应2类可能有效的情形: //1、如果有多个重载函数,其中有一个object类型变参,则其他泛型参数版本会适配到这个非泛型变参版本 //2、有一些方法不需要明确传递泛型参数类型(比如普通实参可推导出泛型参数类型并且泛型参数类型在函数中不明确使用) } } if (null != syms) { int mcount = 0; if (sym.MethodKind == MethodKind.Constructor && sym.ContainingType.IsValueType) { //值类型构造总是按重载处理,默认构造总是会生成 mcount = 2; } else { foreach (var isym in syms) { var msym = isym as IMethodSymbol; if (msym.Parameters.Length == 0) { if (msym.Name == "GetType") { continue; } if (msym.Name == "GetHashCode") { continue; } } var fn = ClassInfo.GetFullName(msym.ContainingType); if (null != msym && msym.IsStatic == sym.IsStatic && msym.DeclaredAccessibility == Accessibility.Public && !msym.IsImplicitlyDeclared && !msym.IsGenericMethod && !ClassInfo.HasAttribute(msym, "System.ObsoleteAttribute")) { bool existPointer = false; foreach (var partype in msym.Parameters) { if (partype.Type.TypeKind == TypeKind.Pointer) { existPointer = true; break; } } if (!existPointer) { ++mcount; } } } } if (mcount > 1) { ExternOverloadedMethodSignature = SymbolTable.CalcExternOverloadedMethodSignature(sym, NonGenericMethodSymbol); } } SymbolTable.Instance.TryAddExternReference(sym); if (!sym.ReturnsVoid) { SymbolTable.Instance.TryAddExternReference(sym.ReturnType); } foreach (var p in sym.Parameters) { if (p.Kind != SymbolKind.TypeParameter) { SymbolTable.Instance.TryAddExternReference(p.Type); } } } else if (sym.IsGenericMethod) { foreach (var arg in sym.TypeArguments) { GenericTypeArgs.Add(arg); } } if (sym.IsGenericMethod) { foreach (var t in sym.TypeArguments) { if (t.TypeKind != TypeKind.TypeParameter) { SymbolTable.Instance.TryAddExternReference(t); } } } }
internal static void CheckInvocation(SemanticModel model, IMethodSymbol sym, IList <ExpressionSyntax> args, IList <ArgDefaultValueInfo> nameOrDefValArgs, IList <IConversionOperation> argConversions, SyntaxNode node, IMethodSymbol callerSym) { if (!SymbolTable.EnableTranslationCheck) { return; } if (ClassInfo.HasAttribute(sym, "Cs2Dsl.DontCheckAttribute")) { return; } if (null != callerSym && ClassInfo.HasAttribute(callerSym, "Cs2Dsl.DontCheckAttribute")) { return; } if (null != callerSym && ClassInfo.HasAttribute(callerSym.ContainingType, "Cs2Dsl.DontCheckAttribute")) { return; } if (!SymbolTable.Instance.IsCs2DslSymbol(sym)) { var ckey = ClassInfo.GetFullName(sym.ContainingType); var oper = null != node?model.GetOperationEx(node) as IInvocationOperation : null; var realType = null != oper && null != oper.Instance ? oper.Instance.Type : null; bool isOverload = false; ClassSymbolInfo info; if (SymbolTable.Instance.ClassSymbols.TryGetValue(ckey, out info)) { info.SymbolOverloadFlags.TryGetValue(sym.Name, out isOverload); } string callerInfo = string.Empty; if (null != callerSym) { var callerClass = ClassInfo.GetFullName(callerSym.ContainingType); var callerMethod = SymbolTable.Instance.NameCs2DslMangling(callerSym); callerInfo = string.Format(" caller:{0}.{1}", callerClass, callerMethod); } if (sym.IsExtensionMethod && !SymbolTable.Instance.IsLegalExtension(sym.ContainingType)) { //不支持的语法 Logger.Instance.Log(node, "unsupported extern extension method {0}.{1} !{2}", ckey, sym.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } else { if (SymbolTable.Instance.IsIllegalMethod(sym)) { Logger.Instance.Log(node, "unsupported extern method {0}.{1} !{2}", ckey, sym.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } if (sym.ContainingType.TypeKind == TypeKind.Delegate || (null == realType || realType == sym.ContainingType) && sym.ContainingType.IsGenericType && SymbolTable.Instance.IsLegalGenericType(sym.ContainingType, true) || sym.IsGenericMethod && SymbolTable.Instance.IsLegalGenericMethod(sym)) { //如果是标记为合法的泛型类或委托类型的成员,则不用再进行类型检查 } else { int ix = 0; foreach (var param in sym.Parameters) { ITypeSymbol _argType = null; if (ix < args.Count) { _argType = null != args[ix] ? model.GetTypeInfoEx(args[ix]).Type : null; } else if (ix < args.Count + nameOrDefValArgs.Count) { _argType = nameOrDefValArgs[ix - args.Count].Type; } IConversionOperation argConv = null; if (ix < argConversions.Count) { argConv = argConversions[ix]; } ++ix; INamedTypeSymbol argType = null; if (null != _argType && (null == argConv || null == argConv.OperatorMethod)) { argType = _argType as INamedTypeSymbol; } var paramType = param.Type as INamedTypeSymbol; if (param.IsParams && isOverload) { Logger.Instance.Log(node, "extern overloaded method {0}.{1} parameter {2} is params, please check export api code !{3}", ckey, sym.Name, param.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); continue; } if (null != paramType && paramType.TypeKind != TypeKind.Delegate) { bool isContainerIntf = paramType.Name == "IEnumerable" || paramType.Name == "ICollection" || paramType.Name == "IDictionary" || paramType.Name == "IList"; if (null != realType && SymbolTable.Instance.IsCs2DslSymbol(realType) && isContainerIntf && null != argType && (argType.IsGenericType || SymbolTable.Instance.IsCs2DslSymbol(argType))) { Logger.Instance.Log(node, "extern method {0}.{1} parameter {2} can't assign a script object to it !{3}", ckey, sym.Name, param.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } else if (paramType.IsGenericType) { if (!SymbolTable.Instance.IsLegalParameterGenericType(paramType)) { Logger.Instance.Log(node, "extern method {0}.{1} parameter {2} is generic type, please replace with non generic type !{3}", ckey, sym.Name, param.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } else { if (SymbolTable.Instance.IsIllegalType(paramType)) { Logger.Instance.Log(node, "extern method {0}.{1} parameter {2} is unsupported type, please replace with non generic type !{3}", ckey, sym.Name, param.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } } } if (!sym.ReturnsVoid) { var type = sym.ReturnType as INamedTypeSymbol; if (null != type && type.TypeKind != TypeKind.Delegate) { if (type.IsGenericType) { if (!SymbolTable.Instance.IsLegalParameterGenericType(type)) { Logger.Instance.Log(node, "extern method {0}.{1} return {2} is generic type, please replace with non generic type !{3}", ckey, sym.Name, type.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } else { if (SymbolTable.Instance.IsIllegalType(type)) { Logger.Instance.Log(node, "extern method {0}.{1} return {2} is unsupported type, please replace with non generic type !{3}", ckey, sym.Name, type.Name, string.IsNullOrEmpty(callerInfo) ? string.Empty : callerInfo); } } } } } } }
private static string CalcFullName(ISymbol type, bool includeSelfName) { if (null == type) { return(string.Empty); } List <string> list = new List <string>(); if (includeSelfName) { //如果一个类标记为忽略,如果它是泛型类,则创建对象的名字使用泛型参数构建而不是实际类型参数构建 //这种类因为需要在脚本里手动实现,假定都是可以一个类实现泛型类的功能的。 //注意:由于这里是计算类型名称,使用命令行参数标记的忽略是没有效果(它使用名称来标记),此时仍然需要使用属性标记忽略的泛型类 bool ignore = ClassInfo.HasAttribute(type, "Cs2Dsl.IgnoreAttribute"); if (ignore) { list.Add(CalcNameWithTypeParameters(type)); } else { list.Add(CalcNameWithTypeArguments(type)); } } INamespaceSymbol ns = type.ContainingNamespace; var ct = type.ContainingType; string name = string.Empty; if (null != ct) { bool ignore = ClassInfo.HasAttribute(ct, "Cs2Dsl.IgnoreAttribute"); if (ignore) { name = CalcNameWithTypeParameters(ct); } else { name = CalcNameWithTypeArguments(ct); } } while (null != ct && name.Length > 0) { list.Insert(0, name); ns = ct.ContainingNamespace; ct = ct.ContainingType; if (null != ct) { bool ignore = ClassInfo.HasAttribute(ct, "Cs2Dsl.IgnoreAttribute"); if (ignore) { name = CalcNameWithTypeParameters(ct); } else { name = CalcNameWithTypeArguments(ct); } } else { name = string.Empty; } } while (null != ns && ns.Name.Length > 0) { list.Insert(0, ns.Name); ns = ns.ContainingNamespace; } return(string.Join(".", list.ToArray())); }