From e0c660f7bb16aaae7ee5982cd823cca439d4e67e Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 7 Sep 2008 14:58:18 +0000 Subject: [PATCH] Improved "Extract Method" and added IsReferenceType to IReturnType git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3512 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/CSharpMethodExtractor.cs | 51 +++++++++++++++---- .../Src/MethodExtractorBase.cs | 25 +++++---- .../Src/AstBuilder/ExpressionBuilder.cs | 30 +++++++++++ .../Visitors/VBNetConstructsConvertVisitor.cs | 36 ++----------- .../Base/Test/Utils/MockDefaultReturnType.cs | 6 +++ .../Src/Implementations/AbstractReturnType.cs | 2 + .../Src/Implementations/DefaultReturnType.cs | 8 +++ .../Src/Implementations/GenericReturnType.cs | 4 ++ .../Src/Implementations/ProxyReturnType.cs | 9 ++++ .../Project/Src/Interfaces/IReturnType.cs | 2 + .../Project/Src/Refactoring/CodeGenerator.cs | 9 ++++ 11 files changed, 129 insertions(+), 53 deletions(-) diff --git a/src/AddIns/Misc/SharpRefactoring/Src/CSharpMethodExtractor.cs b/src/AddIns/Misc/SharpRefactoring/Src/CSharpMethodExtractor.cs index dbb8723c59..ac35964eb5 100644 --- a/src/AddIns/Misc/SharpRefactoring/Src/CSharpMethodExtractor.cs +++ b/src/AddIns/Misc/SharpRefactoring/Src/CSharpMethodExtractor.cs @@ -4,18 +4,23 @@ // // $Revision: 3287 $ // +using ICSharpCode.SharpDevelop; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; - using ICSharpCode.Core; using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.AstBuilder; using ICSharpCode.NRefactory.PrettyPrinter; using ICSharpCode.NRefactory.Visitors; +using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver; +using ICSharpCode.SharpDevelop.Project; using ICSharpCode.TextEditor.Document; using SharpRefactoring.Transformers; using SharpRefactoring.Visitors; +using Dom = ICSharpCode.SharpDevelop.Dom; namespace SharpRefactoring { @@ -52,6 +57,8 @@ namespace SharpRefactoring this.specialsList = parser.Lexer.SpecialTracker.RetrieveSpecials(); } + this.currentProjectContent = ParserService.GetProjectContent(ProjectService.CurrentProject); + MethodDeclaration newMethod = new MethodDeclaration(); List possibleReturnValues = new List(); @@ -74,7 +81,7 @@ namespace SharpRefactoring newMethod.Modifier = parentNode.Modifier; - newMethod.Modifier &= ~(Modifiers.Internal | Modifiers.Protected | Modifiers.Private | Modifiers.Public); + newMethod.Modifier &= ~(Modifiers.Internal | Modifiers.Protected | Modifiers.Private | Modifiers.Public | Modifiers.Override); foreach (ParameterDeclarationExpression pde in parentNode.Parameters) { @@ -105,36 +112,40 @@ namespace SharpRefactoring parentNode.AcceptVisitor(ltv, null); + Location start = new Location(this.currentSelection.StartPosition.Column + 1, this.currentSelection.StartPosition.Line + 1); + Location end = new Location(this.currentSelection.EndPosition.Column + 1, this.currentSelection.EndPosition.Line + 1); + foreach (KeyValuePair> pair in ltv.Variables) { foreach (LocalLookupVariable variable in pair.Value) { + if (variable.StartPos > end) + continue; + 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)); } - Location start = new Location(this.currentSelection.StartPosition.Column + 1, this.currentSelection.StartPosition.Line + 1); - Location end = new Location(this.currentSelection.EndPosition.Column + 1, this.currentSelection.EndPosition.Line + 1); FindReferenceVisitor frv = new FindReferenceVisitor(true, variable.Name, start, end); 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 hasOccurrencesAfter = 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) + if (hasOccurrencesAfter && isInitialized) newMethod.Parameters.Add(new ParameterDeclarationExpression(variable.TypeRef, variable.Name, ParameterModifiers.Ref)); else { - if (hasOccurrences && hasAssignment) + if (hasOccurrencesAfter && hasAssignment) newMethod.Parameters.Add(new ParameterDeclarationExpression(variable.TypeRef, variable.Name, ParameterModifiers.Out)); else { - if (!hasOccurrences && getsAssigned) + if (!hasOccurrencesAfter && getsAssigned) newMethod.Parameters.Add(new ParameterDeclarationExpression(variable.TypeRef, variable.Name, ParameterModifiers.None)); else { - if (!hasOccurrences && !isInitialized) + if (!hasOccurrencesAfter && !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)); @@ -159,12 +170,32 @@ namespace SharpRefactoring this.beforeCallDeclarations.Add(new LocalVariableDeclaration(varDecl)); } } - + ReplaceUnnecessaryVariableDeclarationsTransformer t = new ReplaceUnnecessaryVariableDeclarationsTransformer(paramsAsVarDecls); newMethod.AcceptVisitor(t, null); CreateReturnStatement(newMethod, possibleReturnValues); + + bool hasReturnStatement = false; + + foreach (INode node in newMethod.Body.Children) { + if (node is ReturnStatement) { + hasReturnStatement = true; + } + } + + if (!hasReturnStatement) { + Dom.IMember member = GetParentMember(this.textEditor, this.currentSelection.StartPosition); + + Dom.IReturnType returnType = TypeVisitor.CreateReturnType(newMethod.TypeReference, member.DeclaringType, member, + this.currentSelection.StartPosition.Line, this.currentSelection.StartPosition.Column, member.DeclaringType.ProjectContent, true); + + if (returnType.IsReferenceType == null || returnType.IsReferenceType == true) + newMethod.Body.AddChild(new ReturnStatement(new PrimitiveExpression(null, "null"))); + else + newMethod.Body.AddChild(new ReturnStatement(ExpressionBuilder.CreateDefaultValueForType(newMethod.TypeReference))); + } this.extractedMethod = newMethod; diff --git a/src/AddIns/Misc/SharpRefactoring/Src/MethodExtractorBase.cs b/src/AddIns/Misc/SharpRefactoring/Src/MethodExtractorBase.cs index 529f6e4b2b..84a51be665 100644 --- a/src/AddIns/Misc/SharpRefactoring/Src/MethodExtractorBase.cs +++ b/src/AddIns/Misc/SharpRefactoring/Src/MethodExtractorBase.cs @@ -4,17 +4,18 @@ // // $Revision: 3287 $ // +using ICSharpCode.TextEditor; 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.SharpDevelop.Project; using ICSharpCode.TextEditor.Document; using SharpRefactoring.Visitors; using Dom = ICSharpCode.SharpDevelop.Dom; @@ -37,6 +38,9 @@ namespace SharpRefactoring protected VariableDeclaration returnedVariable; protected List specialsList; + protected Dom.IClass currentClass; + protected Dom.IProjectContent currentProjectContent; + public Statement Caller { get { return caller; } } @@ -88,19 +92,15 @@ namespace SharpRefactoring 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 { + } 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))); + this.returnedVariable = possibleReturnValues[possibleReturnValues.Count - 1]; + } else { + newMethod.TypeReference = new TypeReference("void"); + this.returnedVariable = null; } - else newMethod.TypeReference = new TypeReference("void"); - } - - if (newMethod.TypeReference.Type == "void") { - this.returnedVariable = null; - } else { - this.returnedVariable = possibleReturnValues[possibleReturnValues.Count - 1]; } } @@ -208,6 +208,11 @@ namespace SharpRefactoring throw new InvalidOperationException("Cannot use plain MethodExtractor, please use a language specific implementation!"); } + protected Dom.IMember GetParentMember(ICSharpCode.TextEditor.TextEditorControl textEditor, TextLocation location) + { + return GetParentMember(textEditor, location.Line, location.Column); + } + protected Dom.IMember GetParentMember(ICSharpCode.TextEditor.TextEditorControl textEditor, int line, int column) { Dom.ParseInformation parseInfo = ParserService.GetParseInformation(textEditor.FileName); diff --git a/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs b/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs index 373c84e98d..59856ff762 100644 --- a/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs +++ b/src/Libraries/NRefactory/Project/Src/AstBuilder/ExpressionBuilder.cs @@ -53,6 +53,36 @@ namespace ICSharpCode.NRefactory.AstBuilder throw new ArgumentNullException("arguments"); return new ObjectCreateExpression(createType, new List(arguments)); } + + public static Expression CreateDefaultValueForType(TypeReference type) + { + if (type != null && !type.IsArrayType) { + switch (type.SystemType) { + case "System.SByte": + case "System.Byte": + case "System.Int16": + case "System.UInt16": + case "System.Int32": + case "System.UInt32": + case "System.Int64": + case "System.UInt64": + case "System.Single": + case "System.Double": + return new PrimitiveExpression(0, "0"); + case "System.Char": + return new PrimitiveExpression('\0', "'\\0'"); + case "System.Object": + case "System.String": + return new PrimitiveExpression(null, "null"); + case "System.Boolean": + return new PrimitiveExpression(false, "false"); + default: + return new DefaultValueExpression(type); + } + } else { + return new PrimitiveExpression(null, "null"); + } + } } #endif } diff --git a/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs b/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs index 505b8b9ed1..257960c7c3 100644 --- a/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs +++ b/src/Libraries/NRefactory/Project/Src/Visitors/VBNetConstructsConvertVisitor.cs @@ -5,10 +5,10 @@ // $Revision$ // +using ICSharpCode.NRefactory.AstBuilder; using System; using System.Collections.Generic; using System.Reflection; - using ICSharpCode.NRefactory.Ast; using Attribute = ICSharpCode.NRefactory.Ast.Attribute; @@ -244,7 +244,7 @@ namespace ICSharpCode.NRefactory.Visitors methodDeclaration.Body.AcceptVisitor(visitor, null); if (visitor.replacementCount > 0) { Expression init; - init = GetDefaultValueForType(methodDeclaration.TypeReference); + init = ExpressionBuilder.CreateDefaultValueForType(methodDeclaration.TypeReference); methodDeclaration.Body.Children.Insert(0, new LocalVariableDeclaration(new VariableDeclaration(FunctionReturnValueName, init, methodDeclaration.TypeReference))); methodDeclaration.Body.Children[0].Parent = methodDeclaration.Body; methodDeclaration.Body.AddChild(new ReturnStatement(new IdentifierExpression(FunctionReturnValueName))); @@ -497,41 +497,11 @@ namespace ICSharpCode.NRefactory.Visitors VariableDeclaration decl = localVariableDeclaration.Variables[i]; if (decl.FixedArrayInitialization.IsNull && decl.Initializer.IsNull) { TypeReference type = localVariableDeclaration.GetTypeForVariable(i); - decl.Initializer = GetDefaultValueForType(type); + decl.Initializer = ExpressionBuilder.CreateDefaultValueForType(type); } } } return base.VisitLocalVariableDeclaration(localVariableDeclaration, data); } - - Expression GetDefaultValueForType(TypeReference type) - { - if (type != null && !type.IsArrayType) { - switch (type.SystemType) { - case "System.SByte": - case "System.Byte": - case "System.Int16": - case "System.UInt16": - case "System.Int32": - case "System.UInt32": - case "System.Int64": - case "System.UInt64": - case "System.Single": - case "System.Double": - return new PrimitiveExpression(0, "0"); - case "System.Char": - return new PrimitiveExpression('\0', "'\\0'"); - case "System.Object": - case "System.String": - return new PrimitiveExpression(null, "null"); - case "System.Boolean": - return new PrimitiveExpression(false, "false"); - default: - return new DefaultValueExpression(type); - } - } else { - return new PrimitiveExpression(null, "null"); - } - } } } diff --git a/src/Main/Base/Test/Utils/MockDefaultReturnType.cs b/src/Main/Base/Test/Utils/MockDefaultReturnType.cs index cd7ef8af72..fdbbde1ff4 100644 --- a/src/Main/Base/Test/Utils/MockDefaultReturnType.cs +++ b/src/Main/Base/Test/Utils/MockDefaultReturnType.cs @@ -148,5 +148,11 @@ namespace ICSharpCode.SharpDevelop.Tests.Utils { throw new NotImplementedException(); } + + public Nullable IsReferenceType { + get { + throw new NotImplementedException(); + } + } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs index 43d8e21c5f..a571031e4b 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs @@ -129,5 +129,7 @@ namespace ICSharpCode.SharpDevelop.Dom { return null; } + + public virtual bool? IsReferenceType { get { return null; } } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs index 1b04b0699f..9fe6cb188b 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs @@ -226,5 +226,13 @@ namespace ICSharpCode.SharpDevelop.Dom return c.DotNetName; } } + + public override Nullable IsReferenceType { + get { + return (this.c.ClassType == ClassType.Class + || this.c.ClassType == ClassType.Interface + || this.c.ClassType == ClassType.Delegate); + } + } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GenericReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GenericReturnType.cs index fb11589903..14aba0d875 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GenericReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GenericReturnType.cs @@ -117,6 +117,10 @@ namespace ICSharpCode.SharpDevelop.Dom return list; } + public override Nullable IsReferenceType { + get { return null; } + } + public override string ToString() { return String.Format("[GenericReturnType: {0}]", typeParameter); diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs index 55f620de41..f50acf3618 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs @@ -217,5 +217,14 @@ namespace ICSharpCode.SharpDevelop.Dom { return CastToDecoratingReturnType(); } + + public virtual bool? IsReferenceType { + get { + IReturnType baseType = BaseType; + bool? tmp = (baseType != null && TryEnter()) ? baseType.IsReferenceType : null; + Leave(); + return tmp; + } + } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IReturnType.cs index 0addea2fe9..128c66acf6 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IReturnType.cs @@ -126,5 +126,7 @@ namespace ICSharpCode.SharpDevelop.Dom bool IsConstructedReturnType { get; } ConstructedReturnType CastToConstructedReturnType(); + + bool? IsReferenceType { get; } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs index 95cc86ee3a..ade32f0bc6 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs @@ -717,5 +717,14 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring document.EndUndoableAction(); } #endregion + + public static NR.Expression CreateDefaultValueForType(IReturnType type) + { + if (type.IsReferenceType != null && type.IsReferenceType != false) { + return null; + } + + return null; + } } }