diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index b3b9add5b5..9c4c3aa1d8 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -278,7 +278,6 @@ - @@ -536,6 +535,7 @@ + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToStaticMethodAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToStaticMethodAction.cs deleted file mode 100644 index 0d18436be4..0000000000 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertToStaticMethodAction.cs +++ /dev/null @@ -1,100 +0,0 @@ - -// ConvertToStaticMethodAction.cs -// -// Author: -// Ciprian Khlud -// -// Copyright (c) 2013 Ciprian Khlud -// -// 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.Collections.Generic; -using ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod; -using ICSharpCode.NRefactory.CSharp.Resolver; -using ICSharpCode.NRefactory.Semantics; -using System.Linq; -using ICSharpCode.NRefactory.TypeSystem; - -namespace ICSharpCode.NRefactory.CSharp.Refactoring -{ - [ContextAction("Make this method static", Description = "This method doesn't use any non static members so it can be made static")] - public class ConvertToStaticMethodAction : ICodeActionProvider - { - public IEnumerable GetActions(RefactoringContext context) - { - // TODO: Invert if without else - // ex. if (cond) DoSomething () == if (!cond) return; DoSomething () - // beware of loop contexts return should be continue then. - var methodDeclaration = GetMethodDeclaration(context); - if (methodDeclaration == null) - yield break; - - var resolved = context.Resolve(methodDeclaration) as MemberResolveResult; - if (resolved == null) - yield break; - var isImplementingInterface = resolved.Member.ImplementedInterfaceMembers.Any(); - - if (isImplementingInterface) - yield break; - yield return new CodeAction(context.TranslateString(string.Format("Make '{0}' static", methodDeclaration.Name)), script => - { - var clonedDeclaration = (MethodDeclaration)methodDeclaration.Clone(); - clonedDeclaration.Modifiers |= Modifiers.Static; - script.Replace(methodDeclaration, clonedDeclaration); - var rr = context.Resolve (methodDeclaration) as MemberResolveResult; - var method = (IMethod)rr.Member; - //method.ImplementedInterfaceMembers.Any(m => methodGroupResolveResult.Methods.Contains((IMethod)m)); - - script.DoGlobalOperationOn(rr.Member, (fctx, fscript, fnode) => { - if (fnode is MemberReferenceExpression) { - var memberReference = new MemberReferenceExpression ( - new TypeReferenceExpression (fctx.CreateShortType (rr.Member.DeclaringType)), - rr.Member.Name - ); - fscript.Replace (fnode, memberReference); - } else if (fnode is InvocationExpression) { - var invoke = (InvocationExpression)fnode; - if (!(invoke.Target is MemberReferenceExpression)) - return; - var memberReference = new MemberReferenceExpression ( - new TypeReferenceExpression (fctx.CreateShortType (rr.Member.DeclaringType)), - rr.Member.Name - ); - fscript.Replace (invoke.Target, memberReference); - } - }); - }, methodDeclaration); - } - - static MethodDeclaration GetMethodDeclaration(RefactoringContext context) - { - var result = context.GetNode (); - if (result == null) - return null; - //unsafe transformation for now. For all other public instances the code should - //replace the variable.Call(...) to ClassName.Call() - const Modifiers ignoredModifiers = Modifiers.Override | Modifiers.Virtual | Modifiers.Static; - if ((result.Modifiers & ignoredModifiers) != 0) - return null; - - var usesNonStatic = StaticVisitor.UsesNotStaticMember(context, result); - if (usesNonStatic) return null; - return result; - } - } -} diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConvertToStaticMethodIssue.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConvertToStaticMethodIssue.cs new file mode 100644 index 0000000000..a00a1498ee --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConvertToStaticMethodIssue.cs @@ -0,0 +1,125 @@ +// +// ConvertToStaticMethodIssue.cs +// +// Author: +// Ciprian Khlud +// +// Copyright (c) 2013 Ciprian Khlud +// +// 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 ICSharpCode.NRefactory.CSharp.Refactoring; +using System.Collections.Generic; +using ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod; +using ICSharpCode.NRefactory.Semantics; +using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring +{ + [IssueDescription("Make this method static", + Description = "This method doesn't use any non static members so it can be made static", + Severity = Severity.Hint, + IssueMarker = IssueMarker.Underline)] + public class ConvertToStaticMethodIssue : ICodeIssueProvider + { + public IEnumerable GetIssues(BaseRefactoringContext context) + { + return new GatherVisitor(context).GetIssues(); + } + + private class GatherVisitor : GatherVisitorBase + { + private bool initializerInvoked; + private ConstructorInitializer initializer; + + public GatherVisitor(BaseRefactoringContext context) + : base(context) + { + } + + public override void VisitMethodDeclaration(MethodDeclaration declaration) + { + // TODO: Invert if without else + // ex. if (cond) DoSomething () == if (!cond) return; DoSomething () + // beware of loop contexts return should be continue then. + var context = ctx; + var methodDeclaration = declaration; + + var resolved = context.Resolve(methodDeclaration) as MemberResolveResult; + if (resolved == null) + return; + var isImplementingInterface = resolved.Member.ImplementedInterfaceMembers.Any(); + + if (isImplementingInterface) + return; + + AddIssue(methodDeclaration.StartLocation, methodDeclaration.Body.StartLocation, + context.TranslateString(string.Format("Make '{0}' static", methodDeclaration.Name)), + script => ExecuteScriptToFixStaticMethodIssue(script, context, methodDeclaration)); + } + + private static void ExecuteScriptToFixStaticMethodIssue(Script script, + BaseRefactoringContext context, + AstNode methodDeclaration) + { + var clonedDeclaration = (MethodDeclaration) methodDeclaration.Clone(); + clonedDeclaration.Modifiers |= Modifiers.Static; + script.Replace(methodDeclaration, clonedDeclaration); + var rr = context.Resolve(methodDeclaration) as MemberResolveResult; + var method = (IMethod) rr.Member; + //method.ImplementedInterfaceMembers.Any(m => methodGroupResolveResult.Methods.Contains((IMethod)m)); + + script.DoGlobalOperationOn(rr.Member, + (fctx, fscript, fnode) => { DoStaticMethodGlobalOperation(fnode, fctx, rr, fscript); }); + } + + private static void DoStaticMethodGlobalOperation(AstNode fnode, RefactoringContext fctx, MemberResolveResult rr, + Script fscript) + { + if (fnode is MemberReferenceExpression) + { + var memberReference = new MemberReferenceExpression + ( + new TypeReferenceExpression( + fctx.CreateShortType(rr.Member.DeclaringType)), + rr.Member.Name + ); + fscript.Replace(fnode, memberReference); + } + else + { + var invoke = fnode as InvocationExpression; + if (invoke == null) return; + if ((invoke.Target is MemberReferenceExpression)) + return; + var memberReference = new MemberReferenceExpression + ( + new TypeReferenceExpression( + fctx.CreateShortType( + rr.Member.DeclaringType)), + rr.Member.Name + ); + fscript.Replace(invoke.Target, memberReference); + } + } + } + + } +} + diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToStaticMethodActionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToStaticMethodIssueTests.cs similarity index 57% rename from ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToStaticMethodActionTests.cs rename to ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToStaticMethodIssueTests.cs index 2b8a224406..a32fa16d80 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/ConvertToStaticMethodActionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToStaticMethodIssueTests.cs @@ -1,10 +1,10 @@ // -// ConvertToStaticMethodActionTests.cs +// ConvertToStaticMethodIssue.cs // // Author: -// Ciprian Khlud +// Ciprian Khlud // -// Copyright (c) 2013 Ciprian Khlud +// Copyright (c) 2013 Ciprian Khlud // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -23,50 +23,53 @@ // 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 ICSharpCode.NRefactory.CSharp.Refactoring; + using NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.Refactoring; -namespace ICSharpCode.NRefactory.CSharp.CodeActions { - [TestFixture] - public class ConvertToStaticMethodActionTests : ContextActionTestBase - { - [Test] - public void Test() - { - Test( - @"class TestClass +namespace ICSharpCode.NRefactory.CSharp.CodeIssues +{ + [TestFixture] + public class ConvertToStaticMethodIssueTests : InspectionActionTestBase + { + + [Test] + public void Test() + { + Test( + @"class TestClass { void $Test () { int a = 2; } }", - @"class TestClass + @"class TestClass { static void Test () { int a = 2; } }" - ); - } - [Test] - public void TestWithVirtualFunction() { - - var input = @"class TestClass + ); + } + [Test] + public void TestWithVirtualFunction() { + + var input = @"class TestClass { public virtual void $Test () { int a = 2; } -}"; - TestWrongContext(input); - } - - [Test] - public void TestWithInterface() { - - var input = @"interface IBase { +}"; + TestWrongContext(input); + } + + [Test] + public void TestWithInterface() { + + var input = @"interface IBase { void Test(); } class TestClass : IBase @@ -76,20 +79,22 @@ class TestClass : IBase int a = 2; } }"; - TestWrongContext(input); - } - [Test] - public void TestWithStaticFunction() - { - - var input = @"class TestClass + TestWrongContext(input); + } + [Test] + public void TestWithStaticFunction() + { + + var input = @"class TestClass { static void $Test () { int a = 2; } }"; - TestWrongContext(input); - } - } -} \ No newline at end of file + TestWrongContext(input); + } + + } + +} diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs index f20d38102f..ecef790c70 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/InspectionActionTestBase.cs @@ -95,6 +95,12 @@ namespace ICSharpCode.NRefactory.CSharp.CodeIssues Assert.AreEqual (1, issues.Count); CheckFix (context, issues[0], output, fixIndex); } + + protected static void TestWrongContext (string input) + where T : ICodeIssueProvider, new () + { + Test(input, 0); + } } } diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index caba03e74c..be51d7f2e8 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -109,7 +109,6 @@ - @@ -411,6 +410,7 @@ +