/// <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);
                }
            }
        }