public override List<Change> PerformChanges (RefactoringOptions options, object prop) { List<Change> result = new List<Change> (); ExtractMethodParameters param = (ExtractMethodParameters)prop; TextEditorData data = options.GetTextEditorData (); INRefactoryASTProvider provider = options.GetASTProvider (); IResolver resolver = options.GetResolver (); ICSharpCode.NRefactory.Ast.INode node = Analyze (options, param, false); if (param.VariablesToGenerate.Count > 0) { TextReplaceChange varGen = new TextReplaceChange (); varGen.Description = GettextCatalog.GetString ("Generate some temporary variables"); varGen.FileName = options.Document.FileName; LineSegment line = data.Document.GetLine (Math.Max (0, data.Document.OffsetToLineNumber (data.SelectionRange.Offset) - 1)); varGen.Offset = line.Offset + line.EditableLength; varGen.InsertedText = Environment.NewLine + options.GetWhitespaces (line.Offset); foreach (VariableDescriptor var in param.VariablesToGenerate) { TypeReference tr = options.ShortenTypeName (var.ReturnType).ConvertToTypeReference (); varGen.InsertedText += provider.OutputNode (options.Dom, new LocalVariableDeclaration (new VariableDeclaration (var.Name, null, tr))).Trim (); } result.Add (varGen); } InvocationExpression invocation = new InvocationExpression (new IdentifierExpression (param.Name)); foreach (VariableDescriptor var in param.Parameters) { if (!param.OneChangedVariable && param.ChangedVariables.Contains (var.Name)) { FieldDirection fieldDirection = FieldDirection.Ref; VariableDescriptor outsideVar = null; if (param.VariablesOutside.TryGetValue (var.Name, out outsideVar) && (var.GetsAssigned || param.VariablesToGenerate.Where (v => v.Name == var.Name).Any ())) { if (!outsideVar.GetsAssigned) fieldDirection = FieldDirection.Out; } invocation.Arguments.Add (new DirectionExpression (fieldDirection, new IdentifierExpression (var.Name))); } else { invocation.Arguments.Add (new IdentifierExpression (var.Name)); } } // string mimeType = DesktopService.GetMimeTypeForUri (options.Document.FileName); TypeReference returnType = new TypeReference ("System.Void", true); ICSharpCode.NRefactory.Ast.INode outputNode; if (param.OneChangedVariable) { string name = param.ChangedVariables.First (); returnType = options.ShortenTypeName (param.Variables.Find (v => v.Name == name).ReturnType).ConvertToTypeReference (); if (param.OutsideVariableList.Any (v => v.Name == name && !v.IsDefined)) { LocalVariableDeclaration varDecl = new LocalVariableDeclaration (returnType); varDecl.Variables.Add (new VariableDeclaration (name, invocation)); outputNode = varDecl; } else { outputNode = new ExpressionStatement (new AssignmentExpression (new IdentifierExpression (name), ICSharpCode.NRefactory.Ast.AssignmentOperatorType.Assign, invocation)); } } else { outputNode = node is BlockStatement ? (ICSharpCode.NRefactory.Ast.INode)new ExpressionStatement (invocation) : invocation; } TextReplaceChange replacement = new TextReplaceChange (); replacement.Description = string.Format (GettextCatalog.GetString ("Substitute selected statement(s) with call to {0}"), param.Name); replacement.FileName = options.Document.FileName; replacement.Offset = options.Document.Editor.SelectionRange.Offset; replacement.RemovedChars = options.Document.Editor.SelectionRange.Length; replacement.MoveCaretToReplace = true; LineSegment line1 = data.Document.GetLineByOffset (options.Document.Editor.SelectionRange.EndOffset); if (options.Document.Editor.SelectionRange.EndOffset == line1.Offset) { if (line1.Offset > 0) { LineSegment line2 = data.Document.GetLineByOffset (line1.Offset - 1); replacement.RemovedChars -= line2.DelimiterLength; } } replacement.InsertedText = options.GetWhitespaces (options.Document.Editor.SelectionRange.Offset) + provider.OutputNode (options.Dom, outputNode).Trim (); result.Add (replacement); TextReplaceChange insertNewMethod = new TextReplaceChange (); insertNewMethod.FileName = options.Document.FileName; insertNewMethod.Description = string.Format (GettextCatalog.GetString ("Create new method {0} from selected statement(s)"), param.Name); insertNewMethod.RemovedChars = param.InsertionPoint.LineBefore == NewLineInsertion.Eol ? 0 : param.InsertionPoint.Location.Column; insertNewMethod.Offset = data.Document.LocationToOffset (param.InsertionPoint.Location) - insertNewMethod.RemovedChars; ExtractMethodAstTransformer transformer = new ExtractMethodAstTransformer (param.VariablesToGenerate); node.AcceptVisitor (transformer, null); if (!param.OneChangedVariable && node is Expression) { ResolveResult resolveResult = resolver.Resolve (new ExpressionResult ("(" + provider.OutputNode (options.Dom, node) + ")"), new DomLocation (options.Document.Editor.Caret.Line, options.Document.Editor.Caret.Column)); if (resolveResult.ResolvedType != null) returnType = options.ShortenTypeName (resolveResult.ResolvedType).ConvertToTypeReference (); } MethodDeclaration methodDecl = new MethodDeclaration (); methodDecl.Name = param.Name; methodDecl.Modifier = param.Modifiers; methodDecl.TypeReference = returnType; if (!param.ReferencesMember) methodDecl.Modifier |= ICSharpCode.NRefactory.Ast.Modifiers.Static; if (node is BlockStatement) { methodDecl.Body = new BlockStatement (); methodDecl.Body.AddChild (new EmptyStatement ()); if (param.OneChangedVariable) methodDecl.Body.AddChild (new ReturnStatement (new IdentifierExpression (param.ChangedVariables.First ()))); } else if (node is Expression) { methodDecl.Body = new BlockStatement (); methodDecl.Body.AddChild (new ReturnStatement (node as Expression)); } foreach (VariableDescriptor var in param.VariablesToDefine) { BlockStatement block = methodDecl.Body; LocalVariableDeclaration varDecl = new LocalVariableDeclaration (options.ShortenTypeName (var.ReturnType).ConvertToTypeReference ()); varDecl.Variables.Add (new VariableDeclaration (var.Name)); block.Children.Insert (0, varDecl); } foreach (VariableDescriptor var in param.Parameters) { TypeReference typeReference = options.ShortenTypeName (var.ReturnType).ConvertToTypeReference (); ParameterDeclarationExpression pde = new ParameterDeclarationExpression (typeReference, var.Name); if (!param.OneChangedVariable) { if (param.ChangedVariables.Contains (var.Name)) pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Ref; if (param.VariablesToGenerate.Where (v => v.Name == var.Name).Any ()) { pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out; } VariableDescriptor outsideVar = null; if (var.GetsAssigned && param.VariablesOutside.TryGetValue (var.Name, out outsideVar)) { if (!outsideVar.GetsAssigned) pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out; } } methodDecl.Parameters.Add (pde); } string indent = options.GetIndent (param.DeclaringMember); StringBuilder methodText = new StringBuilder (); switch (param.InsertionPoint.LineBefore) { case NewLineInsertion.Eol: methodText.AppendLine (); break; case NewLineInsertion.BlankLine: methodText.Append (indent); methodText.AppendLine (); break; } if (param.GenerateComment) { methodText.Append (indent); methodText.AppendLine ("/// <summary>"); methodText.Append (indent); methodText.AppendLine ("/// TODO: write a comment."); methodText.Append (indent); methodText.AppendLine ("/// </summary>"); Ambience ambience = AmbienceService.GetAmbienceForFile (options.Document.FileName); foreach (ParameterDeclarationExpression pde in methodDecl.Parameters) { methodText.Append (indent); methodText.Append ("/// <param name=\""); methodText.Append (pde.ParameterName); methodText.Append ("\"> A "); methodText.Append (ambience.GetString (pde.TypeReference.ConvertToReturnType (), OutputFlags.IncludeGenerics | OutputFlags.UseFullName)); methodText.Append (" </param>"); methodText.AppendLine (); } if (methodDecl.TypeReference.Type != "System.Void") { methodText.Append (indent); methodText.AppendLine ("/// <returns>"); methodText.Append (indent); methodText.Append ("/// A "); methodText.AppendLine (ambience.GetString (methodDecl.TypeReference.ConvertToReturnType (), OutputFlags.IncludeGenerics | OutputFlags.UseFullName)); methodText.Append (indent); methodText.AppendLine ("/// </returns>"); } } methodText.Append (indent); if (node is BlockStatement) { string text = provider.OutputNode (options.Dom, methodDecl, indent).Trim (); int emptyStatementMarker = text.LastIndexOf (';'); if (param.OneChangedVariable) emptyStatementMarker = text.LastIndexOf (';', emptyStatementMarker - 1); StringBuilder sb = new StringBuilder (); sb.Append (text.Substring (0, emptyStatementMarker)); sb.Append (AddIndent (param.Text, indent + "\t")); sb.Append (text.Substring (emptyStatementMarker + 1)); methodText.Append (sb.ToString ()); } else { methodText.Append (provider.OutputNode (options.Dom, methodDecl, options.GetIndent (param.DeclaringMember)).Trim ()); } switch (param.InsertionPoint.LineAfter) { case NewLineInsertion.Eol: methodText.AppendLine (); break; case NewLineInsertion.BlankLine: methodText.AppendLine (); methodText.AppendLine (); methodText.Append (indent); break; } insertNewMethod.InsertedText = methodText.ToString (); result.Add (insertNewMethod); return result; }
public override List <Change> PerformChanges(RefactoringOptions options, object prop) { List <Change> result = new List <Change> (); ExtractMethodParameters param = (ExtractMethodParameters)prop; TextEditorData data = options.GetTextEditorData(); INRefactoryASTProvider provider = options.GetASTProvider(); IResolver resolver = options.GetResolver(); ICSharpCode.NRefactory.Ast.INode node = Analyze(options, param, false); if (param.VariablesToGenerate.Count > 0) { TextReplaceChange varGen = new TextReplaceChange(); varGen.Description = GettextCatalog.GetString("Generate some temporary variables"); varGen.FileName = options.Document.FileName; LineSegment line = data.Document.GetLine(Math.Max(0, data.Document.OffsetToLineNumber(data.SelectionRange.Offset) - 1)); varGen.Offset = line.Offset + line.EditableLength; varGen.InsertedText = Environment.NewLine + options.GetWhitespaces(line.Offset); foreach (VariableDescriptor var in param.VariablesToGenerate) { TypeReference tr = options.ShortenTypeName(var.ReturnType).ConvertToTypeReference(); varGen.InsertedText += provider.OutputNode(options.Dom, new LocalVariableDeclaration(new VariableDeclaration(var.Name, null, tr))).Trim(); } result.Add(varGen); } InvocationExpression invocation = new InvocationExpression(new IdentifierExpression(param.Name)); foreach (VariableDescriptor var in param.Parameters) { if (!param.OneChangedVariable && param.ChangedVariables.Contains(var.Name)) { FieldDirection fieldDirection = FieldDirection.Ref; VariableDescriptor outsideVar = null; if (param.VariablesOutside.TryGetValue(var.Name, out outsideVar) && (var.GetsAssigned || param.VariablesToGenerate.Where(v => v.Name == var.Name).Any())) { if (!outsideVar.GetsAssigned) { fieldDirection = FieldDirection.Out; } } invocation.Arguments.Add(new DirectionExpression(fieldDirection, new IdentifierExpression(var.Name))); } else { invocation.Arguments.Add(new IdentifierExpression(var.Name)); } } // string mimeType = DesktopService.GetMimeTypeForUri (options.Document.FileName); TypeReference returnType = new TypeReference("System.Void", true); ICSharpCode.NRefactory.Ast.INode outputNode; if (param.OneChangedVariable) { string name = param.ChangedVariables.First(); returnType = options.ShortenTypeName(param.Variables.Find(v => v.Name == name).ReturnType).ConvertToTypeReference(); if (param.OutsideVariableList.Any(v => v.Name == name && !v.IsDefined)) { LocalVariableDeclaration varDecl = new LocalVariableDeclaration(returnType); varDecl.Variables.Add(new VariableDeclaration(name, invocation)); outputNode = varDecl; } else { outputNode = new ExpressionStatement(new AssignmentExpression(new IdentifierExpression(name), ICSharpCode.NRefactory.Ast.AssignmentOperatorType.Assign, invocation)); } } else { outputNode = node is BlockStatement ? (ICSharpCode.NRefactory.Ast.INode) new ExpressionStatement(invocation) : invocation; } TextReplaceChange replacement = new TextReplaceChange(); replacement.Description = string.Format(GettextCatalog.GetString("Substitute selected statement(s) with call to {0}"), param.Name); replacement.FileName = options.Document.FileName; replacement.Offset = options.Document.TextEditor.SelectionStartPosition; replacement.RemovedChars = options.Document.TextEditor.SelectionEndPosition - options.Document.TextEditor.SelectionStartPosition; replacement.MoveCaretToReplace = true; LineSegment line1 = data.Document.GetLineByOffset(options.Document.TextEditor.SelectionEndPosition); if (options.Document.TextEditor.SelectionEndPosition == line1.Offset) { if (line1.Offset > 0) { LineSegment line2 = data.Document.GetLineByOffset(line1.Offset - 1); replacement.RemovedChars -= line2.DelimiterLength; } } replacement.InsertedText = options.GetWhitespaces(options.Document.TextEditor.SelectionStartPosition) + provider.OutputNode(options.Dom, outputNode).Trim(); result.Add(replacement); TextReplaceChange insertNewMethod = new TextReplaceChange(); insertNewMethod.FileName = options.Document.FileName; insertNewMethod.Description = string.Format(GettextCatalog.GetString("Create new method {0} from selected statement(s)"), param.Name); insertNewMethod.RemovedChars = param.InsertionPoint.LineBefore == NewLineInsertion.Eol ? 0 : param.InsertionPoint.Location.Column; insertNewMethod.Offset = data.Document.LocationToOffset(param.InsertionPoint.Location) - insertNewMethod.RemovedChars; ExtractMethodAstTransformer transformer = new ExtractMethodAstTransformer(param.VariablesToGenerate); node.AcceptVisitor(transformer, null); if (!param.OneChangedVariable && node is Expression) { ResolveResult resolveResult = resolver.Resolve(new ExpressionResult("(" + provider.OutputNode(options.Dom, node) + ")"), new DomLocation(options.Document.TextEditor.CursorLine, options.Document.TextEditor.CursorColumn)); if (resolveResult.ResolvedType != null) { returnType = options.ShortenTypeName(resolveResult.ResolvedType).ConvertToTypeReference(); } } MethodDeclaration methodDecl = new MethodDeclaration(); methodDecl.Name = param.Name; methodDecl.Modifier = param.Modifiers; methodDecl.TypeReference = returnType; if (!param.ReferencesMember) { methodDecl.Modifier |= ICSharpCode.NRefactory.Ast.Modifiers.Static; } if (node is BlockStatement) { methodDecl.Body = new BlockStatement(); methodDecl.Body.AddChild(new EmptyStatement()); if (param.OneChangedVariable) { methodDecl.Body.AddChild(new ReturnStatement(new IdentifierExpression(param.ChangedVariables.First()))); } } else if (node is Expression) { methodDecl.Body = new BlockStatement(); methodDecl.Body.AddChild(new ReturnStatement(node as Expression)); } foreach (VariableDescriptor var in param.VariablesToDefine) { BlockStatement block = methodDecl.Body; LocalVariableDeclaration varDecl = new LocalVariableDeclaration(options.ShortenTypeName(var.ReturnType).ConvertToTypeReference()); varDecl.Variables.Add(new VariableDeclaration(var.Name)); block.Children.Insert(0, varDecl); } foreach (VariableDescriptor var in param.Parameters) { TypeReference typeReference = options.ShortenTypeName(var.ReturnType).ConvertToTypeReference(); ParameterDeclarationExpression pde = new ParameterDeclarationExpression(typeReference, var.Name); if (!param.OneChangedVariable) { if (param.ChangedVariables.Contains(var.Name)) { pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Ref; } if (param.VariablesToGenerate.Where(v => v.Name == var.Name).Any()) { pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out; } VariableDescriptor outsideVar = null; if (var.GetsAssigned && param.VariablesOutside.TryGetValue(var.Name, out outsideVar)) { if (!outsideVar.GetsAssigned) { pde.ParamModifier = ICSharpCode.NRefactory.Ast.ParameterModifiers.Out; } } } methodDecl.Parameters.Add(pde); } string indent = options.GetIndent(param.DeclaringMember); StringBuilder methodText = new StringBuilder(); switch (param.InsertionPoint.LineBefore) { case NewLineInsertion.Eol: methodText.AppendLine(); break; case NewLineInsertion.BlankLine: methodText.Append(indent); methodText.AppendLine(); break; } if (param.GenerateComment) { methodText.Append(indent); methodText.AppendLine("/// <summary>"); methodText.Append(indent); methodText.AppendLine("/// TODO: write a comment."); methodText.Append(indent); methodText.AppendLine("/// </summary>"); Ambience ambience = AmbienceService.GetAmbienceForFile(options.Document.FileName); foreach (ParameterDeclarationExpression pde in methodDecl.Parameters) { methodText.Append(indent); methodText.Append("/// <param name=\""); methodText.Append(pde.ParameterName); methodText.Append("\"> A "); methodText.Append(ambience.GetString(pde.TypeReference.ConvertToReturnType(), OutputFlags.IncludeGenerics | OutputFlags.UseFullName)); methodText.Append(" </param>"); methodText.AppendLine(); } if (methodDecl.TypeReference.Type != "System.Void") { methodText.Append(indent); methodText.AppendLine("/// <returns>"); methodText.Append(indent); methodText.Append("/// A "); methodText.AppendLine(ambience.GetString(methodDecl.TypeReference.ConvertToReturnType(), OutputFlags.IncludeGenerics | OutputFlags.UseFullName)); methodText.Append(indent); methodText.AppendLine("/// </returns>"); } } methodText.Append(indent); if (node is BlockStatement) { string text = provider.OutputNode(options.Dom, methodDecl, indent).Trim(); int emptyStatementMarker = text.LastIndexOf(';'); if (param.OneChangedVariable) { emptyStatementMarker = text.LastIndexOf(';', emptyStatementMarker - 1); } StringBuilder sb = new StringBuilder(); sb.Append(text.Substring(0, emptyStatementMarker)); sb.Append(AddIndent(param.Text, indent + "\t")); sb.Append(text.Substring(emptyStatementMarker + 1)); methodText.Append(sb.ToString()); } else { methodText.Append(provider.OutputNode(options.Dom, methodDecl, options.GetIndent(param.DeclaringMember)).Trim()); } switch (param.InsertionPoint.LineAfter) { case NewLineInsertion.Eol: methodText.AppendLine(); break; case NewLineInsertion.BlankLine: methodText.AppendLine(); methodText.AppendLine(); methodText.Append(indent); break; } insertNewMethod.InsertedText = methodText.ToString(); result.Add(insertNewMethod); return(result); }