diff --git a/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs b/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs index 0942c6dc34..15b4993d23 100644 --- a/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs +++ b/ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs @@ -121,10 +121,11 @@ namespace ICSharpCode.NRefactory.CSharp { } - public ParameterDeclaration(AstType type, string name) + public ParameterDeclaration(AstType type, string name, ParameterModifier modifier = ParameterModifier.None) { - this.Type = type; - this.Name = name; + Type = type; + Name = name; + ParameterModifier = modifier; } } } diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 3767b2e0d7..68115c61d7 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -359,6 +359,9 @@ + + + @@ -371,6 +374,7 @@ + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs index 242c9c3b9d..47261ed6a7 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/BaseRefactoringContext.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { public abstract class BaseRefactoringContext : IServiceProvider { - protected readonly CSharpAstResolver resolver; + readonly CSharpAstResolver resolver; readonly CancellationToken cancellationToken; public virtual bool Supports(Version version) @@ -65,6 +65,12 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring } } + public CSharpAstResolver Resolver { + get { + return resolver; + } + } + public virtual CSharpParsedFile ParsedFile { get { return resolver.ParsedFile; diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/ExtractMethodAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/ExtractMethodAction.cs new file mode 100644 index 0000000000..c07a36c33d --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/ExtractMethodAction.cs @@ -0,0 +1,185 @@ +// +// ExtractMethodAction.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.Semantics; +using System.Linq; +using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.CSharp.Analysis; +using System.Threading; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod +{ + [ContextAction("Extract method", Description = "Creates a new method out of selected text.")] + public class ExtractMethodAction : ICodeActionProvider + { + public IEnumerable GetActions(RefactoringContext context) + { + if (!context.IsSomethingSelected) + yield break; + var selected = new List(context.GetSelectedNodes()); + if (selected.Count == 0) + yield break; + + if (selected.Count == 1 && selected [0] is Expression) { + var codeAction = CreateFromExpression(context, (Expression)selected [0]); + if (codeAction == null) + yield break; + yield return codeAction; + } + + foreach (var node in selected) { + if (!(node is Statement)) + yield break; + } + + yield return CreateFromStatements(context, new List (selected.OfType ())); + } + + CodeAction CreateFromExpression(RefactoringContext context, Expression expression) + { + var resolveResult = context.Resolve(expression); + if (resolveResult.IsError) + return null; + + return new CodeAction(context.TranslateString("Extract method"), script => { + string methodName = "NewMethod"; + var method = new MethodDeclaration() { + ReturnType = context.CreateShortType(resolveResult.Type), + Name = methodName, + Body = new BlockStatement() { + new ReturnStatement(expression.Clone()) + } + }; + if (!StaticVisitor.UsesNotStaticMember(context, expression)) + method.Modifiers |= Modifiers.Static; + script.InsertWithCursor(context.TranslateString("Extract method"), method, Script.InsertPosition.Before); + var target = new IdentifierExpression(methodName); + script.Replace(expression, new InvocationExpression(target)); + script.Link(target, method.NameToken); + }); + } + + CodeAction CreateFromStatements(RefactoringContext context, List statements) + { + if (!(statements [0].Parent is Statement)) + return null; + + return new CodeAction(context.TranslateString("Extract method"), script => { + string methodName = "NewMethod"; + var method = new MethodDeclaration() { + ReturnType = new PrimitiveType("void"), + Name = methodName, + Body = new BlockStatement() + }; + bool usesNonStaticMember = false; + foreach (Statement node in statements) { + usesNonStaticMember |= StaticVisitor.UsesNotStaticMember(context, node); + method.Body.Add(node.Clone()); + } + if (!usesNonStaticMember) + method.Modifiers |= Modifiers.Static; + + var target = new IdentifierExpression(methodName); + var invocation = new InvocationExpression(target); + + var usedVariables = VariableLookupVisitor.Analyze(context, statements); + + var extractedCodeAnalysis = new DefiniteAssignmentAnalysis((Statement)statements [0].Parent, context.Resolver, context.CancellationToken); + var lastStatement = statements [statements.Count - 1]; + extractedCodeAnalysis.SetAnalyzedRange(statements [0], lastStatement); + var statusAfterMethod = new List>(); + + foreach (var variable in usedVariables) { + extractedCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken); + statusAfterMethod.Add(Tuple.Create(variable, extractedCodeAnalysis.GetStatusAfter(lastStatement))); + } + var stmt = statements [0].GetParent(); + while (stmt.GetParent () != null) { + stmt = stmt.GetParent(); + } + + var wholeCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken); + var statusBeforeMethod = new Dictionary(); + foreach (var variable in usedVariables) { + wholeCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken); + statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]); + } + + var afterCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken); + var statusAtEnd = new Dictionary(); + afterCodeAnalysis.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true); + + foreach (var variable in usedVariables) { + afterCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken); + statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]); + } + var beforeVisitor = new VariableLookupVisitor(context); + beforeVisitor.SetAnalyzedRange(stmt, statements [0], true, false); + stmt.AcceptVisitor(beforeVisitor); + var afterVisitor = new VariableLookupVisitor(context); + afterVisitor.SetAnalyzedRange(lastStatement, stmt, false, true); + stmt.AcceptVisitor(afterVisitor); + + foreach (var status in statusAfterMethod) { + if (!beforeVisitor.UsedVariables.Contains(status.Item1) && !afterVisitor.UsedVariables.Contains(status.Item1)) + continue; + Expression argumentExpression = new IdentifierExpression(status.Item1.Name); + + ParameterModifier mod; + switch (status.Item2) { + case DefiniteAssignmentStatus.AssignedAfterTrueExpression: + case DefiniteAssignmentStatus.AssignedAfterFalseExpression: + case DefiniteAssignmentStatus.PotentiallyAssigned: + mod = ParameterModifier.Ref; + argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression); + break; + case DefiniteAssignmentStatus.DefinitelyAssigned: + if (statusBeforeMethod [status.Item1] != DefiniteAssignmentStatus.PotentiallyAssigned) + goto case DefiniteAssignmentStatus.PotentiallyAssigned; + mod = ParameterModifier.Out; + argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression); + break; +// case DefiniteAssignmentStatus.Unassigned: + default: + mod = ParameterModifier.None; + break; + } + method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(status.Item1.Type), status.Item1.Name, mod)); + invocation.Arguments.Add(argumentExpression); + } + + script.InsertWithCursor(context.TranslateString("Extract method"), method, Script.InsertPosition.Before); + foreach (var node in statements.Skip (1)) { + script.Remove(node); + } + script.Replace(statements [0], new ExpressionStatement(invocation)); + script.Link(target, method.NameToken); + }); + } + } +} diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/StaticVisitor.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/StaticVisitor.cs new file mode 100644 index 0000000000..168fe3e3df --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/StaticVisitor.cs @@ -0,0 +1,85 @@ +// +// StaticVisitor.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using ICSharpCode.NRefactory.Semantics; +using System.Linq; +using ICSharpCode.NRefactory.CSharp.Resolver; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod +{ + class StaticVisitor : DepthFirstAstVisitor + { + readonly RefactoringContext context; + public bool UsesNonStaticMember = false; + + StaticVisitor(RefactoringContext context) + { + this.context = context; + } + + + public static bool UsesNotStaticMember(RefactoringContext context, AstNode node) + { + var visitor = new StaticVisitor(context); + node.AcceptVisitor(visitor); + return visitor.UsesNonStaticMember; + } + + protected override void VisitChildren(AstNode node) + { + if (UsesNonStaticMember) + return; + base.VisitChildren(node); + } + + public override void VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression) + { + UsesNonStaticMember = true; + base.VisitThisReferenceExpression(thisReferenceExpression); + } + + public override void VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression) + { + UsesNonStaticMember = true; + base.VisitBaseReferenceExpression(baseReferenceExpression); + } + + public override void VisitIdentifierExpression(IdentifierExpression identifierExpression) + { + var resolveResult = context.Resolve(identifierExpression); + if (resolveResult is MemberResolveResult) { + var memberResult = (MemberResolveResult)resolveResult; + if (!memberResult.Member.IsStatic) + UsesNonStaticMember = true; + } else if (resolveResult is MethodGroupResolveResult) { + var methodGroupResolveResult = (MethodGroupResolveResult)resolveResult; + if (methodGroupResolveResult.Methods.Any(m => !m.IsStatic)) + UsesNonStaticMember = true; + } + } + } +} diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/VariableLookupVisitor.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/VariableLookupVisitor.cs new file mode 100644 index 0000000000..3613ebb2a7 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ExtractMethod/VariableLookupVisitor.cs @@ -0,0 +1,97 @@ +// +// VariableLookupVisitor.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod +{ + class VariableLookupVisitor : DepthFirstAstVisitor + { + readonly RefactoringContext context; + + public List UsedVariables = new List (); + + TextLocation startLocation = TextLocation.Empty; + TextLocation endLocation = TextLocation.Empty; + + + public VariableLookupVisitor (RefactoringContext context) + { + this.context = context; + } + + public void SetAnalyzedRange(AstNode start, AstNode end, bool startInclusive = true, bool endInclusive = true) + { + if (start == null) + throw new ArgumentNullException("start"); + if (end == null) + throw new ArgumentNullException("end"); + startLocation = startInclusive ? start.StartLocation : start.EndLocation; + endLocation = endInclusive ? end.EndLocation : end.StartLocation; + } + + public override void VisitIdentifierExpression(IdentifierExpression identifierExpression) + { + if (startLocation.IsEmpty || startLocation <= identifierExpression.StartLocation && identifierExpression.EndLocation <= endLocation) { + var result = context.Resolve(identifierExpression); + var local = result as LocalResolveResult; + if (local != null && !UsedVariables.Contains(local.Variable)) + UsedVariables.Add(local.Variable); + } + } + + public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) + { + base.VisitVariableDeclarationStatement(variableDeclarationStatement); + foreach (var varDecl in variableDeclarationStatement.Variables) { + if (startLocation.IsEmpty || startLocation <= varDecl.StartLocation && varDecl.EndLocation <= endLocation) { + var result = context.Resolve(varDecl); + var local = result as LocalResolveResult; + if (local != null && !UsedVariables.Contains(local.Variable)) + UsedVariables.Add(local.Variable); + } + } + } + + + public static List Analyze(RefactoringContext context, Expression expression) + { + var visitor = new VariableLookupVisitor(context); + expression.AcceptVisitor(visitor); + return visitor.UsedVariables; + } + + public static List Analyze(RefactoringContext context, List statements) + { + var visitor = new VariableLookupVisitor(context); + statements.ForEach(stmt => stmt.AcceptVisitor(visitor)); + return visitor.UsedVariables; + } + } +} + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs index 23754bb6bf..76dc5e24c9 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs @@ -47,7 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring public virtual AstType CreateShortType (IType fullType) { - var csResolver = resolver.GetResolverStateBefore(GetNode()); + var csResolver = Resolver.GetResolverStateBefore(GetNode()); var builder = new TypeSystemAstBuilder(csResolver); return builder.ConvertType(fullType); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractMethodTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractMethodTests.cs new file mode 100644 index 0000000000..e77b91901f --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ExtractMethodTests.cs @@ -0,0 +1,373 @@ +// +// ExtractMethodTests.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod; + +namespace ICSharpCode.NRefactory.CSharp.CodeActions +{ + [TestFixture] + public class ExtractMethodTests : ContextActionTestBase + { + + [Ignore("FIXME!!")] + [Test()] + public void ExtractMethodResultStatementTest() + { + Test(@"class TestClass +{ + int member = 5; + void TestMethod () + { + int i = 5; + <-i = member + 1;-> + Console.WriteLine (i); + } +} +", @"class TestClass +{ + int member = 5; + void NewMethod (ref int i) + { + i = member + 1; + } + void TestMethod () + { + int i = 5; + NewMethod (ref i); + Console.WriteLine (i); + } +} +"); + } + + [Test()] + public void ExtractMethodResultExpressionTest() + { + Test(@"class TestClass +{ + int member = 5; + void TestMethod () + { + int i = <-member + 1->; + Console.WriteLine (i); + } +} +", @"class TestClass +{ + int member = 5; + int NewMethod () + { + return member + 1; + } + void TestMethod () + { + int i = NewMethod (); + Console.WriteLine (i); + } +} +"); + } + + [Ignore("FIXME!!")] + [Test()] + public void ExtractMethodStaticResultStatementTest() + { + Test(@"class TestClass +{ + void TestMethod () + { + int i = 5; + <-i = i + 1;-> + Console.WriteLine (i); + } +} +", @"class TestClass +{ + static void NewMethod (ref int i) + { + i = i + 1; + } + void TestMethod () + { + int i = 5; + NewMethod (ref i); + Console.WriteLine (i); + } +} +"); + } + + [Test()] + public void ExtractMethodStaticResultExpressionTest() + { + Test(@"class TestClass +{ + void TestMethod () + { + int i = <-5 + 1->; + Console.WriteLine (i); + } +} +", @"class TestClass +{ + static int NewMethod () + { + return 5 + 1; + } + void TestMethod () + { + int i = NewMethod (); + Console.WriteLine (i); + } +} +"); + } + + [Ignore("FIXME!!")] + [Test()] + public void ExtractMethodMultiVariableTest() + { + Test(@"class TestClass +{ + int member; + void TestMethod () + { + int i = 5, j = 10, k; + <-j = i + j; + k = j + member;-> + Console.WriteLine (k + j); + } +} +", @"class TestClass +{ + int member; + void NewMethod (ref int j, int i, out int k) + { + j = i + j; + k = j + member; + } + void TestMethod () + { + int i = 5, j = 10, k; + NewMethod (i, ref j, out k); + Console.WriteLine (k + j); + } +} +"); + } + + /// + /// Bug 607990 - "Extract Method" refactoring sometimes tries to pass in unnecessary parameter depending on selection + /// + [Test()] + public void TestBug607990() + { + Test(@"class TestClass +{ + void TestMethod () + { + <-Object obj1 = new Object(); + obj1.ToString();-> + } +} +", @"class TestClass +{ + static void NewMethod () + { + Object obj1 = new Object (); + obj1.ToString (); + } + void TestMethod () + { + NewMethod (); + } +} +"); + } + + + /// + /// Bug 616193 - Extract method passes param with does not exists any more in main method + /// + [Ignore("FIXME!!")] + [Test()] + public void TestBug616193() + { + Test(@"class TestClass +{ + void TestMethod () + { + string ret; + string x; + int y; + <-string z = ret + y; + ret = x + z;-> + } +} +", @"class TestClass +{ + static void NewMethod (out string ret, string x, int y) + { + string z = ret + y; + ret = x + z; + } + void TestMethod () + { + string ret; + string x; + int y; + NewMethod (out ret, x, y); + } +} +"); + } + + /// + /// Bug 616199 - Extract method forgets to return a local var which is used in main method + /// + [Ignore("FIXME!!")] + [Test()] + public void TestBug616199() + { + Test(@"class TestClass +{ + void TestMethod () + { + <-string z = ""test"" + ""x"";-> + string ret = ""test1"" + z; + } +} +", @"class TestClass +{ + static string NewMethod () + { + string z = ""test"" + ""x""; + return z; + } + void TestMethod () + { + string z = NewMethod (); + string ret = ""test1"" + z; + } +} +"); + } + + /// + /// Bug 666271 - "Extract Method" on single line adds two semi-colons in method, none in replaced text + /// + [Test()] + public void TestBug666271() + { + Test(@"class TestClass +{ + void TestMethod () + { + <-TestMethod ();-> + } +} +", @"class TestClass +{ + void NewMethod () + { + TestMethod (); + } + void TestMethod () + { + NewMethod (); + } +} +"); + } + + + /// + /// Bug 693944 - Extracted method returns void instead of the correct type + /// + [Test()] + public void TestBug693944() + { + Test(@"class TestClass +{ + void TestMethod () + { + TestMethod (<-""Hello""->); + } +} +", @"class TestClass +{ + static string NewMethod () + { + return ""Hello""; + } + void TestMethod () + { + TestMethod (NewMethod ()); + } +} +"); + } + + + [Ignore("FIXME!!")] + [Test()] + public void ExtractMethodMultiVariableWithLocalReturnVariableTest() + { + Test(@"class TestClass +{ + int member; + void TestMethod () + { + int i = 5, j = 10, k; + <-int test; + j = i + j; + k = j + member; + test = i + j + k;-> + Console.WriteLine (test); + } +} +", @"class TestClass +{ + int member; + void NewMethod (ref int j, int i, out int k, out int test) + { + j = i + j; + k = j + member; + test = i + j + k; + } + void TestMethod () + { + int i = 5, j = 10, k; + int test; + NewMethod (i, ref j, out k, out test); + Console.WriteLine (test); + } +} +"); + } + } +} + diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index afc6c6ef61..63a6c799e8 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -260,6 +260,7 @@ + @@ -294,6 +295,8 @@ + +