Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3330 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
9 changed files with 639 additions and 453 deletions
@ -0,0 +1,171 @@
@@ -0,0 +1,171 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision: 3287 $</version>
|
||||
// </file>
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.NRefactory; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.PrettyPrinter; |
||||
using ICSharpCode.NRefactory.Visitors; |
||||
using ICSharpCode.TextEditor.Document; |
||||
using SharpRefactoring.Transformers; |
||||
using SharpRefactoring.Visitors; |
||||
|
||||
namespace SharpRefactoring |
||||
{ |
||||
public class CSharpMethodExtractor : MethodExtractorBase |
||||
{ |
||||
public CSharpMethodExtractor(ICSharpCode.TextEditor.TextEditorControl textEditor, ISelection selection) |
||||
: base(textEditor, selection, new CSharpOutputVisitor()) |
||||
{ |
||||
} |
||||
|
||||
protected override string GenerateCode(INode unit, bool installSpecials) |
||||
{ |
||||
CSharpOutputVisitor visitor = new CSharpOutputVisitor(); |
||||
|
||||
if (installSpecials) { |
||||
SpecialNodesInserter.Install(this.specialsList, visitor); |
||||
} |
||||
|
||||
unit.AcceptVisitor(visitor, null); |
||||
return visitor.Text; |
||||
} |
||||
|
||||
public override bool Extract() |
||||
{ |
||||
using (IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader("class Tmp { void Test() {\n " + this.currentSelection.SelectedText + "\n}}"))) { |
||||
parser.Parse(); |
||||
|
||||
if (parser.Errors.Count > 0) { |
||||
MessageService.ShowError("Errors occured during parsing! Cannot extract a new method!"); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
this.specialsList = parser.Lexer.SpecialTracker.RetrieveSpecials(); |
||||
} |
||||
|
||||
MethodDeclaration newMethod = new MethodDeclaration(); |
||||
|
||||
List<VariableDeclaration> possibleReturnValues = new List<VariableDeclaration>(); |
||||
|
||||
List<VariableDeclaration> otherReturnValues = new List<VariableDeclaration>(); |
||||
|
||||
// Initialise new method
|
||||
newMethod.Body = GetBlock(this.currentSelection.SelectedText); |
||||
newMethod.Body.StartLocation = new Location(0,0); |
||||
|
||||
this.parentNode = GetParentMember(this.currentSelection.StartPosition.Line, this.currentSelection.StartPosition.Column, this.currentSelection.EndPosition.Line, this.currentSelection.EndPosition.Column); |
||||
|
||||
if (parentNode == null) { |
||||
MessageService.ShowError("Invalid selection! Please select a valid range."); |
||||
return false; |
||||
} |
||||
|
||||
if (!CheckForJumpInstructions(newMethod, this.currentSelection)) |
||||
return false; |
||||
|
||||
newMethod.Modifier = parentNode.Modifier; |
||||
|
||||
newMethod.Modifier &= ~(Modifiers.Internal | Modifiers.Protected | Modifiers.Private | Modifiers.Public); |
||||
|
||||
foreach (ParameterDeclarationExpression pde in parentNode.Parameters) |
||||
{ |
||||
FindReferenceVisitor frv = new FindReferenceVisitor(true, pde.ParameterName, newMethod.Body.StartLocation, newMethod.Body.EndLocation); |
||||
|
||||
newMethod.AcceptVisitor(frv, null); |
||||
|
||||
if (frv.Identifiers.Count > 0) { |
||||
bool isIn = true; |
||||
foreach (IdentifierExpression identifier in frv.Identifiers) { |
||||
if (!IsInSel(identifier.StartLocation, this.currentSelection)) |
||||
isIn = false; |
||||
} |
||||
|
||||
if (isIn) { |
||||
possibleReturnValues.Add(new VariableDeclaration(pde.ParameterName, null, pde.TypeReference)); |
||||
} |
||||
|
||||
bool hasOccurrences = HasOccurrencesAfter(true, parentNode, new Location(this.currentSelection.EndPosition.Column + 1, this.currentSelection.EndPosition.Line + 1), pde.ParameterName, newMethod.Body.StartLocation, newMethod.Body.EndLocation); |
||||
if (hasOccurrences) |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(pde.TypeReference, pde.ParameterName, ParameterModifiers.Ref)); |
||||
else |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(pde.TypeReference, pde.ParameterName, pde.ParamModifier)); |
||||
} |
||||
} |
||||
|
||||
LookupTableVisitor ltv = new LookupTableVisitor(SupportedLanguage.CSharp); |
||||
|
||||
parentNode.AcceptVisitor(ltv, null); |
||||
|
||||
foreach (KeyValuePair<string, List<LocalLookupVariable>> pair in ltv.Variables) { |
||||
foreach (LocalLookupVariable variable in pair.Value) { |
||||
if (IsInSel(variable.StartPos, this.currentSelection) && HasOccurrencesAfter(true, this.parentNode, new Location(this.currentSelection.EndPosition.Column + 1, this.currentSelection.EndPosition.Line + 1), variable.Name, variable.StartPos, variable.EndPos)) { |
||||
possibleReturnValues.Add(new VariableDeclaration(variable.Name, variable.Initializer, variable.TypeRef)); |
||||
otherReturnValues.Add(new VariableDeclaration(variable.Name, variable.Initializer, variable.TypeRef)); |
||||
} |
||||
|
||||
FindReferenceVisitor frv = new FindReferenceVisitor(true, variable.Name, variable.StartPos, variable.EndPos); |
||||
|
||||
parentNode.AcceptVisitor(frv, null); |
||||
|
||||
if ((frv.Identifiers.Count > 0) && (!(IsInSel(variable.StartPos, this.currentSelection) || IsInSel(variable.EndPos, this.currentSelection)))) { |
||||
bool hasOccurrences = HasOccurrencesAfter(true, this.parentNode, new Location(this.currentSelection.EndPosition.Column + 1, this.currentSelection.EndPosition.Line + 1), variable.Name, variable.StartPos, variable.EndPos); |
||||
bool isInitialized = IsInitializedVariable(true, this.parentNode, variable); |
||||
bool hasAssignment = HasAssignment(newMethod, variable); |
||||
bool getsAssigned = pair.Value.Count > 0; |
||||
|
||||
if (hasOccurrences && isInitialized) |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(variable.TypeRef, variable.Name, ParameterModifiers.Ref)); |
||||
else { |
||||
if (hasOccurrences && hasAssignment) |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(variable.TypeRef, variable.Name, ParameterModifiers.Out)); |
||||
else { |
||||
if (!hasOccurrences && getsAssigned) |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(variable.TypeRef, variable.Name, ParameterModifiers.None)); |
||||
else { |
||||
if (!hasOccurrences && !isInitialized) |
||||
newMethod.Body.Children.Insert(0, new LocalVariableDeclaration(new VariableDeclaration(variable.Name, variable.Initializer, variable.TypeRef))); |
||||
else |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(variable.TypeRef, variable.Name, ParameterModifiers.In)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
List<VariableDeclaration> paramsAsVarDecls = new List<VariableDeclaration>(); |
||||
this.beforeCallDeclarations = new List<LocalVariableDeclaration>(); |
||||
|
||||
for (int i = 0; i < otherReturnValues.Count - 1; i++) { |
||||
VariableDeclaration varDecl = otherReturnValues[i]; |
||||
paramsAsVarDecls.Add(varDecl); |
||||
ParameterDeclarationExpression p = new ParameterDeclarationExpression(varDecl.TypeReference, varDecl.Name); |
||||
p.ParamModifier = ParameterModifiers.Out; |
||||
if (!newMethod.Parameters.Contains(p)) { |
||||
newMethod.Parameters.Add(p); |
||||
} else { |
||||
this.beforeCallDeclarations.Add(new LocalVariableDeclaration(varDecl)); |
||||
} |
||||
} |
||||
|
||||
ReplaceUnnecessaryVariableDeclarationsTransformer t = new ReplaceUnnecessaryVariableDeclarationsTransformer(paramsAsVarDecls); |
||||
|
||||
newMethod.AcceptVisitor(t, null); |
||||
|
||||
CreateReturnStatement(newMethod, possibleReturnValues); |
||||
|
||||
this.extractedMethod = newMethod; |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
} |
@ -1,411 +0,0 @@
@@ -1,411 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
using ICSharpCode.NRefactory; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.PrettyPrinter; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Refactoring; |
||||
using ICSharpCode.TextEditor.Document; |
||||
using SharpRefactoring.Visitors; |
||||
using Dom = ICSharpCode.SharpDevelop.Dom; |
||||
using SharpRefactoring.Forms; |
||||
using System.Text.RegularExpressions; |
||||
|
||||
namespace SharpRefactoring |
||||
{ |
||||
public class ExtractMethod : AbstractRefactoringCommand |
||||
{ |
||||
ISelection currentSelection; |
||||
IDocument currentDocument; |
||||
ICSharpCode.SharpDevelop.Dom.Refactoring.CodeGenerator generator; |
||||
ParametrizedNode parent; |
||||
VariableDeclaration returnVar; |
||||
IList<ISpecial> specialsList; |
||||
|
||||
protected override void Run(ICSharpCode.TextEditor.TextEditorControl textEditor, ICSharpCode.SharpDevelop.Dom.Refactoring.RefactoringProvider provider) |
||||
{ |
||||
if (textEditor.ActiveTextAreaControl.SelectionManager.HasSomethingSelected) |
||||
{ |
||||
this.currentDocument = textEditor.Document; |
||||
this.currentSelection = textEditor.ActiveTextAreaControl.SelectionManager.SelectionCollection[0]; |
||||
this.generator = ProjectService.CurrentProject.LanguageProperties.CodeGenerator; |
||||
|
||||
MethodDeclaration method = GetMethod(this.currentDocument, this.currentSelection); |
||||
|
||||
if (method == null) return; |
||||
|
||||
Statement caller; |
||||
InvocationExpression expr = new InvocationExpression(new IdentifierExpression(method.Name), CreateArgumentExpressions(method.Parameters)); |
||||
|
||||
if (method.TypeReference.Type != "void") { |
||||
if (parent is MethodDeclaration) { |
||||
if (method.TypeReference == (parent as MethodDeclaration).TypeReference) |
||||
caller = new ReturnStatement(expr); |
||||
else { |
||||
this.returnVar.Initializer = expr; |
||||
caller = new LocalVariableDeclaration(this.returnVar); |
||||
} |
||||
} else { |
||||
this.returnVar.Initializer = expr; |
||||
caller = new LocalVariableDeclaration(this.returnVar); |
||||
} |
||||
} else { |
||||
caller = new ExpressionStatement(expr); |
||||
} |
||||
|
||||
TextEditorDocument doc = new TextEditorDocument(this.currentDocument); |
||||
|
||||
string line = this.currentDocument.GetText(this.currentDocument.GetLineSegment(this.currentSelection.StartPosition.Line)); |
||||
string indent = ""; |
||||
|
||||
foreach (char c in line) { |
||||
if ((c == ' ') || (c == '\t')) |
||||
indent += c; |
||||
else |
||||
break; |
||||
} |
||||
|
||||
textEditor.Document.UndoStack.StartUndoGroup(); |
||||
|
||||
// TODO : Implement VB.NET support
|
||||
IOutputAstVisitor csOutput = new CSharpOutputVisitor(); |
||||
|
||||
// FIXME : Problems with comments at the begin of the selection
|
||||
RemoveUnneededSpecials(); |
||||
|
||||
using (SpecialNodesInserter.Install(this.specialsList, csOutput)) { |
||||
method.AcceptVisitor(csOutput, null); |
||||
string code = "\n\n" + csOutput.Text; |
||||
|
||||
code = code.TrimEnd('\n', ' ', '\t'); |
||||
|
||||
Dom.IMember p = GetParentMember(textEditor, this.currentSelection.StartPosition.Line, this.currentSelection.StartPosition.Column); |
||||
|
||||
textEditor.Document.Insert(textEditor.Document.PositionToOffset( |
||||
new ICSharpCode.TextEditor.TextLocation( |
||||
p.BodyRegion.EndColumn - 1, p.BodyRegion.EndLine - 1) |
||||
), code); |
||||
} |
||||
|
||||
string call = indent + GenerateCode(new CSharpOutputVisitor(), caller); |
||||
|
||||
call += (textEditor.ActiveTextAreaControl.SelectionManager.SelectedText.EndsWith("\n")) ? "\n" : ""; |
||||
textEditor.Document.Replace(currentSelection.Offset, currentSelection.Length, call); |
||||
textEditor.Document.FormattingStrategy.IndentLines(textEditor.ActiveTextAreaControl.TextArea, 0, textEditor.Document.TotalNumberOfLines - 1); |
||||
|
||||
textEditor.Document.UndoStack.EndUndoGroup(); |
||||
|
||||
textEditor.ActiveTextAreaControl.SelectionManager.ClearSelection(); |
||||
|
||||
} |
||||
} |
||||
|
||||
void RemoveUnneededSpecials() |
||||
{ |
||||
int i = 0; |
||||
|
||||
while (i < this.specialsList.Count) { |
||||
ISpecial spec = this.specialsList[i]; |
||||
if (!IsInSel(spec.EndPosition, this.currentSelection) || !IsInSel(spec.StartPosition, this.currentSelection)) { |
||||
this.specialsList.RemoveAt(i); |
||||
continue; |
||||
} else { |
||||
if (spec is Comment) { |
||||
Comment comment = spec as Comment; |
||||
this.specialsList[i] = new Comment(comment.CommentType, comment.CommentText, |
||||
new Location(spec.StartPosition.Column, spec.StartPosition.Line - this.currentSelection.StartPosition.Line + 1), |
||||
new Location(spec.EndPosition.Column, spec.EndPosition.Line - this.currentSelection.StartPosition.Line + 1)); |
||||
} else { |
||||
if (spec is PreprocessingDirective) { |
||||
PreprocessingDirective ppd = spec as PreprocessingDirective; |
||||
|
||||
this.specialsList[i] = new PreprocessingDirective(ppd.Cmd, ppd.Arg, |
||||
new Location(spec.StartPosition.Column, spec.StartPosition.Line - this.currentSelection.StartPosition.Line + 1), |
||||
new Location(spec.EndPosition.Column, spec.EndPosition.Line - this.currentSelection.StartPosition.Line + 1)); |
||||
} else { |
||||
this.specialsList[i] = new BlankLine(new Location(spec.StartPosition.Column, spec.StartPosition.Line - this.currentSelection.StartPosition.Line + 1)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
i++; |
||||
} |
||||
} |
||||
|
||||
static List<Expression> CreateArgumentExpressions(List<ParameterDeclarationExpression> parameters) |
||||
{ |
||||
List<Expression> expressions = new List<Expression>(); |
||||
|
||||
foreach (ParameterDeclarationExpression pde in parameters) |
||||
{ |
||||
expressions.Add(new DirectionExpression( |
||||
(FieldDirection)Enum.Parse(typeof(FieldDirection),pde.ParamModifier.ToString()), |
||||
new IdentifierExpression(pde.ParameterName))); |
||||
} |
||||
|
||||
return expressions; |
||||
} |
||||
|
||||
CompilationUnit GetCurrentCompilationUnit(IDocument doc) |
||||
{ |
||||
using (IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(doc.TextContent))) { |
||||
parser.Parse(); |
||||
this.specialsList = parser.Lexer.SpecialTracker.RetrieveSpecials(); |
||||
|
||||
if (parser.Errors.Count > 0) { |
||||
MessageService.ShowError(null, parser.Errors.ErrorOutput); |
||||
return null; |
||||
} |
||||
|
||||
return parser.CompilationUnit; |
||||
} |
||||
} |
||||
|
||||
MethodDeclaration GetMethod(ICSharpCode.TextEditor.Document.IDocument doc, ISelection sel) |
||||
{ |
||||
MethodDeclaration newMethod = new MethodDeclaration(); |
||||
|
||||
CompilationUnit unit = GetCurrentCompilationUnit(doc); |
||||
|
||||
if (unit == null) |
||||
return null; |
||||
|
||||
// Initialise new method
|
||||
newMethod.Body = GetBlock(sel.SelectedText); |
||||
newMethod.Body.StartLocation = new Location(0,0); |
||||
|
||||
this.parent = GetParentMember(unit, sel.StartPosition.Line, sel.StartPosition.Column, sel.EndPosition.Line, sel.EndPosition.Column); |
||||
|
||||
if (parent == null) { |
||||
MessageService.ShowError("Invalid selection! Please select a valid range."); |
||||
return null; |
||||
} |
||||
|
||||
if (!CheckForJumpInstructions(newMethod, sel)) |
||||
return null; |
||||
|
||||
newMethod.Modifier = parent.Modifier; |
||||
|
||||
newMethod.Modifier &= ~(Modifiers.Internal | Modifiers.Protected | Modifiers.Private | Modifiers.Public); |
||||
|
||||
List<VariableDeclaration> possibleReturnValues = new List<VariableDeclaration>(); |
||||
|
||||
foreach (ParameterDeclarationExpression pde in parent.Parameters) |
||||
{ |
||||
FindReferenceVisitor frv = new FindReferenceVisitor(pde.ParameterName, pde.TypeReference); |
||||
|
||||
newMethod.AcceptVisitor(frv, null); |
||||
|
||||
if (frv.Identifiers.Count > 0) { |
||||
bool isIn = true; |
||||
foreach (IdentifierExpression identifier in frv.Identifiers) { |
||||
if (!IsInSel(identifier.StartLocation, sel)) |
||||
isIn = false; |
||||
} |
||||
|
||||
if (isIn) { |
||||
possibleReturnValues.Add(new VariableDeclaration(pde.ParameterName, null, pde.TypeReference)); |
||||
} |
||||
|
||||
bool hasOccurrences = HasOccurrencesAfter(parent, new Location(sel.EndPosition.Column + 1, sel.EndPosition.Line + 1), pde.ParameterName, pde.TypeReference); if (hasOccurrences) |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(pde.TypeReference, pde.ParameterName, ParameterModifiers.Ref)); |
||||
else |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(pde.TypeReference, pde.ParameterName, ParameterModifiers.In)); |
||||
} |
||||
} |
||||
|
||||
FindLocalVariablesVisitor flvv = new FindLocalVariablesVisitor(); |
||||
|
||||
parent.AcceptVisitor(flvv, null); |
||||
|
||||
foreach (VariableDeclaration lvd in flvv.Variables) |
||||
{ |
||||
FindReferenceVisitor frv = new FindReferenceVisitor(lvd.Name, lvd.TypeReference); |
||||
|
||||
newMethod.AcceptVisitor(frv, null); |
||||
|
||||
if (IsInSel(lvd.StartLocation, sel) && HasOccurrencesAfter(parent, new Location(sel.EndPosition.Column + 1, sel.EndPosition.Line + 1), lvd.Name, lvd.TypeReference)) |
||||
possibleReturnValues.Add(new VariableDeclaration(lvd.Name, null, lvd.TypeReference)); |
||||
|
||||
if ((frv.Identifiers.Count > 0) && (!(IsInSel(lvd.StartLocation, sel) || IsInSel(lvd.EndLocation, sel)))) { |
||||
bool hasOccurrences = HasOccurrencesAfter(parent, new Location(sel.EndPosition.Column + 1, sel.EndPosition.Line + 1), lvd.Name, lvd.TypeReference); |
||||
bool isInitialized = IsInitializedVariable(parent, lvd); |
||||
bool hasAssignment = HasAssignment(newMethod, lvd); |
||||
if (hasOccurrences && isInitialized) |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(lvd.TypeReference, lvd.Name, ParameterModifiers.Ref)); |
||||
else { |
||||
if (hasOccurrences && hasAssignment) |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(lvd.TypeReference, lvd.Name, ParameterModifiers.Out)); |
||||
else { |
||||
if (!hasOccurrences && !isInitialized) |
||||
newMethod.Body.Children.Insert(0, new LocalVariableDeclaration(lvd)); |
||||
else |
||||
newMethod.Parameters.Add(new ParameterDeclarationExpression(lvd.TypeReference, lvd.Name, ParameterModifiers.In)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
HasReturnStatementVisitor hrsv = new HasReturnStatementVisitor(); |
||||
|
||||
newMethod.AcceptVisitor(hrsv, null); |
||||
|
||||
if (hrsv.HasReturn) { |
||||
if (parent is MethodDeclaration) |
||||
newMethod.TypeReference = (parent as MethodDeclaration).TypeReference; |
||||
if (parent is PropertyDeclaration) |
||||
newMethod.TypeReference = (parent as PropertyDeclaration).TypeReference; |
||||
if (parent is OperatorDeclaration) |
||||
newMethod.TypeReference = (parent as OperatorDeclaration).TypeReference; |
||||
} else { |
||||
if (possibleReturnValues.Count > 0) { |
||||
newMethod.TypeReference = possibleReturnValues[0].TypeReference; |
||||
newMethod.Body.Children.Add(new ReturnStatement(new IdentifierExpression(possibleReturnValues[0].Name))); |
||||
this.returnVar = possibleReturnValues[0]; |
||||
} else |
||||
newMethod.TypeReference = new TypeReference("void"); |
||||
} |
||||
|
||||
IOutputAstVisitor output = new CSharpOutputVisitor(); |
||||
|
||||
newMethod.Name = "NewMethod"; |
||||
|
||||
BlockStatement body = newMethod.Body; |
||||
newMethod.Body = new BlockStatement(); |
||||
|
||||
newMethod.AcceptVisitor(output, null); |
||||
|
||||
string preview = output.Text; |
||||
|
||||
ExtractMethodForm form = new ExtractMethodForm("NewMethod", preview); |
||||
|
||||
if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK) |
||||
{ |
||||
newMethod.Name = form.Text; |
||||
newMethod.Body = body; |
||||
} |
||||
else |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
return newMethod; |
||||
} |
||||
|
||||
Dom.IMember GetParentMember(ICSharpCode.TextEditor.TextEditorControl textEditor, int line, int column) |
||||
{ |
||||
Dom.ParseInformation parseInfo = ParserService.GetParseInformation(textEditor.FileName); |
||||
if (parseInfo != null) { |
||||
Dom.IClass c = parseInfo.MostRecentCompilationUnit.GetInnermostClass(line, column); |
||||
if (c != null) { |
||||
foreach (Dom.IMember member in c.Properties) { |
||||
if (member.BodyRegion.IsInside(line, column)) { |
||||
return member; |
||||
} |
||||
} |
||||
foreach (Dom.IMember member in c.Methods) { |
||||
if (member.BodyRegion.IsInside(line, column)) { |
||||
return member; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
static bool CheckForJumpInstructions(MethodDeclaration method, ISelection selection) |
||||
{ |
||||
FindJumpInstructionsVisitor fjiv = new FindJumpInstructionsVisitor(method, selection); |
||||
|
||||
method.AcceptVisitor(fjiv, null); |
||||
|
||||
return fjiv.IsOk; |
||||
} |
||||
|
||||
static bool IsInSel(Location location, ISelection sel) |
||||
{ |
||||
bool result = (sel.ContainsPosition(new ICSharpCode.TextEditor.TextLocation(location.Column - 1, location.Line - 1))); |
||||
return result; |
||||
} |
||||
|
||||
static BlockStatement GetBlock(string data) |
||||
{ |
||||
data = "class Temp { public void t() {" + data + "} }"; |
||||
|
||||
using (IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(data))) { |
||||
parser.Parse(); |
||||
|
||||
if (parser.Errors.Count > 0) { |
||||
throw new ArgumentException("Invalid selection! Please select a valid range!"); |
||||
} |
||||
|
||||
MethodDeclaration method = (MethodDeclaration)(parser.CompilationUnit.Children[0].Children[0]); |
||||
|
||||
return method.Body; |
||||
} |
||||
} |
||||
|
||||
static string GenerateCode(IOutputAstVisitor outputVisitor, INode unit) |
||||
{ |
||||
unit.AcceptVisitor(outputVisitor, null); |
||||
return outputVisitor.Text; |
||||
} |
||||
|
||||
static ParametrizedNode GetParentMember(CompilationUnit unit, int startLine, int startColumn, int endLine, int endColumn) |
||||
{ |
||||
FindMemberVisitor fmv = new FindMemberVisitor(startColumn, startLine, endColumn, endLine); |
||||
|
||||
unit.AcceptVisitor(fmv, null); |
||||
|
||||
return fmv.Member; |
||||
} |
||||
|
||||
static bool HasOccurrencesAfter(ParametrizedNode member, Location location, string name, TypeReference type) |
||||
{ |
||||
FindReferenceVisitor frv = new FindReferenceVisitor(name, type); |
||||
|
||||
member.AcceptVisitor(frv, null); |
||||
|
||||
foreach (IdentifierExpression identifier in frv.Identifiers) |
||||
{ |
||||
if (identifier.StartLocation > location) |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool IsInitializedVariable(ParametrizedNode member, VariableDeclaration variable) |
||||
{ |
||||
if (!(variable.Initializer.IsNull)) { |
||||
return true; |
||||
} else { |
||||
FindReferenceVisitor frv = new FindReferenceVisitor(variable.Name, variable.TypeReference); |
||||
|
||||
member.AcceptVisitor(frv, null); |
||||
|
||||
foreach (IdentifierExpression expr in frv.Identifiers) { |
||||
if ((expr.EndLocation < new Location(currentSelection.StartPosition.Column, currentSelection.StartPosition.Line)) && |
||||
!(expr.IsNull)) |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
static bool HasAssignment(MethodDeclaration method, VariableDeclaration variable) |
||||
{ |
||||
HasAssignmentsVisitor hav = new HasAssignmentsVisitor(variable.Name, variable.TypeReference); |
||||
|
||||
method.AcceptVisitor(hav, null); |
||||
|
||||
return hav.HasAssignment; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using ICSharpCode.TextEditor; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Text.RegularExpressions; |
||||
using System.Windows.Forms; |
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.NRefactory; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.PrettyPrinter; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
using ICSharpCode.SharpDevelop.Refactoring; |
||||
using ICSharpCode.TextEditor.Document; |
||||
using SharpRefactoring.Forms; |
||||
using SharpRefactoring.Transformers; |
||||
using SharpRefactoring.Visitors; |
||||
|
||||
namespace SharpRefactoring |
||||
{ |
||||
public class ExtractMethodCommand : AbstractRefactoringCommand |
||||
{ |
||||
protected override void Run(ICSharpCode.TextEditor.TextEditorControl textEditor, ICSharpCode.SharpDevelop.Dom.Refactoring.RefactoringProvider provider) |
||||
{ |
||||
if (textEditor.ActiveTextAreaControl.SelectionManager.HasSomethingSelected) |
||||
{ |
||||
MethodExtractorBase extractor = GetCurrentExtractor(textEditor); |
||||
|
||||
if (extractor.Extract()) { |
||||
ExtractMethodForm form = new ExtractMethodForm("NewMethod", extractor.CreatePreview()); |
||||
|
||||
if (form.ShowDialog() == DialogResult.OK) { |
||||
extractor.ExtractedMethod.Name = form.Text; |
||||
textEditor.Document.UndoStack.StartUndoGroup(); |
||||
extractor.InsertAfterCurrentMethod(); |
||||
extractor.InsertCall(); |
||||
textEditor.Document.FormattingStrategy.IndentLines(textEditor.ActiveTextAreaControl.TextArea, 0, textEditor.Document.TotalNumberOfLines - 1); |
||||
textEditor.Document.UndoStack.EndUndoGroup(); |
||||
textEditor.ActiveTextAreaControl.SelectionManager.ClearSelection(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
MethodExtractorBase GetCurrentExtractor(TextEditorControl editor) |
||||
{ |
||||
switch (ProjectService.CurrentProject.Language) { |
||||
case "C#": |
||||
return new CSharpMethodExtractor(editor, editor.ActiveTextAreaControl.SelectionManager.SelectionCollection[0]); |
||||
default: |
||||
throw new NotSupportedException("Extracting methods in the current language is not supported!"); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,302 @@
@@ -0,0 +1,302 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision: 3287 $</version>
|
||||
// </file>
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Text; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.NRefactory; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.PrettyPrinter; |
||||
using ICSharpCode.NRefactory.Visitors; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.TextEditor.Document; |
||||
using SharpRefactoring.Visitors; |
||||
using Dom = ICSharpCode.SharpDevelop.Dom; |
||||
|
||||
namespace SharpRefactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Description of MethodExtractorBase.
|
||||
/// </summary>
|
||||
public class MethodExtractorBase |
||||
{ |
||||
protected ICSharpCode.TextEditor.TextEditorControl textEditor; |
||||
protected ISelection currentSelection; |
||||
protected IDocument currentDocument; |
||||
protected MethodDeclaration extractedMethod; |
||||
protected ParametrizedNode parentNode; |
||||
protected Statement caller; |
||||
protected List<LocalVariableDeclaration> beforeCallDeclarations; |
||||
protected IOutputAstVisitor output; |
||||
protected VariableDeclaration returnedVariable; |
||||
protected List<ISpecial> specialsList; |
||||
|
||||
public Statement Caller { |
||||
get { return caller; } |
||||
} |
||||
|
||||
public MethodDeclaration ExtractedMethod { |
||||
get { return extractedMethod; } |
||||
} |
||||
|
||||
public MethodExtractorBase(ICSharpCode.TextEditor.TextEditorControl textEditor, ISelection selection, IOutputAstVisitor output) |
||||
{ |
||||
this.currentDocument = textEditor.Document; |
||||
this.textEditor = textEditor; |
||||
this.currentSelection = selection; |
||||
this.output = output; |
||||
} |
||||
|
||||
protected static Statement CreateCaller(ParametrizedNode parent, MethodDeclaration method, VariableDeclaration returnVariable) |
||||
{ |
||||
Statement caller; |
||||
InvocationExpression expr = new InvocationExpression(new IdentifierExpression(method.Name), CreateArgumentExpressions(method.Parameters)); |
||||
|
||||
if (method.TypeReference.Type != "void") { |
||||
if (parent is MethodDeclaration) { |
||||
if (method.TypeReference == (parent as MethodDeclaration).TypeReference) |
||||
caller = new ReturnStatement(expr); |
||||
else { |
||||
returnVariable.Initializer = expr; |
||||
caller = new LocalVariableDeclaration(returnVariable); |
||||
} |
||||
} |
||||
else { |
||||
returnVariable.Initializer = expr; |
||||
caller = new LocalVariableDeclaration(returnVariable); |
||||
} |
||||
} |
||||
else { |
||||
caller = new ExpressionStatement(expr); |
||||
} |
||||
return caller; |
||||
} |
||||
|
||||
protected void CreateReturnStatement(MethodDeclaration newMethod, List<VariableDeclaration> possibleReturnValues) |
||||
{ |
||||
HasReturnStatementVisitor hrsv = new HasReturnStatementVisitor(); |
||||
|
||||
newMethod.AcceptVisitor(hrsv, null); |
||||
|
||||
if (hrsv.HasReturn) { |
||||
if (this.parentNode is MethodDeclaration) newMethod.TypeReference = (this.parentNode as MethodDeclaration).TypeReference; |
||||
if (this.parentNode is PropertyDeclaration) newMethod.TypeReference = (this.parentNode as PropertyDeclaration).TypeReference; |
||||
if (this.parentNode is OperatorDeclaration) newMethod.TypeReference = (this.parentNode as OperatorDeclaration).TypeReference; |
||||
} |
||||
else { |
||||
if (possibleReturnValues.Count > 0) { |
||||
newMethod.TypeReference = possibleReturnValues[possibleReturnValues.Count - 1].TypeReference; |
||||
newMethod.Body.Children.Add(new ReturnStatement(new IdentifierExpression(possibleReturnValues[possibleReturnValues.Count - 1].Name))); |
||||
} |
||||
else newMethod.TypeReference = new TypeReference("void"); |
||||
} |
||||
|
||||
if (newMethod.TypeReference.Type == "void") { |
||||
this.returnedVariable = null; |
||||
} else { |
||||
this.returnedVariable = possibleReturnValues[possibleReturnValues.Count - 1]; |
||||
} |
||||
} |
||||
|
||||
public string CreatePreview() |
||||
{ |
||||
BlockStatement body = this.extractedMethod.Body; |
||||
this.extractedMethod.Body = new BlockStatement(); |
||||
|
||||
this.extractedMethod.AcceptVisitor(output, null); |
||||
|
||||
this.extractedMethod.Body = body; |
||||
|
||||
return output.Text; |
||||
} |
||||
|
||||
public void InsertCall() |
||||
{ |
||||
string call = GenerateCode(CreateCaller(this.parentNode, this.extractedMethod, this.returnedVariable), false); |
||||
StringBuilder builder = new StringBuilder(); |
||||
|
||||
foreach (LocalVariableDeclaration v in this.beforeCallDeclarations) { |
||||
builder.AppendLine(GenerateCode(v, false)); |
||||
} |
||||
|
||||
this.currentDocument.Replace(this.currentSelection.Offset, this.currentSelection.Length, /*builder.ToString() + "\n" +*/ call); |
||||
} |
||||
|
||||
public void InsertAfterCurrentMethod() |
||||
{ |
||||
using (SpecialNodesInserter.Install(this.specialsList, this.output)) { |
||||
string code = "\n\n" + GenerateCode(this.extractedMethod, true); |
||||
|
||||
code = code.TrimEnd('\n', ' ', '\t'); |
||||
|
||||
Dom.IMember p = GetParentMember(this.textEditor, this.currentSelection.StartPosition.Line, this.currentSelection.StartPosition.Column); |
||||
|
||||
textEditor.Document.Insert(textEditor.Document.PositionToOffset( |
||||
new ICSharpCode.TextEditor.TextLocation( |
||||
p.BodyRegion.EndColumn - 1, p.BodyRegion.EndLine - 1) |
||||
), code); |
||||
} |
||||
} |
||||
|
||||
protected static bool CheckForJumpInstructions(MethodDeclaration method, ISelection selection) |
||||
{ |
||||
FindJumpInstructionsVisitor fjiv = new FindJumpInstructionsVisitor(method, selection); |
||||
|
||||
method.AcceptVisitor(fjiv, null); |
||||
|
||||
return fjiv.IsOk; |
||||
} |
||||
|
||||
protected static bool IsInSel(Location location, ISelection sel) |
||||
{ |
||||
bool result = (sel.ContainsPosition(new ICSharpCode.TextEditor.TextLocation(location.Column - 1, location.Line - 1))); |
||||
return result; |
||||
} |
||||
|
||||
protected static BlockStatement GetBlock(string data) |
||||
{ |
||||
data = "class Temp { public void t() {" + data + "} }"; |
||||
|
||||
using (IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(data))) { |
||||
parser.Parse(); |
||||
|
||||
if (parser.Errors.Count > 0) { |
||||
MessageService.ShowError("Invalid selection! Please select a valid range!"); |
||||
} |
||||
|
||||
MethodDeclaration method = (MethodDeclaration)(parser.CompilationUnit.Children[0].Children[0]); |
||||
|
||||
return method.Body; |
||||
} |
||||
} |
||||
|
||||
protected static string GetIndentation(string line) |
||||
{ |
||||
string indent = ""; |
||||
|
||||
foreach (char c in line) { |
||||
if ((c == ' ') || (c == '\t')) |
||||
indent += c; |
||||
else |
||||
break; |
||||
} |
||||
return indent; |
||||
} |
||||
|
||||
protected static List<Expression> CreateArgumentExpressions(List<ParameterDeclarationExpression> parameters) |
||||
{ |
||||
List<Expression> expressions = new List<Expression>(); |
||||
|
||||
foreach (ParameterDeclarationExpression pde in parameters) |
||||
{ |
||||
expressions.Add(new DirectionExpression( |
||||
(FieldDirection)Enum.Parse(typeof(FieldDirection),pde.ParamModifier.ToString()), |
||||
new IdentifierExpression(pde.ParameterName))); |
||||
} |
||||
|
||||
return expressions; |
||||
} |
||||
|
||||
protected virtual string GenerateCode(INode unit, bool installSpecials) |
||||
{ |
||||
throw new InvalidOperationException("Cannot use plain MethodExtractor, please use a language specific implementation!"); |
||||
} |
||||
|
||||
protected Dom.IMember GetParentMember(ICSharpCode.TextEditor.TextEditorControl textEditor, int line, int column) |
||||
{ |
||||
Dom.ParseInformation parseInfo = ParserService.GetParseInformation(textEditor.FileName); |
||||
if (parseInfo != null) { |
||||
Dom.IClass c = parseInfo.MostRecentCompilationUnit.GetInnermostClass(line, column); |
||||
if (c != null) { |
||||
foreach (Dom.IMember member in c.Properties) { |
||||
if (member.BodyRegion.IsInside(line, column)) { |
||||
return member; |
||||
} |
||||
} |
||||
foreach (Dom.IMember member in c.Methods) { |
||||
if (member.BodyRegion.IsInside(line, column)) { |
||||
return member; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
protected ParametrizedNode GetParentMember(int startLine, int startColumn, int endLine, int endColumn) |
||||
{ |
||||
using (IParser parser = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(this.currentDocument.TextContent))) { |
||||
parser.Parse(); |
||||
|
||||
if (parser.Errors.Count > 0) { |
||||
MessageService.ShowError(null, parser.Errors.ErrorOutput); |
||||
return null; |
||||
} |
||||
|
||||
FindMemberVisitor fmv = new FindMemberVisitor(startColumn, startLine, endColumn, endLine); |
||||
|
||||
parser.CompilationUnit.AcceptVisitor(fmv, null); |
||||
|
||||
return fmv.Member; |
||||
} |
||||
} |
||||
|
||||
protected static bool HasOccurrencesAfter(bool caseSensitive, ParametrizedNode member, Location location, string name, Location start, Location end) |
||||
{ |
||||
FindReferenceVisitor frv = new FindReferenceVisitor(caseSensitive, name, start, end); |
||||
|
||||
member.AcceptVisitor(frv, null); |
||||
|
||||
foreach (IdentifierExpression identifier in frv.Identifiers) |
||||
{ |
||||
if (identifier.StartLocation > location) |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
protected bool IsInitializedVariable(bool caseSensitive, ParametrizedNode member, LocalLookupVariable variable) |
||||
{ |
||||
if (!(variable.Initializer.IsNull)) { |
||||
return true; |
||||
} else { |
||||
FindReferenceVisitor frv = new FindReferenceVisitor(caseSensitive, variable.Name, variable.StartPos, variable.EndPos); |
||||
|
||||
member.AcceptVisitor(frv, null); |
||||
|
||||
foreach (IdentifierExpression expr in frv.Identifiers) { |
||||
if ((expr.EndLocation < new Location(currentSelection.StartPosition.Column, currentSelection.StartPosition.Line)) && |
||||
!(expr.IsNull)) |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
protected static bool HasAssignment(MethodDeclaration method, LocalLookupVariable variable) |
||||
{ |
||||
HasAssignmentsVisitor hav = new HasAssignmentsVisitor(variable.Name, variable.TypeRef); |
||||
|
||||
method.AcceptVisitor(hav, null); |
||||
|
||||
return hav.HasAssignment; |
||||
} |
||||
|
||||
|
||||
public virtual bool Extract() |
||||
{ |
||||
throw new InvalidOperationException("Cannot use plain MethodExtractor, please use a language specific implementation!"); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision: 3287 $</version>
|
||||
// </file>
|
||||
using System; |
||||
using ICSharpCode.NRefactory.Ast; |
||||
using ICSharpCode.NRefactory.Visitors; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace SharpRefactoring.Transformers |
||||
{ |
||||
/// <summary>
|
||||
/// Description of ReplaceUnnecessaryVariableDeclarationsTransformer.
|
||||
/// </summary>
|
||||
public class ReplaceUnnecessaryVariableDeclarationsTransformer : AbstractAstTransformer |
||||
{ |
||||
List<VariableDeclaration> unneededVarDecls; |
||||
|
||||
public ReplaceUnnecessaryVariableDeclarationsTransformer(List<VariableDeclaration> unneededVarDecls) |
||||
{ |
||||
this.unneededVarDecls = unneededVarDecls; |
||||
} |
||||
|
||||
bool Contains(VariableDeclaration varDecl) |
||||
{ |
||||
foreach (VariableDeclaration v in this.unneededVarDecls) { |
||||
if (v.Name == varDecl.Name) { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public override object VisitLocalVariableDeclaration(ICSharpCode.NRefactory.Ast.LocalVariableDeclaration localVariableDeclaration, object data) |
||||
{ |
||||
bool containsAll = true; |
||||
foreach (VariableDeclaration v in localVariableDeclaration.Variables) { |
||||
if (Contains(v)) { |
||||
localVariableDeclaration.Parent.Children.Add(new ExpressionStatement( |
||||
new AssignmentExpression(new IdentifierExpression(v.Name), |
||||
AssignmentOperatorType.Assign, |
||||
v.Initializer))); |
||||
} else |
||||
containsAll = false; |
||||
} |
||||
|
||||
if (containsAll) |
||||
this.RemoveCurrentNode(); |
||||
|
||||
return base.VisitLocalVariableDeclaration(localVariableDeclaration, data); |
||||
} |
||||
|
||||
public override object VisitVariableDeclaration(ICSharpCode.NRefactory.Ast.VariableDeclaration variableDeclaration, object data) |
||||
{ |
||||
if (!(variableDeclaration.Parent is LocalVariableDeclaration)) { |
||||
this.ReplaceCurrentNode(new ExpressionStatement(new AssignmentExpression(new IdentifierExpression(variableDeclaration.Name), AssignmentOperatorType.Assign, variableDeclaration.Initializer))); |
||||
} |
||||
return base.VisitVariableDeclaration(variableDeclaration, data); |
||||
} |
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue