提交 10e4e3b0 编写于 作者: C Cyrus Najmabadi

Add an (internal) overload to Rename to allow features to rename a subset of locations.

上级 e9dbd805
......@@ -180,7 +180,8 @@ private async Task<Result> EncapsulateFieldAsync(IFieldSymbol field, Document do
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var compilation = semanticModel.Compilation;
field = field.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol;
Solution solutionNeedingProperty = null;
var solutionNeedingProperty = solution;
// We couldn't resolve field after annotating its declaration. Bail
if (field == null)
......@@ -188,53 +189,9 @@ private async Task<Result> EncapsulateFieldAsync(IFieldSymbol field, Document do
return null;
}
if (updateReferences)
{
var locationsToIgnore = SpecializedCollections.EmptySet<TextSpan>();
var optionSet = document.Project.Solution.Workspace.Options;
if (field.IsReadOnly)
{
var locationSet = await RenameLocationSet.FindAsync(field, document.Project.Solution, optionSet, cancellationToken).ConfigureAwait(false);
var constructorSyntaxes = GetConstructorNodes(field.ContainingType);
var locations = locationSet.Locations.Where(l => constructorSyntaxes.Any(c => c.Span.IntersectsWith(l.Location.SourceSpan)));
if (locations.Any())
{
locationsToIgnore = locations.Select(l => l.Location.SourceSpan).ToSet();
locationSet = new RenameLocationSet(locations.ToSet(), field, document.Project.Solution, locationSet.ReferencedSymbols, locationSet.ImplicitLocations);
var resolution = await ConflictResolver.ResolveConflictsAsync(locationSet, field.Name, finalFieldName, optionSet, cancellationToken).ConfigureAwait(false);
document = resolution.NewSolution.GetDocument(document.Id);
semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
compilation = semanticModel.Compilation;
field = field.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol;
}
}
var renameLocationSet = await RenameLocationSet.FindAsync(field, document.Project.Solution, optionSet, cancellationToken).ConfigureAwait(false);
renameLocationSet = new RenameLocationSet(renameLocationSet.Locations.Where(l => !locationsToIgnore.Contains(l.Location.SourceSpan)).ToSet(),
renameLocationSet.Symbol, renameLocationSet.Solution, renameLocationSet.ReferencedSymbols, renameLocationSet.ImplicitLocations);
if (renameLocationSet.Locations.Any() || renameLocationSet.ImplicitLocations.Any())
{
var conflictResolution = await ConflictResolver.ResolveConflictsAsync(renameLocationSet, field.Name, generatedPropertyName, optionSet, cancellationToken).ConfigureAwait(false);
if (!conflictResolution.ReplacementTextValid)
{
return null;
}
solutionNeedingProperty = conflictResolution.NewSolution;
document = solutionNeedingProperty.GetDocument(document.Id);
}
}
else
{
solutionNeedingProperty = document.Project.Solution;
document = solutionNeedingProperty.GetDocument(document.Id);
}
solutionNeedingProperty = await UpdateReferencesAsync(
updateReferences, solution, document, field, finalFieldName, generatedPropertyName, cancellationToken).ConfigureAwait(false);
document = solutionNeedingProperty.GetDocument(document.Id);
var markFieldPrivate = field.DeclaredAccessibility != Accessibility.Private;
var rewrittenFieldDeclaration = await RewriteFieldNameAndAccessibility(finalFieldName, markFieldPrivate, document, declarationAnnotation, cancellationToken).ConfigureAwait(false);
......@@ -267,6 +224,44 @@ private async Task<Result> EncapsulateFieldAsync(IFieldSymbol field, Document do
return new Result(solutionWithProperty, originalField.ToDisplayString(), originalField.GetGlyph());
}
private async Task<Solution> UpdateReferencesAsync(
bool updateReferences, Solution solution, Document document, IFieldSymbol field, string finalFieldName, string generatedPropertyName, CancellationToken cancellationToken)
{
if (!updateReferences)
{
return solution;
}
var locationsToIgnore = SpecializedCollections.EmptySet<TextSpan>();
var optionSet = document.Project.Solution.Workspace.Options;
if (field.IsReadOnly)
{
// Inside the constructor we want to rename references the field to the final field name.
var constructorSyntaxes = GetConstructorNodes(field.ContainingType).ToSet();
if (finalFieldName != field.Name && constructorSyntaxes.Count > 0)
{
solution = await Renamer.RenameSymbolAsync(solution, field, finalFieldName, solution.Workspace.Options,
location => constructorSyntaxes.Any(c => c.Span.IntersectsWith(location.SourceSpan)), cancellationToken).ConfigureAwait(false);
document = solution.GetDocument(document.Id);
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
field = field.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol as IFieldSymbol;
}
// Outside the constructor we want to rename references to the field to final property name.
solution = await Renamer.RenameSymbolAsync(solution, field, generatedPropertyName, solution.Workspace.Options,
location => !constructorSyntaxes.Any(c => c.Span.IntersectsWith(location.SourceSpan)), cancellationToken).ConfigureAwait(false);
return solution;
}
else
{
// Just rename everything.
return await Renamer.RenameSymbolAsync(solution, field, generatedPropertyName, solution.Workspace.Options, cancellationToken).ConfigureAwait(false);
}
}
internal abstract IEnumerable<SyntaxNode> GetConstructorNodes(INamedTypeSymbol containingType);
protected async Task<Solution> AddPropertyAsync(Document document, Solution destinationSolution, IFieldSymbol field, IPropertySymbol property, CancellationToken cancellationToken)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Rename.ConflictEngine;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Rename
{
public static class Renamer
{
public static async Task<Solution> RenameSymbolAsync(Solution solution, ISymbol symbol, string newName, OptionSet optionSet, CancellationToken cancellationToken = default(CancellationToken))
public static Task<Solution> RenameSymbolAsync(Solution solution, ISymbol symbol, string newName, OptionSet optionSet, CancellationToken cancellationToken = default(CancellationToken))
{
return RenameSymbolAsync(solution, symbol, newName, optionSet, filter: null, cancellationToken: cancellationToken);
}
internal static async Task<Solution> RenameSymbolAsync(Solution solution, ISymbol symbol, string newName, OptionSet optionSet, Func<Location, bool> filter, CancellationToken cancellationToken)
{
if (solution == null)
{
......@@ -30,7 +38,15 @@ public static async Task<Solution> RenameSymbolAsync(Solution solution, ISymbol
optionSet = optionSet ?? solution.Workspace.Options;
var renameLocationSet = await RenameLocationSet.FindAsync(symbol, solution, optionSet, cancellationToken).ConfigureAwait(false);
var conflictResolution = await ConflictEngine.ConflictResolver.ResolveConflictsAsync(renameLocationSet, symbol.Name, newName, optionSet, cancellationToken).ConfigureAwait(false);
if (filter != null)
{
renameLocationSet = new RenameLocationSet(
renameLocationSet.Locations.Where(loc => filter(loc.Location)).ToSet(),
renameLocationSet.Symbol, renameLocationSet.Solution,
renameLocationSet.ReferencedSymbols, renameLocationSet.ImplicitLocations);
}
var conflictResolution = await ConflictResolver.ResolveConflictsAsync(renameLocationSet, symbol.Name, newName, optionSet, cancellationToken).ConfigureAwait(false);
return conflictResolution.NewSolution;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册