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