public override bool DoMatch(INode other, Match match) { var last = match.Get (referencedGroupName).Last (); if (last == null && other == null) return true; return last.IsMatch(other); }
public override bool DoMatch(INode other, Match match) { CSharp.IdentifierExpression ident = other as CSharp.IdentifierExpression; if (ident == null || ident.TypeArguments.Any()) return false; CSharp.AstNode referenced = (CSharp.AstNode)match.Get(referencedGroupName).Last(); if (referenced == null) return false; return ident.Identifier == referenced.GetChildByRole(CSharp.AstNode.Roles.Identifier).Name; }
Expression ConvertBinaryOperator(InvocationExpression invocation, BinaryOperatorType op, bool?isChecked = null) { if (invocation.Arguments.Count < 2) { return(NotSupported(invocation)); } Expression left = Convert(invocation.Arguments.ElementAt(0)); if (left == null) { return(null); } Expression right = Convert(invocation.Arguments.ElementAt(1)); if (right == null) { return(null); } BinaryOperatorExpression boe = new BinaryOperatorExpression(left, op, right); if (isChecked != null) { boe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); } switch (invocation.Arguments.Count) { case 2: return(boe); case 3: Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2)); if (m.Success) { return(boe.WithAnnotation(m.Get <AstNode>("method").Single().Annotation <IMethod>())); } else { return(null); } case 4: if (!trueOrFalse.IsMatch(invocation.Arguments.ElementAt(2))) { return(null); } m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(3)); if (m.Success) { return(boe.WithAnnotation(m.Get <AstNode>("method").Single().Annotation <IMethod>())); } else { return(null); } default: return(NotSupported(invocation)); } }
Expression ConvertNewObject(InvocationExpression invocation) { if (invocation.Arguments.Count < 1 || invocation.Arguments.Count > 3) { return(NotSupported(invocation)); } Match m = newObjectCtorPattern.Match(invocation.Arguments.First()); if (!m.Success) { return(NotSupported(invocation)); } IMethod ctor = m.Get <AstNode>("ctor").Single().Annotation <IMethod>(); if (ctor == null) { return(null); } AstType declaringTypeNode; ITypeDefOrRef declaringType; if (m.Has("declaringType")) { declaringTypeNode = m.Get <AstType>("declaringType").Single().Clone(); declaringType = declaringTypeNode.Annotation <ITypeDefOrRef>(); } else { declaringTypeNode = AstBuilder.ConvertType(ctor.DeclaringType); declaringType = ctor.DeclaringType; } if (declaringTypeNode == null) { return(null); } ObjectCreateExpression oce = new ObjectCreateExpression(declaringTypeNode); if (invocation.Arguments.Count >= 2) { IList <Expression> arguments = ConvertExpressionsArray(invocation.Arguments.ElementAtOrDefault(1)); if (arguments == null) { return(null); } oce.Arguments.AddRange(arguments); } if (invocation.Arguments.Count >= 3 && declaringType.IsAnonymousType()) { MethodDef resolvedCtor = ctor.ResolveMethodDef(); if (resolvedCtor == null || resolvedCtor.Parameters.Count != oce.Arguments.Count) { return(null); } AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression(); var arguments = oce.Arguments.ToArray(); if (AstMethodBodyBuilder.CanInferAnonymousTypePropertyNamesFromArguments(arguments, resolvedCtor.Parameters)) { oce.Arguments.MoveTo(atce.Initializers); } else { for (int i = 0; i < resolvedCtor.Parameters.Count; i++) { atce.Initializers.Add( new NamedExpression { Name = resolvedCtor.Parameters[i].Name, Expression = arguments[i].Detach() }); } } return(atce); } return(oce); }
static CodeAction HandleNegatedCase(BaseRefactoringContext ctx, IfElseStatement ifElseStatement, Match match, out IsExpression isExpression, out int foundCastCount) { foundCastCount = 0; var outerIs = match.Get <Expression>("isExpression").Single(); isExpression = AlUtil.GetInnerMostExpression(outerIs) as IsExpression; var obj = AlUtil.GetInnerMostExpression(isExpression.Expression); var castToType = isExpression.Type; var cast = new Choice { PatternHelper.OptionalParentheses(PatternHelper.OptionalParentheses(obj.Clone()).CastTo(castToType.Clone())), PatternHelper.OptionalParentheses(PatternHelper.OptionalParentheses(obj.Clone()).CastAs(castToType.Clone())) }; var rr = ctx.Resolve(castToType); if (rr == null || rr.IsError || rr.Type.IsReferenceType == false) { return(null); } var foundCasts = ifElseStatement.GetParent <BlockStatement>().DescendantNodes(n => n.StartLocation >= ifElseStatement.StartLocation && !cast.IsMatch(n)).Where(n => cast.IsMatch(n)).ToList(); foundCastCount = foundCasts.Count; return(new CodeAction(ctx.TranslateString("Use 'as' and check for null"), script => { var varName = ctx.GetNameProposal(CreateMethodDeclarationAction.GuessNameFromType(rr.Type), ifElseStatement.StartLocation); var varDec = new VariableDeclarationStatement(new PrimitiveType("var"), varName, new AsExpression(obj.Clone(), castToType.Clone())); var binaryOperatorIdentifier = new IdentifierExpression(varName); var binaryOperatorExpression = new BinaryOperatorExpression(binaryOperatorIdentifier, BinaryOperatorType.Equality, new NullReferenceExpression()); var linkedNodes = new List <AstNode>(); linkedNodes.Add(varDec.Variables.First().NameToken); linkedNodes.Add(binaryOperatorIdentifier); if (IsEmbeddedStatement(ifElseStatement)) { var block = new BlockStatement(); block.Add(varDec); var newIf = (IfElseStatement)ifElseStatement.Clone(); newIf.Condition = binaryOperatorExpression; foreach (var node in newIf.DescendantNodesAndSelf(n => !cast.IsMatch(n)).Where(n => cast.IsMatch(n))) { var id = new IdentifierExpression(varName); linkedNodes.Add(id); node.ReplaceWith(id); } block.Add(newIf); script.Replace(ifElseStatement, block); } else { script.InsertBefore(ifElseStatement, varDec); script.Replace(ifElseStatement.Condition, binaryOperatorExpression); foreach (var c in foundCasts) { var id = new IdentifierExpression(varName); linkedNodes.Add(id); script.Replace(c, id); } } script.Link(linkedNodes); }, isExpression.IsToken)); }
Expression ConvertCall(InvocationExpression invocation) { if (invocation.Arguments.Count < 2) { return(NotSupported(invocation)); } Expression target; int firstArgumentPosition; Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(0)); if (m.Success) { target = null; firstArgumentPosition = 1; } else { m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); if (!m.Success) { return(NotSupported(invocation)); } target = invocation.Arguments.ElementAt(0); firstArgumentPosition = 2; } IMethod mr = m.Get <AstNode>("method").Single().Annotation <IMethod>(); if (mr == null) { return(null); } Expression convertedTarget; if (target == null || target is NullReferenceExpression) { // static method if (m.Has("declaringType")) { convertedTarget = new TypeReferenceExpression(m.Get <AstType>("declaringType").Single().Clone()); } else { convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType)); } } else { convertedTarget = Convert(target); if (convertedTarget == null) { return(null); } } MemberReferenceExpression mre = convertedTarget.Member(mr.Name); var gim = mr as MethodSpec; if (gim != null) { foreach (var tr in gim.GenericInstMethodSig.GenericArguments) { mre.TypeArguments.Add(AstBuilder.ConvertType(tr)); } } IList <Expression> arguments = null; if (invocation.Arguments.Count == firstArgumentPosition + 1) { Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition); arguments = ConvertExpressionsArray(argumentArray); } if (arguments == null) { arguments = new List <Expression>(); foreach (Expression argument in invocation.Arguments.Skip(firstArgumentPosition)) { Expression convertedArgument = Convert(argument); if (convertedArgument == null) { return(null); } arguments.Add(convertedArgument); } } var methodDef = mr.ResolveMethodDef(); if (methodDef != null && methodDef.IsGetter) { PropertyDef indexer = AstMethodBodyBuilder.GetIndexer(methodDef); if (indexer != null) { return(new IndexerExpression(mre.Target.Detach(), arguments).WithAnnotation(indexer)); } } return(new InvocationExpression(mre, arguments).WithAnnotation(mr)); }
bool TryRemoveTransparentIdentifier(QueryExpression query, QueryFromClause fromClause, QueryExpression innerQuery) { if (!IsTransparentIdentifier(fromClause.Identifier)) { return(false); } Match match = selectTransparentIdentifierPattern.Match(innerQuery.Clauses.Last()); if (!match.Success) { return(false); } QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last(); NamedExpression nae1 = match.Get <NamedExpression>("nae1").SingleOrDefault(); NamedExpression nae2 = match.Get <NamedExpression>("nae2").SingleOrDefault(); if (nae1 != null && nae1.Name != ((IdentifierExpression)nae1.Expression).Identifier) { return(false); } Expression nae2Expr = match.Get <Expression>("nae2Expr").Single(); IdentifierExpression nae2IdentExpr = nae2Expr as IdentifierExpression; if (nae2IdentExpr != null && (nae2 == null || nae2.Name == nae2IdentExpr.Identifier)) { // from * in (from x in ... select new { x = x, y = y }) ... // => // from x in ... ... fromClause.Remove(); selectClause.Remove(); // Move clauses from innerQuery to query QueryClause insertionPos = null; foreach (var clause in innerQuery.Clauses) { query.Clauses.InsertAfter(insertionPos, insertionPos = Detach(clause)); } } else { // from * in (from x in ... select new { x = x, y = expr }) ... // => // from x in ... let y = expr ... fromClause.Remove(); selectClause.Remove(); // Move clauses from innerQuery to query QueryClause insertionPos = null; foreach (var clause in innerQuery.Clauses) { query.Clauses.InsertAfter(insertionPos, insertionPos = Detach(clause)); } string ident; if (nae2 != null) { ident = nae2.Name; } else if (nae2Expr is MemberReferenceExpression) { ident = ((MemberReferenceExpression)nae2Expr).MemberName; } else { throw new InvalidOperationException("Could not infer name from initializer in AnonymousTypeCreateExpression"); } query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = ident, Expression = Detach(nae2Expr) }); } return(true); }
// Module defining this command // Optional custom code for this activity /// <summary> /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. /// </summary> /// <param name="context">The NativeActivityContext for the currently running activity.</param> /// <returns>A populated instance of System.Management.Automation.PowerShell</returns> /// <remarks>The infrastructure takes responsibility for closing and disposing the PowerShell instance returned.</remarks> protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) { System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); // Initialize the arguments if (InputObject.Expression != null) { targetCommand.AddParameter("InputObject", InputObject.Get(context)); } if (FilterScript.Expression != null) { targetCommand.AddParameter("FilterScript", FilterScript.Get(context)); } if (Property.Expression != null) { targetCommand.AddParameter("Property", Property.Get(context)); } if (Value.Expression != null) { targetCommand.AddParameter("Value", Value.Get(context)); } if (EQ.Expression != null) { targetCommand.AddParameter("EQ", EQ.Get(context)); } if (CEQ.Expression != null) { targetCommand.AddParameter("CEQ", CEQ.Get(context)); } if (NE.Expression != null) { targetCommand.AddParameter("NE", NE.Get(context)); } if (CNE.Expression != null) { targetCommand.AddParameter("CNE", CNE.Get(context)); } if (GT.Expression != null) { targetCommand.AddParameter("GT", GT.Get(context)); } if (CGT.Expression != null) { targetCommand.AddParameter("CGT", CGT.Get(context)); } if (LT.Expression != null) { targetCommand.AddParameter("LT", LT.Get(context)); } if (CLT.Expression != null) { targetCommand.AddParameter("CLT", CLT.Get(context)); } if (GE.Expression != null) { targetCommand.AddParameter("GE", GE.Get(context)); } if (CGE.Expression != null) { targetCommand.AddParameter("CGE", CGE.Get(context)); } if (LE.Expression != null) { targetCommand.AddParameter("LE", LE.Get(context)); } if (CLE.Expression != null) { targetCommand.AddParameter("CLE", CLE.Get(context)); } if (Like.Expression != null) { targetCommand.AddParameter("Like", Like.Get(context)); } if (CLike.Expression != null) { targetCommand.AddParameter("CLike", CLike.Get(context)); } if (NotLike.Expression != null) { targetCommand.AddParameter("NotLike", NotLike.Get(context)); } if (CNotLike.Expression != null) { targetCommand.AddParameter("CNotLike", CNotLike.Get(context)); } if (Match.Expression != null) { targetCommand.AddParameter("Match", Match.Get(context)); } if (CMatch.Expression != null) { targetCommand.AddParameter("CMatch", CMatch.Get(context)); } if (NotMatch.Expression != null) { targetCommand.AddParameter("NotMatch", NotMatch.Get(context)); } if (CNotMatch.Expression != null) { targetCommand.AddParameter("CNotMatch", CNotMatch.Get(context)); } if (Contains.Expression != null) { targetCommand.AddParameter("Contains", Contains.Get(context)); } if (CContains.Expression != null) { targetCommand.AddParameter("CContains", CContains.Get(context)); } if (NotContains.Expression != null) { targetCommand.AddParameter("NotContains", NotContains.Get(context)); } if (CNotContains.Expression != null) { targetCommand.AddParameter("CNotContains", CNotContains.Get(context)); } if (In.Expression != null) { targetCommand.AddParameter("In", In.Get(context)); } if (CIn.Expression != null) { targetCommand.AddParameter("CIn", CIn.Get(context)); } if (NotIn.Expression != null) { targetCommand.AddParameter("NotIn", NotIn.Get(context)); } if (CNotIn.Expression != null) { targetCommand.AddParameter("CNotIn", CNotIn.Get(context)); } if (Is.Expression != null) { targetCommand.AddParameter("Is", Is.Get(context)); } if (IsNot.Expression != null) { targetCommand.AddParameter("IsNot", IsNot.Get(context)); } return(new ActivityImplementationContext() { PowerShellInstance = invoker }); }
void AddMatch(BinaryOperatorExpression binaryOperatorExpression, Match match, bool negateAny) { AddIssue(new CodeIssue( binaryOperatorExpression, ctx.TranslateString("Use 'Any()' for increased performance."), negateAny ? ctx.TranslateString("Replace with call to '!Any()'") : ctx.TranslateString("Replace with call to 'Any()'"), script => { Expression expr = new InvocationExpression(new MemberReferenceExpression(match.Get <Expression>("expr").First().Clone(), "Any")); if (negateAny) { expr = new UnaryOperatorExpression(UnaryOperatorType.Not, expr); } script.Replace(binaryOperatorExpression, expr); } )); }
internal void HandleInstanceFieldInitializers(IEnumerable <AstNode> members) { var instanceCtors = members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray(); if (instanceCtorsNotChainingWithThis.Length > 0) { var ctorMethodDef = instanceCtorsNotChainingWithThis[0].GetSymbol() as IMethod; if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsReferenceType == false) { return; } bool ctorIsUnsafe = instanceCtorsNotChainingWithThis.All(c => c.HasModifier(Modifiers.Unsafe)); // Recognize field or property initializers: // Translate first statement in all ctors (if all ctors have the same statement) into an initializer. bool allSame; do { Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault()); if (!m.Success) { break; } IMember fieldOrPropertyOrEvent = (m.Get <AstNode>("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition; if (!(fieldOrPropertyOrEvent is IField) && !(fieldOrPropertyOrEvent is IProperty) && !(fieldOrPropertyOrEvent is IEvent)) { break; } var fieldOrPropertyOrEventDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrPropertyOrEvent) as EntityDeclaration; // Cannot transform if member is not found or if it is a custom event. if (fieldOrPropertyOrEventDecl == null || fieldOrPropertyOrEventDecl is CustomEventDeclaration) { break; } Expression initializer = m.Get <Expression>("initializer").Single(); // 'this'/'base' cannot be used in initializers if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression)) { break; } allSame = true; for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++) { var otherMatch = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault()); if (!otherMatch.Success) { allSame = false; break; } var otherMember = (otherMatch.Get <AstNode>("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition; if (!otherMember.Equals(fieldOrPropertyOrEvent)) { allSame = false; } if (!initializer.IsMatch(otherMatch.Get <AstNode>("initializer").Single())) { allSame = false; } } if (allSame) { foreach (var ctor in instanceCtorsNotChainingWithThis) { ctor.Body.First().Remove(); } if (ctorIsUnsafe && IntroduceUnsafeModifier.IsUnsafe(initializer)) { fieldOrPropertyOrEventDecl.Modifiers |= Modifiers.Unsafe; } if (fieldOrPropertyOrEventDecl is PropertyDeclaration pd) { pd.Initializer = initializer.Detach(); } else { fieldOrPropertyOrEventDecl.GetChildrenByRole(Roles.Variable).Single().Initializer = initializer.Detach(); } } } while (allSame); } }
bool TryRemoveTransparentIdentifier(QueryExpression query, QueryFromClause fromClause, QueryExpression innerQuery, Dictionary <string, object> letClauses) { if (!IsTransparentIdentifier(fromClause.Identifier)) { return(false); } QuerySelectClause selectClause = innerQuery.Clauses.Last() as QuerySelectClause; Match match = selectTransparentIdentifierPattern.Match(selectClause); if (!match.Success) { return(false); } // from * in (from x in ... select new { members of anonymous type }) ... // => // from x in ... { let x = ... } ... fromClause.Remove(); selectClause.Remove(); // Move clauses from innerQuery to query QueryClause insertionPos = null; foreach (var clause in innerQuery.Clauses) { query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); } foreach (var expr in match.Get <Expression>("expr")) { switch (expr) { case IdentifierExpression identifier: letClauses[identifier.Identifier] = identifier.Annotation <ILVariableResolveResult>(); break; case MemberReferenceExpression member: AddQueryLetClause(member.MemberName, member); break; case NamedExpression namedExpression: if (namedExpression.Expression is IdentifierExpression identifierExpression && namedExpression.Name == identifierExpression.Identifier) { letClauses[namedExpression.Name] = identifierExpression.Annotation <ILVariableResolveResult>(); continue; } AddQueryLetClause(namedExpression.Name, namedExpression.Expression); break; } } return(true); void AddQueryLetClause(string name, Expression expression) { QueryLetClause letClause = new QueryLetClause { Identifier = name, Expression = expression.Detach() }; var annotation = new LetIdentifierAnnotation(); letClause.AddAnnotation(annotation); letClauses[name] = annotation; query.Clauses.InsertAfter(insertionPos, letClause); } }
public DoWhileStatement TransformDoWhile(WhileStatement whileLoop) { Match m = doWhilePattern.Match(whileLoop); if (m.Success) { DoWhileStatement doLoop = new DoWhileStatement(); doLoop.Condition = new UnaryOperatorExpression(UnaryOperatorType.Not, m.Get <Expression>("condition").Single().Detach()); //doLoop.Condition.AcceptVisitor(new PushNegation(), null); BlockStatement block = (BlockStatement)whileLoop.EmbeddedStatement; block.Statements.Last().Remove(); // remove if statement doLoop.EmbeddedStatement = block.Detach(); doLoop.CopyAnnotationsFrom(whileLoop); whileLoop.ReplaceWith(doLoop); // we may have to extract variable definitions out of the loop if they were used in the condition: foreach (var varDecl in block.Statements.OfType <VariableDeclarationStatement>()) { VariableInitializer v = varDecl.Variables.Single(); if (doLoop.Condition.DescendantsAndSelf.OfType <IdentifierExpression>().Any(i => i.Identifier == v.Name)) { AssignmentExpression assign = new AssignmentExpression(new IdentifierExpression(v.Name), v.Initializer.Detach()); // move annotations from v to assign: assign.CopyAnnotationsFrom(v); v.RemoveAnnotations <object>(); // remove varDecl with assignment; and move annotations from varDecl to the ExpressionStatement: varDecl.ReplaceWith(new ExpressionStatement(assign).CopyAnnotationsFrom(varDecl)); varDecl.RemoveAnnotations <object>(); // insert the varDecl above the do-while loop: doLoop.Parent.InsertChildBefore(doLoop, varDecl, BlockStatement.StatementRole); } } return(doLoop); } return(null); }
public string CombineQuery(AstNode node, AstNode rootQuery = null) { if (rootQuery == null) { rootQuery = node; } QueryExpression query = node as QueryExpression; if (query != null) { string continuationIdentifier = null; foreach (var clause in query.Clauses) { var continuation = clause as QueryContinuationClause; if (continuation != null) { CombineQuery(continuation.PrecedingQuery); } var from = clause as QueryFromClause; if (from != null) { continuationIdentifier = CombineQuery(from.Expression, rootQuery); } } QueryFromClause fromClause = (QueryFromClause)query.Clauses.First(); QueryExpression innerQuery = fromClause.Expression as QueryExpression; if (innerQuery != null) { continuationIdentifier = continuationIdentifier ?? ((QueryFromClause)innerQuery.Clauses.First()).Identifier; string transparentIdentifier; if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery, continuationIdentifier, out transparentIdentifier)) { RemoveTransparentIdentifierReferences(rootQuery, transparentIdentifier); } else if (fromClause.Type.IsNull) { QueryContinuationClause continuation = new QueryContinuationClause(); continuation.PrecedingQuery = innerQuery.Detach(); continuation.Identifier = fromClause.Identifier; fromClause.ReplaceWith(continuation); } return(transparentIdentifier); } else { Match m = castPattern.Match(fromClause.Expression); if (m.Success) { fromClause.Type = m.Get <AstType>("targetType").Single().Detach(); fromClause.Expression = m.Get <Expression>("inExpr").Single().Detach(); } } } return(null); }
bool TryRemoveTransparentIdentifier(QueryExpression query, QueryFromClause fromClause, QueryExpression innerQuery, string continuationIdentifier, out string transparentIdentifier) { transparentIdentifier = fromClause.Identifier; Match match = selectTransparentIdentifierPattern.Match(innerQuery.Clauses.Last()); if (!match.Success) { return(false); } QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last(); Expression nae1 = match.Get <Expression>("nae1").SingleOrDefault(); string nae1Name = ExtractExpressionName(ref nae1); if (nae1Name == null) { return(false); } Expression nae2 = match.Get <Expression>("nae2").SingleOrDefault(); string nae2Name = ExtractExpressionName(ref nae2); if (nae1Name == null) { return(false); } bool introduceLetClause = true; var nae1Identifier = nae1 as IdentifierExpression; var nae2Identifier = nae2 as IdentifierExpression; if (nae1Identifier != null && nae2Identifier != null && nae1Identifier.Identifier == nae1Name && nae2Identifier.Identifier == nae2Name) { introduceLetClause = false; } if (nae1Name != continuationIdentifier) { if (nae2Name == continuationIdentifier) { //Members are in reversed order string tempName = nae1Name; Expression tempNae = nae1; nae1Name = nae2Name; nae1 = nae2; nae2Name = tempName; nae2 = tempNae; } else { return(false); } } if (introduceLetClause && innerQuery.Clauses.OfType <QueryFromClause>().Any(from => from.Identifier == nae2Name)) { return(false); } if (introduceLetClause && innerQuery.Clauses.OfType <QueryJoinClause>().Any(join => join.JoinIdentifier == nae2Name)) { return(false); } // from * in (from x in ... select new { x = x, y = expr }) ... // => // from x in ... let y = expr ... fromClause.Remove(); selectClause.Remove(); // Move clauses from innerQuery to query QueryClause insertionPos = null; foreach (var clause in innerQuery.Clauses) { query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); } if (introduceLetClause) { query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = nae2Name, Expression = nae2.Detach() }); } return(true); }
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) { var instanceCtors = typeDeclaration.Members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => thisCallPattern.Match(ctor.Body.Statements.FirstOrDefault()) == null).ToArray(); if (instanceCtorsNotChainingWithThis.Length > 0 && typeDeclaration.ClassType == NRefactory.TypeSystem.ClassType.Class) { // Recognize field initializers: // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer. bool allSame; do { Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault()); if (m == null) { break; } FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation <FieldReference>().ResolveWithinSameModule(); if (fieldDef == null) { break; } AttributedNode fieldOrEventDecl = typeDeclaration.Members.FirstOrDefault(f => f.Annotation <FieldDefinition>() == fieldDef); if (fieldOrEventDecl == null) { break; } allSame = true; for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++) { if (instanceCtors[0].Body.First().Match(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault()) == null) { allSame = false; } } if (allSame) { foreach (var ctor in instanceCtorsNotChainingWithThis) { ctor.Body.First().Remove(); } fieldOrEventDecl.GetChildrenByRole(AstNode.Roles.Variable).Single().Initializer = m.Get <Expression>("initializer").Single().Detach(); } } while (allSame); } // Now convert base constructor calls to initializers: base.VisitTypeDeclaration(typeDeclaration, data); // Remove single empty constructor: if (instanceCtors.Length == 1) { ConstructorDeclaration emptyCtor = new ConstructorDeclaration(); emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public); emptyCtor.Body = new BlockStatement(); if (emptyCtor.Match(instanceCtors[0]) != null) { instanceCtors[0].Remove(); } } // Convert static constructor into field initializers if the class is BeforeFieldInit var staticCtor = typeDeclaration.Members.OfType <ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static); if (staticCtor != null) { TypeDefinition typeDef = typeDeclaration.Annotation <TypeDefinition>(); if (typeDef != null && typeDef.IsBeforeFieldInit) { while (true) { ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement; if (es == null) { break; } AssignmentExpression assignment = es.Expression as AssignmentExpression; if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign) { break; } FieldDefinition fieldDef = assignment.Left.Annotation <FieldReference>().ResolveWithinSameModule(); if (fieldDef == null || !fieldDef.IsStatic) { break; } FieldDeclaration fieldDecl = typeDeclaration.Members.OfType <FieldDeclaration>().FirstOrDefault(f => f.Annotation <FieldDefinition>() == fieldDef); if (fieldDecl == null) { break; } fieldDecl.Variables.Single().Initializer = assignment.Right.Detach(); es.Remove(); } if (staticCtor.Body.Statements.Count == 0) { staticCtor.Remove(); } } } return(null); }
ArrayInitializerExpression ConvertMemberBindings(Expression elementsArray) { Match m = memberBindingArrayPattern.Match(elementsArray); if (!m.Success) { return(null); } ArrayInitializerExpression result = new ArrayInitializerExpression(); foreach (var binding in m.Get <Expression>("binding")) { InvocationExpression bindingInvocation = binding as InvocationExpression; if (bindingInvocation == null || bindingInvocation.Arguments.Count != 2) { return(null); } MemberReferenceExpression bindingMRE = bindingInvocation.Target as MemberReferenceExpression; if (bindingMRE == null || !expressionTypeReference.IsMatch(bindingMRE.Target)) { return(null); } Expression bindingTarget = bindingInvocation.Arguments.ElementAt(0); Expression bindingValue = bindingInvocation.Arguments.ElementAt(1); string memberName; Match m2 = getMethodFromHandlePattern.Match(bindingTarget); if (m2.Success) { IMethod setter = m2.Get <AstNode>("method").Single().Annotation <IMethod>(); if (setter == null) { return(null); } memberName = GetPropertyName(setter); } else { return(null); } Expression convertedValue; switch (bindingMRE.MemberName) { case "Bind": convertedValue = Convert(bindingValue); break; case "MemberBind": convertedValue = ConvertMemberBindings(bindingValue); break; case "ListBind": convertedValue = ConvertElementInit(bindingValue); break; default: return(null); } if (convertedValue == null) { return(null); } result.Elements.Add(new NamedExpression(memberName, convertedValue)); } return(result); }
void HandleInstanceFieldInitializers(IEnumerable <AstNode> members) { var instanceCtors = members.OfType <ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray(); if (instanceCtorsNotChainingWithThis.Length > 0) { MethodDef ctorMethodDef = instanceCtorsNotChainingWithThis[0].Annotation <MethodDef>(); if (ctorMethodDef != null && DnlibExtensions.IsValueType(ctorMethodDef.DeclaringType)) { return; } // Recognize field initializers: // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer. bool allSame; do { Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault()); if (!m.Success) { break; } FieldDef fieldDef = m.Get <AstNode>("fieldAccess").Single().Annotation <IField>().ResolveFieldWithinSameModule(); if (fieldDef == null) { break; } AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation <FieldDef>() == fieldDef); if (fieldOrEventDecl == null) { break; } Expression initializer = m.Get <Expression>("initializer").Single(); // 'this'/'base' cannot be used in field initializers if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression)) { break; } allSame = true; for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++) { if (!instanceCtors[0].Body.First().IsMatch(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault())) { allSame = false; break; } } if (allSame) { var ctorIlRanges = new List <Tuple <MemberMapping, List <ILRange> > >(instanceCtorsNotChainingWithThis.Length); for (int i = 0; i < instanceCtorsNotChainingWithThis.Length; i++) { var ctor = instanceCtorsNotChainingWithThis[i]; var stmt = ctor.Body.First(); stmt.Remove(); var mm = ctor.Annotation <MemberMapping>() ?? ctor.Body.Annotation <MemberMapping>(); Debug.Assert(mm != null); if (mm != null) { ctorIlRanges.Add(Tuple.Create(mm, stmt.GetAllRecursiveILRanges())); } } var varInit = fieldOrEventDecl.GetChildrenByRole(Roles.Variable).Single(); initializer.Remove(); initializer.RemoveAllILRangesRecursive(); varInit.Initializer = initializer; fieldOrEventDecl.AddAnnotation(ctorIlRanges); } } while (allSame); } }
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; } TypeDef type = variable.Type.ToTypeDefOrRef().ResolveWithinSameModule(); if (!IsPotentialClosure(context, type)) { continue; } if (displayClassAssignmentMatch.Get <AstType>("type").Single().Annotation <ITypeDefOrRef>().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 <IField>() != null && identExpr.Parent.Annotation <IField>().IsField)) { ok = false; } } } if (!ok) { continue; } Dictionary <IField, AstNode> dict = new Dictionary <IField, AstNode>(); // Delete the variable declaration statement: VariableDeclarationStatement displayClassVarDecl = PatternStatementTransform.FindVariableDeclaration(stmt, variable.Name); if (displayClassVarDecl != null) { displayClassVarDecl.Remove(); //TODO: Save ILRanges } // Delete the assignment statement: AstNode cur = stmt.NextSibling; stmt.Remove(); //TODO: Save ILRanges // 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 = IdentifierExpression.Create(variable.Name, variable.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local), MemberName = Pattern.AnyString }), new AnyNode("right") ) ); Match m = closureFieldAssignmentPattern.Match(cur); if (m.Success) { FieldDef fieldDef = m.Get <MemberReferenceExpression>("left").Single().Annotation <IField>().ResolveFieldWithinSameModule(); 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.ToTypeDefOrRef().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 FieldDef fieldDef2 = mre.Annotation <FieldDef>().ResolveFieldWithinSameModule(); if (fieldDef2 == null || !IsPotentialClosure(context, fieldDef2.FieldType.ToTypeDefOrRef().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) { if (fieldDef != null) { dict[fieldDef] = right; } cur.Remove(); //TODO: Save ILRanges } 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, ILVariable> > variablesToDeclare = new List <Tuple <AstType, ILVariable> >(); foreach (FieldDef 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 { GeneratedByDecompiler = true, Name = capturedVariableName, Type = field.FieldType, }; variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, stringBuilder, field), ilVar)); dict[field] = IdentifierExpression.Create(capturedVariableName, TextTokenKind.Local).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) { MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent; AstNode replacement; var fieldDef = mre.Annotation <IField>().ResolveFieldWithinSameModule(); if (fieldDef != null && dict.TryGetValue(fieldDef, out replacement)) { var newReplacement = replacement.Clone(); newReplacement.AddAnnotation(mre.GetAllRecursiveILRanges()); mre.ReplaceWith(newReplacement); } } } // 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.Item2.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local, tuple.Item1, tuple.Item2.Name); newVarDecl.Variables.Single().AddAnnotation(CapturedVariableAnnotation.Instance); newVarDecl.Variables.Single().AddAnnotation(tuple.Item2); blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl); } } currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock); return(null); }
public override bool DoMatch(INode other, Match match) { return match.Get(referencedGroupName).Last().IsMatch(other); }
public static Pair GetPair(this Match source, int first) => new Pair(source.Get(first).AsInt(), source.Get(first + 1).AsInt());
public static Field MakeField(Match m) => new Field(m.Get(1), m.GetPair(2), m.GetPair(4));
private QueryExpression DecompileQuery(InvocationExpression invocation) { if (invocation == null) { return(null); } MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression; if (mre == null) { return(null); } switch (mre.MemberName) { case "Select": { if (invocation.Arguments.Count != 1) { return(null); } string parameterName; Expression body; if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body)) { QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = ExtractQuery(mre) }); query.Clauses.Add(new QuerySelectClause { Expression = body.Detach() }); return(query); } return(null); } case "Cast": { if (invocation.Arguments.Count == 0 && mre.TypeArguments.Count == 1) { var typeArgument = mre.TypeArguments.First(); QueryExpression query = new QueryExpression(); string varName = GenerateVariableName(); query.Clauses.Add(new QueryFromClause { Identifier = varName, Expression = ExtractQuery(mre), Type = typeArgument.Detach() }); return(query); } return(null); } case "GroupBy": { if (invocation.Arguments.Count == 2) { string parameterName1, parameterName2; Expression keySelector, elementSelector; if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName1, out keySelector) && MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameterName2, out elementSelector) && parameterName1 == parameterName2) { QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName1, Expression = ExtractQuery(mre) }); query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() }); return(query); } } else if (invocation.Arguments.Count == 1) { string parameterName; Expression keySelector; if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out keySelector)) { QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = ExtractQuery(mre) }); query.Clauses.Add(new QueryGroupClause { Projection = new IdentifierExpression(parameterName), Key = keySelector.Detach() }); return(query); } } return(null); } case "SelectMany": { if (invocation.Arguments.Count != 2) { return(null); } string parameterName; Expression collectionSelector; if (!MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName, out collectionSelector)) { return(null); } LambdaExpression lambda = invocation.Arguments.ElementAt(1) as LambdaExpression; if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) { ParameterDeclaration p1 = lambda.Parameters.ElementAt(0); ParameterDeclaration p2 = lambda.Parameters.ElementAt(1); QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = p1.Name, Expression = ExtractQuery(mre) }); query.Clauses.Add(new QueryFromClause { Identifier = p2.Name, Expression = collectionSelector.Detach() }); query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() }); return(query); } return(null); } case "Where": { if (invocation.Arguments.Count != 1) { return(null); } string parameterName; Expression body; if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body)) { QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = ExtractQuery(mre) }); query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() }); return(query); } return(null); } case "OrderBy": case "OrderByDescending": case "ThenBy": case "ThenByDescending": { if (invocation.Arguments.Count != 1) { return(null); } string parameterName; Expression orderExpression; if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out orderExpression)) { if (ValidateThenByChain(invocation, parameterName)) { QueryOrderClause orderClause = new QueryOrderClause(); InvocationExpression tmp = invocation; while (mre.MemberName == "ThenBy" || mre.MemberName == "ThenByDescending") { // insert new ordering at beginning orderClause.Orderings.InsertAfter( null, new QueryOrdering { Expression = orderExpression.Detach(), Direction = (mre.MemberName == "ThenBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending) }); tmp = (InvocationExpression)mre.Target; mre = (MemberReferenceExpression)tmp.Target; MatchSimpleLambda(tmp.Arguments.Single(), out parameterName, out orderExpression); } // insert new ordering at beginning orderClause.Orderings.InsertAfter( null, new QueryOrdering { Expression = orderExpression.Detach(), Direction = (mre.MemberName == "OrderBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending) }); QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = ExtractQuery(mre) }); query.Clauses.Add(orderClause); return(query); } } return(null); } case "Join": case "GroupJoin": { if (invocation.Arguments.Count != 4) { return(null); } Expression source1 = mre.Target; Expression source2 = invocation.Arguments.ElementAt(0); string elementName1, elementName2; Expression key1, key2; if (!MatchSimpleLambda(invocation.Arguments.ElementAt(1), out elementName1, out key1)) { return(null); } if (!MatchSimpleLambda(invocation.Arguments.ElementAt(2), out elementName2, out key2)) { return(null); } LambdaExpression lambda = invocation.Arguments.ElementAt(3) as LambdaExpression; if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) { ParameterDeclaration p1 = lambda.Parameters.ElementAt(0); ParameterDeclaration p2 = lambda.Parameters.ElementAt(1); QueryExpression query = new QueryExpression(); query.Clauses.Add(new QueryFromClause { Identifier = elementName1, Expression = source1.Detach() }); QueryJoinClause joinClause = new QueryJoinClause(); joinClause.JoinIdentifier = elementName2; // join elementName2 joinClause.InExpression = source2.Detach(); // in source2 Match castMatch = castPattern.Match(source2); if (castMatch.Success) { Expression target = castMatch.Get <Expression>("inExpr").Single().Detach(); joinClause.Type = castMatch.Get <AstType>("targetType").Single().Detach(); joinClause.InExpression = target; } joinClause.OnExpression = key1.Detach(); // on key1 joinClause.EqualsExpression = key2.Detach(); // equals key2 if (mre.MemberName == "GroupJoin") { joinClause.IntoIdentifier = p2.Name; // into p2.Name } query.Clauses.Add(joinClause); Expression resultExpr = ((Expression)lambda.Body).Detach(); if (p1.Name != elementName1) { foreach (var identifier in resultExpr.Descendants.OfType <Identifier>().Where(id => id.Name == p1.Name)) { identifier.Name = elementName1; } } if (p2.Name != elementName2 && mre.MemberName != "GroupJoin") { foreach (var identifier in resultExpr.Descendants.OfType <Identifier>().Where(id => id.Name == p2.Name)) { identifier.Name = elementName2; } } query.Clauses.Add(new QuerySelectClause { Expression = resultExpr }); return(query); } return(null); } default: return(null); } }
void AddIssue(AstNode invocationExpression, Match match, bool negate = false) { AddIssue(new CodeIssue( invocationExpression, ctx.TranslateString("Use 'is' operator"), ctx.TranslateString("Replace with 'is' operator"), s => { Expression expression = new IsExpression(CSharpUtil.AddParensForUnaryExpressionIfRequired(match.Get <Expression>("object").Single().Clone()), match.Get <AstType>("Type").Single().Clone()); if (negate) { expression = new UnaryOperatorExpression(UnaryOperatorType.Not, new ParenthesizedExpression(expression)); } s.Replace(invocationExpression, expression); } )); }
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); }
public static ShipAction ToData(Match m) => new ShipAction(m.Get(1)[0], m.Get(2).AsInt());