예제 #1
0
        public static bool IsConditionallyRemoved(InvocationExpression invocationExpression, IEntity entity)
 		{
            if (entity == null)
            {
                return false;
            }
 			var result = new List<string>();
 			foreach (var a in entity.Attributes)
 			{
 				var type = a.AttributeType.GetDefinition();
 				if (type != null && type.FullName.Equals("System.Diagnostics.ConditionalAttribute", StringComparison.Ordinal))
                {
 					if (a.PositionalArguments.Count > 0)
                    {
 						var symbol = a.PositionalArguments[0].ConstantValue as string;
                        if (symbol != null)
                        {
                            result.Add(symbol);
                        }
 					}
 				}
 			}

            if (result.Count > 0)
            {
                var syntaxTree = invocationExpression.GetParent<SyntaxTree>();
                if (syntaxTree != null)
                {
                    return !result.Intersect(syntaxTree.ConditionalSymbols).Any();    
                }
            }

 			return false;
 		}
예제 #2
0
        public static bool IsConditionallyRemoved(InvocationExpression invocationExpression, IEntity entity)
        {
            if (entity == null)
            {
                return(false);
            }
            var result = new List <string>();

            foreach (var a in entity.Attributes)
            {
                var type = a.AttributeType.GetDefinition();
                if (type != null && type.FullName.Equals("System.Diagnostics.ConditionalAttribute", StringComparison.Ordinal))
                {
                    if (a.PositionalArguments.Count > 0)
                    {
                        var symbol = a.PositionalArguments[0].ConstantValue as string;
                        if (symbol != null)
                        {
                            result.Add(symbol);
                        }
                    }
                }
            }

            if (result.Count > 0)
            {
                var syntaxTree = invocationExpression.GetParent <SyntaxTree>();
                if (syntaxTree != null)
                {
                    return(!result.Intersect(syntaxTree.ConditionalSymbols).Any());
                }
            }

            return(false);
        }
예제 #3
0
        public override AstNode VisitInvocationExpression(InvocationExpression invocationExpression)
        {
            try
            {
                var rr = this.Resolver.ResolveNode(invocationExpression, null) as CSharpInvocationResolveResult;

                if (rr != null && rr.IsError)
                {
                    InvocationExpression clonInvocationExpression = (InvocationExpression)base.VisitInvocationExpression(invocationExpression);
                    if (clonInvocationExpression == null)
                    {
                        clonInvocationExpression = (InvocationExpression)invocationExpression.Clone();
                    }

                    var map    = rr.GetArgumentToParameterMap();
                    var orig   = clonInvocationExpression.Arguments.ToArray();
                    var result = clonInvocationExpression.Arguments.ToArray();

                    if (rr.IsExtensionMethodInvocation)
                    {
                        for (int i = 1; i < map.Count; i++)
                        {
                            if (map[i] < 0)
                            {
                                continue;
                            }

                            result[i - 1] = orig[map[i] - 1];
                        }
                    }
                    else
                    {
                        for (int i = 0; i < map.Count; i++)
                        {
                            if (map[i] < 0)
                            {
                                continue;
                            }

                            result[i] = orig[map[i]];
                        }
                    }

                    clonInvocationExpression.Arguments.ReplaceWith(result);
                    return(clonInvocationExpression);
                }
            }
            catch (Exception e)
            {
                var fileName = invocationExpression.GetParent <SyntaxTree>()?.FileName;

                this.log.Warn(string.Format("VisitInvocationExpression fails in {0} ({1}): {2}", fileName, invocationExpression.StartLocation.ToString(), e.Message));
            }

            return(base.VisitInvocationExpression(invocationExpression));
        }
        public override void VisitInvocationExpression(InvocationExpression invocationExpression)
        {
            var match = this.m_Pattern.Match(invocationExpression);

            if (match.Success)
            {
                var method = (invocationExpression.Target as MemberReferenceExpression).MemberName;
                if (method == "Write" || method == "WriteLine")
                {
                    // FIXME: Couldn't get a pattern matcher to work on the MethodDeclaration.
                    var declMethod = invocationExpression.GetParent <MethodDeclaration>();
                    if (declMethod == null)
                    {
                        base.VisitInvocationExpression(invocationExpression);
                        return;
                    }
                    var allowed = (
                        declMethod.Name == "Main" &&
                        declMethod.Modifiers == (Modifiers.Public | Modifiers.Static) &&
                        declMethod.ReturnType.ToString() == "void" &&
                        declMethod.Parameters.Count == 1 &&
                        declMethod.Parameters.ToList()[0].Type.ToString() == "string[]");
                    if (!allowed)
                    {
                        this.Results.Issues.Add(new LintIssue(invocationExpression)
                        {
                            Index      = LintIssueIndex.ConsoleWriteUsedOutsideOfProgramMain,
                            Parameters = new[]
                            {
                                declMethod.GetParent <TypeDeclaration>().Name + "." + declMethod.Name
                            }
                        });
                    }
                }
            }

            base.VisitInvocationExpression(invocationExpression);
        }
        public override void VisitInvocationExpression(InvocationExpression invocationExpression)
        {
            var match = this.m_Pattern.Match(invocationExpression);
            if (match.Success)
            {
                var method = (invocationExpression.Target as MemberReferenceExpression).MemberName;
                if (method == "Write" || method == "WriteLine")
                {
                    // FIXME: Couldn't get a pattern matcher to work on the MethodDeclaration.
                    var declMethod = invocationExpression.GetParent<MethodDeclaration>();
                    if (declMethod == null)
                    {
                        base.VisitInvocationExpression(invocationExpression);
                        return;
                    }
                    var allowed = (
                        declMethod.Name == "Main" &&
                        declMethod.Modifiers == (Modifiers.Public | Modifiers.Static) &&
                        declMethod.ReturnType.ToString() == "void" &&
                        declMethod.Parameters.Count == 1 &&
                        declMethod.Parameters.ToList()[0].Type.ToString() == "string[]");
                    if (!allowed)
                    {
                        this.Results.Issues.Add(new LintIssue(invocationExpression)
                        {
                            Index = LintIssueIndex.ConsoleWriteUsedOutsideOfProgramMain,
                            Parameters = new[]
                            {
                                declMethod.GetParent<TypeDeclaration>().Name + "." + declMethod.Name
                            }
                        });
                    }
                }
            }

            base.VisitInvocationExpression(invocationExpression);
        }
예제 #6
0
        protected void VisitInvocationExpression()
        {
            InvocationExpression invocationExpression = this.InvocationExpression;

            if (this.Emitter.IsForbiddenInvocation(invocationExpression))
            {
                throw new EmitterException(invocationExpression, "This method cannot be invoked directly");
            }

            var oldValue = this.Emitter.ReplaceAwaiterByVar;
            var oldAsyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

            if (this.Emitter.IsAsync && !this.Emitter.AsyncExpressionHandling)
            {
                this.WriteAwaiters(invocationExpression);
                this.Emitter.ReplaceAwaiterByVar     = true;
                this.Emitter.AsyncExpressionHandling = true;
            }

            Tuple <bool, bool, string> inlineInfo = this.Emitter.GetInlineCode(invocationExpression);
            var argsInfo = new ArgumentsInfo(this.Emitter, invocationExpression);

            var argsExpressions = argsInfo.ArgumentsExpressions;
            var paramsArg       = argsInfo.ParamsExpression;
            var argsCount       = argsExpressions.Count();

            if (inlineInfo != null)
            {
                bool   isStaticMethod = inlineInfo.Item1;
                bool   isInlineMethod = inlineInfo.Item2;
                string inlineScript   = inlineInfo.Item3;

                if (isInlineMethod)
                {
                    if (invocationExpression.Arguments.Count == 1)
                    {
                        var code             = invocationExpression.Arguments.First();
                        var inlineExpression = code as PrimitiveExpression;

                        if (inlineExpression == null)
                        {
                            throw new EmitterException(invocationExpression, "Only primitive expression can be inlined");
                        }

                        string value = inlineExpression.Value.ToString().Trim();

                        if (value.Length > 0)
                        {
                            this.Write(inlineExpression.Value);

                            if (value[value.Length - 1] == ';')
                            {
                                this.Emitter.EnableSemicolon = false;
                                this.WriteNewLine();
                            }
                        }
                        else
                        {
                            // Empty string, emit nothing.
                            this.Emitter.EnableSemicolon = false;
                        }

                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                        return;
                    }
                }
                else
                {
                    MemberReferenceExpression targetMemberRef = invocationExpression.Target as MemberReferenceExpression;
                    bool isBase = targetMemberRef != null && targetMemberRef.Target is BaseReferenceExpression;

                    if (!String.IsNullOrEmpty(inlineScript) && (isBase || invocationExpression.Target is IdentifierExpression))
                    {
                        argsInfo.ThisArgument = "this";
                        bool noThis = !inlineScript.Contains("{this}");

                        if (!isStaticMethod && noThis)
                        {
                            this.WriteThis();
                            this.WriteDot();
                        }

                        new InlineArgumentsBlock(this.Emitter, argsInfo, inlineScript).Emit();
                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                        return;
                    }
                }
            }

            MemberReferenceExpression targetMember = invocationExpression.Target as MemberReferenceExpression;

            ResolveResult targetMemberResolveResult = null;

            if (targetMember != null)
            {
                targetMemberResolveResult = this.Emitter.Resolver.ResolveNode(targetMember.Target, this.Emitter);
            }

            if (targetMember != null)
            {
                var member = this.Emitter.Resolver.ResolveNode(targetMember.Target, this.Emitter);

                //var targetResolve = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter);
                var targetResolve = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter);

                if (targetResolve != null)
                {
                    var csharpInvocation = targetResolve as CSharpInvocationResolveResult;

                    InvocationResolveResult invocationResult;
                    bool isExtensionMethodInvocation = false;
                    if (csharpInvocation != null)
                    {
                        if (member != null && member.Type.Kind == TypeKind.Delegate && !csharpInvocation.IsExtensionMethodInvocation)
                        {
                            throw new EmitterException(invocationExpression, "Delegate's methods are not supported. Please use direct delegate invoke.");
                        }

                        if (csharpInvocation.IsExtensionMethodInvocation)
                        {
                            invocationResult            = csharpInvocation;
                            isExtensionMethodInvocation = true;
                            var resolvedMethod = invocationResult.Member as IMethod;
                            if (resolvedMethod != null && resolvedMethod.IsExtensionMethod)
                            {
                                string inline   = this.Emitter.GetInline(resolvedMethod);
                                bool   isNative = this.IsNativeMethod(resolvedMethod);

                                if (string.IsNullOrWhiteSpace(inline) && isNative)
                                {
                                    invocationResult = null;
                                }
                            }
                        }
                        else
                        {
                            invocationResult = null;
                        }

                        if (this.IsEmptyPartialInvoking(csharpInvocation.Member as IMethod))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }
                    else
                    {
                        invocationResult = targetResolve as InvocationResolveResult;

                        if (invocationResult != null && this.IsEmptyPartialInvoking(invocationResult.Member as IMethod))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }

                    if (invocationResult == null)
                    {
                        invocationResult = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter) as InvocationResolveResult;
                    }

                    if (invocationResult != null)
                    {
                        var resolvedMethod = invocationResult.Member as IMethod;

                        if (resolvedMethod != null && resolvedMethod.IsExtensionMethod)
                        {
                            string inline   = this.Emitter.GetInline(resolvedMethod);
                            bool   isNative = this.IsNativeMethod(resolvedMethod);

                            if (isExtensionMethodInvocation)
                            {
                                if (!string.IsNullOrWhiteSpace(inline))
                                {
                                    this.Write("");
                                    StringBuilder savedBuilder = this.Emitter.Output;
                                    this.Emitter.Output = new StringBuilder();
                                    this.WriteThisExtension(invocationExpression.Target);
                                    argsInfo.ThisArgument = this.Emitter.Output.ToString();
                                    this.Emitter.Output   = savedBuilder;
                                    new InlineArgumentsBlock(this.Emitter, argsInfo, inline).Emit();
                                }
                                else if (!isNative)
                                {
                                    var    overloads     = OverloadsCollection.Create(this.Emitter, resolvedMethod);
                                    string name          = BridgeTypes.ToJsName(resolvedMethod.DeclaringType, this.Emitter) + "." + overloads.GetOverloadName();
                                    var    isIgnoreClass = resolvedMethod.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(resolvedMethod.DeclaringTypeDefinition);

                                    this.Write(name);

                                    if (!isIgnoreClass && argsInfo.HasTypeArguments)
                                    {
                                        this.WriteOpenParentheses();
                                        new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                                        this.WriteCloseParentheses();
                                    }

                                    this.WriteOpenParentheses();

                                    this.WriteThisExtension(invocationExpression.Target);

                                    if (argsCount > 0)
                                    {
                                        this.WriteComma();
                                    }

                                    new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg, invocationExpression).Emit();

                                    this.WriteCloseParentheses();
                                }

                                if (!string.IsNullOrWhiteSpace(inline) || !isNative)
                                {
                                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                                    return;
                                }
                            }
                            else if (isNative)
                            {
                                if (!string.IsNullOrWhiteSpace(inline))
                                {
                                    this.Write("");
                                    StringBuilder savedBuilder = this.Emitter.Output;
                                    this.Emitter.Output = new StringBuilder();
                                    this.WriteThisExtension(invocationExpression.Target);
                                    argsInfo.ThisArgument = this.Emitter.Output.ToString();
                                    this.Emitter.Output   = savedBuilder;
                                    new InlineArgumentsBlock(this.Emitter, argsInfo, inline).Emit();
                                }
                                else
                                {
                                    argsExpressions.First().AcceptVisitor(this.Emitter);
                                    this.WriteDot();
                                    string name = this.Emitter.GetEntityName(resolvedMethod);
                                    this.Write(name);
                                    this.WriteOpenParentheses();
                                    new ExpressionListBlock(this.Emitter, argsExpressions.Skip(1), paramsArg, invocationExpression).Emit();
                                    this.WriteCloseParentheses();
                                }

                                this.Emitter.ReplaceAwaiterByVar     = oldValue;
                                this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                                return;
                            }
                        }
                    }
                }
            }

            var proto = false;

            if (targetMember != null && targetMember.Target is BaseReferenceExpression)
            {
                var rr = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter) as MemberResolveResult;

                if (rr != null)
                {
                    proto = rr.IsVirtualCall;

                    /*var method = rr.Member as IMethod;
                     * if (method != null && method.IsVirtual)
                     * {
                     *  proto = true;
                     * }
                     * else
                     * {
                     *  var prop = rr.Member as IProperty;
                     *
                     *  if (prop != null && prop.IsVirtual)
                     *  {
                     *      proto = true;
                     *  }
                     * }*/
                }
            }

            if (proto)
            {
                var baseType = this.Emitter.GetBaseMethodOwnerTypeDefinition(targetMember.MemberName, targetMember.TypeArguments.Count);
                var method   = invocationExpression.GetParent <MethodDeclaration>();

                bool isIgnore = this.Emitter.Validator.IsIgnoreType(baseType);

                if (isIgnore)
                {
                    //throw (System.Exception)this.Emitter.CreateException(targetMember.Target, "Cannot call base method, because parent class code is ignored");
                }

                bool needComma = false;

                var resolveResult = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter);

                string name = null;

                if (this.Emitter.TypeInfo.GetBaseTypes(this.Emitter).Any())
                {
                    name = BridgeTypes.ToJsName(this.Emitter.TypeInfo.GetBaseClass(this.Emitter), this.Emitter);
                }
                else
                {
                    name = BridgeTypes.ToJsName(baseType, this.Emitter);
                }

                string baseMethod;

                if (resolveResult is InvocationResolveResult)
                {
                    InvocationResolveResult invocationResult = (InvocationResolveResult)resolveResult;
                    baseMethod = OverloadsCollection.Create(this.Emitter, invocationResult.Member).GetOverloadName();
                }
                else if (resolveResult is MemberResolveResult)
                {
                    MemberResolveResult memberResult = (MemberResolveResult)resolveResult;
                    baseMethod = OverloadsCollection.Create(this.Emitter, memberResult.Member).GetOverloadName();
                }
                else
                {
                    baseMethod = targetMember.MemberName;
                    baseMethod = this.Emitter.AssemblyInfo.PreserveMemberCase ? baseMethod : Object.Net.Utilities.StringUtils.ToLowerCamelCase(baseMethod);
                }

                this.Write(name, ".prototype.", baseMethod);

                if (!isIgnore && argsInfo.HasTypeArguments)
                {
                    this.WriteOpenParentheses();
                    new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                    this.WriteCloseParentheses();
                }

                this.WriteDot();

                this.Write("call");
                this.WriteOpenParentheses();

                this.WriteThis();
                needComma = true;

                foreach (var arg in argsExpressions)
                {
                    if (needComma)
                    {
                        this.WriteComma();
                    }

                    needComma = true;
                    arg.AcceptVisitor(this.Emitter);
                }

                this.WriteCloseParentheses();
            }
            else
            {
                var dynamicResolveResult = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter) as DynamicInvocationResolveResult;

                if (dynamicResolveResult != null)
                {
                    var group = dynamicResolveResult.Target as MethodGroupResolveResult;

                    if (group != null && group.Methods.Count() > 1)
                    {
                        throw new EmitterException(invocationExpression, "Cannot compile this dynamic invocation because there are two or more method overloads with the same parameter count. To work around this limitation, assign the dynamic value to a non-dynamic variable before use or call a method with different parameter count");
                    }
                }

                var     targetResolveResult     = this.Emitter.Resolver.ResolveNode(invocationExpression.Target, this.Emitter);
                var     invocationResolveResult = targetResolveResult as MemberResolveResult;
                IMethod method = null;

                if (invocationResolveResult != null)
                {
                    method = invocationResolveResult.Member as IMethod;
                }

                if (this.IsEmptyPartialInvoking(method))
                {
                    this.Emitter.SkipSemiColon           = true;
                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                    return;
                }

                int count = this.Emitter.Writers.Count;
                invocationExpression.Target.AcceptVisitor(this.Emitter);

                if (this.Emitter.Writers.Count > count)
                {
                    var tuple = this.Emitter.Writers.Pop();

                    if (method != null && method.IsExtensionMethod)
                    {
                        StringBuilder savedBuilder = this.Emitter.Output;
                        this.Emitter.Output = new StringBuilder();
                        this.WriteThisExtension(invocationExpression.Target);
                        argsInfo.ThisArgument = this.Emitter.Output.ToString();
                        this.Emitter.Output   = savedBuilder;
                    }

                    new InlineArgumentsBlock(this.Emitter, argsInfo, tuple.Item1).Emit();
                    var result = this.Emitter.Output.ToString();
                    this.Emitter.Output    = tuple.Item2;
                    this.Emitter.IsNewLine = tuple.Item3;
                    this.Write(result);
                }
                else
                {
                    var isIgnore = false;

                    if (method != null && method.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition))
                    {
                        isIgnore = true;
                    }

                    if (!isIgnore && argsInfo.HasTypeArguments)
                    {
                        this.WriteOpenParentheses();
                        new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                        this.WriteCloseParentheses();
                    }

                    this.WriteOpenParentheses();
                    new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg, invocationExpression).Emit();
                    this.WriteCloseParentheses();
                }
            }

            Helpers.CheckValueTypeClone(this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter), invocationExpression, this);

            this.Emitter.ReplaceAwaiterByVar     = oldValue;
            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
        }
            public override void VisitInvocationExpression(InvocationExpression invocationExpression)
            {
                InvocationExpression outerInvocationExpression = invocationExpression;
                //Note the invocations are in reverse order, so x.Foo().Bar() will have [0] be the Bar() and [1] be the Foo()
                List <InvocationExpression> invocations = new List <InvocationExpression>();
                LinqMethod outerMethod = null;
                Expression target      = null;

                for (;;)
                {
                    var resolveResult = ctx.Resolve(invocationExpression) as MemberResolveResult;
                    if (resolveResult == null || !(resolveResult.Member is IMethod))
                    {
                        break;
                    }

                    var method = LinqMethods.FirstOrDefault(candidate => candidate.FullName == resolveResult.Member.FullName &&
                                                            candidate.ParameterCount == ((IMethod)resolveResult.Member.MemberDefinition).Parameters.Count);
                    if (method == null || (invocations.Any() && method.IsLast))
                    {
                        break;
                    }

                    var mre = invocationExpression.Target as MemberReferenceExpression;
                    if (mre == null)
                    {
                        break;
                    }

                    if (outerMethod == null)
                    {
                        outerMethod = method;
                    }
                    invocations.Add(invocationExpression);

                    target = mre.Target;

                    var newInvocation = target as InvocationExpression;
                    if (newInvocation == null)
                    {
                        break;
                    }

                    invocationExpression = newInvocation;
                }

                if (target == null)
                {
                    base.VisitInvocationExpression(invocationExpression);
                    return;
                }
                if (!outerMethod.IsPoorStyleAlone && invocations.Count == 1)
                {
                    base.VisitInvocationExpression(invocationExpression);
                    return;
                }

                var currentTypeDeclaration   = outerInvocationExpression.GetParent <TypeDeclaration>();
                var currentTypeResolveResult = ctx.Resolve(currentTypeDeclaration) as TypeResolveResult;

                if (currentTypeResolveResult == null)
                {
                    base.VisitInvocationExpression(invocationExpression);
                    return;
                }

                var currentTypeDefinition = currentTypeResolveResult.Type.GetDefinition();

                var targetResolveResult = ctx.Resolve(target);

                if (!CanIndex(currentTypeDefinition, targetResolveResult))
                {
                    base.VisitInvocationExpression(invocationExpression);
                    return;
                }

                string countPropertyName = GetCountProperty(currentTypeDefinition, targetResolveResult);

                string lastInvocationName = ((MemberReferenceExpression)invocations[0].Target).MemberName;

                bool endsReversed  = invocations.Count(invocation => ((MemberReferenceExpression)invocation.Target).MemberName == "Reverse") % 2 != 0;
                bool requiresCount = lastInvocationName == "Count" || lastInvocationName == "Any" ||
                                     (endsReversed ? lastInvocationName == "First" || lastInvocationName == "ElementAt" : lastInvocationName == "Last");

                if (countPropertyName == null && requiresCount)
                {
                    base.VisitInvocationExpression(invocationExpression);
                    return;
                }

                AddIssue(new CodeIssue(invocations.Last().LParToken.StartLocation,
                                       invocations.First().RParToken.EndLocation,
                                       ctx.TranslateString("Use of Linq method when there's a better alternative"),
                                       ctx.TranslateString("Replace method by simpler version"),
                                       script => {
                    Expression startOffset = null;
                    Expression endOffset   = null;
                    Expression expression  = null;

                    bool reversed = false;
                    foreach (var invocation in invocations.AsEnumerable().Reverse())
                    {
                        string invocationName = ((MemberReferenceExpression)invocation.Target).MemberName;

                        switch (invocationName)
                        {
                        case "Skip":
                            Expression offset = reversed ? endOffset : startOffset;
                            if (offset == null)
                            {
                                offset = invocation.Arguments.Last().Clone();
                            }
                            else
                            {
                                offset = new BinaryOperatorExpression(offset,
                                                                      BinaryOperatorType.Add,
                                                                      invocation.Arguments.Last().Clone());
                            }

                            if (reversed)
                            {
                                endOffset = offset;
                            }
                            else
                            {
                                startOffset = offset;
                            }

                            break;

                        case "Reverse":
                            reversed = !reversed;
                            break;

                        case "First":
                        case "ElementAt":
                        case "Last":
                            {
                                bool fromEnd          = (invocationName == "Last") ^ reversed;
                                Expression index      = invocationName == "ElementAt" ? invocation.Arguments.Last().Clone() : null;
                                Expression baseOffset = fromEnd ? endOffset : startOffset;
                                //Our indexWithOffset is baseOffset + index
                                //A baseOffset/index of null is considered "0".

                                Expression indexWithOffset = baseOffset == null ? index :
                                                             index == null ? baseOffset :
                                                             new BinaryOperatorExpression(baseOffset, BinaryOperatorType.Add, index);

                                Expression indexerExpression = indexWithOffset;
                                if (fromEnd)
                                {
                                    var endExpression = new BinaryOperatorExpression(new MemberReferenceExpression(target.Clone(), countPropertyName),
                                                                                     BinaryOperatorType.Subtract,
                                                                                     new PrimitiveExpression(1));
                                    if (indexerExpression == null)
                                    {
                                        indexerExpression = endExpression;
                                    }
                                    else
                                    {
                                        indexerExpression = new BinaryOperatorExpression(endExpression,
                                                                                         BinaryOperatorType.Subtract,
                                                                                         new ParenthesizedExpression(indexerExpression));
                                    }
                                }

                                indexerExpression = indexerExpression ?? new PrimitiveExpression(0);

                                var newExpression = new IndexerExpression(target.Clone(),
                                                                          indexerExpression);

                                script.Replace(outerInvocationExpression, newExpression);
                                break;
                            }

                        case "Count":
                        case "Any":
                            {
                                Expression takenMembers;
                                if (startOffset == null)
                                {
                                    takenMembers = endOffset;
                                }
                                else if (endOffset == null)
                                {
                                    takenMembers = startOffset;
                                }
                                else
                                {
                                    takenMembers = new BinaryOperatorExpression(startOffset,
                                                                                BinaryOperatorType.Add,
                                                                                endOffset);
                                }

                                var countExpression = new MemberReferenceExpression(target.Clone(), countPropertyName);

                                Expression newExpression;
                                if (invocationName == "Count")
                                {
                                    if (takenMembers == null)
                                    {
                                        newExpression = countExpression;
                                    }
                                    else
                                    {
                                        newExpression = new BinaryOperatorExpression(countExpression,
                                                                                     BinaryOperatorType.Subtract,
                                                                                     new ParenthesizedExpression(takenMembers));
                                    }
                                }
                                else
                                {
                                    newExpression = new BinaryOperatorExpression(countExpression,
                                                                                 BinaryOperatorType.GreaterThan,
                                                                                 new ParenthesizedExpression(takenMembers));
                                }

                                script.Replace(outerInvocationExpression, newExpression);
                                break;
                            }
                        }
                    }
                }));

                base.VisitInvocationExpression(invocationExpression);
            }
예제 #8
0
        protected void VisitInvocationExpression()
        {
            InvocationExpression invocationExpression = this.InvocationExpression;
            var oldValue = this.Emitter.ReplaceAwaiterByVar;
            var oldAsyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

            if (this.Emitter.IsAsync && !this.Emitter.AsyncExpressionHandling)
            {
                this.WriteAwaiters(invocationExpression);
                this.Emitter.ReplaceAwaiterByVar     = true;
                this.Emitter.AsyncExpressionHandling = true;
            }

            Tuple <bool, bool, string> inlineInfo = this.Emitter.GetInlineCode(invocationExpression);
            var argsInfo = new ArgumentsInfo(this.Emitter, invocationExpression);

            var argsExpressions = argsInfo.ArgumentsExpressions;
            var paramsArg       = argsInfo.ParamsExpression;
            var argsCount       = argsExpressions.Count();

            if (inlineInfo != null)
            {
                bool   isStaticMethod = inlineInfo.Item1;
                bool   isInlineMethod = inlineInfo.Item2;
                string inlineScript   = inlineInfo.Item3;

                if (isInlineMethod)
                {
                    if (invocationExpression.Arguments.Count == 1)
                    {
                        var code             = invocationExpression.Arguments.First();
                        var inlineExpression = code as PrimitiveExpression;

                        if (inlineExpression == null)
                        {
                            throw new EmitterException(invocationExpression, "Only primitive expression can be inlined");
                        }

                        string value = inlineExpression.Value.ToString().Trim();

                        if (value.Length > 0)
                        {
                            this.Write(inlineExpression.Value);

                            if (value[value.Length - 1] == ';')
                            {
                                this.Emitter.EnableSemicolon = false;
                                this.WriteNewLine();
                            }
                        }
                        else
                        {
                            // Empty string, emit nothing.
                            this.Emitter.EnableSemicolon = false;
                        }

                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                        return;
                    }
                }
                else if (!String.IsNullOrEmpty(inlineScript) && invocationExpression.Target is IdentifierExpression)
                {
                    argsInfo.ThisArgument = "this";
                    bool noThis = !inlineScript.Contains("{this}");

                    if (!isStaticMethod && noThis)
                    {
                        this.WriteThis();
                        this.WriteDot();
                    }

                    new InlineArgumentsBlock(this.Emitter, argsInfo, inlineScript).Emit();
                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                    return;
                }
            }

            MemberReferenceExpression targetMember = invocationExpression.Target as MemberReferenceExpression;

            ResolveResult targetMemberResolveResult = null;

            if (targetMember != null)
            {
                targetMemberResolveResult = this.Emitter.Resolver.ResolveNode(targetMember.Target, this.Emitter);
            }

            if (targetMember != null)
            {
                var member = this.Emitter.Resolver.ResolveNode(targetMember.Target, this.Emitter);

                if (member != null && member.Type.Kind == TypeKind.Delegate)
                {
                    throw new EmitterException(invocationExpression, "Delegate's methods are not supported. Please use direct delegate invoke.");
                }

                var targetResolve = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter);

                if (targetResolve != null)
                {
                    var csharpInvocation = targetResolve as CSharpInvocationResolveResult;

                    InvocationResolveResult invocationResult;

                    if (csharpInvocation != null)
                    {
                        invocationResult = csharpInvocation.IsExtensionMethodInvocation ? csharpInvocation : null;

                        if (this.IsEmptyPartialInvoking(csharpInvocation.Member as IMethod))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }
                    else
                    {
                        invocationResult = targetResolve as InvocationResolveResult;

                        if (invocationResult != null && this.IsEmptyPartialInvoking(invocationResult.Member as IMethod))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }

                    if (invocationResult == null)
                    {
                        invocationResult = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter) as InvocationResolveResult;
                    }

                    if (invocationResult != null)
                    {
                        var resolvedMethod = invocationResult.Member as IMethod;

                        if (resolvedMethod != null && resolvedMethod.IsExtensionMethod)
                        {
                            string inline = this.Emitter.GetInline(resolvedMethod);

                            if (!string.IsNullOrWhiteSpace(inline))
                            {
                                this.Write("");
                                StringBuilder savedBuilder = this.Emitter.Output;
                                this.Emitter.Output = new StringBuilder();
                                this.WriteThisExtension(invocationExpression.Target);
                                argsInfo.ThisArgument = this.Emitter.Output.ToString();
                                this.Emitter.Output   = savedBuilder;
                                new InlineArgumentsBlock(this.Emitter, argsInfo, inline).Emit();
                            }
                            else
                            {
                                string name          = BridgeTypes.ToJsName(resolvedMethod.DeclaringType, this.Emitter) + "." + this.Emitter.GetEntityName(resolvedMethod);
                                var    isIgnoreClass = resolvedMethod.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(resolvedMethod.DeclaringTypeDefinition);

                                this.Write(name);

                                if (!isIgnoreClass && argsInfo.HasTypeArguments)
                                {
                                    this.WriteOpenParentheses();
                                    new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                                    this.WriteCloseParentheses();
                                }

                                this.WriteOpenParentheses();

                                this.WriteThisExtension(invocationExpression.Target);

                                if (argsCount > 0)
                                {
                                    this.WriteComma();
                                }

                                new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg).Emit();

                                this.WriteCloseParentheses();
                            }

                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }
                }
            }

            var proto = false;

            if (targetMember != null && targetMember.Target is BaseReferenceExpression)
            {
                var rr = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter) as MemberResolveResult;

                if (rr != null)
                {
                    var method = rr.Member as IMethod;
                    if (method != null && method.IsVirtual)
                    {
                        proto = true;
                    }
                    else
                    {
                        var prop = rr.Member as IProperty;

                        if (prop != null && prop.IsVirtual)
                        {
                            proto = true;
                        }
                    }
                }
            }

            if (proto)
            {
                var baseType = this.Emitter.GetBaseMethodOwnerTypeDefinition(targetMember.MemberName, targetMember.TypeArguments.Count);
                var method   = invocationExpression.GetParent <MethodDeclaration>();

                bool isIgnore = this.Emitter.Validator.IsIgnoreType(baseType);

                if (isIgnore)
                {
                    throw (Exception)this.Emitter.CreateException(targetMember.Target, "Cannot call base method, because parent class code is ignored");
                }

                bool needComma = false;

                var resolveResult = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter);

                string name = null;

                if (this.Emitter.TypeInfo.TypeDeclaration.BaseTypes.Any())
                {
                    name = BridgeTypes.ToJsName(this.Emitter.TypeInfo.TypeDeclaration.BaseTypes.First(), this.Emitter);
                }
                else
                {
                    name = BridgeTypes.ToJsName(baseType, this.Emitter);
                }

                if (resolveResult != null && resolveResult is InvocationResolveResult)
                {
                    InvocationResolveResult invocationResult = (InvocationResolveResult)resolveResult;
                    this.Write(name, ".prototype.", this.Emitter.GetEntityName(invocationResult.Member));
                }
                else
                {
                    string baseMethod = targetMember.MemberName;
                    this.Write(name, ".prototype.", this.Emitter.ChangeCase ? Object.Net.Utilities.StringUtils.ToLowerCamelCase(baseMethod) : baseMethod);
                }

                if (!isIgnore && argsInfo.HasTypeArguments)
                {
                    this.WriteOpenParentheses();
                    new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                    this.WriteCloseParentheses();
                }

                this.WriteDot();

                this.Write("call");
                this.WriteOpenParentheses();

                this.WriteThis();
                needComma = true;

                foreach (var arg in argsExpressions)
                {
                    if (needComma)
                    {
                        this.WriteComma();
                    }

                    needComma = true;
                    arg.AcceptVisitor(this.Emitter);
                }

                this.WriteCloseParentheses();
            }
            else
            {
                var     targetResolveResult     = this.Emitter.Resolver.ResolveNode(invocationExpression.Target, this.Emitter);
                var     invocationResolveResult = targetResolveResult as MemberResolveResult;
                IMethod method = null;

                if (invocationResolveResult != null)
                {
                    method = invocationResolveResult.Member as IMethod;
                }

                if (this.IsEmptyPartialInvoking(method))
                {
                    this.Emitter.SkipSemiColon           = true;
                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                    return;
                }

                int count = this.Emitter.Writers.Count;
                invocationExpression.Target.AcceptVisitor(this.Emitter);

                if (this.Emitter.Writers.Count > count)
                {
                    var tuple = this.Emitter.Writers.Pop();

                    if (method != null && method.IsExtensionMethod)
                    {
                        StringBuilder savedBuilder = this.Emitter.Output;
                        this.Emitter.Output = new StringBuilder();
                        this.WriteThisExtension(invocationExpression.Target);
                        argsInfo.ThisArgument = this.Emitter.Output.ToString();
                        this.Emitter.Output   = savedBuilder;
                    }

                    new InlineArgumentsBlock(this.Emitter, argsInfo, tuple.Item1).Emit();
                    var result = this.Emitter.Output.ToString();
                    this.Emitter.Output    = tuple.Item2;
                    this.Emitter.IsNewLine = tuple.Item3;
                    this.Write(result);
                }
                else
                {
                    var isIgnore = false;

                    if (method != null && method.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition))
                    {
                        isIgnore = true;
                    }

                    if (!isIgnore && argsInfo.HasTypeArguments)
                    {
                        this.WriteOpenParentheses();
                        new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                        this.WriteCloseParentheses();
                    }

                    this.WriteOpenParentheses();
                    new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg).Emit();
                    this.WriteCloseParentheses();
                }
            }

            this.Emitter.ReplaceAwaiterByVar     = oldValue;
            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
        }