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 @@
+
+