public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) { ExpressionStatement stmt = constructorDeclaration.Body.Statements.FirstOrDefault() as ExpressionStatement; if (stmt == null) { return(null); } InvocationExpression invocation = stmt.Expression as InvocationExpression; if (invocation == null) { return(null); } MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression; if (mre != null && mre.MemberName == ".ctor") { ConstructorInitializer ci = new ConstructorInitializer(); if (mre.Target is ThisReferenceExpression) { ci.ConstructorInitializerType = ConstructorInitializerType.This; } else if (mre.Target is BaseReferenceExpression) { ci.ConstructorInitializerType = ConstructorInitializerType.Base; } else { return(null); } // Move arguments from invocation to initializer: invocation.Arguments.MoveTo(ci.Arguments); var ilRanges = stmt.GetAllRecursiveILRanges(); // Add the initializer: (unless it is the default 'base()') if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0)) { constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation <IMethod>()); ci.AddAnnotation(ilRanges); } else { constructorDeclaration.Body.HiddenStart = NRefactoryExtensions.CreateHidden(ilRanges, constructorDeclaration.Body.HiddenStart); } // Remove the statement: stmt.Remove(); } return(null); }
public void Run(AstNode node) { Run(node, null); // Declare all the variables at the end, after all the logic has run. // This is done so that definite assignment analysis can work on a single representation and doesn't have to be updated // when we change the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment == null) { BlockStatement block = (BlockStatement)v.InsertionPoint.Parent; var decl = new VariableDeclarationStatement(v.ILVariable != null && v.ILVariable.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local, (AstType)v.Type.Clone(), v.Name); if (v.ILVariable != null) { decl.Variables.Single().AddAnnotation(v.ILVariable); } block.Statements.InsertBefore( v.InsertionPoint, decl); } } // First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST. foreach (var v in variablesToDeclare) { if (v.ReplacedAssignment != null) { // We clone the right expression so that it doesn't get removed from the old ExpressionStatement, // which might be still in use by the definite assignment graph. VariableInitializer initializer = new VariableInitializer(v.ILVariable != null && v.ILVariable.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local, v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment).WithAnnotation(v.ILVariable); VariableDeclarationStatement varDecl = new VariableDeclarationStatement { Type = (AstType)v.Type.Clone(), Variables = { initializer } }; ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement; if (es != null) { // Note: if this crashes with 'Cannot replace the root node', check whether two variables were assigned the same name es.ReplaceWith(varDecl.CopyAnnotationsFrom(es)); varDecl.AddAnnotation(es.GetAllRecursiveILRanges()); } else { varDecl.AddAnnotation(v.ReplacedAssignment.GetAllRecursiveILRanges()); v.ReplacedAssignment.ReplaceWith(varDecl); } } } variablesToDeclare.Clear(); }