Example #1
0
        public override object VisitBlockStatement(BlockStatement blockStatement, object data)
        {
            int numberOfVariablesOutsideBlock = currentlyUsedVariableNames.Count;

            base.VisitBlockStatement(blockStatement, data);
            foreach (ExpressionStatement stmt in blockStatement.Statements.OfType <ExpressionStatement>().ToArray())
            {
                Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt);
                if (!displayClassAssignmentMatch.Success)
                {
                    continue;
                }

                ILVariable variable = displayClassAssignmentMatch.Get <AstNode>("variable").Single().Annotation <ILVariable>();
                if (variable == null)
                {
                    continue;
                }
                TypeDefinition type = variable.Type.ResolveWithinSameModule();
                if (!IsPotentialClosure(context, type))
                {
                    continue;
                }
                if (displayClassAssignmentMatch.Get <AstType>("type").Single().Annotation <TypeReference>().ResolveWithinSameModule() != type)
                {
                    continue;
                }

                // Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
                bool ok = true;
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single())
                    {
                        //check if it a cross reference to another generated delegate class's member
                        if (identExpr.Parent is AssignmentExpression)
                        {
                            if ((identExpr.Parent as AssignmentExpression).Left is MemberReferenceExpression
                                )
                            {
                                MemberReferenceExpression tleft = (MemberReferenceExpression)(identExpr.Parent as AssignmentExpression).Left;
                                ILVariable v = tleft.Target.Annotation <ILVariable>();
                                if (v != null)
                                {
                                    TypeDefinition vtype = v.Type.ResolveWithinSameModule();


                                    if (vtype.IsNested && IsPotentialClosure(context, vtype))
                                    {
                                        Console.WriteLine(identExpr.Parent.ToString() + " cross reference by delegate  should be ok");
                                        continue;
                                    }
                                }
                            }
                        }
                        if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation <FieldReference>() != null))
                        {
                            ok = false;
                            break;
                        }
                    }
                }
                if (!ok)
                {
                    continue;
                }
                Dictionary <FieldReference, AstNode> dict = new Dictionary <FieldReference, AstNode>();

                // Delete the variable declaration statement:
                VariableDeclarationStatement displayClassVarDecl = PatternStatementTransform.FindVariableDeclaration(stmt, variable.Name);
                if (displayClassVarDecl != null)
                {
                    displayClassVarDecl.Remove();
                }

                // Delete the assignment statement:
                AstNode cur = stmt.NextSibling;
                stmt.Remove();

                // Delete any following statements as long as they assign parameters to the display class
                BlockStatement    rootBlock            = blockStatement.Ancestors.OfType <BlockStatement>().LastOrDefault() ?? blockStatement;
                List <ILVariable> parameterOccurrances = rootBlock.Descendants.OfType <IdentifierExpression>()
                                                         .Select(n => n.Annotation <ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
                AstNode next;
                for (; cur != null; cur = next)
                {
                    next = cur.NextSibling;

                    // Test for the pattern:
                    // "variableName.MemberName = right;"
                    ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
                        new AssignmentExpression(
                            new NamedNode("left", new MemberReferenceExpression {
                        Target     = new IdentifierExpression(variable.Name),
                        MemberName = Pattern.AnyString
                    }),
                            new AnyNode("right")
                            )
                        );
                    Match m = closureFieldAssignmentPattern.Match(cur);
                    if (m.Success)
                    {
                        FieldDefinition fieldDef    = m.Get <MemberReferenceExpression>("left").Single().Annotation <FieldReference>().ResolveWithinSameModule();
                        AstNode         right       = m.Get <AstNode>("right").Single();
                        bool            isParameter = false;
                        bool            isDisplayClassParentPointerAssignment = false;
                        if (right is ThisReferenceExpression)
                        {
                            isParameter = true;
                        }
                        else if (right is IdentifierExpression)
                        {
                            // handle parameters only if the whole method contains no other occurrence except for 'right'
                            ILVariable v = right.Annotation <ILVariable>();
                            isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1;
                            if (!isParameter && IsPotentialClosure(context, v.Type.ResolveWithinSameModule()))
                            {
                                // parent display class within the same method
                                // (closure2.localsX = closure1;)
                                isDisplayClassParentPointerAssignment = true;
                            }
                        }
                        else if (right is MemberReferenceExpression)
                        {
                            // copy of parent display class reference from an outer lambda
                            // closure2.localsX = this.localsY
                            MemberReferenceExpression mre = m.Get <MemberReferenceExpression>("right").Single();
                            do
                            {
                                // descend into the targets of the mre as long as the field types are closures
                                FieldDefinition fieldDef2 = mre.Annotation <FieldReference>().ResolveWithinSameModule();
                                if (fieldDef2 == null || !IsPotentialClosure(context, fieldDef2.FieldType.ResolveWithinSameModule()))
                                {
                                    break;
                                }
                                // if we finally get to a this reference, it's copying a display class parent pointer
                                if (mre.Target is ThisReferenceExpression)
                                {
                                    isDisplayClassParentPointerAssignment = true;
                                }
                                mre = mre.Target as MemberReferenceExpression;
                            } while (mre != null);
                        }
                        if (isParameter || isDisplayClassParentPointerAssignment)
                        {
                            dict[fieldDef] = right;
                            cur.Remove();
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        //why need to break? continue to match should be ok
                        //break;
                    }
                }

                // Now create variables for all fields of the display class (except for those that we already handled as parameters)
                List <Tuple <AstType, ILVariable> > variablesToDeclare = new List <Tuple <AstType, ILVariable> >();
                foreach (FieldDefinition field in type.Fields)
                {
                    if (field.IsStatic)
                    {
                        continue;                         // skip static fields
                    }
                    if (dict.ContainsKey(field))          // skip field if it already was handled as parameter
                    {
                        continue;
                    }
                    string capturedVariableName = field.Name;
                    if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10)
                    {
                        capturedVariableName = capturedVariableName.Substring(10);
                    }
                    EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
                    currentlyUsedVariableNames.Add(capturedVariableName);
                    ILVariable ilVar = new ILVariable
                    {
                        IsGenerated = true,
                        Name        = capturedVariableName,
                        Type        = field.FieldType,
                    };
                    variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), ilVar));
                    dict[field] = new IdentifierExpression(capturedVariableName).WithAnnotation(ilVar);
                }

                // Now figure out where the closure was accessed and use the simpler replacement expression there:
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name)
                    {
                        if (!(identExpr.Parent is MemberReferenceExpression))
                        {
                            //will delete by the next round of the cross reference delegate class
                            continue;
                        }
                        MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
                        AstNode replacement;
                        if (dict.TryGetValue(mre.Annotation <FieldReference>().ResolveWithinSameModule(), out replacement))
                        {
                            mre.ReplaceWith(replacement.Clone());
                        }
                    }
                }
                // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
                Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
                foreach (var tuple in variablesToDeclare)
                {
                    var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2.Name);
                    newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
                    newVarDecl.Variables.Single().AddAnnotation(tuple.Item2);
                    blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
                }
            }
            currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock);
            return(null);
        }
Example #2
0
        public override object VisitBlockStatement(BlockStatement blockStatement, object data)
        {
            base.VisitBlockStatement(blockStatement, data);
            foreach (ExpressionStatement stmt in blockStatement.Statements.OfType <ExpressionStatement>().ToArray())
            {
                Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt);
                if (displayClassAssignmentMatch == null)
                {
                    continue;
                }

                ILVariable variable = displayClassAssignmentMatch.Get("variable").Single().Annotation <ILVariable>();
                if (variable == null)
                {
                    continue;
                }
                TypeDefinition type = variable.Type.ResolveWithinSameModule();
                if (!IsPotentialClosure(context, type))
                {
                    continue;
                }
                if (displayClassAssignmentMatch.Get("type").Single().Annotation <TypeReference>().ResolveWithinSameModule() != type)
                {
                    continue;
                }

                // Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
                bool ok = true;
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single())
                    {
                        if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation <FieldReference>() != null))
                        {
                            ok = false;
                        }
                    }
                }
                if (!ok)
                {
                    continue;
                }
                Dictionary <FieldReference, AstNode> dict = new Dictionary <FieldReference, AstNode>();
                // Delete the variable declaration statement:
                AstNode cur = stmt.NextSibling;
                stmt.Remove();
                if (blockStatement.Parent.NodeType == NodeType.Member || blockStatement.Parent is Accessor)
                {
                    // Delete any following statements as long as they assign parameters to the display class
                    // Do parameter handling only for closures created in the top scope (direct child of method/accessor)
                    List <ILVariable> parameterOccurrances = blockStatement.Descendants.OfType <IdentifierExpression>()
                                                             .Select(n => n.Annotation <ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
                    AstNode next;
                    for (; cur != null; cur = next)
                    {
                        next = cur.NextSibling;

                        // Test for the pattern:
                        // "variableName.MemberName = right;"
                        ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
                            new AssignmentExpression(
                                new NamedNode("left", new MemberReferenceExpression {
                            Target = new IdentifierExpression(variable.Name)
                        }),
                                new AnyNode("right")
                                )
                            );
                        Match m = closureFieldAssignmentPattern.Match(cur);
                        if (m != null)
                        {
                            AstNode right       = m.Get("right").Single();
                            bool    isParameter = false;
                            if (right is ThisReferenceExpression)
                            {
                                isParameter = true;
                            }
                            else if (right is IdentifierExpression)
                            {
                                // handle parameters only if the whole method contains no other occurrance except for 'right'
                                ILVariable param = right.Annotation <ILVariable>();
                                isParameter = param.IsParameter && parameterOccurrances.Count(c => c == param) == 1;
                            }
                            if (isParameter)
                            {
                                dict[m.Get <MemberReferenceExpression>("left").Single().Annotation <FieldReference>().ResolveWithinSameModule()] = right;
                                cur.Remove();
                            }
                            else
                            {
                                break;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                // Now create variables for all fields of the display class (except for those that we already handled as parameters)
                List <Tuple <AstType, string> > variablesToDeclare = new List <Tuple <AstType, string> >();
                foreach (FieldDefinition field in type.Fields)
                {
                    if (dict.ContainsKey(field))
                    {
                        continue;
                    }
                    variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), field.Name));
                    dict[field] = new IdentifierExpression(field.Name);
                }

                // Now figure out where the closure was accessed and use the simpler replacement expression there:
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name)
                    {
                        MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
                        AstNode replacement;
                        if (dict.TryGetValue(mre.Annotation <FieldReference>().ResolveWithinSameModule(), out replacement))
                        {
                            mre.ReplaceWith(replacement.Clone());
                        }
                    }
                }
                // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
                Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
                foreach (var tuple in variablesToDeclare)
                {
                    var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2);
                    newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
                    blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
                }
            }
            return(null);
        }
Example #3
0
        private void TraverseNodes(AstNode node)
        {
            foreach (var child in node.Children)
            {
                if (Options.MiscCompressing && child is PrimitiveExpression)
                {
                    var primitiveExpression = (PrimitiveExpression)child;
                    if (IsIntegerNumber(primitiveExpression.Value))
                    {
                        string str = primitiveExpression.Value.ToString();
                        long   number;
                        if (long.TryParse(str, out number))
                        {
                            string hex = "0x" + number.ToString("X");
                            primitiveExpression.SetValue(primitiveExpression.Value, str.Length < hex.Length ? str : hex);
                        }
                    }
                }
                else if (Options.MiscCompressing && child is CSharpModifierToken)
                {
                    // private int a => int a
                    var modifier = ((CSharpModifierToken)child).Modifier;
                    if (modifier.HasFlag(Modifiers.Private) && (modifier & ~Modifiers.Private) == 0)
                    {
                        child.Remove();
                    }
                    else
                    {
                        modifier &= ~Modifiers.Private;
                    }
                }
                else if (Options.NamespacesRemoving && child is NamespaceDeclaration)
                {
                    var childrenToRemove = child.Children.TakeWhile(c => !(c is CSharpTokenNode && c.Role.ToString() == "{"));
                    foreach (AstNode childToRemove in childrenToRemove)
                    {
                        childToRemove.Remove();
                    }
                    if (child.Children.Count() > 0)
                    {
                        child.Children.First().Remove();
                    }
                    if (child.Children.Count() > 0)
                    {
                        child.Children.Last().Remove();
                    }
                    var namespaceChildrens = child.Children;

                    var parent = child.Parent;
                    foreach (var c in parent.Children)
                    {
                        if (c == child)
                        {
                            foreach (var nsChildren in namespaceChildrens)
                            {
                                parent.InsertChildAfter(c, nsChildren.Clone(), new Role <AstNode>(nsChildren.Role.ToString()));
                            }
                            c.Remove();
                            break;
                        }
                    }
                    foreach (AstNode c in parent.Children)
                    {
                        TraverseNodes(c);
                    }
                }
                else if (Options.MiscCompressing && child is VariableDeclarationStatement)
                {
                    // List<byte> a = new List<byte>() => var a = new List<byte>()
                    // var a = new b() => b a = new b()
                    var varDecExpr = (VariableDeclarationStatement)child;
                    if (!varDecExpr.Modifiers.HasFlag(Modifiers.Const))
                    {
                        var type = varDecExpr.Type.ToString().Replace(" ", "");
                        if (type == VarId)
                        {
                            // Resolving expression type.
                            CompileAndResolve();
                            var expectedType = _resolver.GetExpectedType(varDecExpr.Variables.Single().Initializer);
                            if (expectedType.Namespace != "System.Collections.Generic")
                            {
                                string typeStr = expectedType.Name;
                                bool   replace = NamesGenerator.CSharpTypeSynonyms.TryGetValue(typeStr, out typeStr);
                                if (!replace)
                                {
                                    typeStr = expectedType.Name;
                                }
                                if (typeStr.Length <= VarId.Length)
                                {
                                    replace = true;
                                }
                                else
                                {
                                    replace = false;
                                }
                                if (replace)
                                {
                                    if (expectedType.Namespace == "System")
                                    {
                                        varDecExpr.Type = new PrimitiveType(typeStr);
                                    }
                                    else
                                    {
                                        varDecExpr.Type = new SimpleType(typeStr);
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (varDecExpr.Variables.Count == 1)
                            {
                                string typeStr;
                                var    typeStrWithoutNamespaces = varDecExpr.Type.ToString();
                                typeStrWithoutNamespaces = typeStrWithoutNamespaces.Substring(typeStrWithoutNamespaces.LastIndexOf('.') + 1);
                                NamesGenerator.CSharpTypeSynonyms.TryGetValue(typeStrWithoutNamespaces, out typeStr);
                                if (typeStr == null)
                                {
                                    typeStr = varDecExpr.Type.ToString();
                                }
                                var initializer = varDecExpr.Variables.Single().Initializer;
                                if (((typeStr == "string" || typeStr == "char" || typeStr == "bool") && initializer != NullReferenceExpression.Null) ||
                                    initializer is ObjectCreateExpression)
                                {
                                    if (VarId.Length < type.Length)
                                    {
                                        varDecExpr.Type = new SimpleType(VarId);
                                    }
                                }
                            }
                        }
                    }
                    foreach (var variable in varDecExpr.Variables)
                    {
                        TraverseNodes(child);
                    }
                }
                else if (child is EmptyStatement)
                {
                    // { ; ; } => {}
                    if (!(child.Parent is BlockStatement))
                    {
                        if (Options.Unsafe)
                        {
                            node.Remove();
                        }
                    }
                    else
                    {
                        child.Remove();
                    }
                }
                else
                {
                    string role = child.Role.ToString();
                    if (Options.MiscCompressing && child is BlockStatement && role != "Body" && role != "TryBlock")
                    {
                        // if (a) { b; } => if (a) b;
                        var childrenCount = child.Children.Count(c => !(c is NewLineNode));
                        if (childrenCount == 3)
                        {
                            child.ReplaceWith(child.Children.Skip(1).FirstOrDefault(c => !(c is NewLineNode)));
                        }
                        else if (childrenCount < 3)
                        {
                            if (!(child.Parent is BlockStatement))
                            {
                                if (Options.Unsafe)
                                {
                                    node.Remove();
                                }
                                else
                                {
                                    child.ReplaceWith(new EmptyStatement());
                                }
                            }
                            else
                            {
                                child.Remove();
                            }
                        }
                    }
                    else if (Options.Unsafe && child is BinaryOperatorExpression)
                    {
                        // if (a == true) => if (a)
                        // if (a == false) => if (!a)
                        var binaryExpression    = (BinaryOperatorExpression)child;
                        var primitiveExpression = binaryExpression.Left as PrimitiveExpression;
                        var expression          = binaryExpression.Right;
                        if (primitiveExpression == null)
                        {
                            primitiveExpression = binaryExpression.Right as PrimitiveExpression;
                            expression          = binaryExpression.Left;
                        }
                        if (primitiveExpression != null && primitiveExpression.Value is bool)
                        {
                            var boolean = (bool)primitiveExpression.Value;
                            expression.Remove();
                            if (boolean)
                            {
                                child.ReplaceWith(expression);
                            }
                            else
                            {
                                child.ReplaceWith(new UnaryOperatorExpression(UnaryOperatorType.Not, expression));
                            }
                        }
                    }
                    TraverseNodes(child);
                }
            }
        }
Example #4
0
        private void MangleStatement(AstNodeCollection<Statement> statements, AstNode node)
        {
            // Remove stray semicolons
            if (node is EmptyStatement) {
                node.Remove();
                return;
            }

            // Inline nested block statements
            var block = node as BlockStatement;
            if (block != null) {
                foreach (var replacement in block.Statements) {
                    replacement.Remove();
                    statements.InsertBefore((Statement)node, replacement);
                }
                node.Remove();
                return;
            }

            // Merge adjacent variable declarations
            var declaration = node as VariableDeclarationStatement;
            if (declaration != null) {
                var previous = PreviousSiblingIgnoringWhitespace(node) as VariableDeclarationStatement;
                if (previous != null) {
                    foreach (var variable in declaration.Variables) {
                        variable.Remove();
                        previous.Variables.Add(variable);
                    }
                    if (node.PrevSibling is NewLineNode) {
                        node.PrevSibling.Remove();
                    }
                    node.Remove();
                }
                return;
            }

            // Bring previous variable declarations into for loops
            var loop = node as ForStatement;
            if (loop != null) {
                var previous = PreviousSiblingIgnoringWhitespace(node) as VariableDeclarationStatement;
                if (previous != null) {
                    var count = loop.Initializers.Count;
                    if (count == 0) {
                        previous.Remove();
                        loop.Initializers.Add(previous);
                    } else if (count == 1) {
                        var initializers = loop.Initializers.FirstOrNullObject() as VariableDeclarationStatement;
                        if (initializers != null) {
                            foreach (var variable in initializers.Variables) {
                                variable.Remove();
                                previous.Variables.Add(variable);
                            }
                            previous.Remove();
                            initializers.Remove();
                            loop.Initializers.Add(previous);
                        }
                    }
                }
                return;
            }
        }