Browse Source

Changed the ContextAction/Inspector API.

newNRvisualizers
Mike Krüger 14 years ago
parent
commit
acfcf370ef
  1. 82
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  2. 55
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeAction.cs
  3. 49
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/AddAnotherAccessor.cs
  4. 54
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CheckIfParameterIsNull.cs
  5. 30
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertDecToHex.cs
  6. 85
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertForeachToFor.cs
  7. 30
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertHexToDec.cs
  8. 76
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateBackingStore.cs
  9. 112
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateEventInvocator.cs
  10. 28
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateField.cs
  11. 48
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateLocalVariable.cs
  12. 26
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateProperty.cs
  13. 23
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/FlipOperatorArguments.cs
  14. 38
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateGetter.cs
  15. 37
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateProperty.cs
  16. 75
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateSwitchLabels.cs
  17. 51
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/InsertAnonymousMethodSignature.cs
  18. 61
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceFormatItem.cs
  19. 34
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/InvertIf.cs
  20. 26
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveBackingStore.cs
  21. 26
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveBraces.cs
  22. 27
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveRegion.cs
  23. 20
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ReplaceEmptyString.cs
  24. 45
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SplitDeclarationAndAssignment.cs
  25. 47
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SplitString.cs
  26. 35
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseExplicitType.cs
  27. 25
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseVarKeyword.cs
  28. 14
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssue.cs
  29. 16
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConditionalToNullCoalescingInspector.cs
  30. 8
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/GatherVisitorBase.cs
  31. 41
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IssueCategories.cs
  32. 5
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/NotImplementedExceptionInspector.cs
  33. 15
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantInternalInspector.cs
  34. 15
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantNamespaceUsageInspector.cs
  35. 17
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantPrivateInspector.cs
  36. 15
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantThisInspector.cs
  37. 17
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantUsingInspector.cs
  38. 20
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyInspector.cs
  39. 8
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/UseVarKeywordInspector.cs
  40. 78
      ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateBackingStore.cs
  41. 110
      ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateEventInvocator.cs
  42. 42
      ICSharpCode.NRefactory.CSharp/Refactoring/ContextActionAttribute.cs
  43. 6
      ICSharpCode.NRefactory.CSharp/Refactoring/ICodeActionProvider.cs
  44. 4
      ICSharpCode.NRefactory.CSharp/Refactoring/ICodeIssueProvider.cs
  45. 50
      ICSharpCode.NRefactory.CSharp/Refactoring/IssueAttribute.cs
  46. 52
      ICSharpCode.NRefactory.CSharp/Refactoring/IssueMarker.cs
  47. 42
      ICSharpCode.NRefactory.CSharp/Refactoring/Severity.cs
  48. 17
      ICSharpCode.NRefactory.Tests/CSharp/ContextAction/ContextActionTestBase.cs
  49. 30
      ICSharpCode.NRefactory.Tests/CSharp/Inspector/ConditionalToNullCoalescingInspectorTests.cs
  50. 12
      ICSharpCode.NRefactory.Tests/CSharp/Inspector/InspectionActionTestBase.cs

82
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -240,31 +240,7 @@ @@ -240,31 +240,7 @@
<Compile Include="Parser\mcs\typespec.cs" />
<Compile Include="Parser\mcs\visit.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Refactoring\ContextAction\AddAnotherAccessor.cs" />
<Compile Include="Refactoring\ContextAction\CheckIfParameterIsNull.cs" />
<Compile Include="Refactoring\ContextAction\ConvertDecToHex.cs" />
<Compile Include="Refactoring\ContextAction\ConvertForeachToFor.cs" />
<Compile Include="Refactoring\ContextAction\ConvertHexToDec.cs" />
<Compile Include="Refactoring\ContextAction\CreateBackingStore.cs" />
<Compile Include="Refactoring\ContextAction\CreateEventInvocator.cs" />
<Compile Include="Refactoring\ContextAction\CreateField.cs" />
<Compile Include="Refactoring\ContextAction\CreateLocalVariable.cs" />
<Compile Include="Refactoring\ContextAction\CreateProperty.cs" />
<Compile Include="Refactoring\ContextAction\FlipOperatorArguments.cs" />
<Compile Include="Refactoring\ContextAction\GenerateGetter.cs" />
<Compile Include="Refactoring\ContextAction\GenerateSwitchLabels.cs" />
<Compile Include="Refactoring\ContextAction\InsertAnonymousMethodSignature.cs" />
<Compile Include="Refactoring\ContextAction\IntroduceFormatItem.cs" />
<Compile Include="Refactoring\ContextAction\InvertIf.cs" />
<Compile Include="Refactoring\ContextAction\RemoveBackingStore.cs" />
<Compile Include="Refactoring\ContextAction\RemoveBraces.cs" />
<Compile Include="Refactoring\ContextAction\ReplaceEmptyString.cs" />
<Compile Include="Refactoring\ContextAction\SplitDeclarationAndAssignment.cs" />
<Compile Include="Refactoring\ContextAction\SplitString.cs" />
<Compile Include="Refactoring\ContextAction\UseExplicitType.cs" />
<Compile Include="Refactoring\ContextAction\UseVarKeyword.cs" />
<Compile Include="Refactoring\DocumentScript.cs" />
<Compile Include="Refactoring\IContextAction.cs" />
<Compile Include="Refactoring\PatternHelper.cs" />
<Compile Include="Refactoring\RefactoringAstHelper.cs" />
<Compile Include="Refactoring\RefactoringContext.cs" />
@ -321,22 +297,52 @@ @@ -321,22 +297,52 @@
<Compile Include="Parser\mcs\settings.cs" />
<Compile Include="Parser\mcs\SourceMethodBuilder.cs" />
<Compile Include="Ast\TokenRole.cs" />
<Compile Include="Refactoring\ContextAction\RemoveRegion.cs" />
<Compile Include="Refactoring\ContextAction\GenerateProperty.cs" />
<Compile Include="Ast\Roles.cs" />
<Compile Include="Refactoring\Inspector\ConditionalToNullCoalescingInspector.cs" />
<Compile Include="Refactoring\IInspector.cs" />
<Compile Include="Refactoring\BaseRefactoringContext.cs" />
<Compile Include="Refactoring\Inspector\GatherVisitorBase.cs" />
<Compile Include="Refactoring\Inspector\NotImplementedExceptionInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantInternalInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantNamespaceUsageInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantPrivateInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantThisInspector.cs" />
<Compile Include="Refactoring\Inspector\RedundantUsingInspector.cs" />
<Compile Include="Refactoring\Inspector\StringIsNullOrEmptyInspector.cs" />
<Compile Include="Refactoring\Inspector\UseVarKeywordInspector.cs" />
<Compile Include="Refactoring\CodeIssue.cs" />
<Compile Include="Refactoring\CodeAction.cs" />
<Compile Include="Refactoring\ICodeActionProvider.cs" />
<Compile Include="Refactoring\CodeActions\AddAnotherAccessor.cs" />
<Compile Include="Refactoring\ICodeIssueProvider.cs" />
<Compile Include="Refactoring\CodeActions\CheckIfParameterIsNull.cs" />
<Compile Include="Refactoring\CodeActions\ConvertDecToHex.cs" />
<Compile Include="Refactoring\CodeActions\ConvertForeachToFor.cs" />
<Compile Include="Refactoring\CodeActions\ConvertHexToDec.cs" />
<Compile Include="Refactoring\CodeActions\CreateBackingStore.cs" />
<Compile Include="Refactoring\CodeActions\CreateEventInvocator.cs" />
<Compile Include="Refactoring\CodeActions\CreateField.cs" />
<Compile Include="Refactoring\CodeActions\CreateLocalVariable.cs" />
<Compile Include="Refactoring\CodeActions\CreateProperty.cs" />
<Compile Include="Refactoring\CodeActions\FlipOperatorArguments.cs" />
<Compile Include="Refactoring\CodeActions\GenerateGetter.cs" />
<Compile Include="Refactoring\CodeActions\GenerateSwitchLabels.cs" />
<Compile Include="Refactoring\CodeActions\InsertAnonymousMethodSignature.cs" />
<Compile Include="Refactoring\CodeActions\IntroduceFormatItem.cs" />
<Compile Include="Refactoring\CodeActions\InvertIf.cs" />
<Compile Include="Refactoring\CodeActions\RemoveBackingStore.cs" />
<Compile Include="Refactoring\CodeActions\RemoveBraces.cs" />
<Compile Include="Refactoring\CodeActions\ReplaceEmptyString.cs" />
<Compile Include="Refactoring\CodeActions\SplitDeclarationAndAssignment.cs" />
<Compile Include="Refactoring\CodeActions\SplitString.cs" />
<Compile Include="Refactoring\CodeActions\UseExplicitType.cs" />
<Compile Include="Refactoring\CodeActions\UseVarKeyword.cs" />
<Compile Include="Refactoring\CodeActions\RemoveRegion.cs" />
<Compile Include="Refactoring\CodeActions\GenerateProperty.cs" />
<Compile Include="Refactoring\ContextActionAttribute.cs" />
<Compile Include="Refactoring\IssueAttribute.cs" />
<Compile Include="Refactoring\CodeIssues\IssueCategories.cs" />
<Compile Include="Refactoring\Severity.cs" />
<Compile Include="Refactoring\IssueMarker.cs" />
<Compile Include="Refactoring\CodeIssues\ConditionalToNullCoalescingInspector.cs" />
<Compile Include="Refactoring\CodeIssues\GatherVisitorBase.cs" />
<Compile Include="Refactoring\CodeIssues\NotImplementedExceptionInspector.cs" />
<Compile Include="Refactoring\CodeIssues\RedundantInternalInspector.cs" />
<Compile Include="Refactoring\CodeIssues\RedundantNamespaceUsageInspector.cs" />
<Compile Include="Refactoring\CodeIssues\RedundantPrivateInspector.cs" />
<Compile Include="Refactoring\CodeIssues\RedundantThisInspector.cs" />
<Compile Include="Refactoring\CodeIssues\RedundantUsingInspector.cs" />
<Compile Include="Refactoring\CodeIssues\StringIsNullOrEmptyInspector.cs" />
<Compile Include="Refactoring\CodeIssues\UseVarKeywordInspector.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
@ -347,7 +353,7 @@ @@ -347,7 +353,7 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Folder Include="Completion\" />
<Folder Include="Refactoring\Inspector\" />
<Folder Include="Refactoring\CodeIssues\" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>

55
ICSharpCode.NRefactory.CSharp/Refactoring/CodeAction.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
//
// CodeAction.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// 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;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class CodeAction
{
public string Description {
get;
private set;
}
public Action<Script> Run {
get;
private set;
}
public CodeAction (string description, Action<Script> action)
{
if (action == null) {
throw new ArgumentNullException ("action");
}
if (description == null) {
throw new ArgumentNullException ("description");
}
Description = description;
Run = action;
}
}
}

49
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/AddAnotherAccessor.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/AddAnotherAccessor.cs

@ -24,38 +24,35 @@ @@ -24,38 +24,35 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Add another accessor to a property declaration that has only one.
/// </summary>
public class AddAnotherAccessor : IContextAction
[ContextAction("Add another accessor", Description = "Adds second accessor to a property.")]
public class AddAnotherAccessor : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
{
var pdecl = GetPropertyDeclaration (context);
if (pdecl == null)
return false;
var type = pdecl.Parent as TypeDeclaration;
if (type != null && type.ClassType == ClassType.Interface)
return false;
return pdecl.Setter.IsNull || pdecl.Getter.IsNull;
}
public void Run(RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var pdecl = GetPropertyDeclaration(context);
var accessorStatement = BuildAccessorStatement(context, pdecl);
Accessor accessor = new Accessor () {
Body = new BlockStatement { accessorStatement }
};
accessor.Role = pdecl.Setter.IsNull ? PropertyDeclaration.SetterRole : PropertyDeclaration.GetterRole;
if (pdecl == null) {
yield break;
}
var type = pdecl.Parent as TypeDeclaration;
if (type != null && type.ClassType == ClassType.Interface) {
yield break;
}
yield return new CodeAction (pdecl.Setter.IsNull ? context.TranslateString("Add getter") : context.TranslateString("Add setter"), script => {
var accessorStatement = BuildAccessorStatement(context, pdecl);
using (var script = context.StartScript ()) {
Accessor accessor = new Accessor () {
Body = new BlockStatement { accessorStatement }
};
accessor.Role = pdecl.Setter.IsNull ? PropertyDeclaration.SetterRole : PropertyDeclaration.GetterRole;
if (pdecl.Setter.IsNull && !pdecl.Getter.IsNull) {
script.InsertBefore(pdecl.RBraceToken, accessor);
} else if (pdecl.Getter.IsNull && !pdecl.Setter.IsNull) {
@ -63,11 +60,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -63,11 +60,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
} else {
script.InsertBefore(pdecl.Getter, accessor);
}
script.Select (accessorStatement);
script.FormatText (pdecl);
}
script.Select(accessorStatement);
script.FormatText(pdecl);
});
}
static Statement BuildAccessorStatement (RefactoringContext context, PropertyDeclaration pdecl)
{
if (pdecl.Setter.IsNull && !pdecl.Getter.IsNull) {

54
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CheckIfParameterIsNull.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CheckIfParameterIsNull.cs

@ -25,48 +25,42 @@ @@ -25,48 +25,42 @@
// THE SOFTWARE.
using ICSharpCode.NRefactory.PatternMatching;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Creates a 'if (param == null) throw new System.ArgumentNullException ();' contruct for a parameter.
/// </summary>
public class CheckIfParameterIsNull : IContextAction
[ContextAction("Check if parameter is null", Description = "Checks function parameter is not null.")]
public class CheckIfParameterIsNull : ICodeActionProvider
{
//TODO: Create 'multiple' null checks when more than 1 parameter is selected.
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var parameter = GetParameterDeclaration (context);
if (parameter == null)
return false;
var parameter = GetParameterDeclaration(context);
if (parameter == null) {
yield break;
}
var bodyStatement = parameter.Parent.GetChildByRole (Roles.Body);
var bodyStatement = parameter.Parent.GetChildByRole(Roles.Body);
if (bodyStatement == null)
return false;
if (bodyStatement == null) {
yield break;
}
var type = context.ResolveType(parameter.Type);
if (type.IsReferenceType == false)
return false;
return !HasNullCheck (parameter);
}
public void Run (RefactoringContext context)
{
var parameter = GetParameterDeclaration (context);
var bodyStatement = parameter.Parent.GetChildByRole (Roles.Body);
var statement = new IfElseStatement () {
Condition = new BinaryOperatorExpression (new IdentifierExpression (parameter.Name), BinaryOperatorType.Equality, new NullReferenceExpression ()),
TrueStatement = new ThrowStatement (new ObjectCreateExpression (context.CreateShortType ("System", "ArgumentNullException"), new PrimitiveExpression (parameter.Name)))
};
using (var script = context.StartScript ()) {
script.AddTo (bodyStatement, statement);
if (type.IsReferenceType == false || HasNullCheck(parameter)) {
yield break;
}
yield return new CodeAction (context.TranslateString("Add null check for parameter"), script => {
var statement = new IfElseStatement () {
Condition = new BinaryOperatorExpression (new IdentifierExpression (parameter.Name), BinaryOperatorType.Equality, new NullReferenceExpression ()),
TrueStatement = new ThrowStatement (new ObjectCreateExpression (context.CreateShortType("System", "ArgumentNullException"), new PrimitiveExpression (parameter.Name)))
};
script.AddTo(bodyStatement, statement);
});
}
static ParameterDeclaration GetParameterDeclaration (RefactoringContext context)
@ -89,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -89,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public CheckNullVisitor (ParameterDeclaration parameter)
{
this.pattern = PatternHelper.CommutativeOperator(new IdentifierExpression(parameter.Name), BinaryOperatorType.Any, new NullReferenceExpression());
pattern = PatternHelper.CommutativeOperator(new IdentifierExpression(parameter.Name), BinaryOperatorType.Any, new NullReferenceExpression());
}
public override object VisitIfElseStatement (IfElseStatement ifElseStatement, object data)

30
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/ConvertDecToHex.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertDecToHex.cs

@ -24,30 +24,30 @@ @@ -24,30 +24,30 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Convert a dec numer to hex. For example: 16 -> 0x10
/// </summary>
public class ConvertDecToHex : IContextAction
[ContextAction("Convert dec to hex.", Description = "Convert dec to hex.")]
public class ConvertDecToHex : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var pexpr = context.GetNode<PrimitiveExpression> ();
if (pexpr == null || pexpr.LiteralValue.StartsWith ("0X", System.StringComparison.OrdinalIgnoreCase))
return false;
return (pexpr.Value is int) || (pexpr.Value is long) || (pexpr.Value is short) || (pexpr.Value is sbyte) ||
(pexpr.Value is uint) || (pexpr.Value is ulong) || (pexpr.Value is ushort) || (pexpr.Value is byte);
}
public void Run (RefactoringContext context)
{
var pexpr = context.GetNode<PrimitiveExpression> ();
using (var script = context.StartScript ()) {
script.Replace (pexpr, new PrimitiveExpression (pexpr.Value, string.Format ("0x{0:x}", pexpr.Value)));
var pexpr = context.GetNode<PrimitiveExpression>();
if (pexpr == null || pexpr.LiteralValue.StartsWith("0X", System.StringComparison.OrdinalIgnoreCase)) {
yield break;
}
if (!((pexpr.Value is int) || (pexpr.Value is long) || (pexpr.Value is short) || (pexpr.Value is sbyte) ||
(pexpr.Value is uint) || (pexpr.Value is ulong) || (pexpr.Value is ushort) || (pexpr.Value is byte))) {
yield break;
}
yield return new CodeAction (context.TranslateString("Add null check for parameter"), script => {
script.Replace(pexpr, new PrimitiveExpression (pexpr.Value, string.Format("0x{0:x}", pexpr.Value)));
});
}
}
}

85
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/ConvertForeachToFor.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertForeachToFor.cs

@ -27,62 +27,63 @@ using System; @@ -27,62 +27,63 @@ using System;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Converts a foreach loop to for.
/// </summary>
public class ConvertForeachToFor : IContextAction
[ContextAction("Convert 'foreach' loop to 'for'", Description = "Works on 'foreach' loops that allow direct access to its elements.")]
public class ConvertForeachToFor : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
return GetForeachStatement (context) != null;
var foreachStatement = GetForeachStatement(context);
if (foreachStatement == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Add null check for parameter"), script => {
var result = context.Resolve (foreachStatement.InExpression);
var countProperty = GetCountProperty (result.Type);
// TODO: use another variable name if 'i' is already in use
var initializer = new VariableDeclarationStatement (new PrimitiveType ("int"), "i", new PrimitiveExpression (0));
var id1 = new IdentifierExpression ("i");
var id2 = id1.Clone ();
var id3 = id1.Clone ();
var forStatement = new ForStatement () {
Initializers = { initializer },
Condition = new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new MemberReferenceExpression (foreachStatement.InExpression.Clone (), countProperty)),
Iterators = { new ExpressionStatement (new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2)) },
EmbeddedStatement = new BlockStatement {
new VariableDeclarationStatement (foreachStatement.VariableType.Clone (), foreachStatement.VariableName, new IndexerExpression (foreachStatement.InExpression.Clone (), id3))
}
};
if (foreachStatement.EmbeddedStatement is BlockStatement) {
foreach (var child in ((BlockStatement)foreachStatement.EmbeddedStatement).Statements) {
forStatement.EmbeddedStatement.AddChild (child.Clone (), BlockStatement.StatementRole);
}
} else {
forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole);
}
script.Replace (foreachStatement, forStatement);
script.Link (initializer.Variables.First ().NameToken, id1, id2, id3);
});
}
static string GetCountProperty (IType type)
static string GetCountProperty(IType type)
{
if (type.Kind == TypeKind.Array)
if (type.Kind == TypeKind.Array) {
return "Length";
}
return "Count";
}
public void Run (RefactoringContext context)
{
var foreachStatement = GetForeachStatement (context);
var result = context.Resolve (foreachStatement.InExpression);
var countProperty = GetCountProperty (result.Type);
// TODO: use another variable name if 'i' is already in use
var initializer = new VariableDeclarationStatement (new PrimitiveType ("int"), "i", new PrimitiveExpression (0));
var id1 = new IdentifierExpression ("i");
var id2 = id1.Clone ();
var id3 = id1.Clone ();
var forStatement = new ForStatement () {
Initializers = { initializer },
Condition = new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new MemberReferenceExpression (foreachStatement.InExpression.Clone (), countProperty)),
Iterators = { new ExpressionStatement (new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2)) },
EmbeddedStatement = new BlockStatement {
new VariableDeclarationStatement (foreachStatement.VariableType.Clone (), foreachStatement.VariableName, new IndexerExpression (foreachStatement.InExpression.Clone (), id3))
}
};
if (foreachStatement.EmbeddedStatement is BlockStatement) {
foreach (var child in ((BlockStatement)foreachStatement.EmbeddedStatement).Statements) {
forStatement.EmbeddedStatement.AddChild (child.Clone (), BlockStatement.StatementRole);
}
} else {
forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole);
}
using (var script = context.StartScript ()) {
script.Replace (foreachStatement, forStatement);
script.Link (initializer.Variables.First ().NameToken, id1, id2, id3);
}
}
static ForeachStatement GetForeachStatement (RefactoringContext context)
{
var astNode = context.GetNode ();

30
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/ConvertHexToDec.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ConvertHexToDec.cs

@ -24,30 +24,30 @@ @@ -24,30 +24,30 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
/// <summary>
/// Convert a hex numer to dec. For example: 0x10 -> 16
/// </summary>
public class ConvertHexToDec: IContextAction
[ContextAction("Convert hex to dec.", Description = "Convert hex to dec.")]
public class ConvertHexToDec: ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var pexpr = context.GetNode<PrimitiveExpression> ();
if (pexpr == null || !pexpr.LiteralValue.StartsWith ("0X", System.StringComparison.OrdinalIgnoreCase))
return false;
return (pexpr.Value is int) || (pexpr.Value is long) || (pexpr.Value is short) || (pexpr.Value is sbyte) ||
(pexpr.Value is uint) || (pexpr.Value is ulong) || (pexpr.Value is ushort) || (pexpr.Value is byte);
}
public void Run (RefactoringContext context)
{
var pexpr = context.GetNode<PrimitiveExpression> ();
using (var script = context.StartScript ()) {
script.Replace (pexpr, new PrimitiveExpression (pexpr.Value));
var pexpr = context.GetNode<PrimitiveExpression>();
if (pexpr == null || !pexpr.LiteralValue.StartsWith("0X", System.StringComparison.OrdinalIgnoreCase)) {
yield break;
}
if (!((pexpr.Value is int) || (pexpr.Value is long) || (pexpr.Value is short) || (pexpr.Value is sbyte) ||
(pexpr.Value is uint) || (pexpr.Value is ulong) || (pexpr.Value is ushort) || (pexpr.Value is byte))) {
yield break;
}
yield return new CodeAction (context.TranslateString("Add null check for parameter"), script => {
script.Replace(pexpr, new PrimitiveExpression (pexpr.Value));
});
}
}
}

76
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateBackingStore.cs

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
//
// CreateBackingStore.cs
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
// Copyright (c) 2011 Mike Krüger <mkrueger@novell.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;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
[ContextAction("Create backing store for auto property", Description = "Creates a backing field for an auto property.")]
public class CreateBackingStore : ICodeActionProvider
{
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var property = context.GetNode<PropertyDeclaration>();
if (!(property != null &&
!property.Getter.IsNull && !property.Setter.IsNull && // automatic properties always need getter & setter
property.Getter.Body.IsNull &&
property.Setter.Body.IsNull)) {
yield break;
}
yield return new CodeAction (context.TranslateString("Add null check for parameter"), script => {
string backingStoreName = context.GetNameProposal (property.Name);
// create field
var backingStore = new FieldDeclaration ();
backingStore.ReturnType = property.ReturnType.Clone ();
var initializer = new VariableInitializer (backingStoreName);
backingStore.Variables.Add (initializer);
// create new property & implement the get/set bodies
var newProperty = (PropertyDeclaration)property.Clone ();
Expression id1;
if (backingStoreName == "value")
id1 = new ThisReferenceExpression().Member("value");
else
id1 = new IdentifierExpression (backingStoreName);
Expression id2 = id1.Clone();
newProperty.Getter.Body = new BlockStatement () {
new ReturnStatement (id1)
};
newProperty.Setter.Body = new BlockStatement () {
new AssignmentExpression (id2, AssignmentOperatorType.Assign, new IdentifierExpression ("value"))
};
script.Replace (property, newProperty);
script.InsertBefore (property, backingStore);
script.Link (initializer, id1, id2);
});
}
}
}

112
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateEventInvocator.cs

@ -0,0 +1,112 @@ @@ -0,0 +1,112 @@
//
// CreateEventInvocator.cs
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
// Copyright (c) 2011 Mike Krüger <mkrueger@novell.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.Linq;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
[ContextAction("Create event invocator", Description = "Creates a standard OnXXX event method.")]
public class CreateEventInvocator : ICodeActionProvider
{
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
VariableInitializer initializer;
var eventDeclaration = GetEventDeclaration(context, out initializer);
if (eventDeclaration == null) {
yield break;
}
var type = (TypeDeclaration)eventDeclaration.Parent;
if (type.Members.Any(m => m is MethodDeclaration && ((MethodDeclaration)m).Name == "On" + initializer.Name)) {
yield break;
}
var resolvedType = context.Resolve(eventDeclaration.ReturnType).Type;
if (resolvedType.Kind == TypeKind.Unknown) {
yield break;
}
var invokeMethod = resolvedType.GetDelegateInvokeMethod();
if (invokeMethod == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create event invocator"), script => {
bool hasSenderParam = false;
IEnumerable<IParameter> pars = invokeMethod.Parameters;
if (invokeMethod.Parameters.Any ()) {
var first = invokeMethod.Parameters [0];
if (first.Name == "sender" /*&& first.Type == "System.Object"*/) {
hasSenderParam = true;
pars = invokeMethod.Parameters.Skip (1);
}
}
const string handlerName = "handler";
var arguments = new List<Expression> ();
if (hasSenderParam)
arguments.Add (new ThisReferenceExpression ());
foreach (var par in pars)
arguments.Add (new IdentifierExpression (par.Name));
var methodDeclaration = new MethodDeclaration () {
Name = "On" + initializer.Name,
ReturnType = new PrimitiveType ("void"),
Modifiers = ICSharpCode.NRefactory.CSharp.Modifiers.Protected | ICSharpCode.NRefactory.CSharp.Modifiers.Virtual,
Body = new BlockStatement () {
new VariableDeclarationStatement (eventDeclaration.ReturnType.Clone (), handlerName, new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name)),
new IfElseStatement () {
Condition = new BinaryOperatorExpression (new IdentifierExpression (handlerName), BinaryOperatorType.InEquality, new PrimitiveExpression (null)),
TrueStatement = new ExpressionStatement (new InvocationExpression (new IdentifierExpression (handlerName), arguments))
}
}
};
foreach (var par in pars) {
var typeName = context.CreateShortType (par.Type);
var decl = new ParameterDeclaration (typeName, par.Name);
methodDeclaration.Parameters.Add (decl);
}
script.InsertWithCursor (context.TranslateString("Create event invocator"), methodDeclaration, Script.InsertPosition.After);
});
}
static EventDeclaration GetEventDeclaration (RefactoringContext context, out VariableInitializer initializer)
{
var result = context.GetNode<EventDeclaration> ();
if (result == null) {
initializer = null;
return null;
}
initializer = result.Variables.FirstOrDefault (v => v.NameToken.Contains (context.Location));
return initializer != null ? result : null;
}
}
}

28
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateField.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateField.cs

@ -29,28 +29,30 @@ using ICSharpCode.NRefactory.PatternMatching; @@ -29,28 +29,30 @@ using ICSharpCode.NRefactory.PatternMatching;
using System.Linq;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class CreateField : IContextAction
[ContextAction("Create field", Description = "Creates a field for a undefined variable.")]
public class CreateField : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var identifier = GetIdentifier (context);
if (identifier == null)
return false;
return context.Resolve (identifier) == null && GuessType (context, identifier) != null;
}
public void Run (RefactoringContext context)
{
var identifier = GetIdentifier (context);
var identifier = GetIdentifier(context);
if (identifier == null) {
yield break;
}
using (var script = context.StartScript ()) {
script.InsertWithCursor ("Create field", GenerateFieldDeclaration (context, identifier), Script.InsertPosition.Before);
if (!(context.Resolve(identifier).IsError && GuessType(context, identifier) != null)) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create field"), script => {
script.InsertWithCursor(context.TranslateString("Create field"), GenerateFieldDeclaration(context, identifier), Script.InsertPosition.Before);
});
}
static AstNode GenerateFieldDeclaration (RefactoringContext context, IdentifierExpression identifier)
{
return new FieldDeclaration () {

48
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateLocalVariable.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateLocalVariable.cs

@ -32,7 +32,8 @@ using System.Threading; @@ -32,7 +32,8 @@ using System.Threading;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class CreateLocalVariable : IContextAction
[ContextAction("Create local variable", Description = "Creates a local variable for a undefined variable.")]
public class CreateLocalVariable : ICodeActionProvider
{
public List<IdentifierExpression> GetUnresolvedArguments (RefactoringContext context)
{
@ -59,36 +60,35 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -59,36 +60,35 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return expressions;
}
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
if (GetUnresolvedArguments (context).Count > 0)
return true;
var identifier = CreateField.GetIdentifier (context);
if (identifier == null)
return false;
if (context.GetNode<Statement> () == null)
return false;
return context.Resolve (identifier) == null && GuessType (context, identifier) != null;
}
public void Run (RefactoringContext context)
{
var stmt = context.GetNode<Statement> ();
var unresolvedArguments = GetUnresolvedArguments (context);
if (unresolvedArguments.Count > 0) {
using (var script = context.StartScript ()) {
if (GetUnresolvedArguments(context).Count <= 0) {
yield break;
}
var identifier = CreateField.GetIdentifier(context);
if (identifier == null) {
yield break;
}
if (context.GetNode<Statement>() == null) {
yield break;
}
if (!(context.Resolve(identifier).IsError && GuessType(context, identifier) != null)) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create local variable"), script => {
var stmt = context.GetNode<Statement> ();
var unresolvedArguments = GetUnresolvedArguments (context);
if (unresolvedArguments.Count > 0) {
foreach (var id in unresolvedArguments) {
script.InsertBefore (stmt, GenerateLocalVariableDeclaration (context, id));
}
return;
}
return;
}
using (var script = context.StartScript ()) {
script.InsertBefore (stmt, GenerateLocalVariableDeclaration (context, CreateField.GetIdentifier (context)));
}
});
}
AstNode GenerateLocalVariableDeclaration (RefactoringContext context, IdentifierExpression identifier)
{
return new VariableDeclarationStatement () {

26
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateProperty.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateProperty.cs

@ -27,25 +27,25 @@ using System; @@ -27,25 +27,25 @@ using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Linq;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class CreateProperty : IContextAction
[ContextAction("Create property", Description = "Creates a property for a undefined variable.")]
public class CreateProperty : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var identifier = CreateField.GetIdentifier (context);
if (identifier == null)
return false;
return context.Resolve (identifier) == null && CreateField.GuessType (context, identifier) != null;
}
public void Run (RefactoringContext context)
{
var identifier = GetIdentifier (context);
using (var script = context.StartScript ()) {
script.InsertWithCursor ("Create property", GeneratePropertyDeclaration (context, identifier), Script.InsertPosition.Before);
var identifier = CreateField.GetIdentifier(context);
if (identifier == null) {
yield break;
}
if (!(context.Resolve(identifier).IsError && CreateField.GuessType(context, identifier) != null)) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create property"), script => {
script.InsertWithCursor(context.TranslateString("Create property"), GeneratePropertyDeclaration(context, identifier), Script.InsertPosition.Before);
});
}
AstNode GeneratePropertyDeclaration (RefactoringContext context, IdentifierExpression identifier)

23
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/FlipOperatorArguments.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/FlipOperatorArguments.cs

@ -25,24 +25,23 @@ @@ -25,24 +25,23 @@
// THE SOFTWARE.
using System;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class FlipOperatorArguments : IContextAction
[ContextAction("Swaps left and right arguments.", Description = "Swaps left and right arguments.")]
public class FlipOperatorArguments : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
return GetBinaryOperatorExpression (context) != null;
}
public void Run (RefactoringContext context)
{
var binop = GetBinaryOperatorExpression (context);
using (var script = context.StartScript ()) {
script.Replace (binop.Left, binop.Right.Clone());
script.Replace (binop.Right, binop.Left.Clone());
var binop = GetBinaryOperatorExpression(context);
if (binop == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Swap left and right arguments"), script => {
script.Replace(binop.Left, binop.Right.Clone());
script.Replace(binop.Right, binop.Left.Clone());
});
}
public static BinaryOperatorExpression GetBinaryOperatorExpression (RefactoringContext context)

38
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/GenerateGetter.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateGetter.cs

@ -28,34 +28,36 @@ using System; @@ -28,34 +28,36 @@ using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Linq;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class GenerateGetter : IContextAction
[ContextAction("Generate getter", Description = "Generates a getter for a field.")]
public class GenerateGetter : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var initializer = GetVariableInitializer (context);
if (initializer == null || !initializer.NameToken.Contains (context.Location.Line, context.Location.Column))
return false;
var initializer = GetVariableInitializer(context);
if (initializer == null || !initializer.NameToken.Contains(context.Location.Line, context.Location.Column)) {
yield break;
}
var type = initializer.Parent.Parent as TypeDeclaration;
if (type == null)
return false;
if (type == null) {
yield break;
}
foreach (var member in type.Members) {
if (member is PropertyDeclaration && ContainsGetter ((PropertyDeclaration)member, initializer))
return false;
if (member is PropertyDeclaration && ContainsGetter((PropertyDeclaration)member, initializer)) {
yield break;
}
}
return initializer.Parent is FieldDeclaration;
}
public void Run (RefactoringContext context)
{
var initializer = GetVariableInitializer (context);
var field = initializer.Parent as FieldDeclaration;
using (var script = context.StartScript ()) {
script.InsertWithCursor ("Create getter", GeneratePropertyDeclaration (context, field, initializer), Script.InsertPosition.After);
if (field == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create getter"), script => {
script.InsertWithCursor(context.TranslateString("Create getter"), GeneratePropertyDeclaration(context, field, initializer), Script.InsertPosition.After);
});
}
static PropertyDeclaration GeneratePropertyDeclaration (RefactoringContext context, FieldDeclaration field, VariableInitializer initializer)

37
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/GenerateProperty.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateProperty.cs

@ -27,34 +27,35 @@ using System; @@ -27,34 +27,35 @@ using System;
using ICSharpCode.NRefactory.PatternMatching;
using System.Linq;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class GenerateProperty : IContextAction
[ContextAction("Generate property", Description = "Generates a getter and setter for a field.")]
public class GenerateProperty : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var initializer = GetVariableInitializer (context);
if (initializer == null || !initializer.NameToken.Contains (context.Location.Line, context.Location.Column))
return false;
var initializer = GetVariableInitializer(context);
if (initializer == null || !initializer.NameToken.Contains(context.Location.Line, context.Location.Column)) {
yield break;
}
var type = initializer.Parent.Parent as TypeDeclaration;
if (type == null)
return false;
if (type == null) {
yield break;
}
foreach (var member in type.Members) {
if (member is PropertyDeclaration && ContainsGetter ((PropertyDeclaration)member, initializer))
return false;
if (member is PropertyDeclaration && ContainsGetter((PropertyDeclaration)member, initializer)) {
yield break;
}
}
return initializer.Parent is FieldDeclaration;
}
public void Run (RefactoringContext context)
{
var initializer = GetVariableInitializer (context);
var field = initializer.Parent as FieldDeclaration;
using (var script = context.StartScript ()) {
script.InsertWithCursor ("Create property", GeneratePropertyDeclaration (context, field, initializer), Script.InsertPosition.After);
if (field == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create property"), script => {
script.InsertWithCursor(context.TranslateString("Create property"), GeneratePropertyDeclaration(context, field, initializer), Script.InsertPosition.After);
});
}
static PropertyDeclaration GeneratePropertyDeclaration (RefactoringContext context, FieldDeclaration field, VariableInitializer initializer)

75
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/GenerateSwitchLabels.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/GenerateSwitchLabels.cs

@ -26,56 +26,53 @@ @@ -26,56 +26,53 @@
using System;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class GenerateSwitchLabels : IContextAction
[ContextAction("Generate switch labels", Description = "Creates switch lables for enumerations.")]
public class GenerateSwitchLabels : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var switchStatement = GetSwitchStatement (context);
if (switchStatement == null)
return false;
var result = context.Resolve (switchStatement.Expression);
if (result == null)
return false;
return result.Type.Kind == TypeKind.Enum;
}
public void Run (RefactoringContext context)
{
var switchStatement = GetSwitchStatement (context);
var result = context.Resolve (switchStatement.Expression);
var type = result.Type;
var newSwitch = (SwitchStatement)switchStatement.Clone ();
var target = new TypeReferenceExpression (context.CreateShortType (result.Type));
foreach (var field in type.GetFields ()) {
if (field.IsSynthetic || !field.IsConst)
continue;
newSwitch.SwitchSections.Add (new SwitchSection () {
var switchStatement = GetSwitchStatement(context);
if (switchStatement == null) {
yield break;
}
var result = context.Resolve(switchStatement.Expression);
if (result.Type.Kind != TypeKind.Enum) {
yield break;
}
yield return new CodeAction (context.TranslateString("Create switch labels"), script => {
var type = result.Type;
var newSwitch = (SwitchStatement)switchStatement.Clone();
var target = new TypeReferenceExpression (context.CreateShortType(result.Type));
foreach (var field in type.GetFields ()) {
if (field.IsSynthetic || !field.IsConst) {
continue;
}
newSwitch.SwitchSections.Add(new SwitchSection () {
CaseLabels = {
new CaseLabel (new MemberReferenceExpression (target.Clone(), field.Name))
},
Statements = {
new BreakStatement ()
}
});
}
newSwitch.SwitchSections.Add(new SwitchSection () {
CaseLabels = {
new CaseLabel (new MemberReferenceExpression (target.Clone (), field.Name))
new CaseLabel ()
},
Statements = {
new BreakStatement ()
new ThrowStatement (new ObjectCreateExpression (context.CreateShortType("System", "ArgumentOutOfRangeException")))
}
});
}
newSwitch.SwitchSections.Add (new SwitchSection () {
CaseLabels = {
new CaseLabel ()
},
Statements = {
new ThrowStatement (new ObjectCreateExpression (context.CreateShortType ("System", "ArgumentOutOfRangeException")))
}
script.Replace(switchStatement, newSwitch);
});
using (var script = context.StartScript ()) {
script.Replace (switchStatement, newSwitch);
}
}
static SwitchStatement GetSwitchStatement (RefactoringContext context)

51
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/InsertAnonymousMethodSignature.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/InsertAnonymousMethodSignature.cs

@ -28,40 +28,39 @@ using ICSharpCode.NRefactory.TypeSystem; @@ -28,40 +28,39 @@ using ICSharpCode.NRefactory.TypeSystem;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class InsertAnonymousMethodSignature : IContextAction
[ContextAction("Insert anonymous method signature", Description = "Inserts a signature to parameterless anonymous methods.")]
public class InsertAnonymousMethodSignature : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
IType type;
return GetAnonymousMethodExpression (context, out type) != null;
}
public void Run (RefactoringContext context)
{
IType type;
var anonymousMethodExpression = GetAnonymousMethodExpression (context, out type);
var delegateMethod = type.GetDelegateInvokeMethod ();
var sb = new StringBuilder ("(");
for (int k = 0; k < delegateMethod.Parameters.Count; k++) {
if (k > 0)
sb.Append (", ");
var anonymousMethodExpression = GetAnonymousMethodExpression(context, out type);
if (anonymousMethodExpression == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Insert anonymous method signature"), script => {
var delegateMethod = type.GetDelegateInvokeMethod();
var paramType = delegateMethod.Parameters [k].Type;
var sb = new StringBuilder ("(");
for (int k = 0; k < delegateMethod.Parameters.Count; k++) {
if (k > 0) {
sb.Append(", ");
}
var paramType = delegateMethod.Parameters [k].Type;
sb.Append(context.CreateShortType(paramType));
sb.Append(" ");
sb.Append(delegateMethod.Parameters [k].Name);
}
sb.Append(")");
sb.Append (context.CreateShortType (paramType));
sb.Append (" ");
sb.Append (delegateMethod.Parameters [k].Name);
}
sb.Append (")");
using (var script = context.StartScript ()) {
script.InsertText (context.GetOffset (anonymousMethodExpression.DelegateToken.EndLocation), sb.ToString ());
}
script.InsertText(context.GetOffset(anonymousMethodExpression.DelegateToken.EndLocation), sb.ToString());
});
}
static AnonymousMethodExpression GetAnonymousMethodExpression (RefactoringContext context, out IType delegateType)

61
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/IntroduceFormatItem.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/IntroduceFormatItem.cs

@ -36,41 +36,46 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -36,41 +36,46 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// Introduce format item. Works on strings that contain selections.
/// "this is <some> string" => string.Format ("this is {0} string", <some>)
/// </summary>
public class IntroduceFormatItem : IContextAction
[ContextAction("Introduce format item", Description = "Creates a string.format call with the selection as parameter.")]
public class IntroduceFormatItem : ICodeActionProvider
{
readonly static MemberReferenceExpression PrototypeFormatReference = new MemberReferenceExpression (new TypeReferenceExpression (new PrimitiveType ("string")), "Format");
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
if (!context.IsSomethingSelected)
return false;
var pexpr = context.GetNode<PrimitiveExpression> ();
if (pexpr == null || !(pexpr.Value is string))
return false;
if (pexpr.LiteralValue.StartsWith ("@"))
return pexpr.StartLocation < new TextLocation (context.Location.Line, context.Location.Column - 1) &&
new TextLocation (context.Location.Line, context.Location.Column + 1) < pexpr.EndLocation;
return pexpr.StartLocation < context.Location && context.Location < pexpr.EndLocation;
}
public void Run (RefactoringContext context)
{
var pexpr = context.GetNode<PrimitiveExpression> ();
var invocation = context.GetNode<InvocationExpression> ();
if (invocation != null && invocation.Target.IsMatch (PrototypeFormatReference)) {
AddFormatCallToInvocation (context, pexpr, invocation);
return;
if (!context.IsSomethingSelected) {
yield break;
}
var pexpr = context.GetNode<PrimitiveExpression>();
if (pexpr == null || !(pexpr.Value is string)) {
yield break;
}
if (pexpr.LiteralValue.StartsWith("@")) {
if (!(pexpr.StartLocation < new TextLocation (context.Location.Line, context.Location.Column - 1) && new TextLocation (context.Location.Line, context.Location.Column + 1) < pexpr.EndLocation)) {
yield break;
}
} else {
if (!(pexpr.StartLocation < context.Location && context.Location < pexpr.EndLocation)) {
yield break;
}
}
yield return new CodeAction (context.TranslateString("Introduce format item"), script => {
var invocation = context.GetNode<InvocationExpression>();
if (invocation != null && invocation.Target.IsMatch(PrototypeFormatReference)) {
AddFormatCallToInvocation(context, pexpr, invocation);
return;
}
var arg = CreateFormatArgument (context);
var newInvocation = new InvocationExpression (PrototypeFormatReference.Clone ()) {
Arguments = { CreateFormatString (context, pexpr, 0), arg }
};
var arg = CreateFormatArgument(context);
var newInvocation = new InvocationExpression (PrototypeFormatReference.Clone()) {
Arguments = { CreateFormatString(context, pexpr, 0), arg }
};
using (var script = context.StartScript ()) {
script.Replace (pexpr, newInvocation);
script.Select (arg);
}
script.Replace(pexpr, newInvocation);
script.Select(arg);
});
}
void AddFormatCallToInvocation (RefactoringContext context, PrimitiveExpression pExpr, InvocationExpression invocation)

34
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/InvertIf.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/InvertIf.cs

@ -25,30 +25,30 @@ @@ -25,30 +25,30 @@
// THE SOFTWARE.
using System;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class InvertIf : IContextAction
[ContextAction("Invert if", Description = "Inverts an 'if ... else' expression.")]
public class InvertIf : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var ifStatement = GetIfElseStatement (context);
return ifStatement != null && !ifStatement.TrueStatement.IsNull && !ifStatement.FalseStatement.IsNull;
}
// TODO: Invert if without else
// ex. if (cond) DoSomething () == if (!cond) return; DoSomething ()
// beware of loop contexts return should be continue then.
public void Run (RefactoringContext context)
{
var ifStatement = GetIfElseStatement (context);
// TODO: Invert if without else
// ex. if (cond) DoSomething () == if (!cond) return; DoSomething ()
// beware of loop contexts return should be continue then.
using (var script = context.StartScript ()) {
script.Replace (ifStatement.Condition, CSharpUtil.InvertCondition (ifStatement.Condition.Clone ()));
script.Replace (ifStatement.TrueStatement, ifStatement.FalseStatement.Clone ());
script.Replace (ifStatement.FalseStatement, ifStatement.TrueStatement.Clone ());
script.FormatText (ifStatement);
var ifStatement = GetIfElseStatement(context);
if (!(ifStatement != null && !ifStatement.TrueStatement.IsNull && !ifStatement.FalseStatement.IsNull)) {
yield break;
}
yield return new CodeAction (context.TranslateString("Invert if"), script => {
script.Replace(ifStatement.Condition, CSharpUtil.InvertCondition(ifStatement.Condition.Clone()));
script.Replace(ifStatement.TrueStatement, ifStatement.FalseStatement.Clone());
script.Replace(ifStatement.FalseStatement, ifStatement.TrueStatement.Clone());
script.FormatText(ifStatement);
});
}
static IfElseStatement GetIfElseStatement (RefactoringContext context)

26
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBackingStore.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveBackingStore.cs

@ -29,32 +29,30 @@ using ICSharpCode.NRefactory.CSharp.Resolver; @@ -29,32 +29,30 @@ using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class RemoveBackingStore : IContextAction
[ContextAction("Remove backing store for property", Description = "Removes the backing store of a property and creates an auto property.")]
public class RemoveBackingStore : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
return GetBackingField (context) != null;
}
public void Run (RefactoringContext context)
{
var property = context.GetNode<PropertyDeclaration> ();
var field = GetBackingField (context);
var property = context.GetNode<PropertyDeclaration>();
var field = GetBackingField(context);
if (field == null) {
yield break;
}
// create new auto property
var newProperty = (PropertyDeclaration)property.Clone ();
var newProperty = (PropertyDeclaration)property.Clone();
newProperty.Getter.Body = BlockStatement.Null;
newProperty.Setter.Body = BlockStatement.Null;
using (var script = context.StartScript ()) {
yield return new CodeAction (context.TranslateString("Remove backing store"), script => {
script.Remove (context.RootNode.GetNodeAt<FieldDeclaration> (field.Region.BeginLine, field.Region.BeginColumn));
script.Replace (property, newProperty);
script.Rename (field, newProperty.Name);
}
});
}
// void ReplaceBackingFieldReferences (MDRefactoringContext context, IField backingStore, PropertyDeclaration property)

26
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBraces.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveBraces.cs

@ -26,25 +26,25 @@ @@ -26,25 +26,25 @@
using System;
using System.Linq;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class RemoveBraces : IContextAction
[ContextAction("Remove braces", Description = "Removes redundant braces around a statement.")]
public class RemoveBraces : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
return GetBlockStatement (context) != null;
}
public void Run (RefactoringContext context)
{
var block = GetBlockStatement (context);
using (var script = context.StartScript ()) {
script.Remove (block.LBraceToken);
script.Remove (block.RBraceToken);
script.FormatText (block.Parent);
var block = GetBlockStatement(context);
if (block == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Remove braces"), script => {
script.Remove(block.LBraceToken);
script.Remove(block.RBraceToken);
script.FormatText(block.Parent);
});
}
static BlockStatement GetBlockStatement (RefactoringContext context)

27
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveRegion.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/RemoveRegion.cs

@ -26,26 +26,27 @@ @@ -26,26 +26,27 @@
using System;
using System.Linq;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class RemoveRegion : IContextAction
[ContextAction("Remove region", Description = "Removes a pre processor #region/#endregion directive.")]
public class RemoveRegion : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
return GetDirective (context) != null;
}
public void Run (RefactoringContext context)
{
var directive = GetDirective (context);
var endDirective = DirectiveSearcher.GetEndRegion (context.RootNode, directive);
if (endDirective == null)
return;
using (var script = context.StartScript ()) {
var directive = GetDirective(context);
if (directive == null) {
yield break;
}
var endDirective = DirectiveSearcher.GetEndRegion(context.RootNode, directive);
if (endDirective == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Remove region"), script => {
script.Remove (directive);
script.Remove (endDirective);
}
});
}
class DirectiveSearcher : DepthFirstAstVisitor

20
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/ReplaceEmptyString.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/ReplaceEmptyString.cs

@ -25,22 +25,22 @@ @@ -25,22 +25,22 @@
// THE SOFTWARE.
using System;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class ReplaceEmptyString : IContextAction
[ContextAction("Use string.Empty", Description = "Replaces \"\" with string.Empty")]
public class ReplaceEmptyString : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
return GetEmptyString (context) != null;
}
public void Run (RefactoringContext context)
{
var expr = GetEmptyString (context);
using (var script = context.StartScript ()) {
script.Replace (expr, new MemberReferenceExpression (new TypeReferenceExpression (new PrimitiveType ("string")), "Empty"));
var expr = GetEmptyString(context);
if (expr == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Remove braces"), script => {
script.Replace(expr, new MemberReferenceExpression (new TypeReferenceExpression (new PrimitiveType ("string")), "Empty"));
});
}
static PrimitiveExpression GetEmptyString (RefactoringContext context)

45
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/SplitDeclarationAndAssignment.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SplitDeclarationAndAssignment.cs

@ -27,36 +27,35 @@ using System; @@ -27,36 +27,35 @@ using System;
using System.Linq;
using ICSharpCode.NRefactory.PatternMatching;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class SplitDeclarationAndAssignment : IContextAction
[ContextAction("Split local variable declaration and assignment", Description = "Splits local variable declaration and assignment.")]
public class SplitDeclarationAndAssignment : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
AstType type;
return GetVariableDeclarationStatement (context, out type) != null;
}
public void Run (RefactoringContext context)
{
AstType type;
var varDecl = GetVariableDeclarationStatement (context, out type);
var assign = new AssignmentExpression (new IdentifierExpression (varDecl.Variables.First ().Name), AssignmentOperatorType.Assign, varDecl.Variables.First ().Initializer.Clone ());
var newVarDecl = (VariableDeclarationStatement)varDecl.Clone ();
newVarDecl.Role = BlockStatement.StatementRole;
if (newVarDecl.Type.IsMatch (new SimpleType ("var")))
newVarDecl.Type = type;
newVarDecl.Variables.First ().Initializer = Expression.Null;
using (var script = context.StartScript ()) {
script.InsertBefore (varDecl, newVarDecl);
script.Replace (varDecl, varDecl.Parent is ForStatement ? (AstNode)assign : new ExpressionStatement (assign));
var varDecl = GetVariableDeclarationStatement(context, out type);
if (varDecl == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Remove braces"), script => {
var assign = new AssignmentExpression (new IdentifierExpression (varDecl.Variables.First().Name), AssignmentOperatorType.Assign, varDecl.Variables.First().Initializer.Clone());
var newVarDecl = (VariableDeclarationStatement)varDecl.Clone();
newVarDecl.Role = BlockStatement.StatementRole;
if (newVarDecl.Type.IsMatch(new SimpleType ("var"))) {
newVarDecl.Type = type;
}
newVarDecl.Variables.First().Initializer = Expression.Null;
script.InsertBefore(varDecl, newVarDecl);
script.Replace(varDecl, varDecl.Parent is ForStatement ? (AstNode)assign : new ExpressionStatement (assign));
});
}
static VariableDeclarationStatement GetVariableDeclarationStatement (RefactoringContext context, out AstType resolvedType, CancellationToken cancellationToken = default(CancellationToken))

47
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/SplitString.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/SplitString.cs

@ -25,32 +25,37 @@ @@ -25,32 +25,37 @@
// THE SOFTWARE.
using System;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class SplitString: IContextAction
[ContextAction("Split string literal", Description = "Splits string literal into two.")]
public class SplitString: ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
if (context.IsSomethingSelected)
return false;
var pexpr = context.GetNode<PrimitiveExpression> ();
if (pexpr == null || !(pexpr.Value is string))
return false;
if (pexpr.LiteralValue.StartsWith ("@"))
return pexpr.StartLocation < new TextLocation (context.Location.Line, context.Location.Column - 2) &&
new TextLocation (context.Location.Line, context.Location.Column + 2) < pexpr.EndLocation;
return pexpr.StartLocation < new TextLocation (context.Location.Line, context.Location.Column - 1) &&
new TextLocation (context.Location.Line, context.Location.Column + 1) < pexpr.EndLocation;
}
public void Run (RefactoringContext context)
{
var pexpr = context.GetNode<PrimitiveExpression> ();
int offset = context.GetOffset (context.Location);
using (var script = context.StartScript ()) {
script.InsertText (offset, pexpr.LiteralValue.StartsWith ("@") ? "\" + @\"" : "\" + \"");
if (context.IsSomethingSelected) {
yield break;
}
var pexpr = context.GetNode<PrimitiveExpression>();
if (pexpr == null || !(pexpr.Value is string)) {
yield break;
}
}
if (pexpr.LiteralValue.StartsWith("@")) {
if (!(pexpr.StartLocation < new TextLocation (context.Location.Line, context.Location.Column - 2) &&
new TextLocation (context.Location.Line, context.Location.Column + 2) < pexpr.EndLocation)) {
yield break;
}
} else {
if (!(pexpr.StartLocation < new TextLocation (context.Location.Line, context.Location.Column - 1) && new TextLocation (context.Location.Line, context.Location.Column + 1) < pexpr.EndLocation)) {
yield break;
}
}
yield return new CodeAction (context.TranslateString("Remove braces"), script => {
int offset = context.GetOffset (context.Location);
script.InsertText (offset, pexpr.LiteralValue.StartsWith ("@") ? "\" + @\"" : "\" + \"");
});
}
}
}

35
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/UseExplicitType.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseExplicitType.cs

@ -28,41 +28,38 @@ using System.Linq; @@ -28,41 +28,38 @@ using System.Linq;
using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class UseExplicitType: IContextAction
[ContextAction("Use explicit type", Description = "Converts local variable declaration to be explicit typed.")]
public class UseExplicitType: ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
var varDecl = GetVariableDeclarationStatement (context);
var varDecl = GetVariableDeclarationStatement(context);
IType type;
if (varDecl != null) {
type = context.Resolve (varDecl.Variables.First ().Initializer).Type;
type = context.Resolve(varDecl.Variables.First().Initializer).Type;
} else {
var foreachStatement = GetForeachStatement (context);
if (foreachStatement == null)
return false;
type = context.Resolve (foreachStatement.VariableType).Type;
var foreachStatement = GetForeachStatement(context);
if (foreachStatement == null) {
yield break;
}
type = context.Resolve(foreachStatement.VariableType).Type;
}
return !type.Equals (SpecialType.NullType) && !type.Equals (SpecialType.UnknownType);
}
public void Run (RefactoringContext context)
{
using (var script = context.StartScript ()) {
var varDecl = GetVariableDeclarationStatement (context);
if (!(!type.Equals(SpecialType.NullType) && !type.Equals(SpecialType.UnknownType))) {
yield break;
}
yield return new CodeAction (context.TranslateString("Remove braces"), script => {
if (varDecl != null) {
var type = context.Resolve (varDecl.Variables.First ().Initializer).Type;
script.Replace (varDecl.Type, context.CreateShortType (type));
} else {
var foreachStatement = GetForeachStatement (context);
var type = context.Resolve (foreachStatement.VariableType).Type;
script.Replace (foreachStatement.VariableType, context.CreateShortType (type));
}
}
});
}
static readonly AstType varType = new SimpleType ("var");

25
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/UseVarKeyword.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/UseVarKeyword.cs

@ -27,26 +27,27 @@ using System; @@ -27,26 +27,27 @@ using System;
using System.Linq;
using ICSharpCode.NRefactory.PatternMatching;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class UseVarKeyword : IContextAction
[ContextAction("Use 'var' keyword", Description = "Converts local variable declaration to be implicit typed.")]
public class UseVarKeyword : ICodeActionProvider
{
public bool IsValid (RefactoringContext context)
public IEnumerable<CodeAction> GetActions(RefactoringContext context)
{
return GetVariableDeclarationStatement (context) != null || GetForeachStatement (context) != null;
}
public void Run (RefactoringContext context)
{
using (var script = context.StartScript ()) {
var varDecl = GetVariableDeclarationStatement (context);
var varDecl = GetVariableDeclarationStatement(context);
var foreachStmt = GetForeachStatement(context);
if (varDecl == null && foreachStmt == null) {
yield break;
}
yield return new CodeAction (context.TranslateString("Remove braces"), script => {
if (varDecl != null) {
script.Replace (varDecl.Type, new SimpleType ("var"));
script.Replace(varDecl.Type, new SimpleType ("var"));
} else {
script.Replace (GetForeachStatement (context).VariableType, new SimpleType ("var"));
script.Replace(foreachStmt.VariableType, new SimpleType ("var"));
}
}
});
}
static readonly AstType varType = new SimpleType ("var");

14
ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssue.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -29,7 +29,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class CodeIssue
{
public string Title {
public string Desription {
get;
private set;
}
@ -44,17 +44,17 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -44,17 +44,17 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
private set;
}
public System.Action Fix {
public CodeAction Action {
get;
private set;
}
public CodeIssue (string title, TextLocation start, TextLocation end, System.Action fix)
public CodeIssue (string description, TextLocation start, TextLocation end, CodeAction action = null)
{
this.Title = title;
this.Start = start;
this.End = end;
this.Fix = fix;
Desription = description;
Start = start;
End = end;
Action = action;
}
}
}

16
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/ConditionalToNullCoalescingInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/ConditionalToNullCoalescingInspector.cs

@ -34,7 +34,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -34,7 +34,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// Checks for "a != null ? a : other"<expr>
/// Converts to: "a ?? other"<expr>
/// </summary>
public class ConditionalToNullCoalescingInspector : IInspector
[IssueDescription("'?:' expression can be converted to '??' expression",
Description="'?:' expression can be converted to '??' expression.",
Category = IssueCategories.Opportunities,
Severity = Severity.Suggestion)]
public class ConditionalToNullCoalescingInspector : ICodeIssueProvider
{
static readonly Pattern pattern = new Choice {
// a != null ? a : other
@ -51,7 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -51,7 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
),
};
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
@ -73,11 +77,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -73,11 +77,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (m.Success) {
var a = m.Get<Expression>("a").Single();
var other = m.Get<Expression>("other").Single();
AddIssue(conditionalExpression, ctx.TranslateString("Convert to '??' expression"), delegate {
using (var script = ctx.StartScript ()) {
var expr = new BinaryOperatorExpression (a.Clone (), BinaryOperatorType.NullCoalescing, other.Clone ());
script.Replace (conditionalExpression, expr);
}
AddIssue(conditionalExpression, ctx.TranslateString("Convert to '??' expression"), script => {
var expr = new BinaryOperatorExpression (a.Clone (), BinaryOperatorType.NullCoalescing, other.Clone ());
script.Replace (conditionalExpression, expr);
});
}
base.VisitConditionalExpression (conditionalExpression);

8
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/GatherVisitorBase.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/GatherVisitorBase.cs

@ -47,14 +47,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -47,14 +47,14 @@ namespace ICSharpCode.NRefactory.CSharp
base.VisitChildren (node);
}
protected void AddIssue (AstNode node, string title, System.Action fix = null)
protected void AddIssue(AstNode node, string title, System.Action<Script> fix = null)
{
FoundIssues.Add (new CodeIssue (title, node.StartLocation, node.EndLocation, fix));
FoundIssues.Add(new CodeIssue (title, node.StartLocation, node.EndLocation, fix != null ? new CodeAction (title, fix) : null));
}
protected void AddIssue(TextLocation start, TextLocation end, string title, System.Action fix = null)
protected void AddIssue(TextLocation start, TextLocation end, string title, System.Action<Script> fix = null)
{
FoundIssues.Add (new CodeIssue (title, start, end, fix));
FoundIssues.Add(new CodeIssue (title, start, end, fix != null ? new CodeAction (title, fix) : null));
}
}

41
ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/IssueCategories.cs

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
//
// IssueCategories.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// 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;
namespace ICSharpCode.NRefactory.CSharp
{
public class IssueCategories
{
public const string Improvements = "Code Improvements";
public const string CodeQualityIssues = "Code Quality Issues";
public const string ConstraintViolations = "Constraint Violations";
public const string Redundancies = "Redundancies";
public const string Opportunities = "Language Usage Opportunities";
public const string Notifications = "Code Notifications";
}
}

5
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/NotImplementedExceptionInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/NotImplementedExceptionInspector.cs

@ -34,9 +34,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -34,9 +34,10 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// This inspector just shows that there is a not implemented exception. It doesn't offer a fix.
/// Should only be shown in overview bar, no underlining.
/// </summary>
public class NotImplementedExceptionInspector : IInspector
[IssueDescription("Show NotImplementedExceptions", Description="Shows NotImplementedException throws in the quick task bar.", Category = IssueCategories.Notifications, Severity = Severity.Suggestion)]
public class NotImplementedExceptionInspector : ICodeIssueProvider
{
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);

15
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantInternalInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantInternalInspector.cs

@ -34,9 +34,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -34,9 +34,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// <summary>
/// Finds redundant internal modifiers.
/// </summary>
public class RedundantInternalInspector : IInspector
[IssueDescription("Remove redunant 'internal' modifier",
Description="Removes 'internal' modifiers that are not required.",
Category = IssueCategories.Redundancies,
Severity = Severity.Hint,
IssueMarker = IssueMarker.GrayOut)]
public class RedundantInternalInspector : ICodeIssueProvider
{
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
@ -57,10 +62,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -57,10 +62,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
foreach (var token_ in typeDeclaration.ModifierTokens) {
var token = token_;
if (token.Modifier == Modifiers.Internal) {
AddIssue(token, ctx.TranslateString ("Remove redundant 'internal' modifier"), delegate {
using (var script = ctx.StartScript ()) {
script.Remove(token);
}
AddIssue(token, ctx.TranslateString ("Remove 'internal' modifier"), script => {
script.Remove(token);
});
}
}

15
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantNamespaceUsageInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantNamespaceUsageInspector.cs

@ -36,9 +36,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -36,9 +36,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// <summary>
/// Finds redundant namespace usages.
/// </summary>
public class RedundantNamespaceUsageInspector : IInspector
[IssueDescription("Remove redundant namespace usages",
Description = "Removes namespace usages that are obsolete.",
Category = IssueCategories.Redundancies,
Severity = Severity.Hint,
IssueMarker = IssueMarker.GrayOut)]
public class RedundantNamespaceUsageInspector : ICodeIssueProvider
{
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
@ -71,10 +76,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -71,10 +76,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var lookupName = state.LookupSimpleNameOrTypeName(memberReferenceExpression.MemberName, new List<IType> (), SimpleNameLookupMode.Expression);
if (lookupName is TypeResolveResult && !lookupName.IsError && wholeResult.Type.Equals(lookupName.Type)) {
AddIssue(memberReferenceExpression.StartLocation, memberReferenceExpression.MemberNameToken.StartLocation, ctx.TranslateString ("Remove redundant namespace usage"), delegate {
using (var script = ctx.StartScript ()) {
script.Replace(memberReferenceExpression, RefactoringAstHelper.RemoveTarget(memberReferenceExpression));
}
AddIssue(memberReferenceExpression.StartLocation, memberReferenceExpression.MemberNameToken.StartLocation, ctx.TranslateString("Remove redundant namespace usage"), script => {
script.Replace(memberReferenceExpression, RefactoringAstHelper.RemoveTarget(memberReferenceExpression));
}
);
}

17
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantPrivateInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantPrivateInspector.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// RedundantPrivateInspector.cs
//
// Author:
@ -34,9 +34,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -34,9 +34,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// <summary>
/// Finds redundant internal modifiers.
/// </summary>
public class RedundantPrivateInspector : IInspector
[IssueDescription("Remove redundant 'private' modifier.",
Description = "Removes 'private' modifiers that are not required.",
Category = IssueCategories.Redundancies,
Severity = Severity.Hint,
IssueMarker = IssueMarker.GrayOut)]
public class RedundantPrivateInspector : ICodeIssueProvider
{
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
@ -57,10 +62,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -57,10 +62,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
foreach (var token_ in node.ModifierTokens) {
var token = token_;
if (token.Modifier == Modifiers.Private) {
AddIssue(token, ctx.TranslateString("Remove redundant 'private' modifier"), delegate {
using (var script = ctx.StartScript ()) {
script.Remove(token);
}
AddIssue(token, ctx.TranslateString("Remove redundant 'private' modifier"), script => {
script.Remove(token);
});
}
}

15
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantThisInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantThisInspector.cs

@ -38,9 +38,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -38,9 +38,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// <summary>
/// Finds redundant namespace usages.
/// </summary>
public class RedundantThisInspector : IInspector
[IssueDescription("Remove redundant 'this.'",
Description= "Removes 'this.' references that are not required.",
Category = IssueCategories.Redundancies,
Severity = Severity.Hint,
IssueMarker = IssueMarker.GrayOut)]
public class RedundantThisInspector : ICodeIssueProvider
{
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
@ -95,10 +100,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -95,10 +100,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
if (isRedundant) {
AddIssue(thisReferenceExpression.StartLocation, memberReference.MemberNameToken.StartLocation, ctx.TranslateString("Remove redundant 'this.'"), delegate {
using (var script = ctx.StartScript ()) {
script.Replace(memberReference, RefactoringAstHelper.RemoveTarget(memberReference));
}
AddIssue(thisReferenceExpression.StartLocation, memberReference.MemberNameToken.StartLocation, ctx.TranslateString("Remove redundant 'this.'"), script => {
script.Replace(memberReference, RefactoringAstHelper.RemoveTarget(memberReference));
}
);
}

17
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/RedundantUsingInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/RedundantUsingInspector.cs

@ -37,9 +37,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -37,9 +37,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// <summary>
/// Finds redundant using declarations.
/// </summary>
public class RedundantUsingInspector : IInspector
[IssueDescription("Remove unused usings",
Description = "Removes used declarations that are not required.",
Category = IssueCategories.Redundancies,
Severity = Severity.Hint,
IssueMarker = IssueMarker.GrayOut)]
public class RedundantUsingInspector : ICodeIssueProvider
{
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
@ -64,11 +69,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -64,11 +69,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
foreach (var u in usingDeclarations.Where (u => !u.Value)) {
var decl = u.Key;
AddIssue(decl, ctx.TranslateString("Remove redundant usings"), delegate {
using (var script = ctx.StartScript ()) {
foreach (var u2 in usingDeclarations.Where (a => !a.Value)) {
script.Remove (u2.Key);
}
AddIssue(decl, ctx.TranslateString("Remove redundant usings"), script => {
foreach (var u2 in usingDeclarations.Where (a => !a.Value)) {
script.Remove (u2.Key);
}
}
);

20
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/StringIsNullOrEmptyInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyInspector.cs

@ -34,7 +34,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -34,7 +34,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// Checks for str == null && str == ""
/// Converts to: string.IsNullOrEmpty (str)
/// </summary>
public class StringIsNullOrEmptyInspector : IInspector
[IssueDescription("Use string.IsNullOrEmpty",
Description = "Uses shorter string.IsNullOrEmpty call instead of a longer condition.",
Category = IssueCategories.Improvements,
Severity = Severity.Suggestion)]
public class StringIsNullOrEmptyInspector : ICodeIssueProvider
{
static readonly Pattern pattern = new Choice {
// str == null || str == ""
@ -66,7 +70,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -66,7 +70,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
),
};
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);
@ -93,13 +97,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -93,13 +97,11 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
if (m.Success) {
var str = m.Get<Expression>("str").Single();
AddIssue(binaryOperatorExpression, ctx.TranslateString("Use string.IsNullOrEmpty"), delegate {
using (var script = ctx.StartScript ()) {
Expression expr = new PrimitiveType ("string").Invoke("IsNullOrEmpty", str.Clone());
if (isNegated)
expr = new UnaryOperatorExpression (UnaryOperatorType.Not, expr);
script.Replace(binaryOperatorExpression, expr);
}
AddIssue(binaryOperatorExpression, ctx.TranslateString("Use string.IsNullOrEmpty"), script => {
Expression expr = new PrimitiveType ("string").Invoke("IsNullOrEmpty", str.Clone());
if (isNegated)
expr = new UnaryOperatorExpression (UnaryOperatorType.Not, expr);
script.Replace(binaryOperatorExpression, expr);
});
return;
}

8
ICSharpCode.NRefactory.CSharp/Refactoring/Inspector/UseVarKeywordInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/UseVarKeywordInspector.cs

@ -36,9 +36,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -36,9 +36,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
/// Checks for places where the 'var' keyword can be used. Note that the action is actually done with a context
/// action.
/// </summary>
public class UseVarKeywordInspector : IInspector
[IssueDescription("Use 'var' keyword",
Description = "Use implicitly typed local variable decaration",
Category = IssueCategories.Opportunities,
Severity = Severity.Hint)]
public class UseVarKeywordInspector : ICodeIssueProvider
{
public IEnumerable<CodeIssue> Run (BaseRefactoringContext context)
public IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context)
{
var visitor = new GatherVisitor (context, this);
context.RootNode.AcceptVisitor (visitor);

78
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateBackingStore.cs

@ -1,78 +0,0 @@ @@ -1,78 +0,0 @@
//
// CreateBackingStore.cs
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
// Copyright (c) 2011 Mike Krüger <mkrueger@novell.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.Threading;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class CreateBackingStore : IContextAction
{
public bool IsValid (RefactoringContext context)
{
var propertyDeclaration = context.GetNode<PropertyDeclaration> ();
return propertyDeclaration != null &&
!propertyDeclaration.Getter.IsNull && !propertyDeclaration.Setter.IsNull && // automatic properties always need getter & setter
propertyDeclaration.Getter.Body.IsNull &&
propertyDeclaration.Setter.Body.IsNull;
}
public void Run (RefactoringContext context)
{
var property = context.GetNode<PropertyDeclaration> ();
string backingStoreName = context.GetNameProposal (property.Name);
// create field
var backingStore = new FieldDeclaration ();
backingStore.ReturnType = property.ReturnType.Clone ();
var initializer = new VariableInitializer (backingStoreName);
backingStore.Variables.Add (initializer);
// create new property & implement the get/set bodies
var newProperty = (PropertyDeclaration)property.Clone ();
Expression id1;
if (backingStoreName == "value")
id1 = new ThisReferenceExpression().Member("value");
else
id1 = new IdentifierExpression (backingStoreName);
Expression id2 = id1.Clone();
newProperty.Getter.Body = new BlockStatement () {
new ReturnStatement (id1)
};
newProperty.Setter.Body = new BlockStatement () {
new AssignmentExpression (id2, AssignmentOperatorType.Assign, new IdentifierExpression ("value"))
};
using (var script = context.StartScript ()) {
script.Replace (property, newProperty);
script.InsertBefore (property, backingStore);
script.Link (initializer, id1, id2);
}
}
}
}

110
ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateEventInvocator.cs

@ -1,110 +0,0 @@ @@ -1,110 +0,0 @@
//
// CreateEventInvocator.cs
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
// Copyright (c) 2011 Mike Krüger <mkrueger@novell.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.Linq;
using System.Collections.Generic;
using ICSharpCode.NRefactory.TypeSystem;
using System.Threading;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class CreateEventInvocator : IContextAction
{
public bool IsValid (RefactoringContext context)
{
VariableInitializer initializer;
var eventDeclaration = GetEventDeclaration (context, out initializer);
if (eventDeclaration == null)
return false;
var type = (TypeDeclaration)eventDeclaration.Parent;
return !type.Members.Any (m => m is MethodDeclaration && ((MethodDeclaration)m).Name == "On" + initializer.Name);
}
public void Run (RefactoringContext context)
{
VariableInitializer initializer;
var eventDeclaration = GetEventDeclaration (context, out initializer);
var type = context.Resolve (eventDeclaration.ReturnType).Type;
if (type == null)
return;
var invokeMethod = type.GetDelegateInvokeMethod ();
if (invokeMethod == null)
return;
bool hasSenderParam = false;
IEnumerable<IParameter> pars = invokeMethod.Parameters;
if (invokeMethod.Parameters.Any ()) {
var first = invokeMethod.Parameters [0];
if (first.Name == "sender" /*&& first.Type == "System.Object"*/) {
hasSenderParam = true;
pars = invokeMethod.Parameters.Skip (1);
}
}
const string handlerName = "handler";
var arguments = new List<Expression> ();
if (hasSenderParam)
arguments.Add (new ThisReferenceExpression ());
foreach (var par in pars)
arguments.Add (new IdentifierExpression (par.Name));
var methodDeclaration = new MethodDeclaration () {
Name = "On" + initializer.Name,
ReturnType = new PrimitiveType ("void"),
Modifiers = ICSharpCode.NRefactory.CSharp.Modifiers.Protected | ICSharpCode.NRefactory.CSharp.Modifiers.Virtual,
Body = new BlockStatement () {
new VariableDeclarationStatement (eventDeclaration.ReturnType.Clone (), handlerName, new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name)),
new IfElseStatement () {
Condition = new BinaryOperatorExpression (new IdentifierExpression (handlerName), BinaryOperatorType.InEquality, new PrimitiveExpression (null)),
TrueStatement = new ExpressionStatement (new InvocationExpression (new IdentifierExpression (handlerName), arguments))
}
}
};
foreach (var par in pars) {
var typeName = context.CreateShortType (par.Type);
var decl = new ParameterDeclaration (typeName, par.Name);
methodDeclaration.Parameters.Add (decl);
}
using (var script = context.StartScript ()) {
script.InsertWithCursor ("Create event invocator", methodDeclaration, Script.InsertPosition.After);
}
}
static EventDeclaration GetEventDeclaration (RefactoringContext context, out VariableInitializer initializer)
{
var result = context.GetNode<EventDeclaration> ();
if (result == null) {
initializer = null;
return null;
}
initializer = result.Variables.FirstOrDefault (v => v.NameToken.Contains (context.Location));
return initializer != null ? result : null;
}
}
}

42
ICSharpCode.NRefactory.CSharp/Refactoring/ContextActionAttribute.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
//
// ProviderDescriptionAttribute.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// 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;
namespace ICSharpCode.NRefactory.CSharp
{
public class ContextActionAttribute : System.Attribute
{
public string Title { get; private set;}
public string Description { get; set; }
public string Category { get; set; }
public ContextActionAttribute (string title)
{
Title = title;
}
}
}

6
ICSharpCode.NRefactory.CSharp/Refactoring/IContextAction.cs → ICSharpCode.NRefactory.CSharp/Refactoring/ICodeActionProvider.cs

@ -25,13 +25,13 @@ @@ -25,13 +25,13 @@
// THE SOFTWARE.
using System;
using System.Threading;
using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public interface IContextAction
public interface ICodeActionProvider
{
bool IsValid (RefactoringContext context);
void Run (RefactoringContext context);
IEnumerable<CodeAction> GetActions (RefactoringContext context);
}
}

4
ICSharpCode.NRefactory.CSharp/Refactoring/IInspector.cs → ICSharpCode.NRefactory.CSharp/Refactoring/ICodeIssueProvider.cs

@ -28,9 +28,9 @@ using System.Collections.Generic; @@ -28,9 +28,9 @@ using System.Collections.Generic;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public interface IInspector
public interface ICodeIssueProvider
{
IEnumerable<CodeIssue> Run (BaseRefactoringContext context);
IEnumerable<CodeIssue> GetIssues (BaseRefactoringContext context);
}
}

50
ICSharpCode.NRefactory.CSharp/Refactoring/IssueAttribute.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
//
// IssueAttribute.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// 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;
namespace ICSharpCode.NRefactory.CSharp
{
public class IssueDescriptionAttribute : System.Attribute
{
public string Title { get; private set;}
public string Description { get; set; }
public string Category { get; set; }
public Severity Severity { get; set; }
public IssueMarker IssueMarker { get; set; }
public IssueDescriptionAttribute (string title)
{
Title = title;
Severity = Severity.Suggestion;
IssueMarker = IssueMarker.Underline;
}
}
}

52
ICSharpCode.NRefactory.CSharp/Refactoring/IssueMarker.cs

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
//
// IssueMarker.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// 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;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// The issue marker is used to set how an issue should be marked inside the text editor.
/// </summary>
public enum IssueMarker
{
/// <summary>
/// The issue is not shown inside the text editor. (But in the task bar)
/// </summary>
None,
/// <summary>
/// The region is marked as underline in the severity color.
/// </summary>
Underline,
/// <summary>
/// The text is grayed out.
/// </summary>
GrayOut
}
}

42
ICSharpCode.NRefactory.CSharp/Refactoring/Severity.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
//
// Severity.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// 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;
namespace ICSharpCode.NRefactory.CSharp
{
public enum Severity
{
None,
Error,
Warning,
Hint,
Suggestion,
Usage
}
}

17
ICSharpCode.NRefactory.Tests/CSharp/ContextAction/ContextActionTestBase.cs

@ -28,28 +28,31 @@ using System; @@ -28,28 +28,31 @@ using System;
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using System.Threading;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp.ContextActions
{
public abstract class ContextActionTestBase
{
protected static string RunContextAction (IContextAction action, string input)
protected static string RunContextAction (ICodeActionProvider action, string input)
{
var context = TestRefactoringContext.Create (input);
bool isValid = action.IsValid (context);
bool isValid = action.GetActions (context).Any ();
if (!isValid)
Console.WriteLine ("invalid node is:" + context.GetNode ());
Assert.IsTrue (isValid, action.GetType () + " is invalid.");
action.Run (context);
using (var script = context.StartScript ()) {
action.GetActions (context).First ().Run (script);
}
return context.doc.Text;
}
protected static void TestWrongContext (IContextAction action, string input)
protected static void TestWrongContext (ICodeActionProvider action, string input)
{
var context = TestRefactoringContext.Create (input);
bool isValid = action.IsValid (context);
bool isValid = action.GetActions (context).Any ();
if (!isValid)
Console.WriteLine ("invalid node is:" + context.GetNode ());
Assert.IsTrue (!isValid, action.GetType () + " shouldn't be valid there.");

30
ICSharpCode.NRefactory.Tests/CSharp/Inspector/ConditionalToNullCoalescingInspectorTests.cs

@ -47,17 +47,15 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector @@ -47,17 +47,15 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector
TestRefactoringContext context;
var issues = GetIssues (new ConditionalToNullCoalescingInspector (), input, out context);
Assert.AreEqual (1, issues.Count);
issues [0].Fix ();
var output = @"class Foo
CheckFix (context, issues [0], @"class Foo
{
void Bar (string str)
{
string c = str ?? ""default"";
}
}";
Assert.AreEqual (output, context.Text);
}");
}
[Test]
@ -74,16 +72,14 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector @@ -74,16 +72,14 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector
var issues = GetIssues (new ConditionalToNullCoalescingInspector (), input, out context);
Assert.AreEqual (1, issues.Count);
issues [0].Fix ();
var output = @"class Foo
CheckFix (context, issues [0], @"class Foo
{
void Bar (string str)
{
string c = str ?? ""default"";
}
}";
Assert.AreEqual (output, context.Text);
}");
}
[Test]
@ -100,16 +96,13 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector @@ -100,16 +96,13 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector
var issues = GetIssues (new ConditionalToNullCoalescingInspector (), input, out context);
Assert.AreEqual (1, issues.Count);
issues [0].Fix ();
var output = @"class Foo
CheckFix (context, issues [0], @"class Foo
{
void Bar (string str)
{
string c = str ?? ""default"";
}
}";
Assert.AreEqual (output, context.Text);
}");
}
[Test]
@ -126,16 +119,13 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector @@ -126,16 +119,13 @@ namespace ICSharpCode.NRefactory.CSharp.Inspector
var issues = GetIssues (new ConditionalToNullCoalescingInspector (), input, out context);
Assert.AreEqual (1, issues.Count);
issues [0].Fix ();
var output = @"class Foo
CheckFix (context, issues [0], @"class Foo
{
void Bar (string str)
{
string c = str ?? ""default"";
}
}";
Assert.AreEqual (output, context.Text);
}");
}
}

12
ICSharpCode.NRefactory.Tests/CSharp/Inspector/InspectionActionTestBase.cs

@ -29,16 +29,24 @@ using System; @@ -29,16 +29,24 @@ using System;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.CSharp.ContextActions;
using System.Collections.Generic;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Inspector
{
public abstract class InspectionActionTestBase
{
protected static List<CodeIssue> GetIssues (IInspector action, string input, out TestRefactoringContext context)
protected static List<CodeIssue> GetIssues (ICodeIssueProvider action, string input, out TestRefactoringContext context)
{
context = TestRefactoringContext.Create (input);
return new List<CodeIssue> (action.Run (context));
return new List<CodeIssue> (action.GetIssues (context));
}
protected static void CheckFix (TestRefactoringContext ctx, CodeIssue issue, string expectedOutput)
{
using (var script = ctx.StartScript ())
issue.Action.Run (script);
Assert.AreEqual (expectedOutput, ctx.Text);
}
}

Loading…
Cancel
Save