提交 3ae177f0 编写于 作者: C Cyrus Najmabadi

Extract a shared subset of the 'Replace Method' code.

上级 63657668
......@@ -6,6 +6,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.ReplaceMethodWithProperty;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.ReplaceMethodWithProperty;
using Roslyn.Test.Utilities;
using Xunit;
......
......@@ -100,7 +100,6 @@
<Compile Include="CodeRefactorings\MoveDeclarationNearReference\MoveDeclarationNearReferenceCodeRefactoringProvider.cs" />
<Compile Include="CodeRefactorings\MoveDeclarationNearReference\MoveDeclarationNearReferenceCodeRefactoringProvider.Rewriter.cs" />
<Compile Include="CodeRefactorings\MoveDeclarationNearReference\MoveDeclarationNearReferenceCodeRefactoringProvider.State.cs" />
<Compile Include="CodeRefactorings\ReplaceMethodWithProperty\ReplaceMethodWithPropertyCodeRefactoringProvider.cs" />
<Compile Include="CodeStyle\CSharpCodeStyleOptions.cs" />
<Compile Include="CodeStyle\CSharpCodeStyleOptionsProvider.cs" />
<Compile Include="Completion\CompletionProviders\AttributeNamedParameterCompletionProvider.ItemRules.cs" />
......@@ -346,6 +345,7 @@
<Compile Include="Organizing\Organizers\StructDeclarationOrganizer.cs" />
<Compile Include="RemoveUnnecessaryImports\CSharpRemoveUnnecessaryImportsService.cs" />
<Compile Include="RemoveUnnecessaryImports\CSharpRemoveUnnecessaryImportsService.Rewriter.cs" />
<Compile Include="ReplaceMethodWithProperty\CSharpReplaceMethodWithPropertyService.cs" />
<Compile Include="SolutionCrawler\CSharpDocumentDifferenceService.cs" />
</ItemGroup>
<ItemGroup>
......@@ -360,7 +360,9 @@
<PublicAPI Include="PublicAPI.Shipped.txt" />
<PublicAPI Include="PublicAPI.Unshipped.txt" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="CodeRefactorings\ReplaceMethodWithProperty\" />
</ItemGroup>
<Import Project="..\..\..\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems" Label="Shared" />
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
......
......@@ -538,15 +538,6 @@ internal class CSharpFeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Method referenced implicitly.
/// </summary>
internal static string MethodReferencedImplicitly {
get {
return ResourceManager.GetString("MethodReferencedImplicitly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Move declaration near reference.
/// </summary>
......@@ -727,24 +718,6 @@ internal class CSharpFeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Replace &apos;{0}&apos; and &apos;{1}&apos; with property.
/// </summary>
internal static string Replace0and1WithProperty {
get {
return ResourceManager.GetString("Replace0and1WithProperty", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Replace &apos;{0}&apos; with property.
/// </summary>
internal static string Replace0WithProperty {
get {
return ResourceManager.GetString("Replace0WithProperty", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Make {0} return Task instead of void..
/// </summary>
......
......@@ -437,15 +437,6 @@
<data name="ERR_NameNotInContext" xml:space="preserve">
<value>The name '{0}' does not exist in the current context.</value>
</data>
<data name="Replace0and1WithProperty" xml:space="preserve">
<value>Replace '{0}' and '{1}' with property</value>
</data>
<data name="Replace0WithProperty" xml:space="preserve">
<value>Replace '{0}' with property</value>
</data>
<data name="MethodReferencedImplicitly" xml:space="preserve">
<value>Method referenced implicitly</value>
</data>
<data name="NonInvokedMethodCannotBeReplacedWithProperty" xml:space="preserve">
<value>Non-invoked method cannot be replaced with property.</value>
</data>
......
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Rename;
using Microsoft.CodeAnalysis.ReplaceMethodWithProperty;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.CodeRefactorings.ReplaceMethodWithProperty
{
[ExportLanguageService(typeof(IReplaceMethodWithPropertyService), LanguageNames.CSharp), Shared]
internal class CSharpReplaceMethodWithPropertyService : IReplaceMethodWithPropertyService
{
public string GetMethodName(SyntaxNode methodNode)
{
return ((MethodDeclarationSyntax)methodNode).Identifier.ValueText;
}
public SyntaxNode GetMethodDeclaration(SyntaxToken token)
{
var containingMethod = token.Parent.FirstAncestorOrSelf<MethodDeclarationSyntax>();
if (containingMethod == null)
{
return null;
}
var start = containingMethod.AttributeLists.Count > 0
? containingMethod.AttributeLists.Last().GetLastToken().GetNextToken().SpanStart
: containingMethod.SpanStart;
// Offer this refactoring anywhere in the signature of the method.
var position = token.SpanStart;
if (position < start || position > containingMethod.ParameterList.Span.End)
{
return null;
}
return containingMethod;
}
public SyntaxNode ConvertMethodToProperty(SyntaxNode methodNode, string propertyName)
{
var method = methodNode as MethodDeclarationSyntax;
if (method == null)
{
return methodNode;
}
var accessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration);
accessor = method.Body == null
? accessor.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
: accessor.WithBody(method.Body);
var property = SyntaxFactory.PropertyDeclaration(method.AttributeLists, method.Modifiers, method.ReturnType,
method.ExplicitInterfaceSpecifier, identifier: SyntaxFactory.Identifier(propertyName),
accessorList: SyntaxFactory.AccessorList(SyntaxFactory.SingletonList(accessor)));
if (method.ExpressionBody != null)
{
property = property.WithExpressionBody(method.ExpressionBody);
property = property.WithSemicolonToken(method.SemicolonToken);
}
return property;
}
public void ReplaceReference(SyntaxEditor editor, SyntaxToken nameToken, string propertyName, bool nameChanged)
{
if (nameToken.Kind() == SyntaxKind.IdentifierToken)
{
var nameNode = nameToken.Parent as IdentifierNameSyntax;
var newName = nameChanged
? SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(propertyName).WithTriviaFrom(nameToken))
: nameNode;
var invocation = nameNode?.FirstAncestorOrSelf<InvocationExpressionSyntax>();
var invocationExpression = invocation?.Expression;
if (IsInvocationName(nameNode, invocationExpression))
{
// It was invoked. Remove the invocation, and also change the name if necessary.
editor.ReplaceNode(invocation, invocation.Expression.ReplaceNode(nameNode, newName));
}
else
{
// Wasn't invoked. Change the name, but report a conflict.
var annotation = ConflictAnnotation.Create(CSharpFeaturesResources.NonInvokedMethodCannotBeReplacedWithProperty);
editor.ReplaceNode(nameNode, newName.WithIdentifier(newName.Identifier.WithAdditionalAnnotations(annotation)));
}
}
}
private static bool IsInvocationName(IdentifierNameSyntax nameNode, ExpressionSyntax invocationExpression)
{
if (invocationExpression == nameNode)
{
return true;
}
if (nameNode.IsAnyMemberAccessExpressionName() && nameNode.Parent == invocationExpression)
{
return true;
}
return false;
}
}
}
......@@ -222,6 +222,8 @@
<Compile Include="IntroduceVariable\AbstractIntroduceVariableService.IntroduceVariableAllOccurrenceCodeAction.cs" />
<Compile Include="LanguageServices\ProjectInfoService\IProjectInfoService.cs" />
<Compile Include="QuickInfo\QuickInfoUtilities.cs" />
<Compile Include="ReplaceMethodWithProperty\ReplaceMethodWithPropertyCodeRefactoringProvider.cs" />
<Compile Include="ReplaceMethodWithProperty\IReplaceMethodWithPropertyService.cs" />
<Compile Include="Shared\Options\OrganizerOptionsProvider.cs" />
<Compile Include="Shared\Options\ServiceComponentOnOffOptionsProvider.cs" />
<Compile Include="Shared\Options\ServiceFeatureOnOffOptions.cs" />
......
......@@ -1321,6 +1321,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Method referenced implicitly.
/// </summary>
internal static string MethodReferencedImplicitly {
get {
return ResourceManager.GetString("MethodReferencedImplicitly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Modifying a catch/finally handler with an active statement in the try block will prevent the debug session from continuing..
/// </summary>
......@@ -1645,6 +1654,24 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Replace &apos;{0}&apos; and &apos;{1}&apos; with property.
/// </summary>
internal static string Replace0and1WithProperty {
get {
return ResourceManager.GetString("Replace0and1WithProperty", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Replace &apos;{0}&apos; with property.
/// </summary>
internal static string Replace0WithProperty {
get {
return ResourceManager.GetString("Replace0WithProperty", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Represents an object whose operations will be resolved at runtime..
/// </summary>
......
......@@ -834,4 +834,13 @@ Do you want to continue?</value>
<data name="UseAutoProperty" xml:space="preserve">
<value>Use auto property</value>
</data>
<data name="Replace0and1WithProperty" xml:space="preserve">
<value>Replace '{0}' and '{1}' with property</value>
</data>
<data name="Replace0WithProperty" xml:space="preserve">
<value>Replace '{0}' with property</value>
</data>
<data name="MethodReferencedImplicitly" xml:space="preserve">
<value>Method referenced implicitly</value>
</data>
</root>
\ No newline at end of file
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.ReplaceMethodWithProperty
{
interface IReplaceMethodWithPropertyService : ILanguageService
{
SyntaxNode GetMethodDeclaration(SyntaxToken token);
SyntaxNode ConvertMethodToProperty(SyntaxNode method, string propertyName);
void ReplaceReference(SyntaxEditor editor, SyntaxToken nameToken, string propertyName, bool nameChanged);
string GetMethodName(SyntaxNode methodDeclaration);
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册