From ceef5713151a91978cdda498224c68ea1e456c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Sun, 1 Apr 2012 08:42:06 +0200 Subject: [PATCH] Added introduce constant action. --- .../ICSharpCode.NRefactory.CSharp.csproj | 1 + .../CodeActions/IntroduceConstantAction.cs | 90 ++++++++++++++++++ .../NamingConventionService.cs | 22 +++++ .../CodeActions/IntroduceConstantTests.cs | 94 +++++++++++++++++++ .../ICSharpCode.NRefactory.Tests.csproj | 1 + 5 files changed, 208 insertions(+) create mode 100644 ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceConstantAction.cs create mode 100644 ICSharpCode.NRefactory.Tests/CSharp/CodeActions/IntroduceConstantTests.cs diff --git a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj index 711487e1fa..3767b2e0d7 100644 --- a/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj +++ b/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj @@ -358,6 +358,7 @@ + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceConstantAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceConstantAction.cs new file mode 100644 index 0000000000..e661ba0125 --- /dev/null +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceConstantAction.cs @@ -0,0 +1,90 @@ +// +// IntroduceConstantAction.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2012 Xamarin +// +// 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; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring +{ + [ContextAction("Introduce constant", Description = "Creates a constant for a non constant primitive expression.")] + public class IntroduceConstantAction : ICodeActionProvider + { + public IEnumerable GetActions(RefactoringContext context) + { + var pexpr = context.GetNode(); + if (pexpr == null) + yield break; + var statement = context.GetNode(); + if (statement == null) { + yield break; + } + + var resolveResult = context.Resolve(pexpr); + + yield return new CodeAction(context.TranslateString("Create local constant"), script => { + string name = CreateMethodDeclarationAction.CreateBaseName(pexpr, resolveResult.Type); + var service = (NamingConventionService)context.GetService(typeof(NamingConventionService)); + if (service != null) + name = service.CheckName(context, name, AffectedEntity.LocalConstant); + + var initializer = new VariableInitializer(name, pexpr.Clone()); + var decl = new VariableDeclarationStatement() { + Type = context.CreateShortType(resolveResult.Type), + Modifiers = Modifiers.Const, + Variables = { initializer } + }; + + script.InsertBefore(statement, decl); + var variableUsage = new IdentifierExpression(name); + script.Replace(pexpr, variableUsage); + script.Link(initializer.NameToken, variableUsage); + }); + + yield return new CodeAction(context.TranslateString("Create constant field"), script => { + string name = CreateMethodDeclarationAction.CreateBaseName(pexpr, resolveResult.Type); + var service = (NamingConventionService)context.GetService(typeof(NamingConventionService)); + if (service != null) + name = service.CheckName(context, name, AffectedEntity.ConstantField); + + var initializer = new VariableInitializer(name, pexpr.Clone()); + + var decl = new FieldDeclaration() { + ReturnType = context.CreateShortType(resolveResult.Type), + Modifiers = Modifiers.Const, + Variables = { initializer } + }; + + script.InsertWithCursor(context.TranslateString("Create constant"), decl, Script.InsertPosition.Before); + + var variableUsage = new IdentifierExpression(name); + script.Replace(pexpr, variableUsage); + script.Link(initializer.NameToken, variableUsage); + }); + } + } +} + diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingConventionService.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingConventionService.cs index e24b54de6f..51d2cf5afc 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingConventionService.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingConventionService.cs @@ -35,6 +35,28 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring get; } + public string CheckName(RefactoringContext ctx, string name, AffectedEntity entity, Modifiers accessibilty = Modifiers.Private, bool isStatic = false) + { + foreach (var rule in Rules) { + if (!rule.AffectedEntity.HasFlag(entity)) { + continue; + } + if (!rule.VisibilityMask.HasFlag(accessibilty)) { + continue; + } + if (isStatic && !rule.IncludeStaticEntities || !isStatic && !rule.IncludeInstanceMembers) { + continue; + } + if (!rule.IsValid(name)) { + IList suggestedNames; + var msg = rule.GetErrorMessage(ctx, name, out suggestedNames); + if (suggestedNames.Any ()) + return suggestedNames [0]; + } + } + return name; + } + public bool IsValidName(string name, AffectedEntity entity, Modifiers accessibilty = Modifiers.Private, bool isStatic = false) { foreach (var rule in Rules) { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/IntroduceConstantTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/IntroduceConstantTests.cs new file mode 100644 index 0000000000..f555cd10b4 --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/IntroduceConstantTests.cs @@ -0,0 +1,94 @@ +// +// IntroduceConstantTests.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2012 Xamarin +// +// 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 NUnit.Framework; +using ICSharpCode.NRefactory.CSharp.Refactoring; + +namespace ICSharpCode.NRefactory.CSharp.CodeActions +{ + [TestFixture] + public class IntroduceConstantTests : ContextActionTestBase + { + [Test()] + public void TestLocalConstant () + { + Test (@"class TestClass +{ + public void Hello () + { + System.Console.WriteLine ($""Hello World""); + } +}", @"class TestClass +{ + public void Hello () + { + const string helloWorld = ""Hello World""; + System.Console.WriteLine (helloWorld); + } +}"); + } + + [Test()] + public void TestLocalConstantHexNumber () + { + Test (@"class TestClass +{ + public void Hello () + { + System.Console.WriteLine ($0xAFFE); + } +}", @"class TestClass +{ + public void Hello () + { + const int i = 0xAFFE; + System.Console.WriteLine (i); + } +}"); + } + + [Test()] + public void TestFieldConstant () + { + Test (@"class TestClass +{ + public void Hello () + { + System.Console.WriteLine ($""Hello World""); + } +}", @"class TestClass +{ + const string HelloWorld = ""Hello World""; + + public void Hello () + { + System.Console.WriteLine (HelloWorld); + } +}", 1); + } + } +} \ No newline at end of file diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index b22149a5ad..afc6c6ef61 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -259,6 +259,7 @@ +