/// <summary> /// Adds the method reference to the list of methods references /// </summary> /// <param name="expression">the method reference expression</param> private void AddToMethodsReferences(MethodInvocationExpression expression) { var methodDecl = expression.Target.TypeInference.Declaration as MethodDeclaration; if (methodDecl != null && methodDecl.ContainsTag(XenkoTags.ShaderScope)) { if (expression.ContainsTag(XenkoTags.StaticRef) || methodDecl.Qualifiers.Contains(StorageQualifier.Static)) parsingInfo.StaticReferences.InsertMethod(methodDecl, expression); else if (expression.ContainsTag(XenkoTags.ExternRef)) parsingInfo.ExternReferences.InsertMethod(methodDecl, expression); else if (expression.ContainsTag(XenkoTags.StageInitRef)) parsingInfo.StageInitReferences.InsertMethod(methodDecl, expression); else parsingInfo.ClassReferences.InsertMethod(methodDecl, expression); } else { parsingInfo.NavigableNodes.Add(expression); } }
/// <summary> /// Analyse the MethodInvocationExpression, link to the base calls, remove "this" from virtual calls, store in the correct list for later analysis /// </summary> /// <param name="expression">the method expression</param> /// <param name="methodName">the method name</param> /// <param name="declarations">the special declarations</param> protected override void ProcessMethodInvocation(MethodInvocationExpression expression, string methodName, List<IDeclaration> declarations) { bool callBaseProcessMethodInvocation = true; bool isNotBaseCall = true; // check if it is a base/this invocation var memberReferenceExpression = expression.Target as MemberReferenceExpression; if (memberReferenceExpression != null) { var variableReferenceExpression = memberReferenceExpression.Target as VariableReferenceExpression; if (variableReferenceExpression != null) { switch (variableReferenceExpression.Name.Text) { case "base": { parsingInfo.BaseMethodCalls.Add(expression); isNotBaseCall = false; callBaseProcessMethodInvocation = false; // get a base method declaration MethodDeclaration baseMethod = null; foreach (var mixin in analyzedModuleMixin.InheritanceList) { baseMethod = mixin.LocalVirtualTable.Methods.Select(x => x.Method).FirstOrDefault(x => x.IsSameSignature(expression)); if (baseMethod != null) break; } if (baseMethod == null) baseMethod = analyzedModuleMixin.LocalVirtualTable.Methods.Select(x => x.Method).FirstOrDefault(x => x.IsSameSignature(expression)); if (baseMethod != null) { expression.TypeInference.TargetType = baseMethod.ReturnType.ResolveType(); expression.Target.TypeInference.Declaration = baseMethod; } else Error(XenkoMessageCode.ErrorImpossibleBaseCall, memberReferenceExpression.Span, expression, analyzedModuleMixin.MixinName); break; } case "this": { // remove "this" keyword var vre = new VariableReferenceExpression(memberReferenceExpression.Member); expression.Target = vre; callBaseProcessMethodInvocation = false; // get top method declaration var topMethod = analyzedModuleMixin.VirtualTable.Methods.Select(x => x.Method).FirstOrDefault(x => x.IsSameSignature(expression)); if (topMethod != null) { expression.TypeInference.TargetType = topMethod.ReturnType.ResolveType(); expression.Target.TypeInference.Declaration = topMethod; } else Error(XenkoMessageCode.ErrorImpossibleVirtualCall, memberReferenceExpression.Span, expression, analyzedModuleMixin.MixinName, analyzedModuleMixin.MixinName); memberReferenceExpression = null; break; } } } if (expression.Target is MemberReferenceExpression) { var typeCall = (expression.Target as MemberReferenceExpression).Target.TypeInference.TargetType; if (typeCall is ShaderClassType) declarations.AddRange(FindDeclarationsFromObject(typeCall, memberReferenceExpression.Member)); } } // call base if (callBaseProcessMethodInvocation) base.ProcessMethodInvocation(expression, methodName, declarations); var methodDecl = expression.Target.TypeInference.Declaration as MethodDeclaration; var isBuiltIn = true; if (methodDecl != null) { // check if it is a recursive call if (ReferenceEquals(currentVisitedMethod, expression.Target.TypeInference.Declaration)) // How to handle "this" keyword? Error(XenkoMessageCode.ErrorCyclicMethod, currentVisitedMethod.Span, currentVisitedMethod, analyzedModuleMixin.MixinName); // check if it is a build-in method isBuiltIn = !methodDecl.ContainsTag(XenkoTags.ShaderScope); if (memberReferenceExpression != null) { var varDecl = memberReferenceExpression.Target.TypeInference.Declaration as Variable; if (memberReferenceExpression.Target is IndexerExpression) varDecl = (memberReferenceExpression.Target as IndexerExpression).Target.TypeInference.Declaration as Variable; if (varDecl != null && varDecl.Qualifiers.Contains(StorageQualifier.Extern)) { if (IsStageInitMember(memberReferenceExpression)) expression.SetTag(XenkoTags.StageInitRef, null); else expression.SetTag(XenkoTags.ExternRef, null); } var shaderDecl = memberReferenceExpression.Target.TypeInference.Declaration as ShaderClassType; if (shaderDecl != null && shaderDecl != analyzedModuleMixin.Shader && analyzedModuleMixin.InheritanceList.All(x => x.Shader != shaderDecl)) expression.SetTag(XenkoTags.StaticRef, null); } if (!isBuiltIn) { // store if not a base call if (isNotBaseCall && !expression.ContainsTag(XenkoTags.ExternRef) && !expression.ContainsTag(XenkoTags.StageInitRef) && !expression.ContainsTag(XenkoTags.StaticRef)) parsingInfo.ThisMethodCalls.Add(expression); if (methodDecl.Qualifiers.Contains(XenkoStorageQualifier.Stage)) parsingInfo.StageMethodCalls.Add(expression); } } }