1350 changed files with 133561 additions and 91603 deletions
@ -1,2 +1,3 @@
@@ -1,2 +1,3 @@
|
||||
*.sln -crlf |
||||
*.csproj -crlf |
||||
*.cs text diff=csharp |
||||
*.sln text eol=crlf |
||||
*.csproj text eol=crlf |
||||
|
||||
@ -1,69 +1,69 @@
@@ -1,69 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<PropertyGroup> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<ProductVersion>10.0.0</ProductVersion> |
||||
<SchemaVersion>2.0</SchemaVersion> |
||||
<ProjectGuid>{961DADFA-7CE6-429F-BC22-47630D6DB826}</ProjectGuid> |
||||
<OutputType>Exe</OutputType> |
||||
<RootNamespace>ICSharpCode.NRefactory.CSharp.AstVerifier</RootNamespace> |
||||
<AssemblyName>AstVerifier</AssemblyName> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Debug\</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
||||
<DebugType>none</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Release\</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'net_4_5_Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\net_4_5_Debug\</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'net_4_5_Release|AnyCPU' "> |
||||
<DebugType>none</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\net_4_5_Release\</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="System" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="Main.cs" /> |
||||
<Compile Include="AssemblyInfo.cs" /> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj"> |
||||
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project> |
||||
<Name>ICSharpCode.NRefactory.CSharp</Name> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> |
||||
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> |
||||
<Name>ICSharpCode.NRefactory</Name> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<PropertyGroup> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<ProductVersion>10.0.0</ProductVersion> |
||||
<SchemaVersion>2.0</SchemaVersion> |
||||
<ProjectGuid>{961DADFA-7CE6-429F-BC22-47630D6DB826}</ProjectGuid> |
||||
<OutputType>Exe</OutputType> |
||||
<RootNamespace>ICSharpCode.NRefactory.CSharp.AstVerifier</RootNamespace> |
||||
<AssemblyName>AstVerifier</AssemblyName> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Debug\</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
||||
<DebugType>none</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\Release\</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'net_4_5_Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\net_4_5_Debug\</OutputPath> |
||||
<DefineConstants>DEBUG;</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'net_4_5_Release|AnyCPU' "> |
||||
<DebugType>none</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>bin\net_4_5_Release\</OutputPath> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
<Externalconsole>true</Externalconsole> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="System" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="Main.cs" /> |
||||
<Compile Include="AssemblyInfo.cs" /> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
||||
<ItemGroup> |
||||
<ProjectReference Include="..\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj"> |
||||
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project> |
||||
<Name>ICSharpCode.NRefactory.CSharp</Name> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> |
||||
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> |
||||
<Name>ICSharpCode.NRefactory</Name> |
||||
</ProjectReference> |
||||
</ItemGroup> |
||||
</Project> |
||||
@ -0,0 +1,198 @@
@@ -0,0 +1,198 @@
|
||||
//
|
||||
// AbstractAndVirtualConversionAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 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 ICSharpCode.NRefactory.CSharp; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Make abstract member virtual", Description = "Implements an abstract member as a virtual one")] |
||||
public class AbstractAndVirtualConversionAction : CodeActionProvider |
||||
{ |
||||
static BlockStatement CreateNotImplementedBody(RefactoringContext context, out ThrowStatement throwStatement) |
||||
{ |
||||
throwStatement = new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException"))); |
||||
return new BlockStatement { throwStatement }; |
||||
} |
||||
|
||||
static ThrowStatement ImplementStub (RefactoringContext context, EntityDeclaration newNode) |
||||
{ |
||||
ThrowStatement throwStatement = null; |
||||
if (newNode is PropertyDeclaration || newNode is IndexerDeclaration) { |
||||
var setter = newNode.GetChildByRole(PropertyDeclaration.SetterRole); |
||||
if (!setter.IsNull) |
||||
setter.AddChild(CreateNotImplementedBody(context, out throwStatement), Roles.Body); |
||||
|
||||
var getter = newNode.GetChildByRole(PropertyDeclaration.GetterRole); |
||||
if (!getter.IsNull) |
||||
getter.AddChild(CreateNotImplementedBody(context, out throwStatement), Roles.Body); |
||||
} else { |
||||
newNode.AddChild(CreateNotImplementedBody(context, out throwStatement), Roles.Body); |
||||
} |
||||
return throwStatement; |
||||
} |
||||
|
||||
static bool CheckBody(EntityDeclaration node) |
||||
{ |
||||
var custom = node as CustomEventDeclaration; |
||||
if (custom != null && !(IsValidBody (custom.AddAccessor.Body) || IsValidBody (custom.RemoveAccessor.Body))) |
||||
return false; |
||||
if (node is PropertyDeclaration || node is IndexerDeclaration) { |
||||
var setter = node.GetChildByRole(PropertyDeclaration.SetterRole); |
||||
var getter = node.GetChildByRole(PropertyDeclaration.GetterRole); |
||||
return IsValidBody(setter.Body) && IsValidBody(getter.Body); |
||||
} |
||||
return IsValidBody(node.GetChildByRole(Roles.Body)); |
||||
} |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var node = context.GetNode<EntityDeclaration>(); |
||||
if (node == null || node.HasModifier(Modifiers.Override)) |
||||
yield break; |
||||
|
||||
var parent = node.Parent as TypeDeclaration; |
||||
if (parent == null) |
||||
yield break; |
||||
|
||||
var custom = node as CustomEventDeclaration; |
||||
if (custom != null) { |
||||
if (!custom.PrivateImplementationType.IsNull) |
||||
yield break; |
||||
} |
||||
|
||||
var selectedNode = node.GetNodeAt(context.Location); |
||||
if (selectedNode == null) |
||||
yield break; |
||||
if (selectedNode != node.NameToken) { |
||||
if ((node is EventDeclaration && node is CustomEventDeclaration || selectedNode.Role != Roles.Identifier) && |
||||
selectedNode.Role != IndexerDeclaration.ThisKeywordRole) { |
||||
var modToken = selectedNode as CSharpModifierToken; |
||||
if (modToken == null || (modToken.Modifier & (Modifiers.Abstract | Modifiers.Virtual)) == 0) |
||||
yield break; |
||||
} else { |
||||
if (!(node is EventDeclaration || node is CustomEventDeclaration) && selectedNode.Parent != node) |
||||
yield break; |
||||
} |
||||
} |
||||
if (!node.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole).IsNull) |
||||
yield break; |
||||
|
||||
if (parent.HasModifier(Modifiers.Abstract)) { |
||||
if ((node.Modifiers & Modifiers.Abstract) != 0) { |
||||
yield return new CodeAction(context.TranslateString("To non-abstract"), script => { |
||||
var newNode = (EntityDeclaration)node.Clone(); |
||||
newNode.Modifiers &= ~Modifiers.Abstract; |
||||
var throwStmt = ImplementStub (context, newNode); |
||||
script.Replace(node, newNode); |
||||
if (throwStmt != null) |
||||
script.Select(throwStmt); |
||||
}, selectedNode); |
||||
} else { |
||||
if (CheckBody(node)) { |
||||
yield return new CodeAction(context.TranslateString("To abstract"), script => { |
||||
var newNode = CloneNodeWithoutBodies(node); |
||||
newNode.Modifiers &= ~Modifiers.Virtual; |
||||
newNode.Modifiers &= ~Modifiers.Static; |
||||
newNode.Modifiers |= Modifiers.Abstract; |
||||
script.Replace(node, newNode); |
||||
}, selectedNode); |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ((node.Modifiers & Modifiers.Virtual) != 0) { |
||||
yield return new CodeAction(context.TranslateString("To non-virtual"), script => { |
||||
script.ChangeModifier(node, node.Modifiers & ~Modifiers.Virtual); |
||||
}, selectedNode); |
||||
} else { |
||||
if ((node.Modifiers & Modifiers.Abstract) != 0) { |
||||
yield return new CodeAction(context.TranslateString("To virtual"), script => { |
||||
var newNode = CloneNodeWithoutBodies(node); |
||||
newNode.Modifiers &= ~Modifiers.Abstract; |
||||
newNode.Modifiers &= ~Modifiers.Static; |
||||
newNode.Modifiers |= Modifiers.Virtual; |
||||
var throwStmt = ImplementStub (context, newNode); |
||||
script.Replace(node, newNode); |
||||
if (throwStmt != null) |
||||
script.Select(throwStmt); |
||||
}, selectedNode); |
||||
} else { |
||||
yield return new CodeAction(context.TranslateString("To virtual"), script => { |
||||
script.ChangeModifier(node, (node.Modifiers & ~Modifiers.Static) | Modifiers.Virtual); |
||||
}, selectedNode); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
static EntityDeclaration CloneNodeWithoutBodies(EntityDeclaration node) |
||||
{ |
||||
EntityDeclaration newNode; |
||||
var custom = node as CustomEventDeclaration; |
||||
|
||||
if (custom == null) { |
||||
newNode = (EntityDeclaration)node.Clone(); |
||||
|
||||
if (newNode is PropertyDeclaration || node is IndexerDeclaration) { |
||||
var getter = newNode.GetChildByRole(PropertyDeclaration.GetterRole); |
||||
if (!getter.IsNull) |
||||
getter.Body.Remove(); |
||||
var setter = newNode.GetChildByRole(PropertyDeclaration.SetterRole); |
||||
if (!setter.IsNull) |
||||
setter.Body.Remove(); |
||||
} else { |
||||
newNode.GetChildByRole(Roles.Body).Remove(); |
||||
} |
||||
} else { |
||||
newNode = new EventDeclaration { |
||||
Modifiers = custom.Modifiers, |
||||
ReturnType = custom.ReturnType.Clone(), |
||||
Variables = { |
||||
new VariableInitializer { |
||||
Name = custom.Name |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
return newNode; |
||||
} |
||||
|
||||
static bool IsValidBody(BlockStatement body) |
||||
{ |
||||
if (body.IsNull) |
||||
return true; |
||||
var first = body.Statements.FirstOrDefault(); |
||||
if (first == null) |
||||
return true; |
||||
if (first.GetNextSibling(s => s.Role == BlockStatement.StatementRole) != null) |
||||
return false; |
||||
return first is EmptyStatement || first is ThrowStatement; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// AddAnotherAccessor.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.Threading; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Add another accessor to a property declaration that has only one.
|
||||
/// </summary>
|
||||
[ContextAction("Add another accessor", Description = "Adds second accessor to a property.")] |
||||
public class AddAnotherAccessorAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var pdecl = context.GetNode<PropertyDeclaration> (); |
||||
if (pdecl == null || !pdecl.Getter.IsNull && !pdecl.Setter.IsNull || !pdecl.NameToken.Contains(context.Location)) { |
||||
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 setter") : context.TranslateString("Add getter"), script => { |
||||
Statement accessorStatement = null; |
||||
|
||||
var accessor = new Accessor (); |
||||
if (!pdecl.Getter.IsNull && !pdecl.Getter.Body.IsNull || !pdecl.Setter.IsNull && !pdecl.Setter.Body.IsNull) { |
||||
accessorStatement = BuildAccessorStatement(context, pdecl); |
||||
accessor.Body = new BlockStatement { accessorStatement }; |
||||
} |
||||
|
||||
accessor.Role = pdecl.Setter.IsNull ? PropertyDeclaration.SetterRole : PropertyDeclaration.GetterRole; |
||||
|
||||
if (pdecl.Setter.IsNull && !pdecl.Getter.IsNull) { |
||||
script.InsertAfter(pdecl.Getter, accessor); |
||||
} else if (pdecl.Getter.IsNull && !pdecl.Setter.IsNull) { |
||||
script.InsertBefore(pdecl.Setter, accessor); |
||||
} else { |
||||
script.InsertBefore(pdecl.Getter, accessor); |
||||
} |
||||
script.FormatText(pdecl); |
||||
if (accessorStatement != null) |
||||
script.Select(accessorStatement); |
||||
}, pdecl.NameToken); |
||||
} |
||||
|
||||
static Statement BuildAccessorStatement (RefactoringContext context, PropertyDeclaration pdecl) |
||||
{ |
||||
if (pdecl.Setter.IsNull && !pdecl.Getter.IsNull) { |
||||
var field = RemoveBackingStoreAction.ScanGetter (context, pdecl); |
||||
if (field != null && !field.IsReadOnly && !field.IsConst) |
||||
return new AssignmentExpression (new IdentifierExpression (field.Name), AssignmentOperatorType.Assign, new IdentifierExpression ("value")); |
||||
} |
||||
|
||||
if (!pdecl.Setter.IsNull && pdecl.Getter.IsNull) { |
||||
var field = RemoveBackingStoreAction.ScanSetter (context, pdecl); |
||||
if (field != null) |
||||
return new ReturnStatement (new IdentifierExpression (field.Name)); |
||||
} |
||||
|
||||
return new ThrowStatement (new ObjectCreateExpression (context.CreateShortType ("System", "NotImplementedException"))); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,205 @@
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// AddArgumentNameAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Ji Kun <jikun.nus@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Ji Kun <jikun.nus@gmail.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 ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.Refactoring; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Add name for argument
|
||||
/// </summary>
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
[ContextAction("Add name for argument", Description = "Add name for argument including method, indexer invocation and Attibute Usage")] |
||||
public class AddArgumentNameAction : SpecializedCodeAction<Expression> |
||||
{ |
||||
List<Expression> CollectNodes(AstNode parant, AstNode node) |
||||
{ |
||||
List<Expression> returned = new List<Expression>(); |
||||
|
||||
var children = parant.GetChildrenByRole(Roles.Argument); |
||||
for (int i = 0; i< children.Count(); i++) { |
||||
if (children.ElementAt(i).Equals(node)) { |
||||
for (int j = i; j< children.Count(); j++) { |
||||
if (children.ElementAt(j) is Expression && children.ElementAt(j).Role == Roles.Argument && !(children.ElementAt(j) is NamedArgumentExpression)) { |
||||
returned.Add(children.ElementAt(j)); |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return returned; |
||||
} |
||||
|
||||
protected override CodeAction GetAction(RefactoringContext context, Expression expression) |
||||
{ |
||||
if (expression == null) |
||||
return null; |
||||
if (expression.Role != Roles.Argument || expression is NamedArgumentExpression) |
||||
return null; |
||||
if (context.Location != expression.StartLocation) |
||||
return null; |
||||
var parent = expression.Parent; |
||||
if (!(parent is CSharp.Attribute) && !(parent is IndexerExpression) && !(parent is InvocationExpression)) |
||||
return null; |
||||
|
||||
if (parent is CSharp.Attribute) { |
||||
var resolvedResult = context.Resolve(parent as CSharp.Attribute); |
||||
if (resolvedResult.IsError) |
||||
return null; |
||||
var arguments = (parent as CSharp.Attribute).Arguments; |
||||
IMember member = (resolvedResult as CSharpInvocationResolveResult).Member; |
||||
|
||||
int index = 0; |
||||
int temp = 0; |
||||
List<Expression> nodes = new List<Expression>(); |
||||
foreach (var argument in arguments) { |
||||
if (argument.Equals(expression)) { |
||||
nodes = CollectNodes(parent, expression); |
||||
break; |
||||
} |
||||
temp++; |
||||
} |
||||
index = temp; |
||||
if (!nodes.Any()) |
||||
return null; |
||||
var method = member as IMethod; |
||||
if (method == null || method.Parameters.Count == 0 || method.Parameters.Last().IsParams) |
||||
return null; |
||||
|
||||
var parameterMap = (resolvedResult as CSharpInvocationResolveResult).GetArgumentToParameterMap(); |
||||
var parameters = method.Parameters; |
||||
if (index >= parameterMap.Count) |
||||
return null; |
||||
var name = parameters.ElementAt(parameterMap [index]).Name; |
||||
return new CodeAction(string.Format(context.TranslateString("Add argument name '{0}'"), name), script => { |
||||
for (int i = 0; i < nodes.Count; i++) { |
||||
int p = index + i; |
||||
if (p >= parameterMap.Count) |
||||
break; |
||||
name = parameters.ElementAt(parameterMap [p]).Name; |
||||
var namedArgument = new NamedArgumentExpression(name, arguments.ElementAt(p).Clone()); |
||||
script.Replace(arguments.ElementAt(p), namedArgument); |
||||
}}, |
||||
expression |
||||
); |
||||
} |
||||
|
||||
if (parent is IndexerExpression) { |
||||
var resolvedResult = context.Resolve(parent as IndexerExpression); |
||||
if (resolvedResult.IsError) |
||||
return null; |
||||
var arguments = (parent as IndexerExpression).Arguments; |
||||
IMember member = (resolvedResult as CSharpInvocationResolveResult).Member; |
||||
|
||||
int index = 0; |
||||
int temp = 0; |
||||
List<Expression> nodes = new List<Expression>(); |
||||
foreach (var argument in arguments) { |
||||
if (argument.Equals(expression)) { |
||||
nodes = CollectNodes(parent, expression); |
||||
break; |
||||
} |
||||
temp++; |
||||
} |
||||
index = temp; |
||||
if (!nodes.Any()) |
||||
return null; |
||||
var property = member as IProperty; |
||||
if (property == null || property.Parameters.Count == 0 || property.Parameters.Last().IsParams) { |
||||
return null; |
||||
} |
||||
var parameterMap = (resolvedResult as CSharpInvocationResolveResult).GetArgumentToParameterMap(); |
||||
var parameters = property.Parameters; |
||||
if (index >= parameterMap.Count) |
||||
return null; |
||||
var name = parameters.ElementAt(parameterMap [index]).Name; |
||||
return new CodeAction(string.Format(context.TranslateString("Add argument name '{0}'"), name), script => { |
||||
for (int i = 0; i< nodes.Count; i++) { |
||||
int p = index + i; |
||||
if (p >= parameterMap.Count) |
||||
break; |
||||
name = parameters.ElementAt(parameterMap [p]).Name; |
||||
var namedArgument = new NamedArgumentExpression(name, arguments.ElementAt(p).Clone()); |
||||
script.Replace(arguments.ElementAt(p), namedArgument); |
||||
}}, |
||||
expression |
||||
); |
||||
} |
||||
|
||||
if (parent is InvocationExpression) { |
||||
var resolvedResult = context.Resolve(parent as InvocationExpression); |
||||
if (resolvedResult.IsError) |
||||
return null; |
||||
var arguments = (parent as InvocationExpression).Arguments; |
||||
IMember member = (resolvedResult as CSharpInvocationResolveResult).Member; |
||||
|
||||
int index = 0; |
||||
int temp = 0; |
||||
List<Expression> nodes = new List<Expression>(); |
||||
foreach (var argument in arguments) { |
||||
if (argument.Equals(expression)) { |
||||
nodes = CollectNodes(parent, expression); |
||||
break; |
||||
} |
||||
temp++; |
||||
} |
||||
index = temp; |
||||
if (!nodes.Any()) |
||||
return null; |
||||
|
||||
var method = member as IMethod; |
||||
if (method == null || method.Parameters.Count == 0 || method.Parameters.Last().IsParams) |
||||
return null; |
||||
|
||||
var parameterMap = (resolvedResult as CSharpInvocationResolveResult).GetArgumentToParameterMap(); |
||||
var parameters = method.Parameters; |
||||
if (index >= parameterMap.Count) |
||||
return null; |
||||
var name = parameters.ElementAt(parameterMap [index]).Name; |
||||
return new CodeAction(string.Format(context.TranslateString("Add argument name '{0}'"), name), script => { |
||||
for (int i = 0; i< nodes.Count; i++) { |
||||
int p = index + i; |
||||
if (p >= parameterMap.Count) |
||||
break; |
||||
name = parameters.ElementAt(parameterMap [p]).Name; |
||||
var namedArgument = new NamedArgumentExpression(name, arguments.ElementAt(p).Clone()); |
||||
script.Replace(arguments.ElementAt(p), namedArgument); |
||||
}}, |
||||
expression |
||||
); |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// AddBracesAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Add braces", Description = "Removes redundant braces around a statement.")] |
||||
public class AddBracesAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
string keyword; |
||||
Statement embeddedStatement; |
||||
// BlockStatement block;
|
||||
|
||||
var curNode = context.GetNode(); |
||||
if (!RemoveBracesAction.IsSpecialNode(curNode, out keyword, out embeddedStatement)) |
||||
yield break; |
||||
if (embeddedStatement is BlockStatement) |
||||
yield break; |
||||
yield return new CodeAction ( |
||||
string.Format(context.TranslateString("Add braces to '{0}'"), keyword), |
||||
script => { |
||||
script.Replace(embeddedStatement, new BlockStatement { embeddedStatement.Clone() }); |
||||
}, |
||||
curNode |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// AddCatchTypeAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Add type to general catch clause", |
||||
Description = "Adds an exception type specifier to general catch clauses.")] |
||||
public class AddCatchTypeAction : CodeActionProvider |
||||
{ |
||||
#region ICodeActionProvider implementation
|
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var catchClause = context.GetNode<CatchClause>(); |
||||
if (catchClause == null) |
||||
yield break; |
||||
if (!catchClause.Type.IsNull) |
||||
yield break; |
||||
yield return new CodeAction(context.TranslateString("Add type specifier"), script => { |
||||
var newType = context.CreateShortType("System", "Exception"); |
||||
var namingHelper = new NamingHelper(context); |
||||
var newIdentifier = Identifier.Create(namingHelper.GenerateVariableName(newType, "e")); |
||||
|
||||
script.Replace(catchClause, new CatchClause { |
||||
Type = newType, |
||||
VariableNameToken = newIdentifier, |
||||
Body = catchClause.Body.Clone() as BlockStatement |
||||
}); |
||||
script.Select(newType); |
||||
}, catchClause); |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
||||
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// AddExceptionDescriptionAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 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 ICSharpCode.NRefactory.CSharp; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.Xml; |
||||
using ICSharpCode.NRefactory.Documentation; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Add an exception description to the xml documentation", |
||||
Description = "Add an exception description to the xml documentation")] |
||||
public class AddExceptionDescriptionAction : SpecializedCodeAction<ThrowStatement> |
||||
{ |
||||
static AstNode SearchInsertionNode (AstNode entity) |
||||
{ |
||||
AstNode result = entity; |
||||
while (result != null && (result.Role == Roles.Comment || result.Role == Roles.NewLine || result.Role == Roles.Whitespace)) |
||||
result = result.NextSibling; |
||||
return result; |
||||
} |
||||
|
||||
protected override CodeAction GetAction (RefactoringContext context, ThrowStatement node) |
||||
{ |
||||
var entity = node.GetParent<EntityDeclaration> (); |
||||
if (entity == null) |
||||
return null; |
||||
var rr = context.Resolve (entity) as MemberResolveResult; |
||||
if (rr == null || rr.IsError) |
||||
return null; |
||||
var expr = context.Resolve (node.Expression); |
||||
if (expr == null || expr.IsError || expr.Type.GetDefinition () == null) |
||||
return null; |
||||
|
||||
var docElement = XmlDocumentationElement.Get (rr.Member); |
||||
if (docElement == null || docElement.Children.Count == 0) |
||||
return null; |
||||
foreach (var de in docElement.Children) { |
||||
if (de.Name == "exception") { |
||||
if (de.ReferencedEntity == expr.Type) |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
return new CodeAction ( |
||||
context.TranslateString ("Add exception to xml documentation"), |
||||
script => { |
||||
var startText = string.Format (" <exception cref=\"{0}\">", expr.Type.GetDefinition ().GetIdString ()); |
||||
var comment = new Comment (startText +"</exception>", CommentType.Documentation); |
||||
script.InsertBefore ( |
||||
SearchInsertionNode (entity.FirstChild) ?? entity, |
||||
comment |
||||
); |
||||
script.Select (script.GetSegment (comment).Offset + ("///" + startText).Length, 0); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,134 @@
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// AddOptionalParameterToInvocationAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Luís Reis
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.Xml; |
||||
using ICSharpCode.NRefactory.Documentation; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Add one or more optional parameters to an invocation, using their default values", |
||||
Description = "Add one or more optional parameters to an invocation.")] |
||||
public class AddOptionalParameterToInvocationAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var invocationExpression = context.GetNode<InvocationExpression>(); |
||||
if (invocationExpression == null) |
||||
yield break; |
||||
|
||||
var resolveResult = context.Resolve(invocationExpression) as InvocationResolveResult; |
||||
if (resolveResult == null) { |
||||
yield break; |
||||
} |
||||
|
||||
var method = (IMethod)resolveResult.Member; |
||||
|
||||
bool foundOptionalParameter = false; |
||||
foreach (var parameter in method.Parameters) { |
||||
if (parameter.IsParams) { |
||||
yield break; |
||||
} |
||||
|
||||
if (parameter.IsOptional) { |
||||
foundOptionalParameter = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!foundOptionalParameter) { |
||||
yield break; |
||||
} |
||||
|
||||
//Basic sanity checks done, now see if there are any missing optional arguments
|
||||
var missingParameters = new List<IParameter>(method.Parameters); |
||||
if (resolveResult.Arguments.Count != invocationExpression.Arguments.Count) { |
||||
//Extension method
|
||||
missingParameters.RemoveAt (0); |
||||
} |
||||
foreach (var argument in invocationExpression.Arguments) { |
||||
var namedArgument = argument as NamedArgumentExpression; |
||||
if (namedArgument == null) { |
||||
missingParameters.RemoveAt(0); |
||||
} else { |
||||
missingParameters.RemoveAll(parameter => parameter.Name == namedArgument.Name); |
||||
} |
||||
} |
||||
|
||||
foreach (var parameterToAdd in missingParameters) { |
||||
//Add specific parameter
|
||||
yield return new CodeAction(string.Format(context.TranslateString("Add optional parameter \"{0}\""), |
||||
parameterToAdd.Name), |
||||
script => { |
||||
|
||||
var newInvocation = (InvocationExpression)invocationExpression.Clone(); |
||||
AddArgument(newInvocation, parameterToAdd, parameterToAdd == missingParameters.First()); |
||||
script.Replace(invocationExpression, newInvocation); |
||||
|
||||
}, invocationExpression); |
||||
} |
||||
|
||||
if (missingParameters.Count > 1) { |
||||
//Add all parameters at once
|
||||
yield return new CodeAction(context.TranslateString("Add all optional parameters"), |
||||
script => { |
||||
|
||||
var newInvocation = (InvocationExpression)invocationExpression.Clone(); |
||||
|
||||
foreach (var parameterToAdd in missingParameters) { |
||||
//We'll add the remaining parameters, in the order they were declared in the function
|
||||
AddArgument(newInvocation, parameterToAdd, true); |
||||
} |
||||
script.Replace(invocationExpression, newInvocation); |
||||
|
||||
}, invocationExpression); |
||||
} |
||||
} |
||||
|
||||
static void AddArgument(InvocationExpression newNode, IParameter parameterToAdd, bool isNextInSequence) |
||||
{ |
||||
Expression defaultValue; |
||||
if (parameterToAdd.ConstantValue == null) { |
||||
defaultValue = new NullReferenceExpression(); |
||||
} |
||||
else { |
||||
defaultValue = new PrimitiveExpression(parameterToAdd.ConstantValue); |
||||
} |
||||
Expression newArgument; |
||||
if (newNode.Arguments.Any(argument => argument is NamedExpression) || !isNextInSequence) { |
||||
newArgument = new NamedArgumentExpression(parameterToAdd.Name, defaultValue); |
||||
} |
||||
else { |
||||
newArgument = defaultValue; |
||||
} |
||||
newNode.Arguments.Add(newArgument); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) 2013 Daniel Grunwald
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// 1) When a type cannot be resolved, offers to add a using declaration
|
||||
/// or to replace it with the fully qualified type name.
|
||||
/// 2) When an extension method cannot be resolved, offers to add a using declaration.
|
||||
/// 3) When the caret is on a namespace name, offers to add a using declaration
|
||||
/// and simplify the type references to use the new shorter option.
|
||||
/// </summary>
|
||||
[ContextAction ("Add using", Description = "Add missing using declaration.")] |
||||
public class AddUsingAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
AstNode node = context.GetNode(); |
||||
if (node is Identifier) |
||||
node = node.Parent; |
||||
if (node is SimpleType || node is IdentifierExpression) { |
||||
return GetActionsForType(context, node) |
||||
.Concat(GetActionsForAddNamespaceUsing(context, node)); |
||||
} else if (node is MemberReferenceExpression && node.Parent is InvocationExpression) { |
||||
return GetActionsForExtensionMethodInvocation(context, (InvocationExpression)node.Parent); |
||||
} else if (node is MemberReferenceExpression) { |
||||
return GetActionsForAddNamespaceUsing(context, node); |
||||
} else { |
||||
return EmptyList<CodeAction>.Instance; |
||||
} |
||||
} |
||||
|
||||
IEnumerable<CodeAction> GetActionsForType(RefactoringContext context, AstNode node) |
||||
{ |
||||
var rr = context.Resolve(node) as UnknownIdentifierResolveResult; |
||||
if (rr == null) |
||||
return EmptyList<CodeAction>.Instance; |
||||
|
||||
string identifier = rr.Identifier; |
||||
int tc = rr.TypeArgumentCount; |
||||
string attributeIdentifier = null; |
||||
if (node.Parent is Attribute) |
||||
attributeIdentifier = identifier + "Attribute"; |
||||
|
||||
var lookup = new MemberLookup(null, context.Compilation.MainAssembly); |
||||
List<CodeAction> actions = new List<CodeAction>(); |
||||
foreach (var typeDefinition in context.Compilation.GetAllTypeDefinitions()) { |
||||
if ((typeDefinition.Name == identifier || typeDefinition.Name == attributeIdentifier) |
||||
&& typeDefinition.TypeParameterCount == tc |
||||
&& lookup.IsAccessible(typeDefinition, false)) |
||||
{ |
||||
if (typeDefinition.DeclaringTypeDefinition == null) { |
||||
actions.Add(NewUsingAction(context, node, typeDefinition.Namespace)); |
||||
} |
||||
actions.Add(ReplaceWithFullTypeNameAction(context, node, typeDefinition)); |
||||
} |
||||
} |
||||
return actions; |
||||
} |
||||
|
||||
CodeAction NewUsingAction(RefactoringContext context, AstNode node, string ns) |
||||
{ |
||||
return new CodeAction("using " + ns + ";", s => UsingHelper.InsertUsingAndRemoveRedundantNamespaceUsage(context, s, ns), node); |
||||
} |
||||
|
||||
CodeAction ReplaceWithFullTypeNameAction(RefactoringContext context, AstNode node, ITypeDefinition typeDefinition) |
||||
{ |
||||
AstType astType = context.CreateShortType(typeDefinition); |
||||
string textWithoutGenerics = astType.ToString(); |
||||
foreach (var typeArg in node.GetChildrenByRole(Roles.TypeArgument)) { |
||||
astType.AddChild(typeArg.Clone(), Roles.TypeArgument); |
||||
} |
||||
return new CodeAction(textWithoutGenerics, s => s.Replace(node, astType), node); |
||||
} |
||||
|
||||
IEnumerable<CodeAction> GetActionsForExtensionMethodInvocation(RefactoringContext context, InvocationExpression invocation) |
||||
{ |
||||
var rr = context.Resolve(invocation) as UnknownMethodResolveResult; |
||||
if (rr == null) |
||||
return EmptyList<CodeAction>.Instance; |
||||
|
||||
var lookup = new MemberLookup(null, context.Compilation.MainAssembly); |
||||
HashSet<string> namespaces = new HashSet<string>(); |
||||
List<CodeAction> result = new List<CodeAction>(); |
||||
foreach (var typeDefinition in context.Compilation.GetAllTypeDefinitions()) { |
||||
if (!(typeDefinition.HasExtensionMethods && lookup.IsAccessible(typeDefinition, false))) { |
||||
continue; |
||||
} |
||||
foreach (var method in typeDefinition.Methods.Where(m => m.IsExtensionMethod && m.Name == rr.MemberName)) { |
||||
IType[] inferredTypes; |
||||
if (CSharpResolver.IsEligibleExtensionMethod(rr.TargetType, method, true, out inferredTypes)) { |
||||
// avoid offering the same namespace twice
|
||||
if (namespaces.Add(typeDefinition.Namespace)) { |
||||
result.Add(NewUsingAction(context, invocation, typeDefinition.Namespace)); |
||||
} |
||||
break; // continue with the next type
|
||||
} |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
IEnumerable<CodeAction> GetActionsForAddNamespaceUsing(RefactoringContext context, AstNode node) |
||||
{ |
||||
var nrr = context.Resolve(node) as NamespaceResolveResult; |
||||
if (nrr == null) |
||||
return EmptyList<CodeAction>.Instance; |
||||
|
||||
var trr = context.Resolve(node.Parent) as TypeResolveResult; |
||||
if (trr == null) |
||||
return EmptyList<CodeAction>.Instance; |
||||
ITypeDefinition typeDef = trr.Type.GetDefinition(); |
||||
if (typeDef == null) |
||||
return EmptyList<CodeAction>.Instance; |
||||
|
||||
IList<IType> typeArguments; |
||||
ParameterizedType parameterizedType = trr.Type as ParameterizedType; |
||||
if (parameterizedType != null) |
||||
typeArguments = parameterizedType.TypeArguments; |
||||
else |
||||
typeArguments = EmptyList<IType>.Instance; |
||||
|
||||
var resolver = context.GetResolverStateBefore(node.Parent); |
||||
if (resolver.ResolveSimpleName(typeDef.Name, typeArguments) is UnknownIdentifierResolveResult) { |
||||
// It's possible to remove the explicit namespace usage and introduce a using instead
|
||||
return new[] { NewUsingAction(context, node, typeDef.Namespace) }; |
||||
} |
||||
return EmptyList<CodeAction>.Instance; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,435 @@
@@ -0,0 +1,435 @@
|
||||
//
|
||||
// AutoLinqSum.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Convers a loop to a Linq expression.
|
||||
/// </summary>
|
||||
[ContextAction("Convert loop to Linq expression", Description = "Converts a loop to a Linq expression")] |
||||
public class AutoLinqSumAction : CodeActionProvider |
||||
{ |
||||
// Disabled for nullables, since int? x = 3; x += null; has result x = null,
|
||||
// but LINQ Sum behaves differently : nulls are treated as zero
|
||||
static readonly IEnumerable<string> LinqSummableTypes = new string[] { |
||||
"System.UInt16", |
||||
"System.Int16", |
||||
"System.UInt32", |
||||
"System.Int32", |
||||
"System.UInt64", |
||||
"System.Int64", |
||||
"System.Single", |
||||
"System.Double", |
||||
"System.Decimal" |
||||
}; |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var loop = GetForeachStatement (context); |
||||
if (loop == null) { |
||||
yield break; |
||||
} |
||||
|
||||
if (context.GetResolverStateBefore(loop) |
||||
.LookupSimpleNameOrTypeName("Enumerable", new List<IType>(), NameLookupMode.Type) |
||||
.Type.FullName != "System.Linq.Enumerable") { |
||||
|
||||
yield break; |
||||
} |
||||
|
||||
var outputStatement = GetTransformedAssignmentExpression (context, loop); |
||||
if (outputStatement == null) { |
||||
yield break; |
||||
} |
||||
|
||||
yield return new CodeAction(context.TranslateString("Convert foreach loop to LINQ expression"), script => { |
||||
|
||||
var prevSibling = loop.GetPrevSibling(node => node is Statement); |
||||
|
||||
Expression leftSide = outputStatement.Left; |
||||
Expression rightSide = outputStatement.Right; |
||||
|
||||
Expression expressionToReplace = GetExpressionToReplace(prevSibling, leftSide); |
||||
|
||||
if (expressionToReplace != null) { |
||||
Expression replacementExpression = rightSide.Clone(); |
||||
if (!IsZeroPrimitive(expressionToReplace)) { |
||||
replacementExpression = new BinaryOperatorExpression(ParenthesizeIfNeeded(expressionToReplace).Clone(), |
||||
BinaryOperatorType.Add, |
||||
replacementExpression); |
||||
} |
||||
|
||||
script.Replace(expressionToReplace, replacementExpression); |
||||
script.Remove(loop); |
||||
} |
||||
else { |
||||
script.Replace(loop, new ExpressionStatement(outputStatement)); |
||||
} |
||||
|
||||
}, loop); |
||||
} |
||||
|
||||
bool IsZeroPrimitive(Expression expr) |
||||
{ |
||||
//We want a very simple check -- no looking at constants, no constant folding, etc.
|
||||
//So 1+1 should return false, but (0) should return true
|
||||
|
||||
var parenthesizedExpression = expr as ParenthesizedExpression; |
||||
if (parenthesizedExpression != null) { |
||||
return IsZeroPrimitive(parenthesizedExpression.Expression); |
||||
} |
||||
|
||||
var zeroLiteralInteger = new PrimitiveExpression(0); |
||||
var zeroLiteralFloat = new PrimitiveExpression(0.0f); |
||||
var zeroLiteralDouble = new PrimitiveExpression(0.0); |
||||
var zeroLiteralDecimal = new PrimitiveExpression(0.0m); |
||||
|
||||
return SameNode(zeroLiteralInteger, expr) || |
||||
SameNode(zeroLiteralFloat, expr) || |
||||
SameNode(zeroLiteralDouble, expr) || |
||||
SameNode(zeroLiteralDecimal, expr); |
||||
} |
||||
|
||||
Expression GetExpressionToReplace(AstNode prevSibling, Expression requiredLeftSide) |
||||
{ |
||||
if (prevSibling == null) { |
||||
return null; |
||||
} |
||||
|
||||
var declarationStatement = prevSibling as VariableDeclarationStatement; |
||||
if (declarationStatement != null) |
||||
{ |
||||
if (declarationStatement.Variables.Count != 1) { |
||||
return null; |
||||
} |
||||
|
||||
var identifierExpr = requiredLeftSide as IdentifierExpression; |
||||
if (identifierExpr == null) { |
||||
return null; |
||||
} |
||||
|
||||
var variableDecl = declarationStatement.Variables.First(); |
||||
|
||||
if (!SameNode(identifierExpr.IdentifierToken, variableDecl.NameToken)) { |
||||
return null; |
||||
} |
||||
|
||||
return variableDecl.Initializer; |
||||
} |
||||
|
||||
var exprStatement = prevSibling as ExpressionStatement; |
||||
if (exprStatement != null) { |
||||
var assignment = exprStatement.Expression as AssignmentExpression; |
||||
if (assignment != null) { |
||||
if (assignment.Operator != AssignmentOperatorType.Assign && |
||||
assignment.Operator != AssignmentOperatorType.Add) { |
||||
|
||||
return null; |
||||
} |
||||
|
||||
if (!SameNode(requiredLeftSide, assignment.Left)) { |
||||
return null; |
||||
} |
||||
|
||||
return assignment.Right; |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
bool IsUnaryModifierExpression(UnaryOperatorExpression expr) |
||||
{ |
||||
return expr.Operator == UnaryOperatorType.Increment || expr.Operator == UnaryOperatorType.PostIncrement || expr.Operator == UnaryOperatorType.Decrement || expr.Operator == UnaryOperatorType.PostDecrement; |
||||
} |
||||
|
||||
AssignmentExpression GetTransformedAssignmentExpression (RefactoringContext context, ForeachStatement foreachStatement) |
||||
{ |
||||
var enumerableToIterate = foreachStatement.InExpression.Clone(); |
||||
|
||||
Statement statement = foreachStatement.EmbeddedStatement; |
||||
|
||||
Expression leftExpression, rightExpression; |
||||
if (!ExtractExpression(statement, out leftExpression, out rightExpression)) { |
||||
return null; |
||||
} |
||||
if (leftExpression == null || rightExpression == null) { |
||||
return null; |
||||
} |
||||
|
||||
var type = context.Resolve(leftExpression).Type; |
||||
if (!IsLinqSummableType(type)) { |
||||
return null; |
||||
} |
||||
|
||||
if (rightExpression.DescendantsAndSelf.OfType<AssignmentExpression>().Any()) { |
||||
// Reject loops such as
|
||||
// int k = 0;
|
||||
// foreach (var x in y) { k += (z = 2); }
|
||||
|
||||
return null; |
||||
} |
||||
|
||||
if (rightExpression.DescendantsAndSelf.OfType<UnaryOperatorExpression>().Any(IsUnaryModifierExpression)) { |
||||
// int k = 0;
|
||||
// foreach (var x in y) { k += (z++); }
|
||||
|
||||
return null; |
||||
} |
||||
|
||||
var zeroLiteral = new PrimitiveExpression(0); |
||||
|
||||
Expression baseExpression = enumerableToIterate; |
||||
for (;;) { |
||||
ConditionalExpression condition = rightExpression as ConditionalExpression; |
||||
if (condition == null) { |
||||
break; |
||||
} |
||||
|
||||
if (SameNode(zeroLiteral, condition.TrueExpression)) { |
||||
baseExpression = new InvocationExpression(new MemberReferenceExpression(baseExpression.Clone(), "Where"), |
||||
BuildLambda(foreachStatement.VariableName, CSharpUtil.InvertCondition(condition.Condition))); |
||||
rightExpression = condition.FalseExpression.Clone(); |
||||
|
||||
continue; |
||||
} |
||||
|
||||
if (SameNode(zeroLiteral, condition.FalseExpression)) { |
||||
baseExpression = new InvocationExpression(new MemberReferenceExpression(baseExpression.Clone(), "Where"), |
||||
BuildLambda(foreachStatement.VariableName, condition.Condition.Clone())); |
||||
rightExpression = condition.TrueExpression.Clone(); |
||||
|
||||
continue; |
||||
} |
||||
|
||||
break; |
||||
} |
||||
|
||||
var primitiveOne = new PrimitiveExpression(1); |
||||
bool isPrimitiveOne = SameNode(primitiveOne, rightExpression); |
||||
|
||||
var arguments = new List<Expression>(); |
||||
|
||||
string method = isPrimitiveOne ? "Count" : "Sum"; |
||||
|
||||
if (!isPrimitiveOne && !IsIdentifier(rightExpression, foreachStatement.VariableName)) { |
||||
var lambda = BuildLambda(foreachStatement.VariableName, rightExpression); |
||||
|
||||
arguments.Add(lambda); |
||||
} |
||||
|
||||
var rightSide = new InvocationExpression(new MemberReferenceExpression(baseExpression, method), arguments); |
||||
|
||||
return new AssignmentExpression(leftExpression.Clone(), AssignmentOperatorType.Add, rightSide); |
||||
} |
||||
|
||||
static LambdaExpression BuildLambda(string variableName, Expression expression) |
||||
{ |
||||
var lambda = new LambdaExpression(); |
||||
lambda.Parameters.Add(new ParameterDeclaration() { |
||||
Name = variableName |
||||
}); |
||||
lambda.Body = expression.Clone(); |
||||
return lambda; |
||||
} |
||||
|
||||
bool IsIdentifier(Expression expr, string variableName) |
||||
{ |
||||
var identifierExpr = expr as IdentifierExpression; |
||||
if (identifierExpr != null) { |
||||
return identifierExpr.Identifier == variableName; |
||||
} |
||||
|
||||
var parenthesizedExpr = expr as ParenthesizedExpression; |
||||
if (parenthesizedExpr != null) { |
||||
return IsIdentifier(parenthesizedExpr.Expression, variableName); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool IsLinqSummableType(IType type) { |
||||
return LinqSummableTypes.Contains(type.FullName); |
||||
} |
||||
|
||||
bool ExtractExpression (Statement statement, out Expression leftSide, out Expression rightSide) { |
||||
ExpressionStatement expression = statement as ExpressionStatement; |
||||
if (expression != null) { |
||||
AssignmentExpression assignment = expression.Expression as AssignmentExpression; |
||||
if (assignment != null) { |
||||
if (assignment.Operator == AssignmentOperatorType.Add) { |
||||
leftSide = assignment.Left; |
||||
rightSide = assignment.Right; |
||||
return true; |
||||
} |
||||
if (assignment.Operator == AssignmentOperatorType.Subtract) { |
||||
leftSide = assignment.Left; |
||||
rightSide = new UnaryOperatorExpression(UnaryOperatorType.Minus, assignment.Right.Clone()); |
||||
return true; |
||||
} |
||||
|
||||
leftSide = null; |
||||
rightSide = null; |
||||
return false; |
||||
} |
||||
|
||||
UnaryOperatorExpression unary = expression.Expression as UnaryOperatorExpression; |
||||
if (unary != null) { |
||||
leftSide = unary.Expression; |
||||
if (unary.Operator == UnaryOperatorType.Increment || unary.Operator == UnaryOperatorType.PostIncrement) { |
||||
rightSide = new PrimitiveExpression(1); |
||||
return true; |
||||
} else if (unary.Operator == UnaryOperatorType.Decrement || unary.Operator == UnaryOperatorType.PostDecrement) { |
||||
rightSide = new PrimitiveExpression(-1); |
||||
return true; |
||||
} else { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (statement is EmptyStatement || statement.IsNull) { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
return true; |
||||
} |
||||
|
||||
BlockStatement block = statement as BlockStatement; |
||||
if (block != null) { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
|
||||
foreach (Statement child in block.Statements) { |
||||
Expression newLeft, newRight; |
||||
if (!ExtractExpression(child, out newLeft, out newRight)) { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
return false; |
||||
} |
||||
|
||||
if (newLeft == null) { |
||||
continue; |
||||
} |
||||
|
||||
if (leftSide == null) { |
||||
leftSide = newLeft; |
||||
rightSide = newRight; |
||||
} else if (SameNode(leftSide, newLeft)) { |
||||
rightSide = new BinaryOperatorExpression(ParenthesizeIfNeeded(rightSide).Clone(), |
||||
BinaryOperatorType.Add, |
||||
ParenthesizeIfNeeded(newRight).Clone()); |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
IfElseStatement condition = statement as IfElseStatement; |
||||
if (condition != null) { |
||||
Expression ifLeft, ifRight; |
||||
if (!ExtractExpression(condition.TrueStatement, out ifLeft, out ifRight)) { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
return false; |
||||
} |
||||
|
||||
Expression elseLeft, elseRight; |
||||
if (!ExtractExpression(condition.FalseStatement, out elseLeft, out elseRight)) { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
return false; |
||||
} |
||||
|
||||
if (ifLeft == null && elseLeft == null) { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
return true; |
||||
} |
||||
|
||||
if (ifLeft != null && elseLeft != null && !SameNode(ifLeft, elseLeft)) { |
||||
leftSide = null; |
||||
rightSide = null; |
||||
return false; |
||||
} |
||||
|
||||
ifRight = ifRight ?? new PrimitiveExpression(0); |
||||
elseRight = elseRight ?? new PrimitiveExpression(0); |
||||
|
||||
leftSide = ifLeft ?? elseLeft; |
||||
rightSide = new ConditionalExpression(condition.Condition.Clone(), ifRight.Clone(), elseRight.Clone()); |
||||
return true; |
||||
} |
||||
|
||||
leftSide = null; |
||||
rightSide = null; |
||||
return false; |
||||
} |
||||
|
||||
Expression ParenthesizeIfNeeded(Expression expr) |
||||
{ |
||||
if (expr is ConditionalExpression) { |
||||
return new ParenthesizedExpression(expr.Clone()); |
||||
} |
||||
|
||||
var binaryExpression = expr as BinaryOperatorExpression; |
||||
if (binaryExpression != null) { |
||||
if (binaryExpression.Operator != BinaryOperatorType.Multiply && |
||||
binaryExpression.Operator != BinaryOperatorType.Divide && |
||||
binaryExpression.Operator != BinaryOperatorType.Modulus) { |
||||
|
||||
return new ParenthesizedExpression(expr.Clone()); |
||||
} |
||||
} |
||||
|
||||
return expr; |
||||
} |
||||
|
||||
bool SameNode(INode expr1, INode expr2) |
||||
{ |
||||
Match m = expr1.Match(expr2); |
||||
return m.Success; |
||||
} |
||||
|
||||
static ForeachStatement GetForeachStatement (RefactoringContext context) |
||||
{ |
||||
var foreachStatement = context.GetNode<ForeachStatement>(); |
||||
if (foreachStatement == null || !foreachStatement.ForeachToken.Contains(context.Location)) |
||||
return null; |
||||
|
||||
return foreachStatement; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,71 @@
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// CS1520MethodMustHaveAReturnTypeAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Class, struct or interface method must have a return type", Description = "Found method without return type.")] |
||||
public class CS1520MethodMustHaveAReturnTypeAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var entity = context.GetNode<ConstructorDeclaration>(); |
||||
if (entity == null) |
||||
yield break; |
||||
var type = entity.Parent as TypeDeclaration; |
||||
|
||||
if (type == null || entity.Name == type.Name) |
||||
yield break; |
||||
|
||||
var typeDeclaration = entity.GetParent<TypeDeclaration>(); |
||||
|
||||
yield return new CodeAction(context.TranslateString("This is a constructor"), script => script.Replace(entity.NameToken, Identifier.Create(typeDeclaration.Name, TextLocation.Empty)), entity) { |
||||
Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error |
||||
}; |
||||
|
||||
yield return new CodeAction(context.TranslateString("This is a void method"), script => { |
||||
var generatedMethod = new MethodDeclaration(); |
||||
generatedMethod.Modifiers = entity.Modifiers; |
||||
generatedMethod.ReturnType = new PrimitiveType("void"); |
||||
generatedMethod.Name = entity.Name; |
||||
generatedMethod.Parameters.AddRange(entity.Parameters.Select(parameter => (ParameterDeclaration)parameter.Clone())); |
||||
generatedMethod.Body = (BlockStatement)entity.Body.Clone(); |
||||
generatedMethod.Attributes.AddRange(entity.Attributes.Select(attribute => (AttributeSection)attribute.Clone())); |
||||
|
||||
script.Replace(entity, generatedMethod); |
||||
}, entity) { |
||||
Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,175 @@
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// ChangeAccessModifierAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Changes the access level of an entity declaration
|
||||
/// </summary>
|
||||
[ContextAction("Change the access level of an entity declaration", Description = "Changes the access level of an entity declaration")] |
||||
public class ChangeAccessModifierAction : CodeActionProvider |
||||
{ |
||||
Dictionary<string, Modifiers> accessibilityLevels = new Dictionary<string, Modifiers> { |
||||
{ "private", Modifiers.Private }, |
||||
{ "protected", Modifiers.Protected }, |
||||
{ "protected internal", Modifiers.Protected | Modifiers.Internal }, |
||||
{ "internal", Modifiers.Internal }, |
||||
{ "public", Modifiers.Public } |
||||
}; |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var node = context.GetNode<EntityDeclaration>(); |
||||
if (node == null) |
||||
yield break; |
||||
|
||||
var selectedNode = node.GetNodeAt(context.Location); |
||||
if (selectedNode == null) |
||||
yield break; |
||||
|
||||
if (selectedNode.Role != PropertyDeclaration.SetKeywordRole && |
||||
selectedNode.Role != PropertyDeclaration.GetKeywordRole && |
||||
selectedNode != node.NameToken) { |
||||
if (selectedNode.Role == EntityDeclaration.ModifierRole) { |
||||
var mod = (CSharpModifierToken)selectedNode; |
||||
if ((mod.Modifier & Modifiers.VisibilityMask) == 0) |
||||
yield break; |
||||
} else { |
||||
yield break; |
||||
} |
||||
} |
||||
|
||||
if (node is EnumMemberDeclaration) { |
||||
yield break; |
||||
} |
||||
|
||||
if (node.HasModifier(Modifiers.Override)) |
||||
yield break; |
||||
|
||||
var parentTypeDeclaration = node.GetParent<TypeDeclaration>(); |
||||
if (parentTypeDeclaration != null && parentTypeDeclaration.ClassType == ClassType.Interface) { |
||||
//Interface members have no access modifiers
|
||||
yield break; |
||||
} |
||||
|
||||
var resolveResult = context.Resolve(node) as MemberResolveResult; |
||||
if (resolveResult != null) { |
||||
if (resolveResult.Member.ImplementedInterfaceMembers.Any()) |
||||
yield break; |
||||
} |
||||
|
||||
foreach (var accessName in accessibilityLevels.Keys) { |
||||
var access = accessibilityLevels [accessName]; |
||||
|
||||
if (parentTypeDeclaration == null && ((access & (Modifiers.Private | Modifiers.Protected)) != 0)) { |
||||
//Top-level declarations can only be public or internal
|
||||
continue; |
||||
} |
||||
|
||||
var accessor = node as Accessor; |
||||
if (accessor != null) { |
||||
//Allow only converting to modifiers stricter than the parent entity
|
||||
|
||||
var actualParentAccess = GetActualAccess(parentTypeDeclaration, accessor.GetParent<EntityDeclaration>()); |
||||
if (access != actualParentAccess && !IsStricterThan (access, actualParentAccess)) { |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
if (GetActualAccess(parentTypeDeclaration, node) != access) { |
||||
yield return GetActionForLevel(context, accessName, access, node, selectedNode); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static bool IsStricterThan(Modifiers access1, Modifiers access2) |
||||
{ |
||||
//First cover the basic cases
|
||||
if (access1 == access2) { |
||||
return false; |
||||
} |
||||
|
||||
if (access1 == Modifiers.Private) { |
||||
return true; |
||||
} |
||||
if (access2 == Modifiers.Private) { |
||||
return false; |
||||
} |
||||
|
||||
if (access1 == Modifiers.Public) { |
||||
return false; |
||||
} |
||||
if (access2 == Modifiers.Public) { |
||||
return true; |
||||
} |
||||
|
||||
return access2 == (Modifiers.Protected | Modifiers.Internal); |
||||
} |
||||
|
||||
static Modifiers GetActualAccess(AstNode parentTypeDeclaration, EntityDeclaration node) |
||||
{ |
||||
Modifiers nodeAccess = node.Modifiers & Modifiers.VisibilityMask; |
||||
if (nodeAccess == Modifiers.None && node is Accessor) { |
||||
EntityDeclaration parent = node.GetParent<EntityDeclaration>(); |
||||
|
||||
nodeAccess = parent.Modifiers & Modifiers.VisibilityMask; |
||||
} |
||||
|
||||
if (nodeAccess == Modifiers.None) { |
||||
if (parentTypeDeclaration == null) { |
||||
return Modifiers.Internal; |
||||
} |
||||
return Modifiers.Private; |
||||
} |
||||
|
||||
return nodeAccess & Modifiers.VisibilityMask; |
||||
} |
||||
|
||||
CodeAction GetActionForLevel(RefactoringContext context, string accessName, Modifiers access, EntityDeclaration node, AstNode selectedNode) |
||||
{ |
||||
return new CodeAction(context.TranslateString("To " + accessName), script => { |
||||
|
||||
Modifiers newModifiers = node.Modifiers; |
||||
newModifiers &= ~Modifiers.VisibilityMask; |
||||
|
||||
if (!(node is Accessor) || access != (node.GetParent<EntityDeclaration>().Modifiers & Modifiers.VisibilityMask)) { |
||||
//Do not add access modifier for accessors if the new access level is the same as the parent
|
||||
//That is, in public int X { $private get; } if access == public, then the result should not have the modifier
|
||||
newModifiers |= access; |
||||
} |
||||
|
||||
script.ChangeModifier(node, newModifiers); |
||||
|
||||
}, selectedNode); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// CheckIfParameterIsNull.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 ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Creates a 'if (param == null) throw new System.ArgumentNullException ();' contruct for a parameter.
|
||||
/// </summary>
|
||||
[ContextAction("Check if parameter is null", Description = "Checks function parameter is not null.")] |
||||
public class CheckIfParameterIsNullAction : SpecializedCodeAction<ParameterDeclaration> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, ParameterDeclaration parameter) |
||||
{ |
||||
if (!parameter.NameToken.Contains(context.Location)) |
||||
return null; |
||||
BlockStatement bodyStatement; |
||||
if (parameter.Parent is LambdaExpression) { |
||||
bodyStatement = parameter.Parent.GetChildByRole (LambdaExpression.BodyRole) as BlockStatement; |
||||
} else { |
||||
bodyStatement = parameter.Parent.GetChildByRole (Roles.Body); |
||||
} |
||||
if (bodyStatement == null || bodyStatement.IsNull) |
||||
return null; |
||||
var type = context.ResolveType(parameter.Type); |
||||
if (type.IsReferenceType == false || HasNullCheck(parameter)) |
||||
return null; |
||||
|
||||
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); |
||||
}, parameter.NameToken); |
||||
} |
||||
|
||||
static bool HasNullCheck (ParameterDeclaration parameter) |
||||
{ |
||||
var visitor = new CheckNullVisitor (parameter); |
||||
parameter.Parent.AcceptVisitor (visitor, null); |
||||
return visitor.ContainsNullCheck; |
||||
} |
||||
|
||||
class CheckNullVisitor : DepthFirstAstVisitor<object, object> |
||||
{ |
||||
readonly Expression pattern; |
||||
|
||||
internal bool ContainsNullCheck; |
||||
|
||||
public CheckNullVisitor (ParameterDeclaration parameter) |
||||
{ |
||||
pattern = PatternHelper.CommutativeOperator(new IdentifierExpression(parameter.Name), BinaryOperatorType.Any, new NullReferenceExpression()); |
||||
} |
||||
|
||||
public override object VisitIfElseStatement (IfElseStatement ifElseStatement, object data) |
||||
{ |
||||
if (ifElseStatement.Condition is BinaryOperatorExpression) { |
||||
var binOp = ifElseStatement.Condition as BinaryOperatorExpression; |
||||
if ((binOp.Operator == BinaryOperatorType.Equality || binOp.Operator == BinaryOperatorType.InEquality) && pattern.IsMatch(binOp)) { |
||||
ContainsNullCheck = true; |
||||
} |
||||
} |
||||
|
||||
return base.VisitIfElseStatement (ifElseStatement, data); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// ComputeConstantValueAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Ji Kun <jikun.nus@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Ji Kun <jikun.nus@gmail.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 ICSharpCode.NRefactory.CSharp; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Compute constant value", Description = "Computes the value of the current expression and replaces it.")] |
||||
public class ComputeConstantValueAction : CodeActionProvider |
||||
{ |
||||
public override System.Collections.Generic.IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var expression = context.GetNode(i => i is BinaryOperatorExpression || i is UnaryOperatorExpression); |
||||
if (expression == null) |
||||
yield break; |
||||
var node = context.GetNode(); |
||||
if (node == null || !(node is PrimitiveExpression) && node.StartLocation != context.Location) |
||||
yield break; |
||||
|
||||
var rr = context.Resolve(expression); |
||||
if (rr.ConstantValue == null) |
||||
yield break; |
||||
yield return new CodeAction( |
||||
context.TranslateString("Compute constant value"), |
||||
script => script.Replace(expression, new PrimitiveExpression(rr.ConstantValue)), |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,95 @@
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// ConvertAnonymousDelegateToExpression.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Simon Lindgren
|
||||
//
|
||||
// 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.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert anonymous delegate to lambda", |
||||
Description = "Converts an anonymous delegate into a lambda")] |
||||
public class ConvertAnonymousDelegateToLambdaAction : SpecializedCodeAction<AnonymousMethodExpression> |
||||
{ |
||||
#region implemented abstract members of SpecializedCodeAction
|
||||
|
||||
protected override CodeAction GetAction(RefactoringContext context, AnonymousMethodExpression node) |
||||
{ |
||||
if (context.Location < node.DelegateToken.StartLocation || context.Location >= node.Body.StartLocation) |
||||
return null; |
||||
|
||||
Expression convertExpression = null; |
||||
|
||||
var stmt = node.Body.Statements.FirstOrDefault(); |
||||
if (stmt.GetNextSibling(s => s.Role == BlockStatement.StatementRole) == null) { |
||||
var exprStmt = stmt as ExpressionStatement; |
||||
if (exprStmt != null) { |
||||
convertExpression = exprStmt.Expression; |
||||
} |
||||
} |
||||
|
||||
IType guessedType = null; |
||||
if (!node.HasParameterList) { |
||||
guessedType = TypeGuessing.GuessType(context, node); |
||||
if (guessedType.Kind != TypeKind.Delegate) |
||||
return null; |
||||
} |
||||
|
||||
return new CodeAction(context.TranslateString("Convert to lambda"), |
||||
script => { |
||||
var parent = node.Parent; |
||||
while (!(parent is Statement)) |
||||
parent = parent.Parent; |
||||
bool explicitLambda = parent is VariableDeclarationStatement && ((VariableDeclarationStatement)parent).Type.IsVar(); |
||||
var lambda = new LambdaExpression (); |
||||
|
||||
if (convertExpression != null) { |
||||
lambda.Body = convertExpression.Clone(); |
||||
} else { |
||||
lambda.Body = node.Body.Clone(); |
||||
} |
||||
if (node.HasParameterList) { |
||||
foreach (var parameter in node.Parameters) { |
||||
if (explicitLambda) { |
||||
lambda.Parameters.Add(new ParameterDeclaration { Type = parameter.Type.Clone(), Name = parameter.Name }); |
||||
} else { |
||||
lambda.Parameters.Add(new ParameterDeclaration { Name = parameter.Name }); |
||||
} |
||||
} |
||||
} else { |
||||
var method = guessedType.GetDelegateInvokeMethod (); |
||||
foreach (var parameter in method.Parameters) { |
||||
lambda.Parameters.Add(new ParameterDeclaration { Name = parameter.Name }); |
||||
} |
||||
} |
||||
script.Replace(node, lambda); |
||||
}, |
||||
node); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// ConvertAsToCastAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mansheng Yang <lightyang0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.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.
|
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Converts an 'as' expression to a cast expression
|
||||
/// </summary>
|
||||
[ContextAction("Convert 'as' to cast.", Description = "Convert 'as' to cast.")] |
||||
public class ConvertAsToCastAction : SpecializedCodeAction <AsExpression> |
||||
{ |
||||
static InsertParenthesesVisitor insertParentheses = new InsertParenthesesVisitor (); |
||||
protected override CodeAction GetAction (RefactoringContext context, AsExpression node) |
||||
{ |
||||
if (!node.AsToken.Contains (context.Location)) |
||||
return null; |
||||
return new CodeAction (context.TranslateString ("Convert 'as' to cast"), script => { |
||||
var castExpr = new CastExpression (node.Type.Clone (), node.Expression.Clone ()); |
||||
var parenthesizedExpr = node.Parent as ParenthesizedExpression; |
||||
if (parenthesizedExpr != null && parenthesizedExpr.Parent is Expression) { |
||||
// clone parent expression and replace the ParenthesizedExpression with castExpr to remove
|
||||
// parentheses, then insert parentheses if necessary
|
||||
var parentExpr = (Expression)parenthesizedExpr.Parent.Clone (); |
||||
parentExpr.GetNodeContaining (parenthesizedExpr.StartLocation, parenthesizedExpr.EndLocation) |
||||
.ReplaceWith (castExpr); |
||||
parentExpr.AcceptVisitor (insertParentheses); |
||||
script.Replace (parenthesizedExpr.Parent, parentExpr); |
||||
} else { |
||||
castExpr.AcceptVisitor (insertParentheses); |
||||
script.Replace (node, castExpr); |
||||
} |
||||
}, node.AsToken); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// ConvertAssignmentToIfAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 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.
|
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert assignment to 'if'", |
||||
Description = "Convert assignment to 'if'")] |
||||
public class ConvertAssignmentToIfAction : SpecializedCodeAction<AssignmentExpression> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, AssignmentExpression node) |
||||
{ |
||||
if (!node.OperatorToken.Contains(context.Location) || !(node.Parent is ExpressionStatement)) |
||||
return null; |
||||
|
||||
if (node.Right is ConditionalExpression) |
||||
return CreateForConditionalExpression(context, node, (ConditionalExpression)node.Right); |
||||
|
||||
var bOp = node.Right as BinaryOperatorExpression; |
||||
if (bOp != null && bOp.Operator == BinaryOperatorType.NullCoalescing) |
||||
return CreateForNullCoalesingExpression(context, node, bOp); |
||||
return null; |
||||
} |
||||
|
||||
static CodeAction CreateForConditionalExpression(RefactoringContext ctx, AssignmentExpression node, ConditionalExpression conditionalExpression) |
||||
{ |
||||
return new CodeAction ( |
||||
ctx.TranslateString("Replace with 'if' statement"), |
||||
script => { |
||||
var ifStatement = new IfElseStatement( |
||||
conditionalExpression.Condition.Clone(), |
||||
new AssignmentExpression(node.Left.Clone(), node.Operator, conditionalExpression.TrueExpression.Clone()), |
||||
new AssignmentExpression(node.Left.Clone(), node.Operator, conditionalExpression.FalseExpression.Clone()) |
||||
); |
||||
script.Replace(node.Parent, ifStatement); |
||||
}, |
||||
node.OperatorToken |
||||
); |
||||
} |
||||
|
||||
static CodeAction CreateForNullCoalesingExpression(RefactoringContext ctx, AssignmentExpression node, BinaryOperatorExpression bOp) |
||||
{ |
||||
return new CodeAction ( |
||||
ctx.TranslateString("Replace with 'if' statement"), |
||||
script => { |
||||
var ifStatement = new IfElseStatement( |
||||
new BinaryOperatorExpression(bOp.Left.Clone(), BinaryOperatorType.InEquality, new NullReferenceExpression()), |
||||
new AssignmentExpression(node.Left.Clone(), node.Operator, bOp.Left.Clone()), |
||||
new AssignmentExpression(node.Left.Clone(), node.Operator, bOp.Right.Clone()) |
||||
); |
||||
script.Replace(node.Parent, ifStatement); |
||||
}, |
||||
node.OperatorToken |
||||
); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,110 @@
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// ConvertBitwiseFlagComparisonToHasFlagsAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 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 ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Replace bitwise flag comparison with call to 'Enum.HasFlag'", Description = "Replace bitwise flag comparison with call to 'Enum.HasFlag'")] |
||||
public class ConvertBitwiseFlagComparisonToHasFlagsAction : SpecializedCodeAction<BinaryOperatorExpression> |
||||
{ |
||||
static readonly AstNode truePattern = new Choice { |
||||
new BinaryOperatorExpression (new ParenthesizedExpression(new BinaryOperatorExpression (PatternHelper.OptionalParentheses(new AnyNode("target")), BinaryOperatorType.BitwiseAnd, PatternHelper.OptionalParentheses(new AnyNode("expr")))), BinaryOperatorType.InEquality, PatternHelper.OptionalParentheses(new PrimitiveExpression(0))), |
||||
new BinaryOperatorExpression (new ParenthesizedExpression(new BinaryOperatorExpression (PatternHelper.OptionalParentheses(new AnyNode("target")), BinaryOperatorType.BitwiseAnd, PatternHelper.OptionalParentheses(new AnyNode("expr")))), BinaryOperatorType.Equality, PatternHelper.OptionalParentheses(new Backreference("expr"))) |
||||
}; |
||||
|
||||
static readonly AstNode falsePattern = new Choice { |
||||
new BinaryOperatorExpression (new ParenthesizedExpression(new BinaryOperatorExpression (PatternHelper.OptionalParentheses(new AnyNode("target")), BinaryOperatorType.BitwiseAnd, PatternHelper.OptionalParentheses(new AnyNode("expr")))), BinaryOperatorType.Equality, PatternHelper.OptionalParentheses(new PrimitiveExpression(0))), |
||||
new BinaryOperatorExpression (new ParenthesizedExpression(new BinaryOperatorExpression (PatternHelper.OptionalParentheses(new AnyNode("target")), BinaryOperatorType.BitwiseAnd, PatternHelper.OptionalParentheses(new AnyNode("expr")))), BinaryOperatorType.InEquality, PatternHelper.OptionalParentheses(new Backreference("expr"))) |
||||
}; |
||||
|
||||
internal static Expression MakeFlatExpression (Expression expr, BinaryOperatorType opType) |
||||
{ |
||||
var bOp = expr as BinaryOperatorExpression; |
||||
if (bOp == null) |
||||
return expr.Clone(); |
||||
return new BinaryOperatorExpression( |
||||
MakeFlatExpression(bOp.Left, opType), |
||||
opType, |
||||
MakeFlatExpression(bOp.Right, opType) |
||||
); |
||||
} |
||||
|
||||
static Expression BuildHasFlagExpression (Expression target, Expression expr) |
||||
{ |
||||
var bOp = expr as BinaryOperatorExpression; |
||||
if (bOp == null) |
||||
return new InvocationExpression(new MemberReferenceExpression(target.Clone(), "HasFlag"), expr.Clone()); |
||||
|
||||
if (bOp.Operator == BinaryOperatorType.BitwiseOr) { |
||||
return new BinaryOperatorExpression( |
||||
BuildHasFlagExpression(target, bOp.Left), |
||||
BinaryOperatorType.BitwiseOr, |
||||
BuildHasFlagExpression(target, bOp.Right) |
||||
); |
||||
} |
||||
|
||||
return new InvocationExpression(new MemberReferenceExpression(target.Clone(), "HasFlag"), MakeFlatExpression (bOp, BinaryOperatorType.BitwiseOr)); |
||||
} |
||||
|
||||
static CodeAction CreateAction(BaseRefactoringContext context, Match match, bool negateMatch, BinaryOperatorExpression node) |
||||
{ |
||||
var target = match.Get<Expression>("target").Single(); |
||||
var expr = match.Get<Expression>("expr").Single(); |
||||
|
||||
if (!expr.DescendantsAndSelf.All(x => !(x is BinaryOperatorExpression) || ((BinaryOperatorExpression)x).Operator == BinaryOperatorType.BitwiseOr) && |
||||
!expr.DescendantsAndSelf.All(x => !(x is BinaryOperatorExpression) || ((BinaryOperatorExpression)x).Operator == BinaryOperatorType.BitwiseAnd)) |
||||
return null; |
||||
var rr = context.Resolve(target); |
||||
if (rr.Type.Kind != ICSharpCode.NRefactory.TypeSystem.TypeKind.Enum) |
||||
return null; |
||||
|
||||
return new CodeAction( |
||||
context.TranslateString("Replace with 'Enum.HasFlag'"), |
||||
script => { |
||||
Expression newExpr = BuildHasFlagExpression (target, expr); |
||||
if (negateMatch) |
||||
newExpr = new UnaryOperatorExpression(UnaryOperatorType.Not, newExpr); |
||||
script.Replace(node, newExpr); |
||||
}, |
||||
node.OperatorToken); |
||||
} |
||||
|
||||
protected override CodeAction GetAction(RefactoringContext context, BinaryOperatorExpression node) |
||||
{ |
||||
if (!node.OperatorToken.Contains(context.Location)) |
||||
return null; |
||||
var match = truePattern.Match(node); |
||||
if (match.Success) |
||||
return CreateAction(context, match, false, node); |
||||
match = falsePattern.Match(node); |
||||
if (match.Success) |
||||
return CreateAction(context, match, true, node); |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// ConvertDecToHex.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.Threading; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Convert a dec numer to hex. For example: 16 -> 0x10
|
||||
/// </summary>
|
||||
[ContextAction("Convert dec to hex.", Description = "Convert dec to hex.")] |
||||
public class ConvertDecToHexAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var pexpr = context.GetNode<PrimitiveExpression>(); |
||||
if (pexpr == null || pexpr.LiteralValue.StartsWith("0X", System.StringComparison.OrdinalIgnoreCase)) |
||||
yield break; |
||||
|
||||
var value = pexpr.Value; |
||||
if (value is string || value is bool || value is float || value is double || value is char) |
||||
yield break; |
||||
|
||||
yield return new CodeAction(context.TranslateString("Convert to hex"), script => { |
||||
script.Replace(pexpr, new PrimitiveExpression (value, string.Format("0x{0:x}", value))); |
||||
}, pexpr); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// ConvertDoWhileToWhileLoopAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Luís Reis
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Convert do...while to while. For instance, { do x++; while (Foo(x)); } becomes { while(Foo(x)) x++; }.
|
||||
/// Note that this action will often change the semantics of the code.
|
||||
/// </summary>
|
||||
[ContextAction("Convert do...while to while.", Description = "Converts a do...while to a while loop (changing semantics).")] |
||||
public class ConvertDoWhileToWhileLoopAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var node = context.GetNode<DoWhileStatement>(); |
||||
if (node == null) |
||||
yield break; |
||||
|
||||
var target = node.DoToken; |
||||
if (!target.Contains(context.Location)) { |
||||
target = node.WhileToken; |
||||
if (!target.Contains(context.Location)) { |
||||
yield break; |
||||
} |
||||
} |
||||
|
||||
yield return new CodeAction(context.TranslateString("Convert to while loop"), |
||||
script => ConvertToWhileLoop(script, node), |
||||
target); |
||||
|
||||
} |
||||
|
||||
static void ConvertToWhileLoop(Script script, DoWhileStatement originalStatement) |
||||
{ |
||||
script.Replace(originalStatement, new WhileStatement { |
||||
Condition = originalStatement.Condition.Clone(), |
||||
EmbeddedStatement = originalStatement.EmbeddedStatement.Clone() |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// ConvertEqualityOperatorToEqualsAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 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 ICSharpCode.NRefactory.CSharp; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Convert do...while to while. For instance, { do x++; while (Foo(x)); } becomes { while(Foo(x)) x++; }.
|
||||
/// Note that this action will often change the semantics of the code.
|
||||
/// </summary>
|
||||
[ContextAction("Convert '==' to 'Equals'", Description = "Converts '==' to call to 'object.Equals'")] |
||||
public class ConvertEqualityOperatorToEqualsAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var node = context.GetNode<BinaryOperatorExpression>(); |
||||
if (node == null || |
||||
(node.Operator != BinaryOperatorType.Equality && node.Operator != BinaryOperatorType.InEquality) || |
||||
!node.OperatorToken.Contains(context.Location)) |
||||
yield break; |
||||
|
||||
yield return new CodeAction( |
||||
context.TranslateString("Use 'Equals'"), |
||||
script => { |
||||
Expression expr = new InvocationExpression(GenerateTarget(context, node), node.Left.Clone(), node.Right.Clone()); |
||||
if (node.Operator == BinaryOperatorType.InEquality) |
||||
expr = new UnaryOperatorExpression(UnaryOperatorType.Not, expr); |
||||
script.Replace(node, expr); |
||||
}, |
||||
node.OperatorToken |
||||
); |
||||
} |
||||
|
||||
readonly IList<IType> emptyTypes = new IType[0]; |
||||
|
||||
bool HasDifferentEqualsMethod(IEnumerable<IMethod> methods) |
||||
{ |
||||
foreach (var method in methods) { |
||||
if (method.Parameters.Count == 2 && method.FullName != "System.Object.Equals") { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
Expression GenerateTarget(RefactoringContext context, BinaryOperatorExpression bOp) |
||||
{ |
||||
var rr = context.Resolver.GetResolverStateBefore(bOp).LookupSimpleNameOrTypeName("Equals", emptyTypes, NameLookupMode.Expression) as MethodGroupResolveResult; |
||||
if (rr == null || rr.IsError || HasDifferentEqualsMethod (rr.Methods)) { |
||||
return new MemberReferenceExpression( |
||||
new PrimitiveType ("object"), |
||||
"Equals" |
||||
); |
||||
} |
||||
return new IdentifierExpression("Equals"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// ConvertEqualsToEqualityOperatorAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 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 ICSharpCode.NRefactory.CSharp; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Convert do...while to while. For instance, { do x++; while (Foo(x)); } becomes { while(Foo(x)) x++; }.
|
||||
/// Note that this action will often change the semantics of the code.
|
||||
/// </summary>
|
||||
[ContextAction("Convert 'Equals' to '=='", Description = "Converts 'Equals' call to '=='")] |
||||
public class ConvertEqualsToEqualityOperatorAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var node = context.GetNode<InvocationExpression>(); |
||||
if (node == null) |
||||
yield break; |
||||
if ((node.Target is IdentifierExpression) && !node.Target.IsInside(context.Location)) |
||||
yield break; |
||||
var memberRefExpr = node.Target as MemberReferenceExpression; |
||||
if ((memberRefExpr != null) && !memberRefExpr.MemberNameToken.IsInside(context.Location)) |
||||
yield break; |
||||
var rr = context.Resolve(node) as CSharpInvocationResolveResult; |
||||
if (rr == null || rr.IsError || rr.Member.Name != "Equals" || !rr.Member.DeclaringType.IsKnownType(KnownTypeCode.Object)) |
||||
yield break; |
||||
Expression expr = node; |
||||
bool useEquality = true; |
||||
var uOp = node.Parent as UnaryOperatorExpression; |
||||
if (uOp != null && uOp.Operator == UnaryOperatorType.Not) { |
||||
expr = uOp; |
||||
useEquality = false; |
||||
} |
||||
if (node.Arguments.Count != 2 && (memberRefExpr == null || node.Arguments.Count != 1)) |
||||
yield break; |
||||
yield return new CodeAction( |
||||
useEquality ? context.TranslateString("Use '=='") : context.TranslateString("Use '!='"), |
||||
script => { |
||||
script.Replace( |
||||
expr, |
||||
new BinaryOperatorExpression( |
||||
node.Arguments.Count == 1 ? memberRefExpr.Target.Clone() : node.Arguments.First().Clone(), |
||||
useEquality ? BinaryOperatorType.Equality : BinaryOperatorType.InEquality, |
||||
node.Arguments.Last().Clone() |
||||
) |
||||
); |
||||
}, |
||||
node.Target |
||||
); |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// ConvertForToWhileAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert 'for' loop to 'while'", Description = "Works on 'for' loops.")] |
||||
public class ConvertForToWhileAction : SpecializedCodeAction<ForStatement> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, ForStatement node) |
||||
{ |
||||
if (!node.ForToken.Contains(context.Location)) |
||||
return null; |
||||
return new CodeAction( |
||||
context.TranslateString("Convert to 'while'"), |
||||
script => { |
||||
var body = node.EmbeddedStatement.Clone(); |
||||
var blockStatement = body as BlockStatement ?? new BlockStatement { Statements = { body } }; |
||||
blockStatement.Statements.AddRange(node.Iterators.Select(i => i.Clone ())); |
||||
var whileStatement = new WhileStatement(node.Condition.IsNull ? new PrimitiveExpression(true) : node.Condition.Clone(), blockStatement); |
||||
foreach (var init in node.Initializers) { |
||||
var stmt = init.Clone(); |
||||
stmt.Role = BlockStatement.StatementRole; |
||||
script.InsertBefore(node, stmt); |
||||
} |
||||
script.Replace(node, whileStatement); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,218 @@
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// ConvertForeachToFor.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 ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Converts a foreach loop to for.
|
||||
/// </summary>
|
||||
[ContextAction("Convert 'foreach' loop to 'for'", Description = "Works on 'foreach' loops that allow direct access to its elements.")] |
||||
public class ConvertForeachToForAction : CodeActionProvider |
||||
{ |
||||
static readonly string[] VariableNames = { "i", "j", "k", "l", "n", "m", "x", "y", "z"}; |
||||
static readonly string[] CollectionNames = { "list" }; |
||||
|
||||
static string GetName(ICSharpCode.NRefactory.CSharp.Resolver.CSharpResolver state, string[] variableNames) |
||||
{ |
||||
for (int i = 0; i < 1000; i++) { |
||||
foreach (var vn in variableNames) { |
||||
string id = i > 0 ? vn + i : vn; |
||||
var rr = state.LookupSimpleNameOrTypeName(id, new IType[0], NameLookupMode.Expression); |
||||
if (rr.IsError) |
||||
return id; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
string GetBoundName(Expression inExpression) |
||||
{ |
||||
var ie = inExpression as IdentifierExpression; |
||||
if (ie != null) |
||||
return ie.Identifier; |
||||
var mre = inExpression as MemberReferenceExpression; |
||||
if (mre != null) |
||||
return GetBoundName(mre.Target) + mre.MemberName; |
||||
return "max"; |
||||
} |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
bool hasIndexAccess; |
||||
var foreachStatement = GetForeachStatement(context, out hasIndexAccess); |
||||
if (foreachStatement == null || foreachStatement.EmbeddedStatement == null) |
||||
yield break; |
||||
var state = context.GetResolverStateBefore (foreachStatement.EmbeddedStatement); |
||||
string name = GetName(state, VariableNames); |
||||
if (name == null) // very unlikely, but just in case ...
|
||||
yield break; |
||||
|
||||
yield return new CodeAction(context.TranslateString("Convert 'foreach' loop to 'for'"), script => { |
||||
var result = context.Resolve(foreachStatement.InExpression); |
||||
var countProperty = GetCountProperty(result.Type); |
||||
var inExpression = foreachStatement.InExpression; |
||||
|
||||
var initializer = hasIndexAccess ? new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)) : |
||||
new VariableDeclarationStatement(new SimpleType("var"), name, new InvocationExpression(new MemberReferenceExpression (inExpression.Clone (), "GetEnumerator"))); |
||||
var id1 = new IdentifierExpression(name); |
||||
var id2 = id1.Clone(); |
||||
var id3 = id1.Clone(); |
||||
Statement declarationStatement = null; |
||||
if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { |
||||
string listName = GetName(state, CollectionNames) ?? "col"; |
||||
declarationStatement = new VariableDeclarationStatement ( |
||||
new PrimitiveType ("var"), |
||||
listName, |
||||
inExpression.Clone () |
||||
); |
||||
inExpression = new IdentifierExpression (listName); |
||||
} |
||||
|
||||
var variableDeclarationStatement = new VariableDeclarationStatement( |
||||
foreachStatement.VariableType.Clone(), |
||||
foreachStatement.VariableName, |
||||
hasIndexAccess ? (Expression)new IndexerExpression(inExpression.Clone(), id3) : new MemberReferenceExpression(id1, "Current") |
||||
); |
||||
|
||||
var forStatement = new ForStatement { |
||||
Initializers = { initializer }, |
||||
Condition = hasIndexAccess ? (Expression)new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new MemberReferenceExpression (inExpression.Clone (), countProperty)) : |
||||
new InvocationExpression(new MemberReferenceExpression (id2, "MoveNext")), |
||||
EmbeddedStatement = new BlockStatement { |
||||
variableDeclarationStatement |
||||
} |
||||
}; |
||||
|
||||
if (hasIndexAccess) |
||||
forStatement.Iterators.Add(new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2)); |
||||
|
||||
if (foreachStatement.EmbeddedStatement is BlockStatement) { |
||||
variableDeclarationStatement.Remove(); |
||||
var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); |
||||
if (oldBlock.Statements.Any()) { |
||||
oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); |
||||
} else { |
||||
oldBlock.Statements.Add(variableDeclarationStatement); |
||||
} |
||||
forStatement.EmbeddedStatement = oldBlock; |
||||
} else { |
||||
forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole); |
||||
} |
||||
if (declarationStatement != null) |
||||
script.InsertBefore (foreachStatement, declarationStatement); |
||||
script.Replace (foreachStatement, forStatement); |
||||
if (hasIndexAccess) { |
||||
script.Link (initializer.Variables.First ().NameToken, id1, id2, id3); |
||||
} else { |
||||
script.Link (initializer.Variables.First ().NameToken, id1, id2); |
||||
} |
||||
}, foreachStatement); |
||||
|
||||
if (!hasIndexAccess) |
||||
yield break; |
||||
yield return new CodeAction(context.TranslateString("Convert 'foreach' loop to optimized 'for'"), script => { |
||||
var result = context.Resolve(foreachStatement.InExpression); |
||||
var countProperty = GetCountProperty(result.Type); |
||||
|
||||
var initializer = new VariableDeclarationStatement(new PrimitiveType("int"), name, new PrimitiveExpression(0)); |
||||
var id1 = new IdentifierExpression(name); |
||||
var id2 = id1.Clone(); |
||||
var id3 = id1.Clone(); |
||||
var inExpression = foreachStatement.InExpression; |
||||
Statement declarationStatement = null; |
||||
if (inExpression is ObjectCreateExpression || inExpression is ArrayCreateExpression) { |
||||
string listName = GetName(state, CollectionNames) ?? "col"; |
||||
declarationStatement = new VariableDeclarationStatement ( |
||||
new PrimitiveType ("var"), |
||||
listName, |
||||
inExpression.Clone () |
||||
); |
||||
inExpression = new IdentifierExpression (listName); |
||||
} |
||||
|
||||
var variableDeclarationStatement = new VariableDeclarationStatement( |
||||
foreachStatement.VariableType.Clone(), |
||||
foreachStatement.VariableName, |
||||
new IndexerExpression(inExpression.Clone(), id3) |
||||
); |
||||
|
||||
string optimizedUpperBound = GetBoundName(inExpression) + countProperty; |
||||
initializer.Variables.Add(new VariableInitializer(optimizedUpperBound, new MemberReferenceExpression (inExpression.Clone (), countProperty))); |
||||
var forStatement = new ForStatement { |
||||
Initializers = { initializer }, |
||||
Condition = new BinaryOperatorExpression (id1, BinaryOperatorType.LessThan, new IdentifierExpression(optimizedUpperBound)), |
||||
Iterators = { new UnaryOperatorExpression (UnaryOperatorType.PostIncrement, id2) }, |
||||
EmbeddedStatement = new BlockStatement { |
||||
variableDeclarationStatement |
||||
} |
||||
}; |
||||
|
||||
if (foreachStatement.EmbeddedStatement is BlockStatement) { |
||||
variableDeclarationStatement.Remove(); |
||||
var oldBlock = (BlockStatement)foreachStatement.EmbeddedStatement.Clone(); |
||||
if (oldBlock.Statements.Any()) { |
||||
oldBlock.Statements.InsertBefore(oldBlock.Statements.First(), variableDeclarationStatement); |
||||
} else { |
||||
oldBlock.Statements.Add(variableDeclarationStatement); |
||||
} |
||||
forStatement.EmbeddedStatement = oldBlock; |
||||
} else { |
||||
forStatement.EmbeddedStatement.AddChild (foreachStatement.EmbeddedStatement.Clone (), BlockStatement.StatementRole); |
||||
} |
||||
if (declarationStatement != null) |
||||
script.InsertBefore (foreachStatement, declarationStatement); |
||||
script.Replace (foreachStatement, forStatement); |
||||
script.Link (initializer.Variables.First ().NameToken, id1, id2, id3); |
||||
}, foreachStatement); |
||||
} |
||||
|
||||
static string GetCountProperty(IType type) |
||||
{ |
||||
return type.Kind == TypeKind.Array ? "Length" : "Count"; |
||||
} |
||||
|
||||
static ForeachStatement GetForeachStatement (RefactoringContext context, out bool hasIndexAccess) |
||||
{ |
||||
var astNode = context.GetNode (); |
||||
if (astNode == null) { |
||||
hasIndexAccess = false; |
||||
return null; |
||||
} |
||||
var result = (astNode as ForeachStatement) ?? astNode.Parent as ForeachStatement; |
||||
if (result == null) { |
||||
hasIndexAccess = false; |
||||
return null; |
||||
} |
||||
var collection = context.Resolve (result.InExpression); |
||||
hasIndexAccess = collection.Type.Kind == TypeKind.Array || collection.Type.GetProperties(p => p.IsIndexer).Any(); |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// ConvertHasFlagsToBitwiseFlagComparisonAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Replace 'Enum.HasFlag' call with bitwise flag comparison", Description = "Replace 'Enum.HasFlag' call with bitwise flag comparison")] |
||||
public class ConvertHasFlagsToBitwiseFlagComparisonAction : SpecializedCodeAction<InvocationExpression> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, InvocationExpression node) |
||||
{ |
||||
var mRef = node.Target as MemberReferenceExpression; |
||||
if (mRef == null) |
||||
return null; |
||||
var rr = context.Resolve(node) as CSharpInvocationResolveResult; |
||||
if (rr == null || rr.IsError) |
||||
return null; |
||||
if (rr.Member.Name != "HasFlag" || rr.Member.DeclaringType.GetDefinition().KnownTypeCode != ICSharpCode.NRefactory.TypeSystem.KnownTypeCode.Enum) |
||||
return null; |
||||
var arg = node.Arguments.First ().Clone (); |
||||
if (!arg.DescendantsAndSelf.All(x => !(x is BinaryOperatorExpression) || ((BinaryOperatorExpression)x).Operator == BinaryOperatorType.BitwiseOr)) |
||||
return null; |
||||
arg = ConvertBitwiseFlagComparisonToHasFlagsAction.MakeFlatExpression(arg, BinaryOperatorType.BitwiseAnd); |
||||
if (arg is BinaryOperatorExpression) |
||||
arg = new ParenthesizedExpression(arg); |
||||
return new CodeAction( |
||||
context.TranslateString("Replace with bitwise flag comparison"), |
||||
script => { |
||||
var uOp = node.Parent as UnaryOperatorExpression; |
||||
if (uOp != null && uOp.Operator == UnaryOperatorType.Not) { |
||||
script.Replace(uOp, |
||||
new BinaryOperatorExpression( |
||||
new ParenthesizedExpression(new BinaryOperatorExpression(mRef.Target.Clone(), BinaryOperatorType.BitwiseAnd, arg)), |
||||
BinaryOperatorType.Equality, |
||||
new PrimitiveExpression(0) |
||||
) |
||||
); |
||||
} else { |
||||
script.Replace(node, |
||||
new BinaryOperatorExpression( |
||||
new ParenthesizedExpression(new BinaryOperatorExpression(mRef.Target.Clone(), BinaryOperatorType.BitwiseAnd, arg)), |
||||
BinaryOperatorType.InEquality, |
||||
new PrimitiveExpression(0) |
||||
) |
||||
); |
||||
} |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// ConvertHexToDec.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.Threading; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Convert a hex numer to dec. For example: 0x10 -> 16
|
||||
/// </summary>
|
||||
[ContextAction("Convert hex to dec.", Description = "Convert hex to dec.")] |
||||
public class ConvertHexToDecAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
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("Convert to dec"), script => { |
||||
script.Replace(pexpr, new PrimitiveExpression (pexpr.Value)); |
||||
}, pexpr); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// ConvertIfStatementToConditionalTernaryExpressionAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert 'if' to '?:'", |
||||
Description = "Convert 'if' to '?:'")] |
||||
public class ConvertIfStatementToConditionalTernaryExpressionAction : SpecializedCodeAction <IfElseStatement> |
||||
{ |
||||
static readonly AstNode Pattern = |
||||
new IfElseStatement( |
||||
new AnyNode("condition"), |
||||
PatternHelper.EmbeddedStatement (new ExpressionStatement(new NamedNode ("assign1", new AssignmentExpression(new AnyNode("target"), AssignmentOperatorType.Any, new AnyNode("expr1"))))), |
||||
PatternHelper.EmbeddedStatement (new ExpressionStatement(new NamedNode ("assign2", new AssignmentExpression(new Backreference("target"), AssignmentOperatorType.Any, new AnyNode("expr2"))))) |
||||
); |
||||
|
||||
public static bool GetMatch(IfElseStatement ifElseStatement, out Match match) |
||||
{ |
||||
match = ConvertIfStatementToConditionalTernaryExpressionAction.Pattern.Match(ifElseStatement); |
||||
if (!match.Success || ifElseStatement.Parent is IfElseStatement) |
||||
return false; |
||||
var firstAssign = match.Get<AssignmentExpression>("assign1").Single(); |
||||
var secondAssign = match.Get<AssignmentExpression>("assign2").Single(); |
||||
return firstAssign.Operator == secondAssign.Operator; |
||||
} |
||||
|
||||
static CodeAction CreateAction (BaseRefactoringContext ctx, IfElseStatement ifElseStatement, Match match) |
||||
{ |
||||
var target = match.Get<Expression>("target").Single(); |
||||
var condition = match.Get<Expression>("condition").Single(); |
||||
var trueExpr = match.Get<Expression>("expr1").Single(); |
||||
var falseExpr = match.Get<Expression>("expr2").Single(); |
||||
var firstAssign = match.Get<AssignmentExpression>("assign1").Single(); |
||||
|
||||
return new CodeAction( |
||||
ctx.TranslateString("Replace with '?:' expression"), |
||||
script => { |
||||
script.Replace( |
||||
ifElseStatement, |
||||
new ExpressionStatement( |
||||
new AssignmentExpression( |
||||
target.Clone(), |
||||
firstAssign.Operator, |
||||
new ConditionalExpression(condition.Clone(), trueExpr.Clone(), falseExpr.Clone()) |
||||
) |
||||
) |
||||
); |
||||
}, |
||||
ifElseStatement |
||||
); |
||||
} |
||||
|
||||
protected override CodeAction GetAction(RefactoringContext context, IfElseStatement node) |
||||
{ |
||||
if (!node.IfToken.Contains(context.Location)) |
||||
return null; |
||||
Match match; |
||||
if (!GetMatch(node, out match)) |
||||
return null; |
||||
return CreateAction(context, node, match); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,165 @@
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// ConvertIfToNullCoalescingAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Luís Reis
|
||||
//
|
||||
// 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 ICSharpCode.NRefactory.PatternMatching; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Convert 'if' to '??' expression", |
||||
Category = IssueCategories.Opportunities, |
||||
Description = "Convert 'if' statement to '??' expression.")] |
||||
public class ConvertIfStatementToNullCoalescingExpressionAction : SpecializedCodeAction <IfElseStatement> |
||||
{ |
||||
const string expressionGroupName = "expression"; |
||||
const string comparedNodeGroupName = "comparedNode"; |
||||
const string valueOnNullGroupName = "valueOnNull"; |
||||
|
||||
static readonly Expression ActionPattern = |
||||
PatternHelper.OptionalParentheses( |
||||
new NamedNode( |
||||
expressionGroupName, |
||||
new Choice { |
||||
PatternHelper.CommutativeOperatorWithOptionalParentheses(new AnyNode(comparedNodeGroupName), BinaryOperatorType.Equality, new NullReferenceExpression()), |
||||
PatternHelper.CommutativeOperatorWithOptionalParentheses(new AnyNode(comparedNodeGroupName), BinaryOperatorType.InEquality, new NullReferenceExpression()) |
||||
} |
||||
) |
||||
); |
||||
|
||||
internal static Expression CheckNode(IfElseStatement node, out Expression rightSide) |
||||
{ |
||||
rightSide = null; |
||||
var match = ActionPattern.Match(node.Condition); |
||||
if (!match.Success) |
||||
return null; |
||||
var conditionExpression = match.Get<BinaryOperatorExpression>(expressionGroupName).Single(); |
||||
bool isEqualityComparison = conditionExpression.Operator == BinaryOperatorType.Equality; |
||||
Expression comparedNode = match.Get<Expression>(comparedNodeGroupName).Single(); |
||||
Statement contentStatement; |
||||
if (isEqualityComparison) { |
||||
contentStatement = node.TrueStatement; |
||||
if (!IsEmpty(node.FalseStatement)) |
||||
return null; |
||||
} |
||||
else { |
||||
contentStatement = node.FalseStatement; |
||||
if (!IsEmpty(node.TrueStatement)) |
||||
return null; |
||||
} |
||||
contentStatement = GetSimpleStatement(contentStatement); |
||||
if (contentStatement == null) |
||||
return null; |
||||
var leftExpressionPattern = PatternHelper.OptionalParentheses(comparedNode); |
||||
var expressionPattern = new AssignmentExpression(leftExpressionPattern, AssignmentOperatorType.Assign, new AnyNode(valueOnNullGroupName)); |
||||
var statementPattern = new ExpressionStatement(PatternHelper.OptionalParentheses(expressionPattern)); |
||||
var statementMatch = statementPattern.Match(contentStatement); |
||||
if (!statementMatch.Success) |
||||
return null; |
||||
rightSide = statementMatch.Get<Expression>(valueOnNullGroupName).Single(); |
||||
return comparedNode; |
||||
} |
||||
|
||||
protected override CodeAction GetAction (RefactoringContext context, IfElseStatement node) |
||||
{ |
||||
if (!node.IfToken.Contains(context.Location)) |
||||
return null; |
||||
Expression rightSide; |
||||
var comparedNode = CheckNode(node, out rightSide); |
||||
if (comparedNode == null) |
||||
return null; |
||||
|
||||
return new CodeAction(context.TranslateString("Replace with '??'"), |
||||
script => { |
||||
|
||||
var previousNode = node.GetPrevSibling(sibling => sibling is Statement); |
||||
|
||||
var previousDeclaration = previousNode as VariableDeclarationStatement; |
||||
if (previousDeclaration != null && previousDeclaration.Variables.Count() == 1) { |
||||
var variable = previousDeclaration.Variables.First(); |
||||
|
||||
var comparedNodeIdentifierExpression = comparedNode as IdentifierExpression; |
||||
if (comparedNodeIdentifierExpression != null && |
||||
comparedNodeIdentifierExpression.Identifier == variable.Name) { |
||||
|
||||
script.Replace(variable.Initializer, new BinaryOperatorExpression(variable.Initializer.Clone(), |
||||
BinaryOperatorType.NullCoalescing, |
||||
rightSide.Clone())); |
||||
script.Remove(node); |
||||
|
||||
return; |
||||
} |
||||
} |
||||
|
||||
var previousExpressionStatement = previousNode as ExpressionStatement; |
||||
if (previousExpressionStatement != null) |
||||
{ |
||||
var previousAssignment = previousExpressionStatement.Expression as AssignmentExpression; |
||||
if (previousAssignment != null && |
||||
comparedNode.IsMatch(previousAssignment.Left)) { |
||||
|
||||
var newExpression = new BinaryOperatorExpression(previousAssignment.Right.Clone(), |
||||
BinaryOperatorType.NullCoalescing, |
||||
rightSide.Clone()); |
||||
|
||||
script.Replace(previousAssignment.Right, newExpression); |
||||
script.Remove(node); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
var coalescedExpression = new BinaryOperatorExpression(comparedNode.Clone(), |
||||
BinaryOperatorType.NullCoalescing, |
||||
rightSide.Clone()); |
||||
|
||||
var newAssignment = new ExpressionStatement(new AssignmentExpression(comparedNode.Clone(), coalescedExpression)); |
||||
script.Replace(node, newAssignment); |
||||
}, node); |
||||
} |
||||
|
||||
static Statement GetSimpleStatement (Statement statement) |
||||
{ |
||||
BlockStatement blockStatement; |
||||
while ((blockStatement = statement as BlockStatement) != null) { |
||||
var statements = blockStatement.Descendants.OfType<Statement>() |
||||
.Where(descendant => !IsEmpty(descendant)).ToList(); |
||||
|
||||
if (statements.Count() != 1) { |
||||
return null; |
||||
} |
||||
|
||||
statement = statements.First(); |
||||
} |
||||
return statement; |
||||
} |
||||
|
||||
static bool IsEmpty (Statement statement) |
||||
{ |
||||
return statement.IsNull || |
||||
!statement.DescendantsAndSelf.OfType<Statement>().Any(descendant => !(descendant is EmptyStatement || descendant is BlockStatement)); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// ConvertIfStatementToReturnStatementAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert 'if' to 'return'", |
||||
Description = "Convert 'if' to 'return'")] |
||||
public class ConvertIfStatementToReturnStatementAction : SpecializedCodeAction <IfElseStatement> |
||||
{ |
||||
static readonly AstNode ifElsePattern = |
||||
new IfElseStatement( |
||||
new AnyNode("condition"), |
||||
PatternHelper.EmbeddedStatement (new ReturnStatement(new AnyNode("expr1"))), |
||||
PatternHelper.EmbeddedStatement (new ReturnStatement(new AnyNode("expr2"))) |
||||
); |
||||
|
||||
static readonly AstNode ifPattern = |
||||
new IfElseStatement( |
||||
new AnyNode("condition"), |
||||
PatternHelper.EmbeddedStatement (new ReturnStatement(new AnyNode("expr1"))) |
||||
); |
||||
|
||||
static readonly AstNode returnPattern = |
||||
new ReturnStatement(new AnyNode("expr2")); |
||||
|
||||
public static bool GetMatch(IfElseStatement ifElseStatement, out Expression condition, out Expression expr1, out Expression expr2, out AstNode returnStatement) |
||||
{ |
||||
var match = ifElsePattern.Match(ifElseStatement); |
||||
returnStatement = null; |
||||
if (match.Success) { |
||||
condition = match.Get<Expression>("condition").Single(); |
||||
expr1 = match.Get<Expression>("expr1").Single(); |
||||
expr2 = match.Get<Expression>("expr2").Single(); |
||||
return true; |
||||
} |
||||
|
||||
match = ifPattern.Match(ifElseStatement); |
||||
if (match.Success) { |
||||
returnStatement = ifElseStatement.GetNextSibling(s => s.Role == BlockStatement.StatementRole); |
||||
var match2 = returnPattern.Match(returnStatement); |
||||
|
||||
if (match2.Success) { |
||||
condition = match.Get<Expression>("condition").Single(); |
||||
expr1 = match.Get<Expression>("expr1").Single(); |
||||
expr2 = match2.Get<Expression>("expr2").Single(); |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
condition = expr1 = expr2 = null; |
||||
return false; |
||||
} |
||||
|
||||
static readonly AstNode truePattern = PatternHelper.OptionalParentheses(new PrimitiveExpression (true)); |
||||
static readonly AstNode falsePattern = PatternHelper.OptionalParentheses(new PrimitiveExpression (false)); |
||||
|
||||
static Expression CreateCondition(Expression c, Expression e1, Expression e2) |
||||
{ |
||||
if (truePattern.IsMatch(e1) && falsePattern.IsMatch(e2)) |
||||
return c.Clone(); |
||||
return new ConditionalExpression(c.Clone(), e1.Clone(), e2.Clone()); |
||||
} |
||||
|
||||
protected override CodeAction GetAction(RefactoringContext context, IfElseStatement ifElseStatement) |
||||
{ |
||||
if (!ifElseStatement.IfToken.Contains(context.Location)) |
||||
return null; |
||||
|
||||
Expression c, e1, e2; |
||||
AstNode rs; |
||||
if (!ConvertIfStatementToReturnStatementAction.GetMatch(ifElseStatement, out c, out e1, out e2, out rs)) |
||||
return null; |
||||
return new CodeAction ( |
||||
context.TranslateString("Replace with 'return'"), |
||||
script => { |
||||
script.Replace(ifElseStatement, new ReturnStatement( |
||||
CreateCondition(c, e1, e2) |
||||
)); |
||||
if (rs != null) |
||||
script.Remove(rs); |
||||
}, |
||||
ifElseStatement |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,196 @@
@@ -0,0 +1,196 @@
|
||||
//
|
||||
// ConvertIfToSwitchAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mansheng Yang <lightyang0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.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 ICSharpCode.NRefactory.PatternMatching; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ( |
||||
"Convert 'if' to 'switch'", |
||||
Description = "Convert 'if' statement to 'switch' statement")] |
||||
public class ConvertIfStatementToSwitchStatementAction : SpecializedCodeAction<IfElseStatement> |
||||
{ |
||||
protected override CodeAction GetAction (RefactoringContext context, IfElseStatement node) |
||||
{ |
||||
if (!node.IfToken.Contains (context.Location)) |
||||
return null; |
||||
|
||||
var switchExpr = GetSwitchExpression (context, node.Condition); |
||||
if (switchExpr == null) |
||||
return null; |
||||
|
||||
var switchSections = new List<SwitchSection> (); |
||||
if (!CollectSwitchSections (switchSections, context, node, switchExpr)) |
||||
return null; |
||||
|
||||
return new CodeAction (context.TranslateString ("Convert to 'switch'"), |
||||
script => |
||||
{ |
||||
var switchStatement = new SwitchStatement { Expression = switchExpr.Clone () }; |
||||
switchStatement.SwitchSections.AddRange (switchSections); |
||||
script.Replace (node, switchStatement); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
|
||||
internal static Expression GetSwitchExpression (BaseRefactoringContext context, Expression expr) |
||||
{ |
||||
var binaryOp = expr as BinaryOperatorExpression; |
||||
if (binaryOp == null) |
||||
return null; |
||||
|
||||
if (binaryOp.Operator == BinaryOperatorType.ConditionalOr) |
||||
return GetSwitchExpression (context, binaryOp.Left); |
||||
|
||||
if (binaryOp.Operator == BinaryOperatorType.Equality) { |
||||
Expression switchExpr = null; |
||||
if (IsConstantExpression (context, binaryOp.Right)) |
||||
switchExpr = binaryOp.Left; |
||||
if (IsConstantExpression (context, binaryOp.Left)) |
||||
switchExpr = binaryOp.Right; |
||||
if (switchExpr != null && IsValidSwitchType (context.Resolve (switchExpr).Type)) |
||||
return switchExpr; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
static bool IsConstantExpression (BaseRefactoringContext context, Expression expr) |
||||
{ |
||||
if (expr is PrimitiveExpression || expr is NullReferenceExpression) |
||||
return true; |
||||
return context.Resolve (expr).IsCompileTimeConstant; |
||||
} |
||||
|
||||
static readonly KnownTypeCode [] validTypes = |
||||
{ |
||||
KnownTypeCode.String, KnownTypeCode.Boolean, KnownTypeCode.Char, |
||||
KnownTypeCode.Byte, KnownTypeCode.SByte, |
||||
KnownTypeCode.Int16, KnownTypeCode.Int32, KnownTypeCode.Int64, |
||||
KnownTypeCode.UInt16, KnownTypeCode.UInt32, KnownTypeCode.UInt64 |
||||
}; |
||||
|
||||
static bool IsValidSwitchType (IType type) |
||||
{ |
||||
if (type.Kind == TypeKind.Enum) |
||||
return true; |
||||
var typeDefinition = type.GetDefinition (); |
||||
if (typeDefinition == null) |
||||
return false; |
||||
|
||||
if (typeDefinition.KnownTypeCode == KnownTypeCode.NullableOfT) { |
||||
var nullableType = (ParameterizedType)type; |
||||
typeDefinition = nullableType.TypeArguments [0].GetDefinition (); |
||||
if (typeDefinition == null) |
||||
return false; |
||||
} |
||||
return Array.IndexOf (validTypes, typeDefinition.KnownTypeCode) != -1; |
||||
} |
||||
|
||||
internal static bool CollectSwitchSections (ICollection<SwitchSection> result, BaseRefactoringContext context, |
||||
IfElseStatement ifStatement, Expression switchExpr) |
||||
{ |
||||
// if
|
||||
var section = new SwitchSection (); |
||||
if (!CollectCaseLabels (section.CaseLabels, context, ifStatement.Condition, switchExpr)) |
||||
return false; |
||||
CollectSwitchSectionStatements (section.Statements, context, ifStatement.TrueStatement); |
||||
result.Add (section); |
||||
|
||||
if (ifStatement.TrueStatement.Descendants.Any(n => n is BreakStatement)) |
||||
return false; |
||||
|
||||
if (ifStatement.FalseStatement.IsNull) |
||||
return true; |
||||
|
||||
// else if
|
||||
var falseStatement = ifStatement.FalseStatement as IfElseStatement; |
||||
if (falseStatement != null) |
||||
return CollectSwitchSections (result, context, falseStatement, switchExpr); |
||||
|
||||
if (ifStatement.FalseStatement.Descendants.Any(n => n is BreakStatement)) |
||||
return false; |
||||
// else (default label)
|
||||
var defaultSection = new SwitchSection (); |
||||
defaultSection.CaseLabels.Add (new CaseLabel ()); |
||||
CollectSwitchSectionStatements (defaultSection.Statements, context, ifStatement.FalseStatement); |
||||
result.Add (defaultSection); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
static bool CollectCaseLabels (AstNodeCollection<CaseLabel> result, BaseRefactoringContext context, |
||||
Expression condition, Expression switchExpr) |
||||
{ |
||||
if (condition is ParenthesizedExpression) |
||||
return CollectCaseLabels (result, context, ((ParenthesizedExpression)condition).Expression, switchExpr); |
||||
|
||||
var binaryOp = condition as BinaryOperatorExpression; |
||||
if (binaryOp == null) |
||||
return false; |
||||
|
||||
if (binaryOp.Operator == BinaryOperatorType.ConditionalOr) |
||||
return CollectCaseLabels (result, context, binaryOp.Left, switchExpr) && |
||||
CollectCaseLabels (result, context, binaryOp.Right, switchExpr); |
||||
|
||||
if (binaryOp.Operator == BinaryOperatorType.Equality) { |
||||
if (switchExpr.Match (binaryOp.Left).Success) { |
||||
if (IsConstantExpression (context, binaryOp.Right)) { |
||||
result.Add (new CaseLabel (binaryOp.Right.Clone ())); |
||||
return true; |
||||
} |
||||
} else if (switchExpr.Match (binaryOp.Right).Success) { |
||||
if (IsConstantExpression (context, binaryOp.Left)) { |
||||
result.Add (new CaseLabel (binaryOp.Left.Clone ())); |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
static void CollectSwitchSectionStatements (AstNodeCollection<Statement> result, BaseRefactoringContext context, |
||||
Statement statement) |
||||
{ |
||||
BlockStatement blockStatement = statement as BlockStatement; |
||||
if (blockStatement != null) |
||||
result.AddRange(blockStatement.Statements.Select(s => s.Clone())); |
||||
else |
||||
result.Add(statement.Clone()); |
||||
|
||||
// add 'break;' at end if necessary
|
||||
var reachabilityAnalysis = context.CreateReachabilityAnalysis (statement); |
||||
if (reachabilityAnalysis.IsEndpointReachable(statement)) |
||||
result.Add(new BreakStatement()); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// ConvertLambdaBodyExpressionToStatementAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mansheng Yang <lightyang0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.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.
|
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Converts expression of lambda body to statement", |
||||
Description = "Converts expression of lambda body to statement")] |
||||
public class ConvertLambdaBodyExpressionToStatementAction : SpecializedCodeAction<LambdaExpression> |
||||
{ |
||||
|
||||
protected override CodeAction GetAction (RefactoringContext context, LambdaExpression node) |
||||
{ |
||||
if (!node.ArrowToken.Contains (context.Location)) |
||||
return null; |
||||
|
||||
var bodyExpr = node.Body as Expression; |
||||
if (bodyExpr == null) |
||||
return null; |
||||
return new CodeAction (context.TranslateString ("Convert to lambda statement"), |
||||
script => |
||||
{ |
||||
var body = new BlockStatement (); |
||||
if (RequireReturnStatement (context, node)) { |
||||
body.Add (new ReturnStatement (bodyExpr.Clone ())); |
||||
} else { |
||||
body.Add (bodyExpr.Clone ()); |
||||
} |
||||
script.Replace (bodyExpr, body); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
|
||||
static bool RequireReturnStatement (RefactoringContext context, LambdaExpression lambda) |
||||
{ |
||||
var type = LambdaHelper.GetLambdaReturnType (context, lambda); |
||||
return type != null && type.ReflectionName != "System.Void"; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// ConvertLambdaBodyStatementToExpressionAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mansheng Yang <lightyang0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.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.
|
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Converts statement of lambda body to expression", |
||||
Description = "Converts statement of lambda body to expression")] |
||||
public class ConvertLambdaBodyStatementToExpressionAction : SpecializedCodeAction<LambdaExpression> |
||||
{ |
||||
internal static bool TryGetConvertableExpression(AstNode body, out BlockStatement blockStatement, out Expression expr) |
||||
{ |
||||
expr = null; |
||||
blockStatement = body as BlockStatement; |
||||
if (blockStatement == null || blockStatement.Statements.Count > 1) |
||||
return false; |
||||
var returnStatement = blockStatement.Statements.FirstOrNullObject() as ReturnStatement; |
||||
if (returnStatement != null) { |
||||
expr = returnStatement.Expression; |
||||
} else { |
||||
var exprStatement = blockStatement.Statements.FirstOrNullObject() as ExpressionStatement; |
||||
if (exprStatement == null) |
||||
return false; |
||||
expr = exprStatement.Expression; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
internal static CodeAction CreateAction (BaseRefactoringContext context, AstNode node, BlockStatement blockStatement, Expression expr) |
||||
{ |
||||
return new CodeAction ( |
||||
context.TranslateString ("Convert to lambda expression"), |
||||
script => script.Replace (blockStatement, expr.Clone ()), |
||||
node |
||||
); |
||||
} |
||||
|
||||
protected override CodeAction GetAction (RefactoringContext context, LambdaExpression node) |
||||
{ |
||||
if (!node.ArrowToken.Contains (context.Location)) |
||||
return null; |
||||
|
||||
BlockStatement blockStatement; |
||||
Expression expr; |
||||
if (!TryGetConvertableExpression(node.Body, out blockStatement, out expr)) |
||||
return null; |
||||
|
||||
|
||||
return CreateAction (context, node.ArrowToken, blockStatement, expr); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// ConvertLambdaToDelegateAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert lambda to anonymous delegate", |
||||
Description = "Converts a lambda to an anonymous delegate.")] |
||||
public class ConvertLambdaToAnonymousDelegateAction : SpecializedCodeAction<LambdaExpression> |
||||
{ |
||||
#region implemented abstract members of SpecializedCodeAction
|
||||
protected override CodeAction GetAction(RefactoringContext context, LambdaExpression node) |
||||
{ |
||||
if (context.Location < node.StartLocation || context.Location >= node.Body.StartLocation) |
||||
return null; |
||||
|
||||
var lambdaResolveResult = context.Resolve(node) as LambdaResolveResult; |
||||
if (lambdaResolveResult == null) |
||||
return null; |
||||
|
||||
return new CodeAction(context.TranslateString("Convert to anonymous delegate"), script => { |
||||
BlockStatement newBody; |
||||
if (node.Body is BlockStatement) { |
||||
newBody = (BlockStatement)node.Body.Clone(); |
||||
} else { |
||||
var expression = (Expression)node.Body.Clone(); |
||||
|
||||
Statement statement; |
||||
if (RequireReturnStatement(context, node)) { |
||||
statement = new ReturnStatement(expression); |
||||
} |
||||
else { |
||||
statement = expression; |
||||
} |
||||
|
||||
newBody = new BlockStatement { |
||||
Statements = { |
||||
statement |
||||
} |
||||
}; |
||||
} |
||||
var method = new AnonymousMethodExpression (newBody, GetParameters(lambdaResolveResult.Parameters, context)); |
||||
script.Replace(node, method); |
||||
}, node); |
||||
} |
||||
#endregion
|
||||
|
||||
IEnumerable<ParameterDeclaration> GetParameters(IList<IParameter> parameters, RefactoringContext context) |
||||
{ |
||||
if (parameters == null || parameters.Count == 0) |
||||
return null; |
||||
var result = new List<ParameterDeclaration> (); |
||||
foreach (var parameter in parameters) { |
||||
var type = context.CreateShortType(parameter.Type); |
||||
var name = parameter.Name; |
||||
ParameterModifier modifier = ParameterModifier.None; |
||||
if (parameter.IsRef) |
||||
modifier |= ParameterModifier.Ref; |
||||
if (parameter.IsOut) |
||||
modifier |= ParameterModifier.Out; |
||||
result.Add (new ParameterDeclaration(type, name, modifier)); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static bool RequireReturnStatement (RefactoringContext context, LambdaExpression lambda) |
||||
{ |
||||
var type = LambdaHelper.GetLambdaReturnType (context, lambda); |
||||
return type != null && type.ReflectionName != "System.Void"; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// ConvertMethodGroupToAnonymousMethodAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert method group to anoymous method", |
||||
Description = "Convert method group to anoymous method")] |
||||
public class ConvertMethodGroupToAnonymousMethodAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
Expression node = context.GetNode<IdentifierExpression>(); |
||||
if (node == null) { |
||||
var mr = context.GetNode<MemberReferenceExpression>(); |
||||
if (mr == null || !mr.MemberNameToken.IsInside(context.Location)) |
||||
yield break; |
||||
node = mr; |
||||
} |
||||
if (node == null) |
||||
yield break; |
||||
var rr = context.Resolve(node) as MethodGroupResolveResult; |
||||
if (rr == null || rr.IsError) |
||||
yield break; |
||||
var type = TypeGuessing.GetValidTypes(context.Resolver, node).FirstOrDefault(t => t.Kind == TypeKind.Delegate); |
||||
if (type == null) |
||||
yield break; |
||||
var invocationMethod = type.GetDelegateInvokeMethod(); |
||||
if (invocationMethod == null) |
||||
yield break; |
||||
|
||||
yield return new CodeAction( |
||||
context.TranslateString("Convert to anonymous method"), |
||||
script => { |
||||
var expr = new InvocationExpression(node.Clone(), invocationMethod.Parameters.Select(p => new IdentifierExpression(context.GetNameProposal(p.Name)))); |
||||
var stmt = invocationMethod.ReturnType.IsKnownType(KnownTypeCode.Void) ? (Statement)expr : new ReturnStatement(expr); |
||||
var anonymousMethod = new AnonymousMethodExpression { |
||||
Body = new BlockStatement { stmt } |
||||
}; |
||||
foreach (var p in invocationMethod.Parameters) { |
||||
var decl = new ParameterDeclaration(context.CreateShortType(p.Type), context.GetNameProposal(p.Name)); |
||||
anonymousMethod.Parameters.Add(decl); |
||||
} |
||||
|
||||
script.Replace(node, anonymousMethod); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,77 @@
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// ConvertMethodGroupToLambdaAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert method group to lambda expression", |
||||
Description = "Convert method group to lambda expression")] |
||||
public class ConvertMethodGroupToLambdaAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
Expression node = context.GetNode<IdentifierExpression>(); |
||||
if (node == null) { |
||||
var mr = context.GetNode<MemberReferenceExpression>(); |
||||
if (mr == null || !mr.MemberNameToken.IsInside(context.Location)) |
||||
yield break; |
||||
node = mr; |
||||
} |
||||
if (node == null) |
||||
yield break; |
||||
var rr = context.Resolve(node) as MethodGroupResolveResult; |
||||
if (rr == null || rr.IsError) |
||||
yield break; |
||||
var type = TypeGuessing.GetValidTypes(context.Resolver, node).FirstOrDefault(t => t.Kind == TypeKind.Delegate); |
||||
if (type == null) |
||||
yield break; |
||||
var invocationMethod = type.GetDelegateInvokeMethod(); |
||||
if (invocationMethod == null) |
||||
yield break; |
||||
|
||||
yield return new CodeAction( |
||||
context.TranslateString("Convert to lambda expression"), |
||||
script => { |
||||
var invocation = new InvocationExpression(node.Clone(), invocationMethod.Parameters.Select(p => new IdentifierExpression(context.GetNameProposal(p.Name)))); |
||||
var lambda = new LambdaExpression { |
||||
Body = invocation |
||||
}; |
||||
lambda.Parameters.AddRange( |
||||
invocation.Arguments |
||||
.Cast<IdentifierExpression>() |
||||
.Select(p => new ParameterDeclaration { Name = p.Identifier }) |
||||
); |
||||
script.Replace(node, lambda); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// ConvertMultiplyToShiftAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert '*'/'/' to '<<'/'>>'", |
||||
Description = "Convert '*'/'/' to '<<'/'>>'")] |
||||
public class ConvertMultiplyToShiftAction : SpecializedCodeAction<BinaryOperatorExpression> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, BinaryOperatorExpression node) |
||||
{ |
||||
if (!node.OperatorToken.Contains(context.Location)) |
||||
return null; |
||||
if (node.Operator != BinaryOperatorType.Multiply && node.Operator != BinaryOperatorType.Divide || !(node.Right is PrimitiveExpression)) |
||||
return null; |
||||
|
||||
var valueObj = context.Resolve(node.Right).ConstantValue; |
||||
if (!(valueObj is int)) |
||||
return null; |
||||
var value = (int)valueObj; |
||||
|
||||
var log2 = (int)Math.Log(value, 2); |
||||
if (value != 1 << log2) |
||||
return null; |
||||
|
||||
return new CodeAction ( |
||||
node.Operator == BinaryOperatorType.Multiply ? context.TranslateString("Replace with '<<'") : context.TranslateString("Replace with '>>'"), |
||||
script => script.Replace( |
||||
node, |
||||
new BinaryOperatorExpression( |
||||
node.Left.Clone(), |
||||
node.Operator == BinaryOperatorType.Multiply ? BinaryOperatorType.ShiftLeft : BinaryOperatorType.ShiftRight, |
||||
new PrimitiveExpression(log2) |
||||
) |
||||
), |
||||
node.OperatorToken |
||||
); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// ConvertNullCoalescingToConditionalExpressionAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 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 |
||||
{ |
||||
[ContextAction("Convert '??' to '?:'", |
||||
Description = "Convert '??' to '?:'")] |
||||
public class ConvertNullCoalescingToConditionalExpressionAction : SpecializedCodeAction<BinaryOperatorExpression> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext ctx, BinaryOperatorExpression node) |
||||
{ |
||||
if (node.Operator != BinaryOperatorType.NullCoalescing || !node.OperatorToken.Contains(ctx.Location)) |
||||
return null; |
||||
return new CodeAction( |
||||
ctx.TranslateString("Replace with '?:' expression"), |
||||
script => { |
||||
Expression expr = new ConditionalExpression ( |
||||
new BinaryOperatorExpression(node.Left.Clone(), BinaryOperatorType.InEquality, new NullReferenceExpression ()), |
||||
node.Left.Clone(), |
||||
node.Right.Clone() |
||||
); |
||||
script.Replace(node, expr); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// ConvertReturnStatementToIfAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert 'return' to 'if'", |
||||
Description = "Convert 'return' to 'if'")] |
||||
public class ConvertReturnStatementToIfAction : SpecializedCodeAction <ReturnStatement> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, ReturnStatement node) |
||||
{ |
||||
if (!node.ReturnToken.Contains(context.Location)) |
||||
return null; |
||||
|
||||
if (node.Expression is ConditionalExpression) |
||||
return CreateForConditionalExpression(context, node, (ConditionalExpression)node.Expression); |
||||
var bOp = node.Expression as BinaryOperatorExpression; |
||||
if (bOp != null && bOp.Operator == BinaryOperatorType.NullCoalescing) |
||||
return CreateForNullCoalesingExpression(context, node, bOp); |
||||
return null; |
||||
} |
||||
|
||||
CodeAction CreateForConditionalExpression(RefactoringContext ctx, ReturnStatement node, ConditionalExpression conditionalExpression) |
||||
{ |
||||
return new CodeAction ( |
||||
ctx.TranslateString("Replace with 'if' statement"), |
||||
script => { |
||||
var ifStatement = new IfElseStatement(conditionalExpression.Condition.Clone(), new ReturnStatement(conditionalExpression.TrueExpression.Clone())); |
||||
script.Replace(node, ifStatement); |
||||
script.InsertAfter(ifStatement, new ReturnStatement(conditionalExpression.FalseExpression.Clone())); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
|
||||
CodeAction CreateForNullCoalesingExpression(RefactoringContext ctx, ReturnStatement node, BinaryOperatorExpression bOp) |
||||
{ |
||||
return new CodeAction ( |
||||
ctx.TranslateString("Replace with 'if' statement"), |
||||
script => { |
||||
var ifStatement = new IfElseStatement(new BinaryOperatorExpression(bOp.Left.Clone(), BinaryOperatorType.InEquality, new NullReferenceExpression()), new ReturnStatement(bOp.Left.Clone())); |
||||
script.Replace(node, ifStatement); |
||||
script.InsertAfter(ifStatement, new ReturnStatement(bOp.Right.Clone())); |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// ConvertShiftToMultiplyAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.CSharp.Refactoring; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert '<<'/'>>' to '*'/'/'", |
||||
Description = "Convert '<<'/'>>' to '*'/'/'")] |
||||
public class ConvertShiftToMultiplyAction : SpecializedCodeAction <BinaryOperatorExpression> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, BinaryOperatorExpression node) |
||||
{ |
||||
if (!node.OperatorToken.Contains(context.Location)) |
||||
return null; |
||||
if (node.Operator != BinaryOperatorType.ShiftLeft && node.Operator != BinaryOperatorType.ShiftRight || !(node.Right is PrimitiveExpression)) |
||||
return null; |
||||
|
||||
var value = context.Resolve(node.Right).ConstantValue; |
||||
if (!(value is int)) |
||||
return null; |
||||
|
||||
return new CodeAction ( |
||||
node.Operator == BinaryOperatorType.ShiftLeft ? context.TranslateString("Replace with '*'") : context.TranslateString("Replace with '/'"), |
||||
script => script.Replace( |
||||
node, |
||||
new BinaryOperatorExpression( |
||||
node.Left.Clone(), |
||||
node.Operator == BinaryOperatorType.ShiftLeft ? BinaryOperatorType.Multiply : BinaryOperatorType.Divide, |
||||
new PrimitiveExpression(1 << (int)value) |
||||
) |
||||
), |
||||
node.OperatorToken |
||||
); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,147 @@
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// ConvertSwitchToIfAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mansheng Yang <lightyang0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.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.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Convert 'switch' to 'if'", Description = "Convert 'switch' statement to 'if' statement")] |
||||
public class ConvertSwitchToIfAction : SpecializedCodeAction<SwitchStatement> |
||||
{ |
||||
static readonly InsertParenthesesVisitor insertParenthesesVisitor = new InsertParenthesesVisitor (); |
||||
|
||||
protected override CodeAction GetAction (RefactoringContext context, SwitchStatement node) |
||||
{ |
||||
if (!node.SwitchToken.Contains (context.Location)) |
||||
return null; |
||||
|
||||
// empty switch
|
||||
if (node.SwitchSections.Count == 0) |
||||
return null; |
||||
|
||||
// switch with default only
|
||||
if (node.SwitchSections.First ().CaseLabels.Any (label => label.Expression.IsNull)) |
||||
return null; |
||||
|
||||
// check non-trailing breaks
|
||||
foreach (var switchSection in node.SwitchSections) { |
||||
var lastStatement = switchSection.Statements.LastOrDefault (); |
||||
var finder = new NonTrailingBreakFinder (lastStatement as BreakStatement); |
||||
if (switchSection.AcceptVisitor (finder)) |
||||
return null; |
||||
} |
||||
|
||||
return new CodeAction (context.TranslateString ("Convert to 'if'"), |
||||
script => |
||||
{ |
||||
IfElseStatement ifStatement = null; |
||||
IfElseStatement currentStatement = null; |
||||
foreach (var switchSection in node.SwitchSections) { |
||||
var condition = CollectCondition (node.Expression, switchSection.CaseLabels); |
||||
var bodyStatement = new BlockStatement (); |
||||
var lastStatement = switchSection.Statements.LastOrDefault (); |
||||
foreach (var statement in switchSection.Statements) { |
||||
// skip trailing break
|
||||
if (statement == lastStatement && statement is BreakStatement) |
||||
continue; |
||||
bodyStatement.Add (statement.Clone ()); |
||||
} |
||||
|
||||
// default -> else
|
||||
if (condition == null) { |
||||
currentStatement.FalseStatement = bodyStatement; |
||||
break; |
||||
} |
||||
var elseIfStatement = new IfElseStatement (condition, bodyStatement); |
||||
if (ifStatement == null) |
||||
ifStatement = elseIfStatement; |
||||
else |
||||
currentStatement.FalseStatement = elseIfStatement; |
||||
currentStatement = elseIfStatement; |
||||
} |
||||
script.Replace (node, ifStatement); |
||||
script.FormatText (ifStatement); |
||||
}, node); |
||||
} |
||||
|
||||
static Expression CollectCondition(Expression switchExpr, AstNodeCollection<CaseLabel> caseLabels) |
||||
{ |
||||
// default
|
||||
if (caseLabels.Count == 0 || caseLabels.Any (label => label.Expression.IsNull)) |
||||
return null; |
||||
|
||||
var conditionList = caseLabels.Select ( |
||||
label => new BinaryOperatorExpression (switchExpr.Clone (), BinaryOperatorType.Equality, label.Expression.Clone ())) |
||||
.ToArray (); |
||||
|
||||
// insert necessary parentheses
|
||||
foreach (var expr in conditionList) |
||||
expr.AcceptVisitor (insertParenthesesVisitor); |
||||
|
||||
if (conditionList.Length == 1) |
||||
return conditionList [0]; |
||||
|
||||
// combine case labels into an conditional or expression
|
||||
BinaryOperatorExpression condition = null; |
||||
BinaryOperatorExpression currentCondition = null; |
||||
for (int i = 0; i < conditionList.Length - 1; i++) { |
||||
var newCondition = new BinaryOperatorExpression |
||||
{ |
||||
Operator = BinaryOperatorType.ConditionalOr, |
||||
Left = conditionList[i] |
||||
}; |
||||
if (currentCondition == null) |
||||
condition = newCondition; |
||||
else |
||||
currentCondition.Right = newCondition; |
||||
currentCondition = newCondition; |
||||
} |
||||
currentCondition.Right = conditionList [conditionList.Length - 1]; |
||||
|
||||
return condition; |
||||
} |
||||
|
||||
class NonTrailingBreakFinder : DepthFirstAstVisitor<bool> |
||||
{ |
||||
BreakStatement trailingBreakStatement; |
||||
|
||||
public NonTrailingBreakFinder (BreakStatement trailingBreak) |
||||
{ |
||||
trailingBreakStatement = trailingBreak; |
||||
} |
||||
|
||||
protected override bool VisitChildren (AstNode node) |
||||
{ |
||||
return node.Children.Any (child => child.AcceptVisitor (this)); |
||||
} |
||||
|
||||
public override bool VisitBreakStatement (BreakStatement breakStatement) |
||||
{ |
||||
return breakStatement != trailingBreakStatement; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,207 @@
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// ConvertInitializerToExplicitInitializationsAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert to explicit initializers", |
||||
Description = "Converts an object or collection initializer to explicit initializations.")] |
||||
public class ConvertInitializerToExplicitInitializationsAction : CodeActionProvider |
||||
{ |
||||
#region ICodeActionProvider implementation
|
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var codeAction = GetActionForVariableInitializer(context); |
||||
if (codeAction != null) { |
||||
yield return codeAction; |
||||
yield break; |
||||
} |
||||
codeAction = GetActionForAssignmentExpression(context); |
||||
if (codeAction != null) { |
||||
yield return codeAction; |
||||
yield break; |
||||
} |
||||
} |
||||
|
||||
public CodeAction GetActionForVariableInitializer(RefactoringContext context) |
||||
{ |
||||
var variableInitializer = context.GetNode<VariableInitializer>(); |
||||
if (variableInitializer == null) |
||||
return null; |
||||
var declaration = variableInitializer.Parent as VariableDeclarationStatement; |
||||
if (declaration == null) |
||||
return null; |
||||
if (variableInitializer.Initializer.IsNull) |
||||
return null; |
||||
var objectCreateExpression = variableInitializer.Initializer as ObjectCreateExpression; |
||||
if (objectCreateExpression == null) |
||||
return null; |
||||
var converter = new InitializerConversionVisitor(context); |
||||
Expression finalExpression; |
||||
var statements = converter.ConvertInitializer(objectCreateExpression, out finalExpression); |
||||
if (statements.Count > 0) { |
||||
return new CodeAction(context.TranslateString("Convert to explicit initializers"), script => { |
||||
foreach (var statement in statements) { |
||||
script.InsertBefore(declaration, statement); |
||||
} |
||||
script.Replace(variableInitializer.Initializer, finalExpression); |
||||
}, variableInitializer); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public CodeAction GetActionForAssignmentExpression(RefactoringContext context) |
||||
{ |
||||
var assignmentExpression = context.GetNode<AssignmentExpression>(); |
||||
if (assignmentExpression == null) |
||||
return null; |
||||
var expressionStatement = assignmentExpression.Parent as ExpressionStatement; |
||||
if (expressionStatement == null) |
||||
return null; |
||||
var objectCreateExpression = assignmentExpression.Right as ObjectCreateExpression; |
||||
if (objectCreateExpression == null) |
||||
return null; |
||||
var converter = new InitializerConversionVisitor(context); |
||||
Expression finalExpression; |
||||
var statements = converter.ConvertInitializer(objectCreateExpression, out finalExpression); |
||||
if (statements.Count > 0) { |
||||
return new CodeAction(context.TranslateString("Convert to explicit initializers"), script => { |
||||
foreach (var statement in statements) { |
||||
script.InsertBefore(expressionStatement, statement); |
||||
} |
||||
script.Replace(assignmentExpression.Right, finalExpression); |
||||
}, assignmentExpression); |
||||
} |
||||
return null; |
||||
} |
||||
#endregion
|
||||
|
||||
class InitializerConversionVisitor : DepthFirstAstVisitor<Expression, Expression> |
||||
{ |
||||
RefactoringContext context; |
||||
IList<Statement> statements; |
||||
NamingHelper namingHelper; |
||||
|
||||
public InitializerConversionVisitor(RefactoringContext context) |
||||
{ |
||||
this.context = context; |
||||
namingHelper = new NamingHelper(context); |
||||
} |
||||
|
||||
AstType GetDeclarationType(AstType type) |
||||
{ |
||||
AstType declarationType; |
||||
if (context.UseExplicitTypes) { |
||||
declarationType = type.Clone(); |
||||
} else { |
||||
declarationType = new SimpleType("var"); |
||||
} |
||||
return declarationType; |
||||
} |
||||
|
||||
public IList<Statement> ConvertInitializer(ObjectCreateExpression initializer, out Expression finalExpression) |
||||
{ |
||||
statements = new List<Statement>(); |
||||
|
||||
finalExpression = initializer.AcceptVisitor(this, null); |
||||
|
||||
return statements; |
||||
} |
||||
|
||||
public override Expression VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, Expression data) |
||||
{ |
||||
var creationType = objectCreateExpression.Type.Clone(); |
||||
|
||||
var parameters = objectCreateExpression.Arguments.Select(arg => arg.Clone()); |
||||
var newCreation = new ObjectCreateExpression(creationType, parameters); |
||||
if (objectCreateExpression.Initializer.IsNull) { |
||||
return newCreation; |
||||
} else { |
||||
AstType declarationType = GetDeclarationType(objectCreateExpression.Type); |
||||
var name = namingHelper.GenerateVariableName(objectCreateExpression.Type); |
||||
var variableInitializer = new VariableDeclarationStatement(declarationType, name, newCreation); |
||||
statements.Add(variableInitializer); |
||||
|
||||
var identifier = new IdentifierExpression(name); |
||||
base.VisitObjectCreateExpression(objectCreateExpression, identifier); |
||||
|
||||
return identifier; |
||||
} |
||||
} |
||||
|
||||
public override Expression VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression, Expression data) |
||||
{ |
||||
if (!(arrayInitializerExpression.Parent is ArrayInitializerExpression)) { |
||||
return base.VisitArrayInitializerExpression(arrayInitializerExpression, data); |
||||
} |
||||
// this a tuple in a collection initializer
|
||||
var arguments = arrayInitializerExpression.Elements.Select(element => element.AcceptVisitor(this, null).Clone()); |
||||
var method = new MemberReferenceExpression { |
||||
Target = data.Clone(), |
||||
MemberName = "Add" |
||||
}; |
||||
statements.Add(new InvocationExpression(method, arguments)); |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public override Expression VisitNamedExpression(NamedExpression namedExpression, Expression data) |
||||
{ |
||||
var member = new MemberReferenceExpression { |
||||
Target = data.Clone(), |
||||
MemberName = namedExpression.Name |
||||
}; |
||||
var expression = namedExpression.Expression.AcceptVisitor(this, member); |
||||
if (expression != null) { |
||||
var statement = new ExpressionStatement { |
||||
Expression = new AssignmentExpression { |
||||
Left = member, |
||||
Right = expression.Clone() |
||||
} |
||||
}; |
||||
statements.Add(statement); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
protected override Expression VisitChildren(AstNode node, Expression data) |
||||
{ |
||||
// Most expressions should just be used as-is, and
|
||||
// a) need not be visited
|
||||
// b) only return themselves
|
||||
if (node is Expression && !(node is ObjectCreateExpression || node is ArrayInitializerExpression || node is NamedExpression)){ |
||||
return (Expression)node; |
||||
} |
||||
return base.VisitChildren(node, data); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// ConvertToInitializerAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Convert to initializer", |
||||
Description = "Converts a set of assignments and .Add() calls to an initializer.")] |
||||
public class ConvertToInitializerAction : CodeActionProvider |
||||
{ |
||||
#region ICodeActionProvider implementation
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var initializer = context.GetNode<VariableInitializer>(); |
||||
if (initializer != null) { |
||||
var action = HandleInitializer(context, initializer); |
||||
if (action != null) |
||||
yield return action; |
||||
} |
||||
var expressionStatement = context.GetNode<ExpressionStatement>(); |
||||
if (expressionStatement != null) { |
||||
var action = HandleExpressionStatement(context, expressionStatement); |
||||
if (action != null) |
||||
yield return action; |
||||
} |
||||
} |
||||
|
||||
CodeAction HandleInitializer(RefactoringContext context, VariableInitializer initializer) |
||||
{ |
||||
var objectCreateExpression = initializer.Initializer as ObjectCreateExpression; |
||||
if (objectCreateExpression == null) |
||||
return null; |
||||
var initializerRR = context.Resolve(initializer) as LocalResolveResult; |
||||
if (initializerRR == null) |
||||
return null; |
||||
IList<AstNode> statements = GetNodes(context.GetNode<Statement>()); |
||||
var converter = new StatementsToInitializerConverter(context); |
||||
var newInitializer = converter.ConvertToInitializer(initializer, ref statements); |
||||
if (newInitializer == null || statements.Count == 0) |
||||
return null; |
||||
return MakeAction(context, initializer, newInitializer, statements); |
||||
} |
||||
|
||||
CodeAction HandleExpressionStatement(RefactoringContext context, ExpressionStatement expressionStatement) |
||||
{ |
||||
var expression = expressionStatement.Expression as AssignmentExpression; |
||||
if (expression == null || expression.Operator != AssignmentOperatorType.Assign) |
||||
return null; |
||||
if (!(expression.Right is ObjectCreateExpression)) |
||||
return null; |
||||
var expressionResolveResult = context.Resolve(expression.Left); |
||||
if (!(expressionResolveResult is LocalResolveResult) && !(expressionResolveResult is MemberResolveResult)) |
||||
return null; |
||||
IList<AstNode> statements = GetNodes(context.GetNode<Statement>()); |
||||
var converter = new StatementsToInitializerConverter(context); |
||||
var newExpression = converter.ConvertToInitializer(expression, ref statements); |
||||
if (newExpression == null || statements.Count == 0) |
||||
return null; |
||||
return MakeAction(context, expression, newExpression, statements); |
||||
} |
||||
|
||||
List<AstNode> GetNodes(Statement startStatement) |
||||
{ |
||||
var statements = new List<AstNode>(); |
||||
AstNode currentNode = startStatement.NextSibling; |
||||
while (currentNode != null) { |
||||
if (currentNode is Statement || currentNode is Comment) |
||||
statements.Add(currentNode); |
||||
currentNode = currentNode.NextSibling; |
||||
} |
||||
return statements; |
||||
} |
||||
|
||||
CodeAction MakeAction(RefactoringContext context, AstNode oldNode, AstNode replacementNode, IEnumerable<AstNode> toRemove) |
||||
{ |
||||
return new CodeAction(context.TranslateString("Convert to initializer"), script => { |
||||
foreach (var statement in toRemove) |
||||
script.Remove(statement); |
||||
script.Replace(oldNode, replacementNode); |
||||
}, oldNode); |
||||
} |
||||
#endregion
|
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// ConvertWhileToDoWhileLoopAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Luís Reis <luiscubal@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Luís Reis
|
||||
//
|
||||
// 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.Threading; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Converts a while loop to a do...while loop.
|
||||
/// For instance: while (foo) {} becomes do { } while (foo);
|
||||
/// </summary>
|
||||
[ContextAction("Convert while loop to do...while", Description = "Convert while loop to do...while (changing semantics)")] |
||||
public class ConvertWhileToDoWhileLoopAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var whileLoop = context.GetNode<WhileStatement>(); |
||||
if (whileLoop == null || !whileLoop.WhileToken.Contains(context.Location)) { |
||||
yield break; |
||||
} |
||||
|
||||
yield return new CodeAction(context.TranslateString("Convert to do...while loop"), |
||||
script => ApplyAction(script, whileLoop), |
||||
whileLoop.WhileToken); |
||||
} |
||||
|
||||
void ApplyAction(Script script, WhileStatement statement) { |
||||
var doWhile = new DoWhileStatement { |
||||
Condition = statement.Condition.Clone(), |
||||
EmbeddedStatement = statement.EmbeddedStatement.Clone() |
||||
}; |
||||
|
||||
script.Replace(statement, doWhile); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// CopyCommentsFromBase.cs
|
||||
//
|
||||
// Author:
|
||||
// Ji Kun <jikun.nus0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Ji Kun <jikun.nus@gmail.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 ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Copies documented comments from base to overriding methods.
|
||||
/// </summary>
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
[ContextAction("Copy comments from base", Description = "Copies documented comments from base to overriding methods.")] |
||||
public class CopyCommentsFromBase: SpecializedCodeAction <MethodDeclaration> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, MethodDeclaration node) |
||||
{ |
||||
if (node == null || !node.HasModifier(Modifiers.Override)) |
||||
return null; |
||||
if (!node.NameToken.Contains(context.Location)) |
||||
return null; |
||||
|
||||
IMethod resolvedMember = (IMethod)(context.Resolve(node) as MemberResolveResult).Member; |
||||
|
||||
if (resolvedMember == null) |
||||
return null; |
||||
|
||||
IMethod originalMember = (IMethod)InheritanceHelper.GetBaseMember(resolvedMember); |
||||
|
||||
if (originalMember == null || originalMember.Documentation == null) |
||||
return null; |
||||
string comments = originalMember.Documentation.ToString(); |
||||
|
||||
if (string.IsNullOrEmpty(comments)) |
||||
return null; |
||||
|
||||
string[] lines = comments.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); |
||||
return new CodeAction(context.TranslateString("Copy comments from base"), script => { |
||||
foreach (string co in lines) { |
||||
script.InsertBefore(node, new Comment(co, CommentType.Documentation)); |
||||
} |
||||
}, node.NameToken); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// CopyCommentsFromInterface.cs
|
||||
//
|
||||
// Author:
|
||||
// Ji Kun <jikun.nus@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2013 Ji Kun <jikun.nus@gmail.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 ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
/// <summary>
|
||||
/// Copies documented comments from interface to overriding methods.
|
||||
/// </summary>
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
[ContextAction("Copy comments from interface", Description = "Copies documented comments from interface to implementing methods.")] |
||||
public class CopyCommentsFromInterface: SpecializedCodeAction <MethodDeclaration> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, MethodDeclaration node) |
||||
{ |
||||
if (!(node.PrivateImplementationType.IsNull)) |
||||
return null; |
||||
|
||||
if (!node.NameToken.Contains(context.Location)) |
||||
return null; |
||||
|
||||
var method = (IMethod)((MemberResolveResult)context.Resolve(node)).Member; |
||||
|
||||
if (method.Documentation != null) |
||||
return null; |
||||
|
||||
IList<IMember> interfaceMethods = method.ImplementedInterfaceMembers; |
||||
|
||||
if (interfaceMethods.Count != 1 || method.DeclaringType.Kind == TypeKind.Interface) |
||||
return null; |
||||
|
||||
var interfaceMethod = interfaceMethods.SingleOrDefault(); |
||||
|
||||
if (interfaceMethod == null) |
||||
return null; |
||||
|
||||
if (interfaceMethod.Documentation == null) |
||||
return null; |
||||
|
||||
string comments = interfaceMethod.Documentation.ToString(); |
||||
|
||||
if (comments == "") |
||||
return null; |
||||
|
||||
string[] lines = comments.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); |
||||
return new CodeAction(context.TranslateString("Copy comments from interface"), script => |
||||
{ |
||||
foreach (string co in lines) { |
||||
script.InsertBefore(node, new Comment(co, CommentType.Documentation)); |
||||
} |
||||
}, node); |
||||
|
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// 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 CreateBackingStoreAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var property = context.GetNode<PropertyDeclaration>(); |
||||
if (property == null || !property.NameToken.Contains(context.Location)) |
||||
yield break; |
||||
|
||||
if (!(!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("Create backing store"), script => { |
||||
string backingStoreName = context.GetNameProposal (property.Name); |
||||
|
||||
// create field
|
||||
var backingStore = new FieldDeclaration (); |
||||
if (property.Modifiers.HasFlag (Modifiers.Static)) |
||||
backingStore.Modifiers |= Modifiers.Static; |
||||
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); |
||||
}, property.NameToken); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// CreateChangedEvent.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create changed event for property", Description = "Creates a changed event for an property.")] |
||||
public class CreateChangedEventAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var property = context.GetNode<PropertyDeclaration>(); |
||||
if (property == null || !property.NameToken.Contains(context.Location)) |
||||
yield break; |
||||
|
||||
var field = RemoveBackingStoreAction.GetBackingField(context, property); |
||||
if (field == null) |
||||
yield break; |
||||
var resolvedType = ReflectionHelper.ParseReflectionName ("System.EventHandler").Resolve (context.Compilation); |
||||
if (resolvedType == null) |
||||
yield break; |
||||
var type = (TypeDeclaration)property.Parent; |
||||
|
||||
yield return new CodeAction(context.TranslateString("Create changed event"), script => { |
||||
var eventDeclaration = CreateChangedEventDeclaration (context, property); |
||||
var methodDeclaration = CreateEventInvocatorAction.CreateEventInvocator (context, type, eventDeclaration, eventDeclaration.Variables.First (), resolvedType.GetDelegateInvokeMethod (), false); |
||||
var stmt = new ExpressionStatement (new InvocationExpression ( |
||||
new IdentifierExpression (methodDeclaration.Name), |
||||
new MemberReferenceExpression (context.CreateShortType("System", "EventArgs"), "Empty") |
||||
)); |
||||
script.InsertWithCursor( |
||||
context.TranslateString("Create event invocator"), |
||||
Script.InsertPosition.After, |
||||
new AstNode[] { eventDeclaration, methodDeclaration } |
||||
).ContinueScript(delegate { |
||||
script.InsertBefore (property.Setter.Body.RBraceToken, stmt); |
||||
script.FormatText (stmt); |
||||
}); |
||||
}, property.NameToken); |
||||
} |
||||
|
||||
EventDeclaration CreateChangedEventDeclaration (RefactoringContext context, PropertyDeclaration propertyDeclaration) |
||||
{ |
||||
return new EventDeclaration { |
||||
Modifiers = propertyDeclaration.HasModifier (Modifiers.Static) ? Modifiers.Public | Modifiers.Static : Modifiers.Public, |
||||
ReturnType = context.CreateShortType("System", "EventHandler"), |
||||
Variables = { |
||||
new VariableInitializer { |
||||
Name = propertyDeclaration.Name + "Changed" |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,330 @@
@@ -0,0 +1,330 @@
|
||||
//
|
||||
// CreateClassDeclarationAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin <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.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create class", Description = "Creates a class declaration out of an object creation.")] |
||||
public class CreateClassDeclarationAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var simpleType = context.GetNode<SimpleType>(); |
||||
if (simpleType != null && !(simpleType.Parent is EventDeclaration || simpleType.Parent is CustomEventDeclaration)) |
||||
return GetActions(context, simpleType); |
||||
|
||||
var createExpression = context.GetNode<ObjectCreateExpression>(); |
||||
if (createExpression != null) |
||||
return GetActions(context, createExpression); |
||||
|
||||
var identifier = context.GetNode<IdentifierExpression>(); |
||||
if (identifier != null && (identifier.Parent is MemberReferenceExpression)) |
||||
return GetActions(context, identifier); |
||||
|
||||
return Enumerable.Empty<CodeAction>(); |
||||
} |
||||
|
||||
static IEnumerable<CodeAction> GetActions(RefactoringContext context, AstNode node) |
||||
{ |
||||
var resolveResult = context.Resolve(node) as UnknownIdentifierResolveResult; |
||||
if (resolveResult == null) |
||||
yield break; |
||||
|
||||
var service = (NamingConventionService)context.GetService(typeof(NamingConventionService)); |
||||
if (service != null && !service.IsValidName(resolveResult.Identifier, AffectedEntity.Class)) { |
||||
yield break; |
||||
} |
||||
ClassType classType = GuessClassTypeByName(service, node); |
||||
ModifyClassTypeBasedOnTypeGuessing(context, node, ref classType); |
||||
|
||||
string message; |
||||
switch (classType) { |
||||
case ClassType.Struct: |
||||
message = context.TranslateString("Create struct"); |
||||
break; |
||||
case ClassType.Interface: |
||||
message = context.TranslateString("Create interface"); |
||||
break; |
||||
default: |
||||
message = context.TranslateString("Create class"); |
||||
break; |
||||
} |
||||
yield return new CodeAction(message, script => { |
||||
script.CreateNewType(CreateType(context, service, node, classType)); |
||||
}, node); |
||||
|
||||
if (node.Parent is TypeDeclaration || classType != ClassType.Class) |
||||
yield break; |
||||
yield return new CodeAction(context.TranslateString("Create nested class"), script => { |
||||
script.InsertWithCursor( |
||||
context.TranslateString("Create nested class"), |
||||
Script.InsertPosition.Before, |
||||
CreateType(context, service, node, classType) |
||||
); |
||||
}, node); |
||||
} |
||||
|
||||
static void ModifyClassTypeBasedOnTypeGuessing(RefactoringContext context, AstNode node, ref ClassType classType) |
||||
{ |
||||
var guessedType = TypeGuessing.GuessType(context, node); |
||||
if (guessedType.Kind == TypeKind.TypeParameter) { |
||||
var tp = (ITypeParameter)guessedType; |
||||
if (tp.HasValueTypeConstraint) |
||||
classType = ClassType.Struct; |
||||
if (tp.HasReferenceTypeConstraint) |
||||
classType = ClassType.Class; |
||||
} |
||||
} |
||||
|
||||
static ClassType GuessClassTypeByName(NamingConventionService service, string identifier) |
||||
{ |
||||
if (service == null) |
||||
return ClassType.Class; |
||||
if (service.IsValidName (identifier, AffectedEntity.Interface, Modifiers.Public)) |
||||
return ClassType.Interface; |
||||
if (!service.IsValidName (identifier, AffectedEntity.Class, Modifiers.Public) && |
||||
service.IsValidName (identifier, AffectedEntity.Struct, Modifiers.Public)) |
||||
return ClassType.Struct; |
||||
return ClassType.Class; |
||||
} |
||||
|
||||
static ClassType GuessClassTypeByName(NamingConventionService service, AstNode node) |
||||
{ |
||||
if (node is SimpleType) |
||||
return GuessClassTypeByName (service, ((SimpleType)node).Identifier); |
||||
if (node is IdentifierExpression) |
||||
return GuessClassTypeByName (service, ((IdentifierExpression)node).Identifier); |
||||
return ClassType.Class; |
||||
} |
||||
|
||||
static TypeDeclaration CreateType(RefactoringContext context, NamingConventionService service, AstNode node, ClassType classType) |
||||
{ |
||||
TypeDeclaration result; |
||||
if (node is SimpleType) { |
||||
result = CreateClassFromType(context, classType, (SimpleType)node); |
||||
} else if (node is ObjectCreateExpression) { |
||||
result = CreateClassFromObjectCreation(context, (ObjectCreateExpression)node); |
||||
} else { |
||||
result = CreateClassFromIdentifier(context, classType, (IdentifierExpression)node); |
||||
} |
||||
|
||||
return AddBaseTypesAccordingToNamingRules(context, service, result); |
||||
} |
||||
|
||||
static TypeDeclaration CreateClassFromIdentifier(RefactoringContext context, ClassType classType, IdentifierExpression identifierExpression) |
||||
{ |
||||
var result = new TypeDeclaration { Name = identifierExpression.Identifier, ClassType = classType }; |
||||
var entity = identifierExpression.GetParent<EntityDeclaration>(); |
||||
if (entity != null) |
||||
result.Modifiers |= entity.Modifiers & Modifiers.Public; |
||||
return result; |
||||
} |
||||
|
||||
static TypeDeclaration CreateClassFromType(RefactoringContext context, ClassType classType, SimpleType simpleType) |
||||
{ |
||||
TypeDeclaration result; |
||||
string className = simpleType.Identifier; |
||||
|
||||
if (simpleType.Parent is Attribute && classType == ClassType.Class) { |
||||
if (!className.EndsWith("Attribute", System.StringComparison.Ordinal)) |
||||
className += "Attribute"; |
||||
} |
||||
|
||||
result = new TypeDeclaration { Name = className, ClassType = classType }; |
||||
var entity = simpleType.GetParent<EntityDeclaration>(); |
||||
if (entity != null) |
||||
result.Modifiers |= entity.Modifiers & Modifiers.Public; |
||||
|
||||
var guessedType = TypeGuessing.GuessType (context, simpleType); |
||||
if (guessedType.Kind == TypeKind.TypeParameter) |
||||
ImplementConstraints (context, result, (ITypeParameter)guessedType); |
||||
return result; |
||||
} |
||||
|
||||
static void ImplementConstraints(RefactoringContext context, TypeDeclaration result, ITypeParameter tp) |
||||
{ |
||||
if (tp.HasValueTypeConstraint) |
||||
result.ClassType = ClassType.Struct; |
||||
if (tp.HasReferenceTypeConstraint) |
||||
result.ClassType = ClassType.Class; |
||||
if (tp.HasDefaultConstructorConstraint) |
||||
result.AddChild (new ConstructorDeclaration { Modifiers = Modifiers.Public, Body = new BlockStatement () }, Roles.TypeMemberRole); |
||||
foreach (var baseType in tp.DirectBaseTypes) { |
||||
if (baseType.Namespace == "System") { |
||||
if (baseType.Name == "Object" || baseType.Name == "ValueType") |
||||
continue; |
||||
} |
||||
result.BaseTypes.Add (context.CreateShortType (baseType)); |
||||
} |
||||
} |
||||
|
||||
static TypeDeclaration CreateClassFromObjectCreation(RefactoringContext context, ObjectCreateExpression createExpression) |
||||
{ |
||||
TypeDeclaration result; |
||||
string className = createExpression.Type.ToString(); |
||||
if (!createExpression.Arguments.Any()) { |
||||
result = new TypeDeclaration { Name = className }; |
||||
} else { |
||||
var decl = new ConstructorDeclaration { |
||||
Name = className, |
||||
Modifiers = Modifiers.Public, |
||||
Body = new BlockStatement { |
||||
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException"))) |
||||
} |
||||
}; |
||||
result = new TypeDeclaration { |
||||
Name = className, |
||||
Members = { |
||||
decl |
||||
} |
||||
}; |
||||
decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters(context, createExpression.Arguments)); |
||||
} |
||||
var guessedType = TypeGuessing.GuessType(context, createExpression); |
||||
if (guessedType.Kind == TypeKind.Interface || guessedType.Kind == TypeKind.Class && guessedType.GetDefinition ().IsAbstract) { |
||||
result.BaseTypes.Add(context.CreateShortType(guessedType)); |
||||
AddImplementation(context, result, guessedType); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
static Modifiers GetModifiers(IEntity property) |
||||
{ |
||||
if (property.DeclaringType.Kind == TypeKind.Interface) |
||||
return Modifiers.Public; |
||||
switch (property.Accessibility) { |
||||
case Accessibility.Public: |
||||
return Modifiers.Public | Modifiers.Override; |
||||
case Accessibility.Protected: |
||||
return Modifiers.Protected | Modifiers.Override; |
||||
case Accessibility.Internal: |
||||
return Modifiers.Internal | Modifiers.Override; |
||||
case Accessibility.ProtectedOrInternal: |
||||
// TODO: oops
|
||||
return Modifiers.Internal | Modifiers.Protected | Modifiers.Override; |
||||
case Accessibility.ProtectedAndInternal: |
||||
// TODO: oops
|
||||
return Modifiers.Internal | Modifiers.Protected | Modifiers.Override; |
||||
} |
||||
return Modifiers.Override; |
||||
} |
||||
|
||||
static void AddImplementation(RefactoringContext context, TypeDeclaration result, IType guessedType) |
||||
{ |
||||
foreach (var property in guessedType.GetProperties ()) { |
||||
if (!property.IsAbstract) |
||||
continue; |
||||
if (property.IsIndexer) { |
||||
var indexerDecl = new IndexerDeclaration { |
||||
ReturnType = context.CreateShortType(property.ReturnType), |
||||
Modifiers = GetModifiers(property), |
||||
Name = property.Name |
||||
}; |
||||
indexerDecl.Parameters.AddRange(ConvertParameters(context, property.Parameters)); |
||||
if (property.CanGet) |
||||
indexerDecl.Getter = new Accessor(); |
||||
if (property.CanSet) |
||||
indexerDecl.Setter = new Accessor(); |
||||
result.AddChild(indexerDecl, Roles.TypeMemberRole); |
||||
continue; |
||||
} |
||||
var propDecl = new PropertyDeclaration { |
||||
ReturnType = context.CreateShortType(property.ReturnType), |
||||
Modifiers = GetModifiers (property), |
||||
Name = property.Name |
||||
}; |
||||
if (property.CanGet) |
||||
propDecl.Getter = new Accessor(); |
||||
if (property.CanSet) |
||||
propDecl.Setter = new Accessor(); |
||||
result.AddChild(propDecl, Roles.TypeMemberRole); |
||||
} |
||||
|
||||
foreach (var method in guessedType.GetMethods ()) { |
||||
if (!method.IsAbstract) |
||||
continue; |
||||
var decl = new MethodDeclaration { |
||||
ReturnType = context.CreateShortType(method.ReturnType), |
||||
Modifiers = GetModifiers (method), |
||||
Name = method.Name, |
||||
Body = new BlockStatement { |
||||
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException"))) |
||||
} |
||||
}; |
||||
decl.Parameters.AddRange(ConvertParameters(context, method.Parameters)); |
||||
result.AddChild(decl, Roles.TypeMemberRole); |
||||
} |
||||
|
||||
foreach (var evt in guessedType.GetEvents ()) { |
||||
if (!evt.IsAbstract) |
||||
continue; |
||||
var decl = new EventDeclaration { |
||||
ReturnType = context.CreateShortType(evt.ReturnType), |
||||
Modifiers = GetModifiers (evt), |
||||
Variables = { |
||||
new VariableInitializer { |
||||
Name = evt.Name |
||||
} |
||||
} |
||||
}; |
||||
decl.Variables.Add(new VariableInitializer(evt.Name)); |
||||
result.AddChild(decl, Roles.TypeMemberRole); |
||||
} |
||||
} |
||||
|
||||
static IEnumerable<ParameterDeclaration> ConvertParameters(RefactoringContext context, IList<IParameter> parameters) |
||||
{ |
||||
foreach (var param in parameters) { |
||||
ParameterModifier mod = ParameterModifier.None; |
||||
if (param.IsOut) { |
||||
mod = ParameterModifier.Out; |
||||
} else if (param.IsRef) { |
||||
mod = ParameterModifier.Ref; |
||||
} else if (param.IsParams) { |
||||
mod = ParameterModifier.Params; |
||||
} |
||||
yield return new ParameterDeclaration(context.CreateShortType(param.Type), param.Name, mod); |
||||
} |
||||
} |
||||
|
||||
static TypeDeclaration AddBaseTypesAccordingToNamingRules(RefactoringContext context, NamingConventionService service, TypeDeclaration result) |
||||
{ |
||||
if (service.HasValidRule(result.Name, AffectedEntity.CustomAttributes, Modifiers.Public)) { |
||||
result.BaseTypes.Add(context.CreateShortType("System", "Attribute")); |
||||
} else if (service.HasValidRule(result.Name, AffectedEntity.CustomEventArgs, Modifiers.Public)) { |
||||
result.BaseTypes.Add(context.CreateShortType("System", "EventArgs")); |
||||
} else if (service.HasValidRule(result.Name, AffectedEntity.CustomExceptions, Modifiers.Public)) { |
||||
result.BaseTypes.Add(context.CreateShortType("System", "Exception")); |
||||
} |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// CreateClassDeclarationAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin <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.Collections.Generic; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create constructor", Description = "Creates a constructor declaration out of an object creation.")] |
||||
public class CreateConstructorDeclarationAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var createExpression = context.GetNode<Expression>() as ObjectCreateExpression; |
||||
if (createExpression == null) |
||||
yield break; |
||||
|
||||
var resolveResult = context.Resolve(createExpression) as CSharpInvocationResolveResult; |
||||
if (resolveResult == null || !resolveResult.IsError || resolveResult.Member.DeclaringTypeDefinition == null || resolveResult.Member.DeclaringTypeDefinition.IsSealed || resolveResult.Member.DeclaringTypeDefinition.Region.IsEmpty) |
||||
yield break; |
||||
|
||||
yield return new CodeAction(context.TranslateString("Create constructor"), script => |
||||
script.InsertWithCursor( |
||||
context.TranslateString("Create constructor"), |
||||
resolveResult.Member.DeclaringTypeDefinition, |
||||
(s, c) => { |
||||
var decl = new ConstructorDeclaration { |
||||
Name = resolveResult.Member.DeclaringTypeDefinition.Name, |
||||
Modifiers = Modifiers.Public, |
||||
Body = new BlockStatement { |
||||
new ThrowStatement(new ObjectCreateExpression(c.CreateShortType("System", "NotImplementedException"))) |
||||
} |
||||
}; |
||||
decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters(context, createExpression.Arguments)); |
||||
return decl; |
||||
} |
||||
) |
||||
, createExpression) { Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error }; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,71 @@
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// CreateDelegateAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin <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.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create delegate", Description = "Creates a delegate declaration out of an event declaration.")] |
||||
public class CreateDelegateAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var simpleType = context.GetNode<SimpleType>(); |
||||
if (simpleType != null && (simpleType.Parent is EventDeclaration || simpleType.Parent is CustomEventDeclaration)) |
||||
return GetActions(context, simpleType); |
||||
|
||||
return Enumerable.Empty<CodeAction>(); |
||||
} |
||||
|
||||
static IEnumerable<CodeAction> GetActions(RefactoringContext context, SimpleType node) |
||||
{ |
||||
var resolveResult = context.Resolve(node) as UnknownIdentifierResolveResult; |
||||
if (resolveResult == null) |
||||
yield break; |
||||
|
||||
yield return new CodeAction(context.TranslateString("Create delegate"), script => { |
||||
script.CreateNewType(CreateType(context, node)); |
||||
}, node); |
||||
|
||||
} |
||||
|
||||
static DelegateDeclaration CreateType(RefactoringContext context, SimpleType simpleType) |
||||
{ |
||||
var result = new DelegateDeclaration() { |
||||
Name = simpleType.Identifier, |
||||
Modifiers = ((EntityDeclaration)simpleType.Parent).Modifiers, |
||||
ReturnType = new PrimitiveType("void"), |
||||
Parameters = { |
||||
new ParameterDeclaration(new PrimitiveType("object"), "sender"), |
||||
new ParameterDeclaration(context.CreateShortType("System", "EventArgs"), "e") |
||||
} |
||||
}; |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// CreateEnumValue.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create enum value", Description = "Creates an enum value for a undefined enum value.")] |
||||
public class CreateEnumValue : CodeActionProvider |
||||
{ |
||||
internal static bool IsInvocationTarget(AstNode node) |
||||
{ |
||||
var invoke = node.Parent as InvocationExpression; |
||||
return invoke != null && invoke.Target == node; |
||||
} |
||||
|
||||
internal static Expression GetCreatePropertyOrFieldNode(RefactoringContext context) |
||||
{ |
||||
return context.GetNode(n => n is IdentifierExpression || n is MemberReferenceExpression || n is NamedExpression) as Expression; |
||||
} |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var expr = GetCreatePropertyOrFieldNode(context); |
||||
if (expr == null) |
||||
yield break; |
||||
if (!(expr is MemberReferenceExpression)) |
||||
yield break; |
||||
var propertyName = CreatePropertyAction.GetPropertyName(expr); |
||||
if (propertyName == null) |
||||
yield break; |
||||
if (IsInvocationTarget(expr)) |
||||
yield break; |
||||
var statement = expr.GetParent<Statement>(); |
||||
if (statement == null) |
||||
yield break; |
||||
if (!(context.Resolve(expr).IsError)) |
||||
yield break; |
||||
var guessedType = TypeGuessing.GuessType(context, expr); |
||||
if (guessedType == null || guessedType.Kind != TypeKind.Enum) |
||||
yield break; |
||||
var state = context.GetResolverStateBefore(expr); |
||||
if (state.CurrentMember == null || state.CurrentTypeDefinition == null) |
||||
yield break; |
||||
|
||||
yield return new CodeAction(context.TranslateString("Create enum value"), script => { |
||||
var decl = new EnumMemberDeclaration { |
||||
Name = propertyName |
||||
}; |
||||
script.InsertWithCursor(context.TranslateString("Create enum value"), guessedType.GetDefinition (), (s, c) => decl); |
||||
}, expr) { Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error }; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,144 @@
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// 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; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create event invocator", Description = "Creates a standard OnXXX event method.")] |
||||
public class CreateEventInvocatorAction : CodeActionProvider |
||||
{ |
||||
/// <summary>
|
||||
/// If <c>true</c> an explicit type will be used for the handler variable; otherwise, 'var' will be used as type.
|
||||
/// Default value is <c>false</c>
|
||||
/// </summary>
|
||||
public bool UseExplictType { |
||||
get; |
||||
set; |
||||
} |
||||
|
||||
public static MethodDeclaration CreateEventInvocator (RefactoringContext context, TypeDeclaration declaringType, EventDeclaration eventDeclaration, VariableInitializer initializer, IMethod invokeMethod, bool useExplictType) |
||||
{ |
||||
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(eventDeclaration.HasModifier (Modifiers.Static) ? (Expression)new PrimitiveExpression (null) : new ThisReferenceExpression()); |
||||
bool useThisMemberReference = false; |
||||
foreach (var par in pars) { |
||||
arguments.Add(new IdentifierExpression(par.Name)); |
||||
useThisMemberReference |= par.Name == initializer.Name; |
||||
} |
||||
var proposedHandlerName = GetNameProposal(initializer); |
||||
var modifiers = eventDeclaration.HasModifier(Modifiers.Static) ? Modifiers.Static : Modifiers.Protected | Modifiers.Virtual; |
||||
if (declaringType.HasModifier (Modifiers.Sealed)) { |
||||
modifiers = Modifiers.None; |
||||
} |
||||
var methodDeclaration = new MethodDeclaration { |
||||
Name = proposedHandlerName, |
||||
ReturnType = new PrimitiveType ("void"), |
||||
Modifiers = modifiers, |
||||
Body = new BlockStatement { |
||||
new VariableDeclarationStatement ( |
||||
useExplictType ? eventDeclaration.ReturnType.Clone () : new PrimitiveType ("var"), handlerName, |
||||
useThisMemberReference ? |
||||
(Expression)new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name) |
||||
: new IdentifierExpression (initializer.Name) |
||||
), |
||||
new IfElseStatement { |
||||
Condition = new BinaryOperatorExpression (new IdentifierExpression (handlerName), BinaryOperatorType.InEquality, new PrimitiveExpression (null)), |
||||
TrueStatement = 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); |
||||
} |
||||
return methodDeclaration; |
||||
} |
||||
|
||||
static string GetNameProposal(VariableInitializer initializer) |
||||
{ |
||||
return "On" + char.ToUpper(initializer.Name[0]) + initializer.Name.Substring(1); |
||||
} |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
VariableInitializer initializer; |
||||
var eventDeclaration = GetEventDeclaration(context, out initializer); |
||||
if (eventDeclaration == null) { |
||||
yield break; |
||||
} |
||||
var type = (TypeDeclaration)eventDeclaration.Parent; |
||||
var proposedHandlerName = GetNameProposal(initializer); |
||||
if (type.Members.Any(m => m is MethodDeclaration && m.Name == proposedHandlerName)) { |
||||
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 => { |
||||
var methodDeclaration = CreateEventInvocator (context, type, eventDeclaration, initializer, invokeMethod, UseExplictType); |
||||
script.InsertWithCursor( |
||||
context.TranslateString("Create event invocator"), |
||||
Script.InsertPosition.After, |
||||
methodDeclaration |
||||
); |
||||
}, initializer); |
||||
} |
||||
|
||||
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; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// CreateField.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@novell.com>
|
||||
//
|
||||
// Copyright (c) 2011 Novell, Inc (http://www.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 ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create field", Description = "Creates a field for a undefined variable.")] |
||||
public class CreateFieldAction : CodeActionProvider |
||||
{ |
||||
internal static bool IsInvocationTarget(AstNode node) |
||||
{ |
||||
var invoke = node.Parent as InvocationExpression; |
||||
return invoke != null && invoke.Target == node; |
||||
} |
||||
|
||||
internal static Expression GetCreatePropertyOrFieldNode(RefactoringContext context) |
||||
{ |
||||
return context.GetNode(n => n is IdentifierExpression || n is MemberReferenceExpression || n is NamedExpression) as Expression; |
||||
} |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var expr = GetCreatePropertyOrFieldNode(context); |
||||
if (expr == null) |
||||
yield break; |
||||
|
||||
if (expr is MemberReferenceExpression && !(((MemberReferenceExpression)expr).Target is ThisReferenceExpression)) |
||||
yield break; |
||||
|
||||
var propertyName = CreatePropertyAction.GetPropertyName(expr); |
||||
if (propertyName == null) |
||||
yield break; |
||||
|
||||
if (IsInvocationTarget(expr)) |
||||
yield break; |
||||
var statement = expr.GetParent<Statement>(); |
||||
if (statement == null) |
||||
yield break; |
||||
if (!(context.Resolve(expr).IsError)) |
||||
yield break; |
||||
var guessedType = TypeGuessing.GuessAstType(context, expr); |
||||
if (guessedType == null) |
||||
yield break; |
||||
var state = context.GetResolverStateBefore(expr); |
||||
if (state.CurrentMember == null || state.CurrentTypeDefinition == null) |
||||
yield break; |
||||
bool isStatic = !(expr is NamedExpression) && (state.CurrentMember.IsStatic | state.CurrentTypeDefinition.IsStatic); |
||||
|
||||
// var service = (NamingConventionService)context.GetService(typeof(NamingConventionService));
|
||||
// if (service != null && !service.IsValidName(identifier.Identifier, AffectedEntity.Field, Modifiers.Private, isStatic)) {
|
||||
// yield break;
|
||||
// }
|
||||
|
||||
yield return new CodeAction(context.TranslateString("Create field"), script => { |
||||
var decl = new FieldDeclaration { |
||||
ReturnType = guessedType, |
||||
Variables = { new VariableInitializer(propertyName) } |
||||
}; |
||||
if (isStatic) |
||||
decl.Modifiers |= Modifiers.Static; |
||||
script.InsertWithCursor(context.TranslateString("Create field"), Script.InsertPosition.Before, decl); |
||||
}, expr.GetNodeAt(context.Location) ?? expr) { Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error }; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// CreateIndexerAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin <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.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Text; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create indexer", Description = "Creates an indexer declaration out of an indexer expression.")] |
||||
public class CreateIndexerAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var indexer = context.GetNode<IndexerExpression>(); |
||||
if (indexer == null) |
||||
yield break; |
||||
if (!(context.Resolve(indexer).IsError)) |
||||
yield break; |
||||
|
||||
var state = context.GetResolverStateBefore(indexer); |
||||
if (state.CurrentTypeDefinition == null) |
||||
yield break; |
||||
var guessedType = TypeGuessing.GuessAstType(context, indexer); |
||||
|
||||
bool createInOtherType = false; |
||||
ResolveResult targetResolveResult = null; |
||||
targetResolveResult = context.Resolve(indexer.Target); |
||||
createInOtherType = !state.CurrentTypeDefinition.Equals(targetResolveResult.Type.GetDefinition()); |
||||
|
||||
bool isStatic; |
||||
if (createInOtherType) { |
||||
if (targetResolveResult.Type.GetDefinition() == null || targetResolveResult.Type.GetDefinition().Region.IsEmpty) |
||||
yield break; |
||||
isStatic = targetResolveResult is TypeResolveResult; |
||||
if (isStatic && targetResolveResult.Type.Kind == TypeKind.Interface || targetResolveResult.Type.Kind == TypeKind.Enum) |
||||
yield break; |
||||
} else { |
||||
isStatic = indexer.Target is IdentifierExpression && state.CurrentMember.IsStatic; |
||||
} |
||||
|
||||
yield return new CodeAction(context.TranslateString("Create indexer"), script => { |
||||
var decl = new IndexerDeclaration() { |
||||
ReturnType = guessedType, |
||||
Getter = new Accessor() { |
||||
Body = new BlockStatement() { |
||||
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException"))) |
||||
} |
||||
}, |
||||
Setter = new Accessor() { |
||||
Body = new BlockStatement() { |
||||
new ThrowStatement(new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException"))) |
||||
} |
||||
}, |
||||
}; |
||||
decl.Parameters.AddRange(CreateMethodDeclarationAction.GenerateParameters(context, indexer.Arguments)); |
||||
if (isStatic) |
||||
decl.Modifiers |= Modifiers.Static; |
||||
|
||||
if (createInOtherType) { |
||||
if (targetResolveResult.Type.Kind == TypeKind.Interface) { |
||||
decl.Getter.Body = null; |
||||
decl.Setter.Body = null; |
||||
decl.Modifiers = Modifiers.None; |
||||
} else { |
||||
decl.Modifiers |= Modifiers.Public; |
||||
} |
||||
|
||||
script.InsertWithCursor(context.TranslateString("Create indexer"), targetResolveResult.Type.GetDefinition(), (s, c) => decl); |
||||
return; |
||||
} |
||||
|
||||
script.InsertWithCursor(context.TranslateString("Create indexer"), Script.InsertPosition.Before, decl); |
||||
}, indexer) { Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error }; |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// CreateLocalVariable.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@novell.com>
|
||||
//
|
||||
// Copyright (c) 2011 Novell, Inc (http://www.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.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create local variable", Description = "Creates a local variable for a undefined variable.")] |
||||
public class CreateLocalVariableAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var identifier = context.GetNode<IdentifierExpression>(); |
||||
if (identifier == null) { |
||||
yield break; |
||||
} |
||||
if (CreateFieldAction.IsInvocationTarget(identifier)) { |
||||
yield break; |
||||
} |
||||
var statement = context.GetNode<Statement>(); |
||||
if (statement == null) { |
||||
yield break; |
||||
} |
||||
|
||||
if (!(context.Resolve(identifier).IsError)) { |
||||
yield break; |
||||
} |
||||
var guessedType = TypeGuessing.GuessAstType(context, identifier); |
||||
if (guessedType == null) { |
||||
yield break; |
||||
} |
||||
|
||||
yield return new CodeAction(context.TranslateString("Create local variable"), script => { |
||||
var initializer = new VariableInitializer(identifier.Identifier); |
||||
var decl = new VariableDeclarationStatement() { |
||||
Type = guessedType, |
||||
Variables = { initializer } |
||||
}; |
||||
if (identifier.Parent is AssignmentExpression && ((AssignmentExpression)identifier.Parent).Left == identifier) { |
||||
initializer.Initializer = ((AssignmentExpression)identifier.Parent).Right.Clone(); |
||||
if (!context.UseExplicitTypes) |
||||
decl.Type = new SimpleType("var"); |
||||
script.Replace(statement, decl); |
||||
} else { |
||||
script.InsertBefore(statement, decl); |
||||
} |
||||
}, identifier) { Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error }; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,379 @@
@@ -0,0 +1,379 @@
|
||||
//
|
||||
// CreateMethodDeclarationAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin <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.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Text; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create method", Description = "Creates a method declaration out of an invocation.")] |
||||
public class CreateMethodDeclarationAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var identifier = context.GetNode<IdentifierExpression>(); |
||||
if (identifier != null && !(identifier.Parent is InvocationExpression && ((InvocationExpression)identifier.Parent).Target == identifier)) |
||||
return GetActionsFromIdentifier(context, identifier); |
||||
|
||||
var memberReference = context.GetNode<MemberReferenceExpression>(); |
||||
if (memberReference != null && !(memberReference.Parent is InvocationExpression && ((InvocationExpression)memberReference.Parent).Target == memberReference)) |
||||
return GetActionsFromMemberReferenceExpression(context, memberReference); |
||||
|
||||
var invocation = context.GetNode<InvocationExpression>(); |
||||
if (invocation != null) |
||||
return GetActionsFromInvocation(context, invocation); |
||||
return Enumerable.Empty<CodeAction>(); |
||||
} |
||||
|
||||
IEnumerable<CodeAction> GetActionsFromMemberReferenceExpression(RefactoringContext context, MemberReferenceExpression invocation) |
||||
{ |
||||
if (!(context.Resolve(invocation).IsError)) |
||||
yield break; |
||||
|
||||
var methodName = invocation.MemberName; |
||||
var guessedType = TypeGuessing.GuessType(context, invocation); |
||||
if (guessedType.Kind != TypeKind.Delegate) |
||||
yield break; |
||||
var invocationMethod = guessedType.GetDelegateInvokeMethod(); |
||||
var state = context.GetResolverStateBefore(invocation); |
||||
if (state.CurrentTypeDefinition == null) |
||||
yield break; |
||||
ResolveResult targetResolveResult = context.Resolve(invocation.Target); |
||||
bool createInOtherType = !state.CurrentTypeDefinition.Equals(targetResolveResult.Type.GetDefinition()); |
||||
|
||||
bool isStatic; |
||||
if (createInOtherType) { |
||||
if (targetResolveResult.Type.GetDefinition() == null || targetResolveResult.Type.GetDefinition().Region.IsEmpty) |
||||
yield break; |
||||
isStatic = targetResolveResult is TypeResolveResult; |
||||
if (isStatic && targetResolveResult.Type.Kind == TypeKind.Interface || targetResolveResult.Type.Kind == TypeKind.Enum) |
||||
yield break; |
||||
} else { |
||||
if (state.CurrentMember == null) |
||||
yield break; |
||||
isStatic = state.CurrentMember.IsStatic || state.CurrentTypeDefinition.IsStatic; |
||||
} |
||||
|
||||
// var service = (NamingConventionService)context.GetService(typeof(NamingConventionService));
|
||||
// if (service != null && !service.IsValidName(methodName, AffectedEntity.Method, Modifiers.Private, isStatic)) {
|
||||
// yield break;
|
||||
// }
|
||||
|
||||
yield return CreateAction( |
||||
context, |
||||
invocation, |
||||
methodName, |
||||
context.CreateShortType(invocationMethod.ReturnType), |
||||
invocationMethod.Parameters.Select(parameter => new ParameterDeclaration(context.CreateShortType(parameter.Type), parameter.Name) { |
||||
ParameterModifier = GetModifiers(parameter) |
||||
}), |
||||
createInOtherType, |
||||
isStatic, |
||||
targetResolveResult); |
||||
} |
||||
|
||||
IEnumerable<CodeAction> GetActionsFromIdentifier(RefactoringContext context, IdentifierExpression identifier) |
||||
{ |
||||
if (!(context.Resolve(identifier).IsError)) |
||||
yield break; |
||||
var methodName = identifier.Identifier; |
||||
var guessedType = TypeGuessing.GuessType(context, identifier); |
||||
if (guessedType.Kind != TypeKind.Delegate) |
||||
yield break; |
||||
var invocationMethod = guessedType.GetDelegateInvokeMethod(); |
||||
if (invocationMethod == null) |
||||
yield break; |
||||
var state = context.GetResolverStateBefore(identifier); |
||||
if (state.CurrentMember == null || state.CurrentTypeDefinition == null) |
||||
yield break; |
||||
bool isStatic = state.CurrentMember.IsStatic || state.CurrentTypeDefinition.IsStatic; |
||||
|
||||
var service = (NamingConventionService)context.GetService(typeof(NamingConventionService)); |
||||
if (service != null && !service.IsValidName(methodName, AffectedEntity.Method, Modifiers.Private, isStatic)) |
||||
yield break; |
||||
|
||||
yield return CreateAction( |
||||
context, |
||||
identifier, |
||||
methodName, |
||||
context.CreateShortType(invocationMethod.ReturnType), |
||||
invocationMethod.Parameters.Select(parameter => new ParameterDeclaration(context.CreateShortType(parameter.Type), parameter.Name) { |
||||
ParameterModifier = GetModifiers(parameter) |
||||
}), |
||||
false, |
||||
isStatic, |
||||
null); |
||||
} |
||||
|
||||
IEnumerable<CodeAction> GetActionsFromInvocation(RefactoringContext context, InvocationExpression invocation) |
||||
{ |
||||
if (!(context.Resolve(invocation.Target).IsError)) |
||||
yield break; |
||||
|
||||
var methodName = GetMethodName(invocation); |
||||
if (methodName == null) |
||||
yield break; |
||||
var state = context.GetResolverStateBefore(invocation); |
||||
if (state.CurrentMember == null || state.CurrentTypeDefinition == null) |
||||
yield break; |
||||
var guessedType = invocation.Parent is ExpressionStatement ? new PrimitiveType("void") : TypeGuessing.GuessAstType(context, invocation); |
||||
|
||||
bool createInOtherType = false; |
||||
ResolveResult targetResolveResult = null; |
||||
if (invocation.Target is MemberReferenceExpression) { |
||||
targetResolveResult = context.Resolve(((MemberReferenceExpression)invocation.Target).Target); |
||||
createInOtherType = !state.CurrentTypeDefinition.Equals(targetResolveResult.Type.GetDefinition()); |
||||
} |
||||
|
||||
bool isStatic; |
||||
if (createInOtherType) { |
||||
if (targetResolveResult.Type.GetDefinition() == null || targetResolveResult.Type.GetDefinition().Region.IsEmpty) |
||||
yield break; |
||||
isStatic = targetResolveResult is TypeResolveResult; |
||||
if (isStatic && targetResolveResult.Type.Kind == TypeKind.Interface || targetResolveResult.Type.Kind == TypeKind.Enum) |
||||
yield break; |
||||
} else { |
||||
isStatic = state.CurrentMember.IsStatic || state.CurrentTypeDefinition.IsStatic; |
||||
} |
||||
|
||||
// var service = (NamingConventionService)context.GetService(typeof(NamingConventionService));
|
||||
// if (service != null && !service.IsValidName(methodName, AffectedEntity.Method, Modifiers.Private, isStatic)) {
|
||||
// yield break;
|
||||
// }
|
||||
|
||||
|
||||
yield return CreateAction( |
||||
context, |
||||
invocation, |
||||
methodName, |
||||
guessedType, |
||||
GenerateParameters(context, invocation.Arguments), |
||||
createInOtherType, |
||||
isStatic, |
||||
targetResolveResult); |
||||
} |
||||
|
||||
static ParameterModifier GetModifiers(IParameter parameter) |
||||
{ |
||||
if (parameter.IsOut) |
||||
return ParameterModifier.Out; |
||||
if (parameter.IsRef) |
||||
return ParameterModifier.Ref; |
||||
if (parameter.IsParams) |
||||
return ParameterModifier.Params; |
||||
return ParameterModifier.None; |
||||
} |
||||
|
||||
static CodeAction CreateAction(RefactoringContext context, AstNode createFromNode, string methodName, AstType returnType, IEnumerable<ParameterDeclaration> parameters, bool createInOtherType, bool isStatic, ResolveResult targetResolveResult) |
||||
{ |
||||
return new CodeAction(context.TranslateString("Create method"), script => { |
||||
var throwStatement = new ThrowStatement(); |
||||
var decl = new MethodDeclaration { |
||||
ReturnType = returnType, |
||||
Name = methodName, |
||||
Body = new BlockStatement { |
||||
throwStatement |
||||
} |
||||
}; |
||||
decl.Parameters.AddRange(parameters); |
||||
|
||||
if (isStatic) |
||||
decl.Modifiers |= Modifiers.Static; |
||||
|
||||
if (createInOtherType) { |
||||
if (targetResolveResult.Type.Kind == TypeKind.Interface) { |
||||
decl.Body = null; |
||||
decl.Modifiers = Modifiers.None; |
||||
} else { |
||||
decl.Modifiers |= Modifiers.Public; |
||||
} |
||||
|
||||
script |
||||
.InsertWithCursor(context.TranslateString("Create method"), targetResolveResult.Type.GetDefinition(), (s, c) => { |
||||
throwStatement.Expression = new ObjectCreateExpression(c.CreateShortType("System", "NotImplementedException")); |
||||
return decl; |
||||
}) |
||||
.ContinueScript(s => s.Select(throwStatement)); |
||||
return; |
||||
} else { |
||||
throwStatement.Expression = new ObjectCreateExpression(context.CreateShortType("System", "NotImplementedException")); |
||||
} |
||||
|
||||
script |
||||
.InsertWithCursor(context.TranslateString("Create method"), Script.InsertPosition.Before, decl) |
||||
.ContinueScript(() => script.Select(throwStatement)); |
||||
}, createFromNode.GetNodeAt(context.Location) ?? createFromNode) { Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error }; |
||||
} |
||||
|
||||
public static IEnumerable<ParameterDeclaration> GenerateParameters(RefactoringContext context, IEnumerable<Expression> arguments) |
||||
{ |
||||
var nameCounter = new Dictionary<string, int>(); |
||||
foreach (var argument in arguments) { |
||||
var direction = ParameterModifier.None; |
||||
AstNode node; |
||||
if (argument is DirectionExpression) { |
||||
var de = (DirectionExpression)argument; |
||||
direction = de.FieldDirection == FieldDirection.Out ? ParameterModifier.Out : ParameterModifier.Ref; |
||||
node = de.Expression; |
||||
} else { |
||||
node = argument; |
||||
} |
||||
|
||||
var resolveResult = context.Resolve(node); |
||||
string name = CreateBaseName(argument, resolveResult.Type); |
||||
if (!nameCounter.ContainsKey(name)) { |
||||
nameCounter [name] = 1; |
||||
} else { |
||||
nameCounter [name]++; |
||||
name += nameCounter [name].ToString(); |
||||
} |
||||
var type = resolveResult.Type.Kind == TypeKind.Unknown || resolveResult.Type.Kind == TypeKind.Null ? new PrimitiveType("object") : context.CreateShortType(resolveResult.Type); |
||||
|
||||
yield return new ParameterDeclaration(type, name) { ParameterModifier = direction}; |
||||
} |
||||
} |
||||
|
||||
static string CreateBaseNameFromString(string str) |
||||
{ |
||||
if (string.IsNullOrEmpty(str)) { |
||||
return "empty"; |
||||
} |
||||
var sb = new StringBuilder(); |
||||
bool firstLetter = true, wordStart = false; |
||||
foreach (char ch in str) { |
||||
if (char.IsWhiteSpace(ch)) { |
||||
wordStart = true; |
||||
continue; |
||||
} |
||||
if (!char.IsLetter(ch)) |
||||
continue; |
||||
if (firstLetter) { |
||||
sb.Append(char.ToLower(ch)); |
||||
firstLetter = false; |
||||
continue; |
||||
} |
||||
if (wordStart) { |
||||
sb.Append(char.ToUpper(ch)); |
||||
wordStart = false; |
||||
continue; |
||||
} |
||||
sb.Append(ch); |
||||
} |
||||
return sb.Length == 0 ? "str" : sb.ToString(); |
||||
} |
||||
|
||||
public static string CreateBaseName(AstNode node, IType type) |
||||
{ |
||||
string name = null; |
||||
if (node is NullReferenceExpression) |
||||
return "o"; |
||||
if (node is DirectionExpression) |
||||
node = ((DirectionExpression)node).Expression; |
||||
if (node is IdentifierExpression) { |
||||
name = ((IdentifierExpression)node).Identifier; |
||||
} else if (node is MemberReferenceExpression) { |
||||
name = ((MemberReferenceExpression)node).MemberName; |
||||
} else if (node is PrimitiveExpression) { |
||||
var pe = (PrimitiveExpression)node; |
||||
if (pe.Value is string) { |
||||
name = CreateBaseNameFromString(pe.Value.ToString()); |
||||
} else { |
||||
return char.ToLower(type.Name [0]).ToString(); |
||||
} |
||||
} else if (node is ArrayCreateExpression) { |
||||
name = "arr"; |
||||
} else { |
||||
if (type.Kind == TypeKind.Unknown) |
||||
return "par"; |
||||
name = GuessNameFromType(type); |
||||
} |
||||
var sb = new StringBuilder (); |
||||
sb.Append (char.ToLower(name [0])); |
||||
for (int i = 1; i < name.Length; i++) { |
||||
var ch = name[i]; |
||||
if (char.IsLetterOrDigit (ch) || ch == '_') |
||||
sb.Append (ch); |
||||
} |
||||
return sb.ToString (); |
||||
} |
||||
|
||||
internal static string GuessNameFromType(IType returnType) |
||||
{ |
||||
switch (returnType.ReflectionName) { |
||||
case "System.Byte": |
||||
case "System.SByte": |
||||
return "b"; |
||||
|
||||
case "System.Int16": |
||||
case "System.UInt16": |
||||
case "System.Int32": |
||||
case "System.UInt32": |
||||
case "System.Int64": |
||||
case "System.UInt64": |
||||
return "i"; |
||||
|
||||
case "System.Boolean": |
||||
return "b"; |
||||
|
||||
case "System.DateTime": |
||||
return "date"; |
||||
|
||||
case "System.Char": |
||||
return "ch"; |
||||
case "System.Double": |
||||
case "System.Decimal": |
||||
return "d"; |
||||
case "System.Single": |
||||
return "f"; |
||||
case "System.String": |
||||
return "str"; |
||||
|
||||
case "System.Exception": |
||||
return "e"; |
||||
case "System.Object": |
||||
return "obj"; |
||||
case "System.Func": |
||||
return "func"; |
||||
case "System.Action": |
||||
return "action"; |
||||
} |
||||
return returnType.Name; |
||||
} |
||||
|
||||
string GetMethodName(InvocationExpression invocation) |
||||
{ |
||||
if (invocation.Target is IdentifierExpression) |
||||
return ((IdentifierExpression)invocation.Target).Identifier; |
||||
if (invocation.Target is MemberReferenceExpression) |
||||
return ((MemberReferenceExpression)invocation.Target).MemberName; |
||||
|
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,154 @@
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// CreateOverloadWithoutParameterAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mansheng Yang <lightyang0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.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.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Create overload without parameter", Description = "Create overload without the selected parameter.")] |
||||
public class CreateOverloadWithoutParameterAction : SpecializedCodeAction<ParameterDeclaration> |
||||
{ |
||||
protected override CodeAction GetAction (RefactoringContext context, ParameterDeclaration node) |
||||
{ |
||||
if (!node.DefaultExpression.IsNull) |
||||
return null; |
||||
if (node.ParameterModifier == ParameterModifier.This || node.ParameterModifier == ParameterModifier.Params) |
||||
return null; |
||||
if (!node.NameToken.Contains(context.Location)) |
||||
return null; |
||||
|
||||
var methodDecl = node.Parent as MethodDeclaration; |
||||
if (methodDecl == null) |
||||
return null; |
||||
|
||||
// explicit implementation
|
||||
if (!methodDecl.PrivateImplementationType.IsNull) |
||||
return null; |
||||
|
||||
// find existing method
|
||||
var method = (IMethod)((MemberResolveResult)context.Resolve (methodDecl)).Member; |
||||
var parameters = new List<IParameter> (method.Parameters.Where (param => param.Name != node.Name)); |
||||
if (method.DeclaringType.GetMethods ( |
||||
m => m.Name == method.Name && m.TypeParameters.Count == method.TypeParameters.Count) |
||||
.Any (m => ParameterListComparer.Instance.Equals (m.Parameters, parameters))) |
||||
return null; |
||||
|
||||
return new CodeAction (context.TranslateString ("Create overload without parameter"), |
||||
script => |
||||
{ |
||||
var defaultExpr = GetDefaultValueExpression (context, node.Type); |
||||
|
||||
var body = new BlockStatement (); |
||||
Expression argExpr; |
||||
if (node.ParameterModifier == ParameterModifier.Ref) { |
||||
body.Add (new VariableDeclarationStatement (node.Type.Clone (), node.Name, defaultExpr)); |
||||
argExpr = GetArgumentExpression (node); |
||||
} else if (node.ParameterModifier == ParameterModifier.Out) { |
||||
body.Add (new VariableDeclarationStatement (node.Type.Clone (), node.Name)); |
||||
argExpr = GetArgumentExpression (node); |
||||
} else { |
||||
argExpr = defaultExpr; |
||||
} |
||||
body.Add (new InvocationExpression (new IdentifierExpression (methodDecl.Name), |
||||
methodDecl.Parameters.Select (param => param == node ? argExpr : GetArgumentExpression(param)))); |
||||
|
||||
var decl = (MethodDeclaration)methodDecl.Clone (); |
||||
decl.Parameters.Remove (decl.Parameters.First (param => param.Name == node.Name)); |
||||
decl.Body = body; |
||||
|
||||
script |
||||
.InsertWithCursor ("Create overload without parameter", Script.InsertPosition.Before, decl) |
||||
.ContinueScript (() => script.Select(argExpr)); |
||||
}, node.NameToken); |
||||
} |
||||
|
||||
static Expression GetArgumentExpression(ParameterDeclaration parameter) |
||||
{ |
||||
var identifierExpr = new IdentifierExpression(parameter.Name); |
||||
switch (parameter.ParameterModifier) { |
||||
case ParameterModifier.Out: |
||||
return new DirectionExpression (FieldDirection.Out, identifierExpr); |
||||
case ParameterModifier.Ref: |
||||
return new DirectionExpression (FieldDirection.Ref, identifierExpr); |
||||
} |
||||
return identifierExpr; |
||||
} |
||||
|
||||
static Expression GetDefaultValueExpression (RefactoringContext context, AstType astType) |
||||
{ |
||||
var type = context.ResolveType (astType); |
||||
|
||||
// array
|
||||
if (type.Kind == TypeKind.Array) |
||||
return new ObjectCreateExpression (astType.Clone ()); |
||||
|
||||
// enum
|
||||
if (type.Kind == TypeKind.Enum) { |
||||
var members = type.GetMembers ().ToArray(); |
||||
if (members.Length == 0) |
||||
return new DefaultValueExpression (astType.Clone ()); |
||||
return astType.Member(members[0].Name).Clone (); |
||||
} |
||||
|
||||
if ((type.IsReferenceType ?? false) || type.Kind == TypeKind.Dynamic) |
||||
return new NullReferenceExpression (); |
||||
|
||||
var typeDefinition = type.GetDefinition (); |
||||
if (typeDefinition != null) { |
||||
switch (typeDefinition.KnownTypeCode) { |
||||
case KnownTypeCode.Boolean: |
||||
return new PrimitiveExpression (false); |
||||
|
||||
case KnownTypeCode.Char: |
||||
return new PrimitiveExpression ('\0'); |
||||
|
||||
case KnownTypeCode.SByte: |
||||
case KnownTypeCode.Byte: |
||||
case KnownTypeCode.Int16: |
||||
case KnownTypeCode.UInt16: |
||||
case KnownTypeCode.Int32: |
||||
case KnownTypeCode.UInt32: |
||||
case KnownTypeCode.Int64: |
||||
case KnownTypeCode.UInt64: |
||||
case KnownTypeCode.Single: |
||||
case KnownTypeCode.Double: |
||||
case KnownTypeCode.Decimal: |
||||
return new PrimitiveExpression (0); |
||||
|
||||
case KnownTypeCode.NullableOfT: |
||||
return new NullReferenceExpression (); |
||||
} |
||||
if (type.Kind == TypeKind.Struct) |
||||
return new ObjectCreateExpression (astType.Clone ()); |
||||
} |
||||
return new DefaultValueExpression (astType.Clone ()); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,131 @@
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// CreateProperty.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@novell.com>
|
||||
//
|
||||
// Copyright (c) 2011 Novell, Inc (http://www.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; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Create property", Description = "Creates a property for a undefined variable.")] |
||||
public class CreatePropertyAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var identifier = CreateFieldAction.GetCreatePropertyOrFieldNode (context); |
||||
if (identifier == null) |
||||
yield break; |
||||
if (CreateFieldAction.IsInvocationTarget(identifier)) |
||||
yield break; |
||||
|
||||
var propertyName = GetPropertyName(identifier); |
||||
if (propertyName == null) |
||||
yield break; |
||||
|
||||
var statement = context.GetNode<Statement>(); |
||||
if (statement == null) |
||||
yield break; |
||||
|
||||
if (!(context.Resolve(identifier).IsError)) |
||||
yield break; |
||||
|
||||
var guessedType = TypeGuessing.GuessAstType(context, identifier); |
||||
if (guessedType == null) |
||||
yield break; |
||||
var state = context.GetResolverStateBefore(identifier); |
||||
if (state.CurrentTypeDefinition == null) |
||||
yield break; |
||||
|
||||
bool createInOtherType = false; |
||||
ResolveResult targetResolveResult = null; |
||||
if (identifier is MemberReferenceExpression) { |
||||
targetResolveResult = context.Resolve(((MemberReferenceExpression)identifier).Target); |
||||
if (targetResolveResult.Type.GetDefinition() == null || targetResolveResult.Type.GetDefinition().Region.IsEmpty) |
||||
yield break; |
||||
createInOtherType = !state.CurrentTypeDefinition.Equals(targetResolveResult.Type.GetDefinition()); |
||||
} |
||||
|
||||
bool isStatic = targetResolveResult is TypeResolveResult; |
||||
if (createInOtherType) { |
||||
if (isStatic && targetResolveResult.Type.Kind == TypeKind.Interface || targetResolveResult.Type.Kind == TypeKind.Enum) |
||||
yield break; |
||||
} else { |
||||
if (state.CurrentMember == null) |
||||
yield break; |
||||
isStatic |= state.CurrentTypeDefinition.IsStatic; |
||||
if (targetResolveResult == null) |
||||
isStatic |= state.CurrentMember.IsStatic; |
||||
} |
||||
isStatic &= !(identifier is NamedExpression); |
||||
|
||||
// var service = (NamingConventionService)context.GetService(typeof(NamingConventionService));
|
||||
// if (service != null && !service.IsValidName(propertyName, AffectedEntity.Property, Modifiers.Private, isStatic)) {
|
||||
// yield break;
|
||||
// }
|
||||
|
||||
yield return new CodeAction(context.TranslateString("Create property"), script => { |
||||
var decl = new PropertyDeclaration() { |
||||
ReturnType = guessedType, |
||||
Name = propertyName, |
||||
Getter = new Accessor(), |
||||
Setter = new Accessor() |
||||
}; |
||||
if (isStatic) |
||||
decl.Modifiers |= Modifiers.Static; |
||||
|
||||
if (createInOtherType) { |
||||
if (targetResolveResult.Type.Kind == TypeKind.Interface) { |
||||
decl.Modifiers = Modifiers.None; |
||||
} else { |
||||
decl.Modifiers |= Modifiers.Public; |
||||
} |
||||
script.InsertWithCursor( |
||||
context.TranslateString("Create property"), |
||||
targetResolveResult.Type.GetDefinition(), |
||||
(s, c) => decl); |
||||
|
||||
return; |
||||
} |
||||
|
||||
script.InsertWithCursor(context.TranslateString("Create property"), Script.InsertPosition.Before, decl); |
||||
|
||||
}, identifier.GetNodeAt(context.Location) ?? identifier) { Severity = ICSharpCode.NRefactory.Refactoring.Severity.Error }; |
||||
} |
||||
|
||||
internal static string GetPropertyName(Expression expr) |
||||
{ |
||||
if (expr is IdentifierExpression) |
||||
return ((IdentifierExpression)expr).Identifier; |
||||
if (expr is MemberReferenceExpression) |
||||
return ((MemberReferenceExpression)expr).MemberName; |
||||
if (expr is NamedExpression) |
||||
return ((NamedExpression)expr).Name; |
||||
|
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,188 @@
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// DeclareLocalVariableAction.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.Threading; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Declare local variable", Description = "Declare a local variable out of a selected expression.")] |
||||
public class DeclareLocalVariableAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
if (!context.IsSomethingSelected) { |
||||
yield break; |
||||
} |
||||
var selected = new List<AstNode>(context.GetSelectedNodes()); |
||||
|
||||
if (selected.Count != 1 || !(selected [0] is Expression)) { |
||||
yield break; |
||||
} |
||||
|
||||
var expr = selected [0] as Expression; |
||||
if (expr is ArrayInitializerExpression) { |
||||
var arr = (ArrayInitializerExpression)expr; |
||||
if (arr.IsSingleElement) { |
||||
expr = arr.Elements.First(); |
||||
} else { |
||||
yield break; |
||||
} |
||||
} |
||||
|
||||
var visitor = new SearchNodeVisitior(expr); |
||||
|
||||
var node = context.GetNode <BlockStatement>(); |
||||
if (node != null) { |
||||
node.AcceptVisitor(visitor); |
||||
} |
||||
|
||||
yield return new CodeAction(context.TranslateString("Declare local variable"), script => { |
||||
var resolveResult = context.Resolve(expr); |
||||
var guessedType = resolveResult.Type; |
||||
if (resolveResult is MethodGroupResolveResult) { |
||||
guessedType = GetDelegateType(context, ((MethodGroupResolveResult)resolveResult).Methods.First(), expr); |
||||
} |
||||
var name = CreateMethodDeclarationAction.CreateBaseName(expr, guessedType); |
||||
var type = context.UseExplicitTypes ? context.CreateShortType(guessedType) : new SimpleType("var"); |
||||
var varDecl = new VariableDeclarationStatement(type, name, expr.Clone()); |
||||
var replaceNode = visitor.Matches.First () as Expression; |
||||
if (replaceNode.Parent is ExpressionStatement) { |
||||
script.Replace(replaceNode.Parent, varDecl); |
||||
script.Select(varDecl.Variables.First().NameToken); |
||||
} else { |
||||
var containing = replaceNode.Parent; |
||||
while (!(containing.Parent is BlockStatement)) { |
||||
containing = containing.Parent; |
||||
} |
||||
|
||||
script.InsertBefore(containing, varDecl); |
||||
var identifierExpression = new IdentifierExpression(name); |
||||
script.Replace(replaceNode, identifierExpression); |
||||
script.Link(varDecl.Variables.First().NameToken, identifierExpression); |
||||
} |
||||
}, expr); |
||||
|
||||
if (visitor.Matches.Count > 1) { |
||||
yield return new CodeAction(string.Format(context.TranslateString("Declare local variable (replace '{0}' occurrences)"), visitor.Matches.Count), script => { |
||||
var resolveResult = context.Resolve(expr); |
||||
var guessedType = resolveResult.Type; |
||||
if (resolveResult is MethodGroupResolveResult) { |
||||
guessedType = GetDelegateType(context, ((MethodGroupResolveResult)resolveResult).Methods.First(), expr); |
||||
} |
||||
var linkedNodes = new List<AstNode>(); |
||||
var name = CreateMethodDeclarationAction.CreateBaseName(expr, guessedType); |
||||
var type = context.UseExplicitTypes ? context.CreateShortType(guessedType) : new SimpleType("var"); |
||||
var varDecl = new VariableDeclarationStatement(type, name, expr.Clone()); |
||||
linkedNodes.Add(varDecl.Variables.First().NameToken); |
||||
var first = visitor.Matches [0]; |
||||
if (first.Parent is ExpressionStatement) { |
||||
script.Replace(first.Parent, varDecl); |
||||
} else { |
||||
var containing = first.Parent; |
||||
while (!(containing.Parent is BlockStatement)) { |
||||
containing = containing.Parent; |
||||
} |
||||
|
||||
script.InsertBefore(containing, varDecl); |
||||
var identifierExpression = new IdentifierExpression(name); |
||||
linkedNodes.Add(identifierExpression); |
||||
script.Replace(first, identifierExpression); |
||||
} |
||||
for (int i = 1; i < visitor.Matches.Count; i++) { |
||||
var identifierExpression = new IdentifierExpression(name); |
||||
linkedNodes.Add(identifierExpression); |
||||
script.Replace(visitor.Matches [i], identifierExpression); |
||||
} |
||||
script.Link(linkedNodes.ToArray ()); |
||||
}, expr); |
||||
} |
||||
} |
||||
|
||||
// Gets Action/Func delegate types for a given method.
|
||||
IType GetDelegateType(RefactoringContext context, IMethod method, Expression expr) |
||||
{ |
||||
var parameters = new List<IType>(); |
||||
var invoke = expr.Parent as InvocationExpression; |
||||
if (invoke == null) { |
||||
return null; |
||||
} |
||||
foreach (var arg in invoke.Arguments) { |
||||
parameters.Add(context.Resolve(arg).Type); |
||||
} |
||||
|
||||
ITypeDefinition genericType; |
||||
if (method.ReturnType.FullName == "System.Void") { |
||||
genericType = context.Compilation.GetAllTypeDefinitions().FirstOrDefault(t => t.FullName == "System.Action" && t.TypeParameterCount == parameters.Count); |
||||
} else { |
||||
parameters.Add(method.ReturnType); |
||||
genericType = context.Compilation.GetAllTypeDefinitions().FirstOrDefault(t => t.FullName == "System.Func" && t.TypeParameterCount == parameters.Count); |
||||
} |
||||
if (genericType == null) { |
||||
return null; |
||||
} |
||||
return new ParameterizedType(genericType, parameters); |
||||
} |
||||
|
||||
|
||||
internal class SearchNodeVisitior : DepthFirstAstVisitor |
||||
{ |
||||
readonly AstNode searchForNode; |
||||
public readonly List<AstNode> Matches = new List<AstNode> (); |
||||
|
||||
public SearchNodeVisitior (AstNode searchForNode) |
||||
{ |
||||
this.searchForNode = searchForNode; |
||||
AddNode (searchForNode); |
||||
} |
||||
|
||||
void AddNode(AstNode node) |
||||
{ |
||||
if (node.Parent is ParenthesizedExpression) { |
||||
Matches.Add(node.Parent); |
||||
} else { |
||||
Matches.Add(node); |
||||
} |
||||
} |
||||
|
||||
protected override void VisitChildren(AstNode node) |
||||
{ |
||||
if (node.StartLocation > searchForNode.StartLocation && node.IsMatch(searchForNode)) { |
||||
AddNode(node); |
||||
return; |
||||
} |
||||
base.VisitChildren (node); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// ExtensionMethodInvocationToStaticMethodInvocationAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Simon Lindgren <simon.n.lindgren@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Simon Lindgren
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Invoke using static method syntax", |
||||
Description = "Converts the call into static method call syntax.")] |
||||
public class ExtensionMethodInvocationToStaticMethodInvocationAction : CodeActionProvider |
||||
{ |
||||
#region ICodeActionProvider implementation
|
||||
|
||||
public override IEnumerable<CodeAction> GetActions (RefactoringContext context) |
||||
{ |
||||
var invocation = context.GetNode<InvocationExpression>(); |
||||
if (invocation == null) |
||||
yield break; |
||||
var memberReference = invocation.Target as MemberReferenceExpression; |
||||
if (memberReference == null) |
||||
yield break; |
||||
var invocationRR = context.Resolve(invocation) as CSharpInvocationResolveResult; |
||||
if (invocationRR == null) |
||||
yield break; |
||||
if (invocationRR.IsExtensionMethodInvocation) |
||||
yield return new CodeAction(context.TranslateString("Convert to static method call"), script => { |
||||
script.Replace(invocation, ToStaticMethodInvocation(invocation, memberReference, invocationRR)); |
||||
}, invocation); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
AstNode ToStaticMethodInvocation(InvocationExpression invocation, MemberReferenceExpression memberReference, |
||||
CSharpInvocationResolveResult invocationRR) |
||||
{ |
||||
var newArgumentList = invocation.Arguments.Select(arg => arg.Clone()).ToList(); |
||||
newArgumentList.Insert(0, memberReference.Target.Clone()); |
||||
var newTarget = memberReference.Clone() as MemberReferenceExpression; |
||||
newTarget.Target = new IdentifierExpression(invocationRR.Member.DeclaringType.Name); |
||||
return new InvocationExpression(newTarget, newArgumentList); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,120 @@
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// ExtractAnonymousMethodAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mansheng Yang <lightyang0@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2012 Mansheng Yang <lightyang0@gmail.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.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction ("Extract anonymous method", |
||||
Description = "Extract anonymous method to method of the containing type")] |
||||
public class ExtractAnonymousMethodAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions (RefactoringContext context) |
||||
{ |
||||
// lambda
|
||||
var lambda = context.GetNode<LambdaExpression> (); |
||||
if (lambda != null && lambda.ArrowToken.Contains(context.Location)) { |
||||
if (ContainsLocalReferences (context, lambda, lambda.Body)) |
||||
yield break; |
||||
|
||||
bool noReturn = false; |
||||
BlockStatement body; |
||||
if (lambda.Body is BlockStatement) { |
||||
body = (BlockStatement)lambda.Body.Clone (); |
||||
} else { |
||||
if (!(lambda.Body is Expression)) |
||||
yield break; |
||||
body = new BlockStatement (); |
||||
|
||||
var type = LambdaHelper.GetLambdaReturnType (context, lambda); |
||||
if (type == null || type.ReflectionName == "System.Void") { |
||||
noReturn = true; |
||||
body.Add ((Expression)lambda.Body.Clone ()); |
||||
} else { |
||||
body.Add (new ReturnStatement ((Expression)lambda.Body.Clone ())); |
||||
} |
||||
} |
||||
var method = GetMethod (context, (LambdaResolveResult)context.Resolve (lambda), body, noReturn); |
||||
yield return GetAction (context, lambda, method); |
||||
} |
||||
|
||||
// anonymous method
|
||||
var anonymousMethod = context.GetNode<AnonymousMethodExpression> (); |
||||
if (anonymousMethod != null && anonymousMethod.DelegateToken.Contains(context.Location)) { |
||||
if (ContainsLocalReferences (context, anonymousMethod, anonymousMethod.Body)) |
||||
yield break; |
||||
|
||||
var method = GetMethod (context, (LambdaResolveResult)context.Resolve (anonymousMethod), |
||||
(BlockStatement)anonymousMethod.Body.Clone ()); |
||||
yield return GetAction (context, anonymousMethod, method); |
||||
} |
||||
} |
||||
|
||||
CodeAction GetAction (RefactoringContext context, AstNode node, MethodDeclaration method) |
||||
{ |
||||
return new CodeAction (context.TranslateString ("Extract anonymous method"), |
||||
script => |
||||
{ |
||||
var identifier = new IdentifierExpression ("Method"); |
||||
script.Replace (node, identifier); |
||||
script.InsertBefore (node.GetParent<EntityDeclaration> (), method); |
||||
script.Link (method.NameToken, identifier); |
||||
}, method.NameToken); |
||||
} |
||||
|
||||
static MethodDeclaration GetMethod (RefactoringContext context, LambdaResolveResult lambda, BlockStatement body, |
||||
bool noReturnValue = false) |
||||
{ |
||||
var method = new MethodDeclaration { Name = "Method" }; |
||||
|
||||
if (noReturnValue) { |
||||
method.ReturnType = new PrimitiveType ("void"); |
||||
} else { |
||||
var type = lambda.ReturnType; |
||||
method.ReturnType = type.Kind == TypeKind.Unknown ? new PrimitiveType ("void") : context.CreateShortType (type); |
||||
} |
||||
|
||||
foreach (var param in lambda.Parameters) |
||||
method.Parameters.Add (new ParameterDeclaration (context.CreateShortType (param.Type), param.Name)); |
||||
|
||||
method.Body = body; |
||||
if (lambda.IsAsync) |
||||
method.Modifiers |= Modifiers.Async; |
||||
|
||||
return method; |
||||
} |
||||
|
||||
static bool ContainsLocalReferences (RefactoringContext context, AstNode expr, AstNode body) |
||||
{ |
||||
var visitor = new ExtractMethod.VariableLookupVisitor (context); |
||||
body.AcceptVisitor (visitor); |
||||
return visitor.UsedVariables.Any (variable => !expr.Contains (variable.Region.Begin)); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// ExtractFieldAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Nieve <>
|
||||
//
|
||||
// Copyright (c) 2012 Nieve
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
using Mono.CSharp; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Extract field", Description = "Extracts a field from a local variable declaration.")] |
||||
public class ExtractFieldAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
//TODO: implement variable assignment & ctor param
|
||||
var varInit = context.GetNode<VariableInitializer>(); |
||||
if (varInit != null) { |
||||
var selectedNode = varInit.GetNodeAt(context.Location); |
||||
if (selectedNode != varInit.NameToken) |
||||
yield break; |
||||
|
||||
AstType type = varInit.GetPrevNode() as AstType; |
||||
if (type == null) yield break; |
||||
if (varInit.Parent is FieldDeclaration) yield break; |
||||
if (CannotExtractField(context, varInit)) yield break; |
||||
|
||||
yield return new CodeAction(context.TranslateString("Assign to new field"), s=>{ |
||||
var name = varInit.Name; |
||||
|
||||
AstType extractedType; |
||||
if (type.IsVar()) { |
||||
IType resolvedType = context.Resolve(varInit.Initializer).Type; |
||||
extractedType = context.CreateShortType(resolvedType); |
||||
} |
||||
else { |
||||
extractedType = (AstType) type.Clone(); |
||||
} |
||||
|
||||
AstNode entityDeclarationNode = varInit.Parent; |
||||
while (!(entityDeclarationNode is EntityDeclaration) || (entityDeclarationNode is Accessor)) { |
||||
entityDeclarationNode = entityDeclarationNode.Parent; |
||||
} |
||||
var entity = (EntityDeclaration) entityDeclarationNode; |
||||
bool isStatic = entity.HasModifier(Modifiers.Static); |
||||
|
||||
FieldDeclaration field = new FieldDeclaration(){ |
||||
Modifiers = isStatic ? Modifiers.Static : Modifiers.None, |
||||
ReturnType = extractedType, |
||||
Variables = { new VariableInitializer(name) } |
||||
}; |
||||
AstNode nodeToRemove = RemoveDeclaration(varInit) ? varInit.Parent : type; |
||||
s.Remove(nodeToRemove, true); |
||||
s.InsertWithCursor(context.TranslateString("Insert new field"),Script.InsertPosition.Before,field); |
||||
s.FormatText(varInit.Parent); |
||||
}, selectedNode); |
||||
} |
||||
|
||||
var idntf = context.GetNode<Identifier>(); |
||||
if (idntf == null) yield break; |
||||
var paramDec = idntf.Parent as ParameterDeclaration; |
||||
if (paramDec != null) { |
||||
var ctor = paramDec.Parent as ConstructorDeclaration; |
||||
if (ctor == null) yield break; |
||||
MemberReferenceExpression thisField = new MemberReferenceExpression(new ThisReferenceExpression(), idntf.Name, new AstType[]{}); |
||||
var assign = new AssignmentExpression(thisField, AssignmentOperatorType.Assign, new IdentifierExpression(idntf.Name)); |
||||
var statement = new ExpressionStatement(assign); |
||||
var type = (idntf.GetPrevNode() as AstType).Clone(); |
||||
FieldDeclaration field = new FieldDeclaration(){ |
||||
ReturnType = type.Clone(), |
||||
Variables = { new VariableInitializer(idntf.Name) } |
||||
}; |
||||
yield return new CodeAction(context.TranslateString("Assign to new field"), s=>{ |
||||
s.InsertWithCursor(context.TranslateString("Insert new field"),Script.InsertPosition.Before,field); |
||||
s.AddTo(ctor.Body, statement); |
||||
}, paramDec.NameToken); |
||||
} |
||||
} |
||||
|
||||
static bool RemoveDeclaration (VariableInitializer varInit){ |
||||
var result = varInit.Parent as VariableDeclarationStatement; |
||||
return result.Variables.First ().Initializer.IsNull; |
||||
} |
||||
|
||||
static bool CannotExtractField (RefactoringContext context, VariableInitializer varInit) |
||||
{ |
||||
var result = varInit.Parent as VariableDeclarationStatement; |
||||
return result == null || result.Variables.Count != 1 || ContainsAnonymousType(context.Resolve(varInit.Initializer).Type); |
||||
} |
||||
|
||||
static bool ContainsAnonymousType (IType type) |
||||
{ |
||||
if (type.Kind == TypeKind.Anonymous) |
||||
return true; |
||||
|
||||
var arrayType = type as ArrayType; |
||||
return arrayType != null && ContainsAnonymousType (arrayType.ElementType); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,243 @@
@@ -0,0 +1,243 @@
|
||||
//
|
||||
// ExtractMethodAction.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; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
using ICSharpCode.NRefactory.CSharp.Analysis; |
||||
using System.Threading; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod |
||||
{ |
||||
[ContextAction("Extract method", Description = "Creates a new method out of selected text.")] |
||||
public class ExtractMethodAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
if (!context.IsSomethingSelected) |
||||
yield break; |
||||
var selected = new List<AstNode>(context.GetSelectedNodes()); |
||||
if (selected.Count == 0) |
||||
yield break; |
||||
|
||||
if (selected.Count == 1 && selected [0] is Expression) { |
||||
var codeAction = CreateFromExpression(context, (Expression)selected [0]); |
||||
if (codeAction == null) |
||||
yield break; |
||||
yield return codeAction; |
||||
} |
||||
|
||||
foreach (var node in selected) { |
||||
if (!(node is Statement) && !(node is Comment) && !(node is NewLineNode) && !(node is PreProcessorDirective)) |
||||
yield break; |
||||
} |
||||
var action = CreateFromStatements (context, new List<AstNode> (selected)); |
||||
if (action != null) |
||||
yield return action; |
||||
} |
||||
|
||||
CodeAction CreateFromExpression(RefactoringContext context, Expression expression) |
||||
{ |
||||
var resolveResult = context.Resolve(expression); |
||||
if (resolveResult.IsError) |
||||
return null; |
||||
|
||||
return new CodeAction(context.TranslateString("Extract method"), script => { |
||||
string methodName = "NewMethod"; |
||||
var method = new MethodDeclaration { |
||||
ReturnType = context.CreateShortType(resolveResult.Type), |
||||
Name = methodName, |
||||
Body = new BlockStatement { |
||||
new ReturnStatement(expression.Clone()) |
||||
} |
||||
}; |
||||
if (!StaticVisitor.UsesNotStaticMember(context, expression)) |
||||
method.Modifiers |= Modifiers.Static; |
||||
|
||||
var usedVariables = VariableLookupVisitor.Analyze(context, expression); |
||||
|
||||
var inExtractedRegion = new VariableUsageAnalyzation (context, usedVariables); |
||||
|
||||
usedVariables.Sort ((l, r) => l.Region.Begin.CompareTo (r.Region.Begin)); |
||||
var target = new IdentifierExpression(methodName); |
||||
var invocation = new InvocationExpression(target); |
||||
foreach (var variable in usedVariables) { |
||||
Expression argumentExpression = new IdentifierExpression(variable.Name); |
||||
|
||||
var mod = ParameterModifier.None; |
||||
if (inExtractedRegion.GetStatus (variable) == VariableState.Changed) { |
||||
mod = ParameterModifier.Ref; |
||||
argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression); |
||||
} |
||||
|
||||
method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(variable.Type), variable.Name, mod)); |
||||
invocation.Arguments.Add(argumentExpression); |
||||
} |
||||
|
||||
script |
||||
.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method) |
||||
.ContinueScript (delegate { |
||||
script.Replace(expression, invocation); |
||||
script.Link(target, method.NameToken); |
||||
}); |
||||
}, expression); |
||||
} |
||||
|
||||
CodeAction CreateFromStatements(RefactoringContext context, List<AstNode> statements) |
||||
{ |
||||
if (!(statements [0].Parent is Statement)) |
||||
return null; |
||||
|
||||
return new CodeAction(context.TranslateString("Extract method"), script => { |
||||
string methodName = "NewMethod"; |
||||
var method = new MethodDeclaration() { |
||||
ReturnType = new PrimitiveType("void"), |
||||
Name = methodName, |
||||
Body = new BlockStatement() |
||||
}; |
||||
bool usesNonStaticMember = false; |
||||
foreach (var node in statements) { |
||||
usesNonStaticMember |= StaticVisitor.UsesNotStaticMember(context, node); |
||||
if (node is Statement) { |
||||
method.Body.Add((Statement)node.Clone()); |
||||
} else { |
||||
method.Body.AddChildUnsafe (node.Clone (), node.Role); |
||||
} |
||||
} |
||||
if (!usesNonStaticMember) |
||||
method.Modifiers |= Modifiers.Static; |
||||
|
||||
var target = new IdentifierExpression(methodName); |
||||
var invocation = new InvocationExpression(target); |
||||
|
||||
var usedVariables = VariableLookupVisitor.Analyze(context, statements); |
||||
|
||||
var inExtractedRegion = new VariableUsageAnalyzation (context, usedVariables); |
||||
var lastStatement = statements [statements.Count - 1]; |
||||
|
||||
var stmt = statements [0].GetParent<BlockStatement>(); |
||||
while (stmt.GetParent<BlockStatement> () != null) { |
||||
stmt = stmt.GetParent<BlockStatement>(); |
||||
} |
||||
|
||||
inExtractedRegion.SetAnalyzedRange(statements [0], lastStatement); |
||||
stmt.AcceptVisitor (inExtractedRegion); |
||||
|
||||
var beforeExtractedRegion = new VariableUsageAnalyzation (context, usedVariables); |
||||
beforeExtractedRegion.SetAnalyzedRange(statements [0].Parent, statements [0], true, false); |
||||
stmt.AcceptVisitor (beforeExtractedRegion); |
||||
|
||||
var afterExtractedRegion = new VariableUsageAnalyzation (context, usedVariables); |
||||
afterExtractedRegion.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true); |
||||
stmt.AcceptVisitor (afterExtractedRegion); |
||||
usedVariables.Sort ((l, r) => l.Region.Begin.CompareTo (r.Region.Begin)); |
||||
|
||||
IVariable generatedReturnVariable = null; |
||||
foreach (var variable in usedVariables) { |
||||
if ((variable is IParameter) || beforeExtractedRegion.Has (variable) || !afterExtractedRegion.Has (variable)) |
||||
continue; |
||||
generatedReturnVariable = variable; |
||||
method.ReturnType = context.CreateShortType (variable.Type); |
||||
method.Body.Add (new ReturnStatement (new IdentifierExpression (variable.Name))); |
||||
break; |
||||
} |
||||
|
||||
int parameterOutCount = 0; |
||||
foreach (var variable in usedVariables) { |
||||
if (!(variable is IParameter) && !beforeExtractedRegion.Has (variable) && !afterExtractedRegion.Has (variable)) |
||||
continue; |
||||
if (variable == generatedReturnVariable) |
||||
continue; |
||||
Expression argumentExpression = new IdentifierExpression(variable.Name); |
||||
|
||||
ParameterModifier mod = ParameterModifier.None; |
||||
if (inExtractedRegion.GetStatus (variable) == VariableState.Changed) { |
||||
if (beforeExtractedRegion.GetStatus (variable) == VariableState.None) { |
||||
mod = ParameterModifier.Out; |
||||
argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression); |
||||
parameterOutCount++; |
||||
} else { |
||||
mod = ParameterModifier.Ref; |
||||
argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression); |
||||
} |
||||
} |
||||
|
||||
method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(variable.Type), variable.Name, mod)); |
||||
invocation.Arguments.Add(argumentExpression); |
||||
} |
||||
|
||||
ParameterDeclaration parameterToTransform = null; |
||||
bool transformParameterToReturn = method.ReturnType is PrimitiveType && |
||||
((PrimitiveType)method.ReturnType).Keyword == "void" && |
||||
parameterOutCount == 1; |
||||
if(transformParameterToReturn) { |
||||
parameterToTransform = method.Parameters.First(p => p.ParameterModifier == ParameterModifier.Out); |
||||
parameterToTransform.Remove(); |
||||
var argumentExpression = invocation.Arguments.OfType<DirectionExpression>().First(a => a.FieldDirection == FieldDirection.Out); |
||||
argumentExpression.Remove(); |
||||
method.ReturnType = parameterToTransform.Type.Clone(); |
||||
var argumentDecl = new VariableDeclarationStatement(parameterToTransform.Type.Clone(),parameterToTransform.Name); |
||||
method.Body.InsertChildBefore(method.Body.First(),argumentDecl,BlockStatement.StatementRole); |
||||
method.Body.Add(new ReturnStatement (new IdentifierExpression (parameterToTransform.Name))); |
||||
} |
||||
|
||||
script |
||||
.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method) |
||||
.ContinueScript(delegate { |
||||
foreach (var node in statements.Skip (1)) { |
||||
if (node is NewLineNode) |
||||
continue; |
||||
script.Remove(node); |
||||
} |
||||
foreach (var variable in usedVariables) { |
||||
if ((variable is IParameter) || beforeExtractedRegion.Has (variable) || !afterExtractedRegion.Has (variable)) |
||||
continue; |
||||
if (variable == generatedReturnVariable) |
||||
continue; |
||||
script.InsertBefore (statements [0], new VariableDeclarationStatement (context.CreateShortType(variable.Type), variable.Name)); |
||||
} |
||||
Statement invocationStatement; |
||||
|
||||
if (generatedReturnVariable != null) { |
||||
invocationStatement = new VariableDeclarationStatement (new SimpleType ("var"), generatedReturnVariable.Name, invocation); |
||||
} else if(transformParameterToReturn) { |
||||
invocationStatement = new AssignmentExpression(new IdentifierExpression(parameterToTransform.Name), invocation); |
||||
} else { |
||||
invocationStatement = invocation; |
||||
} |
||||
|
||||
script.Replace(statements [0], invocationStatement); |
||||
|
||||
|
||||
script.Link(target, method.NameToken); |
||||
}); |
||||
}, statements.First ().StartLocation, statements.Last ().EndLocation); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// StaticVisitor.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; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp.Resolver; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod |
||||
{ |
||||
class StaticVisitor : DepthFirstAstVisitor |
||||
{ |
||||
readonly BaseRefactoringContext context; |
||||
public bool UsesNonStaticMember = false; |
||||
|
||||
StaticVisitor(BaseRefactoringContext context) |
||||
{ |
||||
this.context = context; |
||||
} |
||||
|
||||
|
||||
public static bool UsesNotStaticMember(BaseRefactoringContext context, AstNode node) |
||||
{ |
||||
var visitor = new StaticVisitor(context); |
||||
node.AcceptVisitor(visitor); |
||||
return visitor.UsesNonStaticMember; |
||||
} |
||||
|
||||
protected override void VisitChildren(AstNode node) |
||||
{ |
||||
if (UsesNonStaticMember) |
||||
return; |
||||
base.VisitChildren(node); |
||||
} |
||||
|
||||
public override void VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression) |
||||
{ |
||||
UsesNonStaticMember = true; |
||||
base.VisitThisReferenceExpression(thisReferenceExpression); |
||||
} |
||||
|
||||
public override void VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression) |
||||
{ |
||||
UsesNonStaticMember = true; |
||||
base.VisitBaseReferenceExpression(baseReferenceExpression); |
||||
} |
||||
|
||||
public override void VisitIdentifierExpression(IdentifierExpression identifierExpression) |
||||
{ |
||||
var resolveResult = context.Resolve(identifierExpression); |
||||
if (resolveResult is MemberResolveResult) { |
||||
var memberResult = (MemberResolveResult)resolveResult; |
||||
if (!memberResult.Member.IsStatic) |
||||
UsesNonStaticMember = true; |
||||
} else if (resolveResult is MethodGroupResolveResult) { |
||||
var methodGroupResolveResult = (MethodGroupResolveResult)resolveResult; |
||||
if (methodGroupResolveResult.Methods.Any(m => !m.IsStatic)) |
||||
UsesNonStaticMember = true; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// VariableLookupVisitor.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; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring.ExtractMethod |
||||
{ |
||||
class VariableLookupVisitor : DepthFirstAstVisitor |
||||
{ |
||||
readonly RefactoringContext context; |
||||
|
||||
public List<IVariable> UsedVariables = new List<IVariable> (); |
||||
|
||||
TextLocation startLocation = TextLocation.Empty; |
||||
TextLocation endLocation = TextLocation.Empty; |
||||
|
||||
public VariableLookupVisitor (RefactoringContext context) |
||||
{ |
||||
this.context = context; |
||||
} |
||||
|
||||
public bool Has (IVariable item1) |
||||
{ |
||||
return UsedVariables.Contains (item1); |
||||
} |
||||
|
||||
public void SetAnalyzedRange(AstNode start, AstNode end, bool startInclusive = true, bool endInclusive = true) |
||||
{ |
||||
if (start == null) |
||||
throw new ArgumentNullException("start"); |
||||
if (end == null) |
||||
throw new ArgumentNullException("end"); |
||||
startLocation = startInclusive ? start.StartLocation : start.EndLocation; |
||||
endLocation = endInclusive ? end.EndLocation : end.StartLocation; |
||||
} |
||||
|
||||
public override void VisitIdentifierExpression(IdentifierExpression identifierExpression) |
||||
{ |
||||
if (startLocation.IsEmpty || startLocation <= identifierExpression.StartLocation && identifierExpression.EndLocation <= endLocation) { |
||||
var result = context.Resolve(identifierExpression); |
||||
var local = result as LocalResolveResult; |
||||
if (local != null && !UsedVariables.Contains(local.Variable)&& !anonymousParameters.Contains(local.Variable)) { |
||||
UsedVariables.Add(local.Variable); |
||||
} |
||||
} |
||||
} |
||||
|
||||
HashSet<IVariable> anonymousParameters = new HashSet<IVariable> (); |
||||
public override void VisitLambdaExpression(LambdaExpression lambdaExpression) |
||||
{ |
||||
foreach (var param in lambdaExpression.Parameters) { |
||||
var result = context.Resolve(param); |
||||
var local = result as LocalResolveResult; |
||||
anonymousParameters.Add(local.Variable); |
||||
} |
||||
base.VisitLambdaExpression(lambdaExpression); |
||||
foreach (var param in lambdaExpression.Parameters) { |
||||
var result = context.Resolve(param); |
||||
var local = result as LocalResolveResult; |
||||
anonymousParameters.Remove(local.Variable); |
||||
} |
||||
} |
||||
|
||||
public override void VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) |
||||
{ |
||||
foreach (var param in anonymousMethodExpression.Parameters) { |
||||
var result = context.Resolve(param); |
||||
var local = result as LocalResolveResult; |
||||
anonymousParameters.Add(local.Variable); |
||||
} |
||||
|
||||
|
||||
base.VisitAnonymousMethodExpression(anonymousMethodExpression); |
||||
foreach (var param in anonymousMethodExpression.Parameters) { |
||||
var result = context.Resolve(param); |
||||
var local = result as LocalResolveResult; |
||||
anonymousParameters.Remove(local.Variable); |
||||
} |
||||
} |
||||
|
||||
public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) |
||||
{ |
||||
base.VisitVariableDeclarationStatement(variableDeclarationStatement); |
||||
foreach (var varDecl in variableDeclarationStatement.Variables) { |
||||
if (startLocation.IsEmpty || startLocation <= varDecl.StartLocation && varDecl.EndLocation <= endLocation) { |
||||
var result = context.Resolve(varDecl); |
||||
var local = result as LocalResolveResult; |
||||
if (local != null && !UsedVariables.Contains(local.Variable) && !anonymousParameters.Contains(local.Variable)) |
||||
UsedVariables.Add(local.Variable); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
public static List<IVariable> Analyze(RefactoringContext context, Expression expression) |
||||
{ |
||||
var visitor = new VariableLookupVisitor(context); |
||||
expression.AcceptVisitor(visitor); |
||||
return visitor.UsedVariables; |
||||
} |
||||
|
||||
public static List<IVariable> Analyze(RefactoringContext context, List<AstNode> statements) |
||||
{ |
||||
var visitor = new VariableLookupVisitor(context); |
||||
statements.ForEach(stmt => stmt.AcceptVisitor(visitor)); |
||||
return visitor.UsedVariables; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// ExtractWhileConditionToInternalIfStatementAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
using Mono.CSharp; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Extract field", Description = "Extracts a field from a local variable declaration.")] |
||||
public class ExtractWhileConditionToInternalIfStatementAction : SpecializedCodeAction<WhileStatement> |
||||
{ |
||||
protected override CodeAction GetAction(RefactoringContext context, WhileStatement node) |
||||
{ |
||||
if (!node.WhileToken.Contains(context.Location)) |
||||
return null; |
||||
|
||||
return new CodeAction( |
||||
context.TranslateString("Extract condition to internal 'if' statement"), |
||||
script => { |
||||
script.Replace(node.Condition, new PrimitiveExpression(true)); |
||||
var ifStmt = new IfElseStatement( |
||||
CSharpUtil.InvertCondition(node.Condition), |
||||
new BreakStatement() |
||||
); |
||||
|
||||
var block = node.EmbeddedStatement as BlockStatement; |
||||
if (block != null) { |
||||
script.InsertAfter(block.LBraceToken, ifStmt); |
||||
} else { |
||||
var blockStatement = new BlockStatement { |
||||
ifStmt |
||||
}; |
||||
if (!(node.EmbeddedStatement is EmptyStatement)) |
||||
blockStatement.Statements.Add(node.EmbeddedStatement.Clone()); |
||||
script.Replace(node.EmbeddedStatement, blockStatement); |
||||
} |
||||
}, |
||||
node |
||||
); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,96 @@
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// FlipEqualsQualifierAndArgumentAction.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
using ICSharpCode.NRefactory.TypeSystem; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Swap 'Equals' target and argument", Description = "Swap 'Equals' target and argument")] |
||||
public class FlipEqualsTargetAndArgumentAction : CodeActionProvider |
||||
{ |
||||
Expression GetInnerMostExpression(Expression target) |
||||
{ |
||||
while (target is ParenthesizedExpression) |
||||
target = ((ParenthesizedExpression)target).Expression; |
||||
return target; |
||||
} |
||||
|
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var invocation = context.GetNode<InvocationExpression>(); |
||||
if (invocation == null) |
||||
yield break; |
||||
if (invocation.Arguments.Count != 1 || invocation.Arguments.First() is NullReferenceExpression) |
||||
yield break; |
||||
var target = invocation.Target as MemberReferenceExpression; |
||||
|
||||
if (target == null || target.MemberNameToken.StartLocation > context.Location || invocation.LParToken.StartLocation < context.Location) |
||||
yield break; |
||||
|
||||
var rr = context.Resolve(invocation) as InvocationResolveResult; |
||||
if (rr == null || rr.Member.Name != "Equals" || rr.Member.IsStatic || !rr.Member.ReturnType.IsKnownType(KnownTypeCode.Boolean)) |
||||
yield break; |
||||
|
||||
yield return new CodeAction( |
||||
context.TranslateString("Flip 'Equals' target and argument"), |
||||
script => { |
||||
script.Replace( |
||||
invocation, |
||||
new InvocationExpression( |
||||
new MemberReferenceExpression( |
||||
AddParensIfRequired(invocation.Arguments.First ().Clone()), |
||||
"Equals" |
||||
), |
||||
GetInnerMostExpression (target.Target).Clone() |
||||
) |
||||
); |
||||
}, |
||||
invocation |
||||
); |
||||
} |
||||
|
||||
Expression AddParensIfRequired(Expression expression) |
||||
{ |
||||
if ((expression is BinaryOperatorExpression) || |
||||
(expression is UnaryOperatorExpression) || |
||||
(expression is CastExpression) || |
||||
(expression is AssignmentExpression) || |
||||
(expression is AsExpression) || |
||||
(expression is IsExpression) || |
||||
(expression is LambdaExpression) || |
||||
(expression is ConditionalExpression)) { |
||||
return new ParenthesizedExpression(expression); |
||||
} |
||||
|
||||
return expression; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// FlipOperatorArguments.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; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Swaps left and right arguments.", Description = "Swaps left and right arguments.")] |
||||
public class FlipOperatorArgumentsAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var binop = GetBinaryOperatorExpression(context); |
||||
if (binop == null) { |
||||
yield break; |
||||
} |
||||
|
||||
|
||||
yield return new CodeAction(string.Format(context.TranslateString("Flip '{0}' operator arguments"), binop.OperatorToken.ToString()), script => { |
||||
script.Replace(binop.Left, binop.Right.Clone()); |
||||
script.Replace(binop.Right, binop.Left.Clone()); |
||||
}, binop.OperatorToken); |
||||
} |
||||
|
||||
public static BinaryOperatorExpression GetBinaryOperatorExpression (RefactoringContext context) |
||||
{ |
||||
var node = context.GetNode<BinaryOperatorExpression> (); |
||||
|
||||
if (node == null || !node.OperatorToken.Contains (context.Location)) |
||||
return null; |
||||
var result = node as BinaryOperatorExpression; |
||||
if (result == null || (result.Operator != BinaryOperatorType.Equality && result.Operator != BinaryOperatorType.InEquality)) |
||||
return null; |
||||
return result; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// GenerateGetter.cs
|
||||
//
|
||||
// Author:
|
||||
// Mike Krüger <mkrueger@novell.com>
|
||||
//
|
||||
// Copyright (c) 2011 Novell, Inc (http://www.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 ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Generate getter", Description = "Generates a getter for a field.")] |
||||
public class GenerateGetterAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var initializer = GetVariableInitializer(context); |
||||
if (initializer == null || !initializer.NameToken.Contains(context.Location)) { |
||||
yield break; |
||||
} |
||||
var type = initializer.Parent.Parent as TypeDeclaration; |
||||
if (type == null) { |
||||
yield break; |
||||
} |
||||
foreach (var member in type.Members) { |
||||
if (member is PropertyDeclaration && ContainsGetter((PropertyDeclaration)member, initializer)) { |
||||
yield break; |
||||
} |
||||
} |
||||
var field = initializer.Parent as FieldDeclaration; |
||||
if (field == null) { |
||||
yield break; |
||||
} |
||||
|
||||
yield return new CodeAction(context.TranslateString("Create getter"), script => { |
||||
script.InsertWithCursor( |
||||
context.TranslateString("Create getter"), |
||||
Script.InsertPosition.After, |
||||
GeneratePropertyDeclaration(context, field, initializer)); |
||||
}, initializer); |
||||
} |
||||
|
||||
static PropertyDeclaration GeneratePropertyDeclaration (RefactoringContext context, FieldDeclaration field, VariableInitializer initializer) |
||||
{ |
||||
var mod = ICSharpCode.NRefactory.CSharp.Modifiers.Public; |
||||
if (field.HasModifier (ICSharpCode.NRefactory.CSharp.Modifiers.Static)) |
||||
mod |= ICSharpCode.NRefactory.CSharp.Modifiers.Static; |
||||
|
||||
return new PropertyDeclaration () { |
||||
Modifiers = mod, |
||||
Name = context.GetNameProposal (initializer.Name, false), |
||||
ReturnType = field.ReturnType.Clone (), |
||||
Getter = new Accessor () { |
||||
Body = new BlockStatement () { |
||||
new ReturnStatement (new IdentifierExpression (initializer.Name)) |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
bool ContainsGetter (PropertyDeclaration property, VariableInitializer initializer) |
||||
{ |
||||
if (property.Getter.IsNull || property.Getter.Body.Statements.Count () != 1) |
||||
return false; |
||||
var ret = property.Getter.Body.Statements.Single () as ReturnStatement; |
||||
if (ret == null) |
||||
return false; |
||||
return ret.Expression.IsMatch (new IdentifierExpression (initializer.Name)) || |
||||
ret.Expression.IsMatch (new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name)); |
||||
} |
||||
|
||||
VariableInitializer GetVariableInitializer (RefactoringContext context) |
||||
{ |
||||
return context.GetNode<VariableInitializer> (); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,108 @@
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// GenerateProperty.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; |
||||
using ICSharpCode.NRefactory.PatternMatching; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.NRefactory.Semantics; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||
{ |
||||
[ContextAction("Generate property", Description = "Generates a getter and setter for a field.")] |
||||
public class GeneratePropertyAction : CodeActionProvider |
||||
{ |
||||
public override IEnumerable<CodeAction> GetActions(RefactoringContext context) |
||||
{ |
||||
var initializer = context.GetNode<VariableInitializer>(); |
||||
if (initializer == null || !initializer.NameToken.Contains(context.Location.Line, context.Location.Column)) { |
||||
yield break; |
||||
} |
||||
var type = initializer.Parent.Parent as TypeDeclaration; |
||||
if (type == null) { |
||||
yield break; |
||||
} |
||||
foreach (var member in type.Members) { |
||||
if (member is PropertyDeclaration && ContainsGetter((PropertyDeclaration)member, initializer)) { |
||||
yield break; |
||||
} |
||||
} |
||||
var field = initializer.Parent as FieldDeclaration; |
||||
if (field == null || field.HasModifier(Modifiers.Readonly) || field.HasModifier(Modifiers.Const)) { |
||||
yield break; |
||||
} |
||||
var resolveResult = context.Resolve(initializer) as MemberResolveResult; |
||||
if (resolveResult == null) |
||||
yield break; |
||||
yield return new CodeAction(context.TranslateString("Create property"), script => { |
||||
var fieldName = context.GetNameProposal(initializer.Name, true); |
||||
if (initializer.Name == context.GetNameProposal(initializer.Name, false)) { |
||||
script.Rename(resolveResult.Member, fieldName); |
||||
} |
||||
script.InsertWithCursor( |
||||
context.TranslateString("Create property"), |
||||
Script.InsertPosition.After, GeneratePropertyDeclaration(context, field, fieldName)); |
||||
}, initializer); |
||||
} |
||||
|
||||
static PropertyDeclaration GeneratePropertyDeclaration (RefactoringContext context, FieldDeclaration field, string fieldName) |
||||
{ |
||||
var mod = ICSharpCode.NRefactory.CSharp.Modifiers.Public; |
||||
if (field.HasModifier (ICSharpCode.NRefactory.CSharp.Modifiers.Static)) |
||||
mod |= ICSharpCode.NRefactory.CSharp.Modifiers.Static; |
||||
|
||||
return new PropertyDeclaration () { |
||||
Modifiers = mod, |
||||
Name = context.GetNameProposal (fieldName, false), |
||||
ReturnType = field.ReturnType.Clone (), |
||||
Getter = new Accessor { |
||||
Body = new BlockStatement { |
||||
new ReturnStatement (new IdentifierExpression (fieldName)) |
||||
} |
||||
}, |
||||
Setter = new Accessor { |
||||
Body = new BlockStatement { |
||||
new AssignmentExpression (new IdentifierExpression (fieldName), new IdentifierExpression ("value")) |
||||
} |
||||
} |
||||
}; |
||||
} |
||||
|
||||
bool ContainsGetter (PropertyDeclaration property, VariableInitializer initializer) |
||||
{ |
||||
if (property.Getter.IsNull || property.Getter.Body.Statements.Count () != 1) |
||||
return false; |
||||
var ret = property.Getter.Body.Statements.Single () as ReturnStatement; |
||||
if (ret == null) |
||||
return false; |
||||
return ret.Expression.IsMatch (new IdentifierExpression (initializer.Name)) || |
||||
ret.Expression.IsMatch (new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name)); |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue