提交 54d3f8a4 编写于 作者: C Cyrus Najmabadi

Add a setter to the auto-prop if the field is written to outside of a constructor.

上级 5323f402
......@@ -60,13 +60,18 @@ private async Task<Solution> ProcessResult(CodeFixContext context, Diagnostic di
var propertySymbol = (IPropertySymbol)propertySemanticModel.GetDeclaredSymbol(property);
Debug.Assert(fieldDocument.Project == propertyDocument.Project);
var compilation = await fieldDocument.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var project = fieldDocument.Project;
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
// First, rename all usages of the field to point at the property. Except don't actually
// rename the field itself. We want to be able to find it again post rename.
var solution = context.Document.Project.Solution;
var updatedSolution = await Renamer.RenameSymbolAsync(solution,
fieldSymbol, propertySymbol.Name, solution.Workspace.Options,
var fieldLocations = await Renamer.GetRenameLocationsAsync(solution, fieldSymbol, solution.Workspace.Options, cancellationToken).ConfigureAwait(false);
// First, create the updated property we want to replace the old property with
var updatedProperty = UpdateProperty(project, fieldSymbol, propertySymbol, property, fieldLocations, cancellationToken);
// Now, rename all usages of the field to point at the property. Except don't actually
// rename the field itself. We want to be able to find it again post rename.
var updatedSolution = await Renamer.RenameAsync(fieldLocations, propertySymbol.Name,
location => !location.SourceSpan.IntersectsWith(declaratorLocation.SourceSpan),
symbols => HasConflict(symbols, propertySymbol, compilation, cancellationToken),
cancellationToken).ConfigureAwait(false);
......@@ -90,8 +95,6 @@ private async Task<Solution> ProcessResult(CodeFixContext context, Diagnostic di
var fieldDeclaration = (FieldDeclarationSyntax)declarator.Parent.Parent;
var nodeToRemove = fieldDeclaration.Declaration.Variables.Count > 1 ? declarator : (SyntaxNode)fieldDeclaration;
var updatedProperty = UpdateProperty(property);
const SyntaxRemoveOptions options = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker;
if (fieldDocument == propertyDocument)
{
......@@ -149,9 +152,86 @@ private async Task<Solution> ProcessResult(CodeFixContext context, Diagnostic di
return null;
}
private PropertyDeclarationSyntax UpdateProperty(PropertyDeclarationSyntax propertyDeclaration)
private PropertyDeclarationSyntax UpdateProperty(
Project project, IFieldSymbol fieldSymbol, IPropertySymbol propertySymbol, PropertyDeclarationSyntax propertyDeclaration,
RenameLocations fieldRenameLocations, CancellationToken cancellationToken)
{
var updatedProperty = propertyDeclaration.WithAccessorList(UpdateAccessorList(propertyDeclaration.AccessorList));
// We may need to add a setter if the field is written to outside of the constructor
// of it's class.
if (AddSetterIfNecessary(fieldSymbol, propertyDeclaration, fieldRenameLocations, cancellationToken))
{
var accessor = SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
var generator = SyntaxGenerator.GetGenerator(project);
if (fieldSymbol.DeclaredAccessibility != propertySymbol.DeclaredAccessibility)
{
accessor = (AccessorDeclarationSyntax)generator.WithAccessibility(accessor, fieldSymbol.DeclaredAccessibility);
}
updatedProperty = updatedProperty.AddAccessorListAccessors(accessor);
}
return updatedProperty;
}
private bool AddSetterIfNecessary(
IFieldSymbol fieldSymbol,
PropertyDeclarationSyntax propertyDeclaration,
RenameLocations fieldRenameLocations,
CancellationToken cancellationToken)
{
if (propertyDeclaration.AccessorList.Accessors.Any(SyntaxKind.SetAccessorDeclaration))
{
// No need to add an setter if we already have one.
return false;
}
// If the original field was written to outside of a constructor (or the property
// we're converting), then we'll need to add a setter to the property we're creating.
var containingTypeNodes = fieldSymbol.ContainingType.DeclaringSyntaxReferences.Select(s => s.GetSyntax(cancellationToken)).ToImmutableArray();
return fieldRenameLocations.Locations.Any(loc => NeedsSetter(loc, containingTypeNodes, propertyDeclaration, cancellationToken));
}
private bool NeedsSetter(
RenameLocation location,
ImmutableArray<SyntaxNode> containingTypeNodes,
PropertyDeclarationSyntax propertyDeclaration,
CancellationToken cancellationToken)
{
return propertyDeclaration.WithAccessorList(UpdateAccessorList(propertyDeclaration.AccessorList));
if (!location.IsWrittenTo)
{
// We don't need a setter if we're not writing to this field.
return false;
}
var node = location.Location.FindToken(cancellationToken).Parent;
while (node != null)
{
if (node == propertyDeclaration)
{
// We don't need a setter if we're a reference in the property we're replacing.
return false;
}
if (node.IsKind(SyntaxKind.ConstructorDeclaration))
{
// If we're written to in a constructor in the field's class, we don't need
// a setter.
if (containingTypeNodes.Contains(node.Parent))
{
return false;
}
}
node = node.Parent;
}
// We do need a setter
return true;
}
private AccessorListSyntax UpdateAccessorList(AccessorListSyntax accessorList)
......
......@@ -191,5 +191,29 @@ public void TestUpdateReferencesConflictResolution()
@"class Class { [|int i|]; int P { get { return i; } } public Class(int P) { i = 1; } }",
@"class Class { int P { get; } public Class(int P) { this.P = 1; } }");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestWriteInConstructor()
{
Test(
@"class Class { [|int i|]; int P { get { return i; } } public Class() { i = 1; } }",
@"class Class { int P { get; } public Class() { P = 1; } }");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestWriteInNotInConstructor1()
{
Test(
@"class Class { [|int i|]; int P { get { return i; } } public Foo() { i = 1; } }",
@"class Class { int P { get; set; } public Foo() { P = 1; } }");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestWriteInNotInConstructor2()
{
Test(
@"class Class { [|int i|]; public int P { get { return i; } } public Foo() { i = 1; } }",
@"class Class { public int P { get; private set; } public Foo() { P = 1; } }");
}
}
}
......@@ -14,12 +14,12 @@ internal abstract partial class AbstractEditorInlineRenameService
{
private class InlineRenameLocationSet : IInlineRenameLocationSet
{
private readonly RenameLocationSet _renameLocationSet;
private readonly RenameLocations _renameLocationSet;
private readonly SymbolInlineRenameInfo _renameInfo;
public IList<InlineRenameLocation> Locations { get; }
public InlineRenameLocationSet(SymbolInlineRenameInfo renameInfo, RenameLocationSet renameLocationSet)
public InlineRenameLocationSet(SymbolInlineRenameInfo renameInfo, RenameLocations renameLocationSet)
{
_renameInfo = renameInfo;
_renameLocationSet = renameLocationSet;
......
......@@ -31,7 +31,7 @@ private partial class SymbolInlineRenameInfo : IInlineRenameInfo
private readonly Document _document;
private readonly IEnumerable<IRefactorNotifyService> _refactorNotifyServices;
private Task<RenameLocationSet> _underlyingFindRenameLocationsTask;
private Task<RenameLocations> _underlyingFindRenameLocationsTask;
/// <summary>
/// Whether or not we shortened the trigger span (say because we were renaming an attribute,
......@@ -61,7 +61,7 @@ private partial class SymbolInlineRenameInfo : IInlineRenameInfo
_document = document;
this.RenameSymbol = renameSymbol;
this.HasOverloads = RenameLocationSet.GetOverloadedSymbols(this.RenameSymbol).Any();
this.HasOverloads = RenameLocations.GetOverloadedSymbols(this.RenameSymbol).Any();
this.ForceRenameOverloads = forceRenameOverloads;
_isRenamingAttributePrefix = CanRenameAttributePrefix(document, triggerSpan, cancellationToken);
......@@ -208,14 +208,14 @@ public string GetFinalSymbolName(string replacementText)
public Task<IInlineRenameLocationSet> FindRenameLocationsAsync(OptionSet optionSet, CancellationToken cancellationToken)
{
Task<RenameLocationSet> renameTask;
Task<RenameLocations> renameTask;
lock (_gate)
{
if (_underlyingFindRenameLocationsTask == null)
{
// If this is the first call, then just start finding the initial set of rename
// locations.
_underlyingFindRenameLocationsTask = RenameLocationSet.FindAsync(
_underlyingFindRenameLocationsTask = RenameLocations.FindAsync(
this.RenameSymbol, _document.Project.Solution, optionSet, cancellationToken);
renameTask = _underlyingFindRenameLocationsTask;
......@@ -234,7 +234,7 @@ public Task<IInlineRenameLocationSet> FindRenameLocationsAsync(OptionSet optionS
return GetLocationSet(renameTask, optionSet, cancellationToken);
}
private async Task<IInlineRenameLocationSet> GetLocationSet(Task<RenameLocationSet> renameTask, OptionSet optionSet, CancellationToken cancellationToken)
private async Task<IInlineRenameLocationSet> GetLocationSet(Task<RenameLocations> renameTask, OptionSet optionSet, CancellationToken cancellationToken)
{
var locationSet = await renameTask.ConfigureAwait(false);
if (optionSet != null)
......
......@@ -97,7 +97,7 @@ private IInlineRenameInfo GetRenameInfo(Document document, int position, Cancell
}
}
var symbol = RenameLocationSet.ReferenceProcessing.GetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);
var symbol = RenameLocations.ReferenceProcessing.GetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);
if (symbol == null)
{
return new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement);
......
......@@ -68,7 +68,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename
Dim document = workspace.CurrentSolution.GetDocument(cursorDocument.Id)
Dim symbol = RenameLocationSet.ReferenceProcessing.GetRenamableSymbolAsync(document, cursorPosition, CancellationToken.None).Result
Dim symbol = RenameLocations.ReferenceProcessing.GetRenamableSymbolAsync(document, cursorPosition, CancellationToken.None).Result
If symbol Is Nothing Then
AssertEx.Fail("The symbol touching the $$ could not be found.")
......@@ -82,7 +82,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename
Next
End If
Dim locations = RenameLocationSet.FindAsync(symbol, workspace.CurrentSolution, optionSet, CancellationToken.None).Result
Dim locations = RenameLocations.FindAsync(symbol, workspace.CurrentSolution, optionSet, CancellationToken.None).Result
Dim originalName = symbol.Name.Split("."c).Last()
Dim result = ConflictResolver.ResolveConflictsAsync(locations, originalName, renameTo, optionSet, CancellationToken.None).Result
......
......@@ -614,7 +614,7 @@ private SyntaxToken RenameToken(SyntaxToken oldToken, SyntaxToken newToken, stri
private SyntaxToken RenameInStringLiteral(SyntaxToken oldToken, SyntaxToken newToken, Func<SyntaxTriviaList, string, string, SyntaxTriviaList, SyntaxToken> createNewStringLiteral)
{
var originalString = newToken.ToString();
string replacedString = RenameLocationSet.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText);
string replacedString = RenameLocations.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText);
if (replacedString != originalString)
{
var oldSpan = oldToken.Span;
......@@ -642,7 +642,7 @@ private SyntaxToken RenameInTrivia(SyntaxToken token, IEnumerable<SyntaxTrivia>
private SyntaxTrivia RenameInCommentTrivia(SyntaxTrivia trivia)
{
var originalString = trivia.ToString();
string replacedString = RenameLocationSet.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText);
string replacedString = RenameLocations.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText);
if (replacedString != originalString)
{
var oldSpan = trivia.Span;
......@@ -819,7 +819,7 @@ private SyntaxToken RenameWithinToken(SyntaxToken oldToken, SyntaxToken newToken
var properties = new List<ISymbol>();
foreach (var referencedSymbol in referencedSymbols)
{
var property = await RenameLocationSet.ReferenceProcessing.GetPropertyFromAccessorOrAnOverride(
var property = await RenameLocations.ReferenceProcessing.GetPropertyFromAccessorOrAnOverride(
referencedSymbol, baseSolution, cancellationToken).ConfigureAwait(false);
if (property != null)
{
......
......@@ -36,7 +36,15 @@ public static SyntaxGenerator GetGenerator(Workspace workspace, string language)
/// </summary>
public static SyntaxGenerator GetGenerator(Document document)
{
return document.Project.LanguageServices.GetService<SyntaxGenerator>();
return GetGenerator(document.Project);
}
/// <summary>
/// Gets the <see cref="SyntaxGenerator"/> for the language corresponding to the project.
/// </summary>
public static SyntaxGenerator GetGenerator(Project project)
{
return project.LanguageServices.GetService<SyntaxGenerator>();
}
#region Declarations
......
Microsoft.CodeAnalysis.Editing.SyntaxEditor.RemoveNode(Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.SyntaxRemoveOptions options) -> void
Microsoft.CodeAnalysis.Project.IsSubmission.get -> bool
Microsoft.CodeAnalysis.Workspace.UpdateReferencesAfterAdd() -> void
static Microsoft.CodeAnalysis.Editing.SyntaxGenerator.GetGenerator(Microsoft.CodeAnalysis.Project project) -> Microsoft.CodeAnalysis.Editing.SyntaxGenerator
virtual Microsoft.CodeAnalysis.Editing.SyntaxGenerator.RemoveNode(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.SyntaxRemoveOptions options) -> Microsoft.CodeAnalysis.SyntaxNode
\ No newline at end of file
......@@ -28,7 +28,7 @@ internal static partial class ConflictResolver
private class Session
{
// Set of All Locations that will be renamed (does not include non-reference locations that need to be checked for conflicts)
private readonly RenameLocationSet _renameLocationSet;
private readonly RenameLocations _renameLocationSet;
// Rename Symbol's Source Location
private readonly Location _renameSymbolDeclarationLocation;
......@@ -52,7 +52,7 @@ private class Session
private bool _documentOfRenameSymbolHasBeenRenamed;
public Session(
RenameLocationSet renameLocationSet,
RenameLocations renameLocationSet,
Location renameSymbolDeclarationLocation,
string originalText,
string replacementText,
......
......@@ -45,7 +45,7 @@ internal static partial class ConflictResolver
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A conflict resolution containing the new solution.</returns>
public static Task<ConflictResolution> ResolveConflictsAsync(
RenameLocationSet renameLocationSet,
RenameLocations renameLocationSet,
string originalText,
string replacementText,
OptionSet optionSet,
......
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Rename
/// A helper class that contains some of the methods and filters that must be used when
/// processing the raw results from the FindReferences API.
/// </summary>
internal sealed partial class RenameLocationSet
internal sealed partial class RenameLocations
{
internal static class ReferenceProcessing
{
......@@ -354,7 +354,8 @@ internal static async Task<IEnumerable<RenameLocation>> GetRenamableReferenceLoc
{
if (location.Alias.Name == referencedSymbol.Name)
{
results.Add(new RenameLocation(location.Location, location.Document.Id, isCandidateLocation: location.IsCandidateLocation, isRenamableAliasUsage: true));
results.Add(new RenameLocation(location.Location, location.Document.Id,
isCandidateLocation: location.IsCandidateLocation, isRenamableAliasUsage: true, isWrittenTo: location.IsWrittenTo));
// We also need to add the location of the alias itself
var aliasLocation = location.Alias.Locations.Single();
......@@ -367,6 +368,7 @@ internal static async Task<IEnumerable<RenameLocation>> GetRenamableReferenceLoc
results.Add(new RenameLocation(
location.Location,
location.Document.Id,
isWrittenTo: location.IsWrittenTo,
isCandidateLocation: location.IsCandidateLocation,
isMethodGroupReference: location.IsCandidateLocation && location.CandidateReason == CandidateReason.MemberGroup,
isRenamableAccessor: await IsPropertyAccessorOrAnOverride(referencedSymbol, solution, cancellationToken).ConfigureAwait(false)));
......
......@@ -14,6 +14,7 @@ internal struct RenameLocation : IEquatable<RenameLocation>
public readonly bool IsRenamableAliasUsage;
public readonly bool IsRenamableAccessor;
public readonly TextSpan ContainingLocationForStringOrComment;
public readonly bool IsWrittenTo;
public bool IsRenameInStringOrComment { get { return ContainingLocationForStringOrComment != default(TextSpan); } }
......@@ -26,26 +27,25 @@ internal struct RenameLocation : IEquatable<RenameLocation>
bool isMethodGroupReference = false,
bool isRenamableAliasUsage = false,
bool isRenamableAccessor = false,
bool isWrittenTo = false,
TextSpan containingLocationForStringOrComment = default(TextSpan))
{
this.Location = location;
this.DocumentId = documentId;
this.IsCandidateLocation = isCandidateLocation;
this.IsMethodGroupReference = isMethodGroupReference;
this.IsRenamableAliasUsage = isRenamableAliasUsage;
this.IsRenamableAccessor = isRenamableAccessor;
this.ContainingLocationForStringOrComment = containingLocationForStringOrComment;
Location = location;
DocumentId = documentId;
IsCandidateLocation = isCandidateLocation;
IsMethodGroupReference = isMethodGroupReference;
IsRenamableAliasUsage = isRenamableAliasUsage;
IsRenamableAccessor = isRenamableAccessor;
IsWrittenTo = isWrittenTo;
ContainingLocationForStringOrComment = containingLocationForStringOrComment;
}
public RenameLocation(ReferenceLocation referenceLocation, DocumentId documentId)
: this(referenceLocation.Location, documentId,
isCandidateLocation: referenceLocation.IsCandidateLocation && referenceLocation.CandidateReason != CandidateReason.LateBound,
isMethodGroupReference: referenceLocation.IsCandidateLocation && referenceLocation.CandidateReason == CandidateReason.MemberGroup,
isWrittenTo: referenceLocation.IsWrittenTo)
{
this.Location = referenceLocation.Location;
this.DocumentId = documentId;
this.IsCandidateLocation = referenceLocation.IsCandidateLocation && referenceLocation.CandidateReason != CandidateReason.LateBound;
this.IsMethodGroupReference = referenceLocation.IsCandidateLocation && referenceLocation.CandidateReason == CandidateReason.MemberGroup;
this.IsRenamableAliasUsage = false;
this.IsRenamableAccessor = false;
this.ContainingLocationForStringOrComment = default(TextSpan);
}
public bool Equals(RenameLocation other)
......
......@@ -14,10 +14,10 @@
namespace Microsoft.CodeAnalysis.Rename
{
/// <summary>
/// Holds the ILocations of a symbol that should be renamed, along with the symbol and Solution
/// Holds the Locations of a symbol that should be renamed, along with the symbol and Solution
/// for the set.
/// </summary>
internal sealed partial class RenameLocationSet
internal sealed partial class RenameLocations
{
private class SearchResult
{
......@@ -37,26 +37,27 @@ public SearchResult(ISet<RenameLocation> locations, IEnumerable<ReferenceLocatio
private readonly ISymbol _symbol;
private readonly Solution _solution;
private readonly SearchResult _mergedResult;
internal OptionSet Options { get; }
// possibly null fields
private readonly OptionSet _optionSet;
private readonly SearchResult _originalSymbolResult;
private readonly List<SearchResult> _overloadsResult;
private readonly IEnumerable<RenameLocation> _stringsResult;
private readonly IEnumerable<RenameLocation> _commentsResult;
public RenameLocationSet(ISet<RenameLocation> locations, ISymbol symbol, Solution solution, IEnumerable<ISymbol> referencedSymbols, IEnumerable<ReferenceLocation> implicitLocations)
internal RenameLocations(ISet<RenameLocation> locations, ISymbol symbol, Solution solution, IEnumerable<ISymbol> referencedSymbols, IEnumerable<ReferenceLocation> implicitLocations, OptionSet options)
{
_symbol = symbol;
_solution = solution;
_mergedResult = new SearchResult(locations, implicitLocations, referencedSymbols);
Options = options;
}
private RenameLocationSet(ISymbol symbol, Solution solution, OptionSet optionSet, SearchResult originalSymbolResult, List<SearchResult> overloadsResult, IEnumerable<RenameLocation> stringsResult, IEnumerable<RenameLocation> commentsResult)
private RenameLocations(ISymbol symbol, Solution solution, OptionSet options, SearchResult originalSymbolResult, List<SearchResult> overloadsResult, IEnumerable<RenameLocation> stringsResult, IEnumerable<RenameLocation> commentsResult)
{
_symbol = symbol;
_solution = solution;
_optionSet = optionSet;
Options = options;
_originalSymbolResult = originalSymbolResult;
_overloadsResult = overloadsResult;
_stringsResult = stringsResult;
......@@ -66,18 +67,18 @@ private RenameLocationSet(ISymbol symbol, Solution solution, OptionSet optionSet
var mergedReferencedSymbols = new List<ISymbol>();
var mergedImplicitLocations = new List<ReferenceLocation>();
if (optionSet.GetOption(RenameOptions.RenameInStrings))
if (options.GetOption(RenameOptions.RenameInStrings))
{
mergedLocations.AddRange(stringsResult);
}
if (optionSet.GetOption(RenameOptions.RenameInComments))
if (options.GetOption(RenameOptions.RenameInComments))
{
mergedLocations.AddRange(commentsResult);
}
var renameMethodGroupReferences = optionSet.GetOption(RenameOptions.RenameOverloads) || !GetOverloadedSymbols(symbol).Any();
var overloadsToMerge = (optionSet.GetOption(RenameOptions.RenameOverloads) ? overloadsResult : null) ?? SpecializedCollections.EmptyEnumerable<SearchResult>();
var renameMethodGroupReferences = options.GetOption(RenameOptions.RenameOverloads) || !GetOverloadedSymbols(symbol).Any();
var overloadsToMerge = (options.GetOption(RenameOptions.RenameOverloads) ? overloadsResult : null) ?? SpecializedCollections.EmptyEnumerable<SearchResult>();
foreach (var result in overloadsToMerge.Concat(originalSymbolResult))
{
mergedLocations.AddRange(renameMethodGroupReferences
......@@ -100,22 +101,22 @@ private RenameLocationSet(ISymbol symbol, Solution solution, OptionSet optionSet
/// <summary>
/// Find the locations that need to be renamed.
/// </summary>
public static async Task<RenameLocationSet> FindAsync(ISymbol symbol, Solution solution, OptionSet optionSet, CancellationToken cancellationToken)
internal static async Task<RenameLocations> FindAsync(ISymbol symbol, Solution solution, OptionSet optionSet, CancellationToken cancellationToken)
{
Contract.ThrowIfNull(symbol);
using (Logger.LogBlock(FunctionId.Rename_AllRenameLocations, cancellationToken))
{
symbol = await ReferenceProcessing.FindDefinitionSymbolAsync(symbol, solution, cancellationToken).ConfigureAwait(false);
var originalSymbolResult = await AddLocationsReferenceSymbolsAsync(symbol, solution, cancellationToken).ConfigureAwait(false);
var intermediateResult = new RenameLocationSet(symbol, solution, optionSet, originalSymbolResult, overloadsResult: null, stringsResult: null, commentsResult: null);
var intermediateResult = new RenameLocations(symbol, solution, optionSet, originalSymbolResult, overloadsResult: null, stringsResult: null, commentsResult: null);
return await intermediateResult.FindWithUpdatedOptionsAsync(optionSet, cancellationToken).ConfigureAwait(false);
}
}
public async Task<RenameLocationSet> FindWithUpdatedOptionsAsync(OptionSet optionSet, CancellationToken cancellationToken)
internal async Task<RenameLocations> FindWithUpdatedOptionsAsync(OptionSet optionSet, CancellationToken cancellationToken)
{
Contract.ThrowIfNull(_optionSet, "FindWithUpdatedOptionsAsync can only be called on a result of FindAsync");
Contract.ThrowIfNull(Options, "FindWithUpdatedOptionsAsync can only be called on a result of FindAsync");
using (Logger.LogBlock(FunctionId.Rename_AllRenameLocations, cancellationToken))
{
var overloadsResult = _overloadsResult ?? (optionSet.GetOption(RenameOptions.RenameOverloads)
......@@ -130,7 +131,7 @@ public async Task<RenameLocationSet> FindWithUpdatedOptionsAsync(OptionSet optio
optionSet.GetOption(RenameOptions.RenameInComments) && _commentsResult == null,
cancellationToken).ConfigureAwait(false);
return new RenameLocationSet(_symbol, _solution, optionSet, _originalSymbolResult,
return new RenameLocations(_symbol, _solution, optionSet, _originalSymbolResult,
_overloadsResult ?? overloadsResult,
_stringsResult ?? stringsAndComments.Item1,
_commentsResult ?? stringsAndComments.Item2);
......@@ -191,4 +192,4 @@ internal static IEnumerable<ISymbol> GetOverloadedSymbols(ISymbol symbol)
return new SearchResult(locations, implicitLocations, referencedSymbols);
}
}
}
}
\ No newline at end of file
......@@ -18,14 +18,7 @@ public static Task<Solution> RenameSymbolAsync(Solution solution, ISymbol symbol
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,
Func<IEnumerable<ISymbol>, bool?> hasConflict = null,
CancellationToken cancellationToken = default(CancellationToken))
internal static Task<RenameLocations> GetRenameLocationsAsync(Solution solution, ISymbol symbol, OptionSet options, CancellationToken cancellationToken)
{
if (solution == null)
{
......@@ -37,27 +30,66 @@ public static Task<Solution> RenameSymbolAsync(Solution solution, ISymbol symbol
throw new ArgumentNullException(nameof(symbol));
}
cancellationToken.ThrowIfCancellationRequested();
options = options ?? solution.Workspace.Options;
return RenameLocations.FindAsync(symbol, solution, options, cancellationToken);
}
internal static async Task<Solution> RenameAsync(
RenameLocations locations,
string newName,
Func<Location, bool> filter = null,
Func<IEnumerable<ISymbol>, bool?> hasConflict = null,
CancellationToken cancellationToken = default(CancellationToken))
{
if (string.IsNullOrEmpty(newName))
{
throw new ArgumentException("newName");
throw new ArgumentException(nameof(newName));
}
cancellationToken.ThrowIfCancellationRequested();
optionSet = optionSet ?? solution.Workspace.Options;
var renameLocationSet = await RenameLocationSet.FindAsync(symbol, solution, optionSet, cancellationToken).ConfigureAwait(false);
var symbol = locations.Symbol;
if (filter != null)
{
renameLocationSet = new RenameLocationSet(
renameLocationSet.Locations.Where(loc => filter(loc.Location)).ToSet(),
renameLocationSet.Symbol, renameLocationSet.Solution,
renameLocationSet.ReferencedSymbols, renameLocationSet.ImplicitLocations);
locations = new RenameLocations(
locations.Locations.Where(loc => filter(loc.Location)).ToSet(),
symbol, locations.Solution,
locations.ReferencedSymbols, locations.ImplicitLocations,
locations.Options);
}
var conflictResolution = await ConflictResolver.ResolveConflictsAsync(
renameLocationSet, symbol.Name, newName, optionSet, hasConflict, cancellationToken).ConfigureAwait(false);
locations, symbol.Name, newName, locations.Options, hasConflict, cancellationToken).ConfigureAwait(false);
return conflictResolution.NewSolution;
}
internal static async Task<Solution> RenameSymbolAsync(
Solution solution,
ISymbol symbol,
string newName,
OptionSet options,
Func<Location, bool> filter,
Func<IEnumerable<ISymbol>, bool?> hasConflict = null,
CancellationToken cancellationToken = default(CancellationToken))
{
if (solution == null)
{
throw new ArgumentNullException(nameof(solution));
}
if (symbol == null)
{
throw new ArgumentNullException(nameof(symbol));
}
cancellationToken.ThrowIfCancellationRequested();
options = options ?? solution.Workspace.Options;
var renameLocations = await GetRenameLocationsAsync(solution, symbol, options, cancellationToken).ConfigureAwait(false);
return await RenameAsync(renameLocations, newName, filter, hasConflict, cancellationToken).ConfigureAwait(false);
}
}
}
}
\ No newline at end of file
......@@ -649,7 +649,7 @@
<Compile Include="Rename\RenameEntityKind.cs" />
<Compile Include="Rename\RenameLocation.cs" />
<Compile Include="Rename\RenameLocation.ReferenceProcessing.cs" />
<Compile Include="Rename\RenameLocationSet.cs" />
<Compile Include="Rename\RenameLocations.cs" />
<Compile Include="Rename\RenameOptions.cs" />
<Compile Include="Rename\Renamer.cs" />
<Compile Include="Rename\RenameRewriterParameters.cs" />
......
......@@ -545,7 +545,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename
Private Function RenameInStringLiteral(oldToken As SyntaxToken, newToken As SyntaxToken, createNewStringLiteral As Func(Of SyntaxTriviaList, String, String, SyntaxTriviaList, SyntaxToken)) As SyntaxToken
Dim originalString = newToken.ToString()
Dim replacedString As String = RenameLocationSet.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText)
Dim replacedString As String = RenameLocations.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText)
If replacedString <> originalString Then
Dim oldSpan = oldToken.Span
newToken = createNewStringLiteral(newToken.LeadingTrivia, replacedString, replacedString, newToken.TrailingTrivia)
......@@ -558,7 +558,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename
Private Function RenameInCommentTrivia(trivia As SyntaxTrivia) As SyntaxTrivia
Dim originalString = trivia.ToString()
Dim replacedString As String = RenameLocationSet.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText)
Dim replacedString As String = RenameLocations.ReferenceProcessing.ReplaceMatchingSubStrings(originalString, _originalText, _replacementText)
If replacedString <> originalString Then
Dim oldSpan = trivia.Span
Dim newTrivia = SyntaxFactory.CommentTrivia(replacedString)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册