未验证 提交 e5e9ce4e 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #43045 from CyrusNajmabadi/renameWorkSimple

Remove callbacks from Rename api.
......@@ -41,7 +41,7 @@ public async Task<IInlineRenameReplacementInfo> GetReplacementsAsync(string repl
{
var conflicts = await ConflictResolver.ResolveConflictsAsync(
_renameLocationSet, _renameLocationSet.Symbol.Name,
_renameInfo.GetFinalSymbolName(replacementText), optionSet, hasConflict: null, cancellationToken: cancellationToken).ConfigureAwait(false);
_renameInfo.GetFinalSymbolName(replacementText), optionSet, nonConflictSymbols: null, cancellationToken: cancellationToken).ConfigureAwait(false);
return new InlineRenameReplacementInfo(conflicts);
}
......
......@@ -79,7 +79,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename
Dim locations = RenameLocations.FindAsync(symbolAndProjectId, workspace.CurrentSolution, optionSet, CancellationToken.None).Result
Dim originalName = symbol.Name.Split("."c).Last()
Dim result = ConflictResolver.ResolveConflictsAsync(locations, originalName, renameTo, optionSet, hasConflict:=Nothing, cancellationToken:=CancellationToken.None).Result
Dim result = ConflictResolver.ResolveConflictsAsync(locations, originalName, renameTo, optionSet, nonConflictSymbols:=Nothing, cancellationToken:=CancellationToken.None).Result
engineResult = New RenameEngineResult(workspace, result, renameTo)
engineResult.AssertUnlabeledSpansRenamedAndHaveNoConflicts()
......
......@@ -10,6 +10,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.FindSymbols;
......@@ -244,27 +245,35 @@ private async Task<Result> EncapsulateFieldAsync(IFieldSymbol field, Document do
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)
var constructorLocations = GetConstructorLocations(field.ContainingType);
if (finalFieldName != field.Name && constructorLocations.Count > 0)
{
solution = await Renamer.RenameSymbolAsync(solution,
SymbolAndProjectId.Create(field, projectId),
finalFieldName, solution.Options,
location => constructorSyntaxes.Any(c => c.Span.IntersectsWith(location.SourceSpan)),
cancellationToken: cancellationToken).ConfigureAwait(false);
var initialLocations = await Renamer.GetRenameLocationsAsync(
solution, SymbolAndProjectId.Create(field, projectId), solution.Options, cancellationToken).ConfigureAwait(false);
var insideLocations = initialLocations.Filter(
location => IntersectsWithAny(location, constructorLocations));
solution = await Renamer.RenameAsync(
insideLocations, finalFieldName, cancellationToken: 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;
constructorLocations = GetConstructorLocations(field.ContainingType);
}
// Outside the constructor we want to rename references to the field to final property name.
return await Renamer.RenameSymbolAsync(solution,
SymbolAndProjectId.Create(field, projectId),
generatedPropertyName, solution.Options,
location => !constructorSyntaxes.Any(c => c.Span.IntersectsWith(location.SourceSpan)),
cancellationToken: cancellationToken).ConfigureAwait(false);
var finalLocations = await Renamer.GetRenameLocationsAsync(
solution, SymbolAndProjectId.Create(field, projectId), solution.Options, cancellationToken).ConfigureAwait(false);
var outsideLocations = finalLocations.Filter(
location => !IntersectsWithAny(location, constructorLocations));
return await Renamer.RenameAsync(
outsideLocations, generatedPropertyName, cancellationToken: cancellationToken).ConfigureAwait(false);
}
else
{
......@@ -275,6 +284,20 @@ private async Task<Result> EncapsulateFieldAsync(IFieldSymbol field, Document do
}
}
private bool IntersectsWithAny(Location location, ISet<Location> constructorLocations)
{
foreach (var constructor in constructorLocations)
{
if (location.IntersectsWith(constructor))
return true;
}
return false;
}
private ISet<Location> GetConstructorLocations(INamedTypeSymbol containingType)
=> GetConstructorNodes(containingType).Select(n => n.GetLocation()).ToSet();
internal abstract IEnumerable<SyntaxNode> GetConstructorNodes(INamedTypeSymbol containingType);
protected async Task<Solution> AddPropertyAsync(Document document, Solution destinationSolution, IFieldSymbol field, IPropertySymbol property, CancellationToken cancellationToken)
......
......@@ -120,10 +120,20 @@ private async Task<Solution> ProcessResultAsync(CodeFixContext context, Diagnost
// 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) &&
CanEditDocument(solution, location.SourceTree, linkedFiles, canEdit),
symbols => HasConflict(symbols, propertySymbol, compilation, cancellationToken),
//
// We're asking the rename API to update a bunch of references to an existing field to the same name as an
// existing property. Rename will often flag this situation as an unresolvable conflict because the new
// name won't bind to the field anymore.
//
// To address this, we let rename know that there is no conflict if the new symbol it resolves to is the
// same as the property we're trying to get the references pointing to.
var updatedSolution = await Renamer.RenameAsync(
fieldLocations.Filter(
location => !location.IntersectsWith(declaratorLocation) &&
CanEditDocument(solution, location.SourceTree, linkedFiles, canEdit)),
propertySymbol.Name,
nonConflictSymbols: ImmutableHashSet.Create<ISymbol>(propertySymbol),
cancellationToken).ConfigureAwait(false);
solution = updatedSolution;
......@@ -324,33 +334,6 @@ private async Task<SyntaxNode> FormatAsync(SyntaxNode newRoot, Document document
return true;
}
private bool? HasConflict(IEnumerable<ISymbol> symbols, IPropertySymbol property, Compilation compilation, CancellationToken cancellationToken)
{
// We're asking the rename API to update a bunch of references to an existing field to
// the same name as an existing property. Rename will often flag this situation as
// an unresolvable conflict because the new name won't bind to the field anymore.
//
// To address this, we let rename know that there is no conflict if the new symbol it
// resolves to is the same as the property we're trying to get the references pointing
// to.
foreach (var symbol in symbols)
{
if (symbol is IPropertySymbol otherProperty)
{
var mappedProperty = otherProperty.GetSymbolKey().Resolve(compilation, cancellationToken: cancellationToken).Symbol as IPropertySymbol;
if (property.Equals(mappedProperty))
{
// No conflict.
return false;
}
}
}
// Just do the default check.
return null;
}
private class UseAutoPropertyCodeAction : CodeAction.SolutionChangeAction
{
public UseAutoPropertyCodeAction(string title, Func<CancellationToken, Task<Solution>> createChangedSolution, CodeActionPriority priority)
......
......@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
......@@ -37,7 +38,7 @@ private class Session
private readonly string _originalText;
private readonly string _replacementText;
private readonly OptionSet _optionSet;
private readonly Func<IEnumerable<ISymbol>, bool?> _hasConflictCallback;
private readonly ImmutableHashSet<ISymbol> _nonConflictSymbols;
private readonly CancellationToken _cancellationToken;
private readonly RenameAnnotation _renamedSymbolDeclarationAnnotation;
......@@ -58,7 +59,7 @@ private class Session
string originalText,
string replacementText,
OptionSet optionSet,
Func<IEnumerable<ISymbol>, bool?> newSymbolsAreValid,
ImmutableHashSet<ISymbol> nonConflictSymbols,
CancellationToken cancellationToken)
{
_renameLocationSet = renameLocationSet;
......@@ -66,7 +67,7 @@ private class Session
_originalText = originalText;
_replacementText = replacementText;
_optionSet = optionSet;
_hasConflictCallback = newSymbolsAreValid;
_nonConflictSymbols = nonConflictSymbols;
_cancellationToken = cancellationToken;
_renamedSymbolDeclarationAnnotation = new RenameAnnotation();
......@@ -284,7 +285,7 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
// fixed them because of rename). Also, don't bother checking if a custom
// callback was provided. The caller might be ok with a rename that introduces
// errors.
if (!documentIdErrorStateLookup[documentId] && _hasConflictCallback == null)
if (!documentIdErrorStateLookup[documentId] && _nonConflictSymbols == null)
{
await conflictResolution.NewSolution.GetDocument(documentId).VerifyNoErrorsAsync("Rename introduced errors in error-free code", _cancellationToken, ignoreErrorCodes).ConfigureAwait(false);
}
......@@ -335,6 +336,11 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
var reverseMappedLocations = new Dictionary<Location, Location>();
// If we were giving any non-conflict-symbols then ensure that we know what those symbols are in
// the current project post after our edits so far.
var currentProject = conflictResolution.NewSolution.GetProject(projectId);
var nonConflictSymbols = await GetNonConflictSymbolsAsync(currentProject).ConfigureAwait(false);
foreach (var documentId in documentIdsForConflictResolution)
{
var newDocument = conflictResolution.NewSolution.GetDocument(documentId);
......@@ -359,7 +365,7 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
var conflictAnnotation = annotation;
reverseMappedLocations[tokenOrNode.GetLocation()] = baseSyntaxTree.GetLocation(conflictAnnotation.OriginalSpan);
var originalLocation = conflictAnnotation.OriginalSpan;
IEnumerable<ISymbol> newReferencedSymbols = null;
ImmutableArray<ISymbol> newReferencedSymbols = default;
var hasConflict = _renameAnnotations.HasAnnotation(tokenOrNode, RenameInvalidIdentifierAnnotation.Instance);
if (!hasConflict)
......@@ -374,13 +380,12 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
// the spans would have been modified and so we need to adjust the old position
// to the new position for which we use the renameSpanTracker, which was tracking
// & mapping the old span -> new span during rename
hasConflict = _hasConflictCallback?.Invoke(newReferencedSymbols) ??
await CheckForConflictAsync(conflictResolution, renamedSymbolInNewSolution, newDocument, conflictAnnotation, newReferencedSymbols).ConfigureAwait(false);
}
hasConflict =
!IsConflictFreeChange(newReferencedSymbols, nonConflictSymbols) &&
await CheckForConflictAsync(conflictResolution, renamedSymbolInNewSolution, conflictAnnotation, newReferencedSymbols).ConfigureAwait(false);
if (!hasConflict && !conflictAnnotation.IsInvocationExpression)
{
hasConflict = LocalVariableConflictPerLanguage((SyntaxToken)tokenOrNode, newDocument, newReferencedSymbols);
if (!hasConflict && !conflictAnnotation.IsInvocationExpression)
hasConflict = LocalVariableConflictPerLanguage((SyntaxToken)tokenOrNode, newDocument, newReferencedSymbols);
}
if (!hasConflict)
......@@ -458,6 +463,33 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
}
}
private async Task<ImmutableHashSet<ISymbol>> GetNonConflictSymbolsAsync(Project currentProject)
{
if (_nonConflictSymbols == null)
return null;
var compilation = await currentProject.GetCompilationAsync(_cancellationToken).ConfigureAwait(false);
return ImmutableHashSet.CreateRange(
_nonConflictSymbols.Select(s => s.GetSymbolKey().Resolve(compilation).GetAnySymbol()).WhereNotNull());
}
private bool IsConflictFreeChange(
ImmutableArray<ISymbol> symbols, ImmutableHashSet<ISymbol> nonConflictSymbols)
{
if (_nonConflictSymbols != null)
{
foreach (var symbol in symbols)
{
// Reference not points at a symbol in the conflict-free list. This is a conflict-free change.
if (nonConflictSymbols.Contains(symbol))
return true;
}
}
// Just do the default check.
return false;
}
/// <summary>
/// Gets the list of the nodes that were annotated for a conflict check
/// </summary>
......@@ -473,9 +505,8 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
private async Task<bool> CheckForConflictAsync(
ConflictResolution conflictResolution,
ISymbol renamedSymbolInNewSolution,
Document newDocument,
RenameActionAnnotation conflictAnnotation,
IEnumerable<ISymbol> newReferencedSymbols)
ImmutableArray<ISymbol> newReferencedSymbols)
{
try
{
......@@ -512,15 +543,15 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
}
}
}
else if (!conflictAnnotation.IsRenameLocation && conflictAnnotation.IsOriginalTextLocation && conflictAnnotation.RenameDeclarationLocationReferences.Length > 1 && newReferencedSymbols.Count() == 1)
else if (!conflictAnnotation.IsRenameLocation && conflictAnnotation.IsOriginalTextLocation && conflictAnnotation.RenameDeclarationLocationReferences.Length > 1 && newReferencedSymbols.Length == 1)
{
// an ambiguous situation was resolved through rename in non reference locations
hasConflict = false;
}
else if (newReferencedSymbols.Count() != conflictAnnotation.RenameDeclarationLocationReferences.Length)
else if (newReferencedSymbols.Length != conflictAnnotation.RenameDeclarationLocationReferences.Length)
{
// Don't show conflicts for errors in the old solution that now bind in the new solution.
if (newReferencedSymbols.Count() != 0 && conflictAnnotation.RenameDeclarationLocationReferences.Length == 0)
if (newReferencedSymbols.Length != 0 && conflictAnnotation.RenameDeclarationLocationReferences.Length == 0)
{
hasConflict = false;
}
......@@ -611,31 +642,25 @@ private async Task DebugVerifyNoErrorsAsync(ConflictResolution conflictResolutio
}
}
private IEnumerable<ISymbol> GetSymbolsInNewSolution(Document newDocument, SemanticModel newDocumentSemanticModel, RenameActionAnnotation conflictAnnotation, SyntaxNodeOrToken tokenOrNode)
private ImmutableArray<ISymbol> GetSymbolsInNewSolution(Document newDocument, SemanticModel newDocumentSemanticModel, RenameActionAnnotation conflictAnnotation, SyntaxNodeOrToken tokenOrNode)
{
IEnumerable<ISymbol> newReferencedSymbols = RenameUtilities.GetSymbolsTouchingPosition(tokenOrNode.Span.Start, newDocumentSemanticModel, newDocument.Project.Solution.Workspace, _cancellationToken);
var newReferencedSymbols = RenameUtilities.GetSymbolsTouchingPosition(tokenOrNode.Span.Start, newDocumentSemanticModel, newDocument.Project.Solution.Workspace, _cancellationToken);
if (conflictAnnotation.IsInvocationExpression)
{
IEnumerable<ISymbol> invocationReferencedSymbols = null;
if (tokenOrNode.IsNode)
{
invocationReferencedSymbols = SymbolsForEnclosingInvocationExpressionWorker((SyntaxNode)tokenOrNode, newDocumentSemanticModel, _cancellationToken);
}
if (invocationReferencedSymbols != null)
{
newReferencedSymbols = invocationReferencedSymbols;
var invocationReferencedSymbols = SymbolsForEnclosingInvocationExpressionWorker((SyntaxNode)tokenOrNode, newDocumentSemanticModel, _cancellationToken);
if (!invocationReferencedSymbols.IsDefault)
newReferencedSymbols = invocationReferencedSymbols;
}
}
// if there are more than one symbol, then remove the alias symbols.
// When using (not declaring) an alias, the alias symbol and the target symbol are returned
// by GetSymbolsTouchingPosition
if (newReferencedSymbols.Skip(1).Any())
{
newReferencedSymbols = newReferencedSymbols.Where(a => a.Kind != SymbolKind.Alias);
}
if (newReferencedSymbols.Length >= 2)
newReferencedSymbols = newReferencedSymbols.WhereAsArray(a => a.Kind != SymbolKind.Alias);
return newReferencedSymbols;
}
......
......@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
......@@ -36,16 +37,17 @@ internal static partial class ConflictResolver
private const string s_metadataNameSeparators = " .,:<`>()\r\n";
/// <summary>
/// Performs the renaming of the symbol in the solution, identifies renaming conflicts and automatically resolves them where possible.
/// Performs the renaming of the symbol in the solution, identifies renaming conflicts and automatically
/// resolves them where possible.
/// </summary>
/// <param name="renameLocationSet">The locations to perform the renaming at.</param>
/// <param name="originalText">The original name of the identifier.</param>
/// <param name="replacementText">The new name of the identifier</param>
/// <param name="optionSet">The option for rename</param>
/// <param name="hasConflict">Called after renaming references. Can be used by callers to
/// indicate if the new symbols that the reference binds to should be considered to be ok or
/// are in conflict. 'true' means they are conflicts. 'false' means they are not conflicts.
/// 'null' means that the default conflict check should be used.</param>
/// <param name="nonConflictSymbols">Used after renaming references. References that now bind to any of these
/// symbols are not considered to be in conflict. Useful for features that want to rename existing references to
/// point at some existing symbol. Normally this would be a conflict, but this can be used to override that
/// behavior.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A conflict resolution containing the new solution.</returns>
public static Task<ConflictResolution> ResolveConflictsAsync(
......@@ -53,7 +55,7 @@ internal static partial class ConflictResolver
string originalText,
string replacementText,
OptionSet optionSet,
Func<IEnumerable<ISymbol>, bool?> hasConflict,
ImmutableHashSet<ISymbol> nonConflictSymbols,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -66,26 +68,22 @@ internal static partial class ConflictResolver
throw new ArgumentException(string.Format(WorkspacesResources.Symbol_0_is_not_from_source, renameLocationSet.Symbol.Name));
}
var session = new Session(renameLocationSet, renameSymbolDeclarationLocation, originalText, replacementText, optionSet, hasConflict, cancellationToken);
var session = new Session(
renameLocationSet, renameSymbolDeclarationLocation,
originalText, replacementText,
optionSet, nonConflictSymbols, cancellationToken);
return session.ResolveConflictsAsync();
}
/// <summary>
/// Used to find the symbols associated with the Invocation Expression surrounding the Token
/// </summary>
private static IEnumerable<ISymbol> SymbolsForEnclosingInvocationExpressionWorker(SyntaxNode invocationExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
private static ImmutableArray<ISymbol> SymbolsForEnclosingInvocationExpressionWorker(SyntaxNode invocationExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
{
var symbolInfo = semanticModel.GetSymbolInfo(invocationExpression, cancellationToken);
IEnumerable<ISymbol> symbols = null;
if (symbolInfo.Symbol == null)
{
return null;
}
else
{
symbols = SpecializedCollections.SingletonEnumerable(symbolInfo.Symbol);
return symbols;
}
return symbolInfo.Symbol == null
? default
: ImmutableArray.Create(symbolInfo.Symbol);
}
private static SyntaxNode GetExpansionTargetForLocationPerLanguage(SyntaxToken tokenOrNode, Document document)
......@@ -95,7 +93,7 @@ private static SyntaxNode GetExpansionTargetForLocationPerLanguage(SyntaxToken t
return complexifiedTarget;
}
private static bool LocalVariableConflictPerLanguage(SyntaxToken tokenOrNode, Document document, IEnumerable<ISymbol> newReferencedSymbols)
private static bool LocalVariableConflictPerLanguage(SyntaxToken tokenOrNode, Document document, ImmutableArray<ISymbol> newReferencedSymbols)
{
var renameRewriterService = document.GetLanguageService<IRenameRewriterLanguageService>();
var isConflict = renameRewriterService.LocalVariableConflict(tokenOrNode, newReferencedSymbols);
......
......@@ -218,5 +218,12 @@ internal async Task<RenameLocations> FindWithUpdatedOptionsAsync(OptionSet optio
return new SearchResult(locations, implicitLocations, referencedSymbols);
}
public RenameLocations Filter(Func<Location, bool> filter)
=> new RenameLocations(
this.Locations.Where(loc => filter(loc.Location)).ToSet(),
this.SymbolAndProjectId, this.Solution,
this.ReferencedSymbols, this.ImplicitLocations.Where(loc => filter(loc.Location)),
this.Options);
}
}
......@@ -3,14 +3,12 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Rename.ConflictEngine;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Rename
{
......@@ -28,7 +26,7 @@ public static class Renamer
internal static Task<Solution> RenameSymbolAsync(
Solution solution, SymbolAndProjectId symbolAndProjectId, string newName, OptionSet optionSet, CancellationToken cancellationToken = default)
{
return RenameSymbolAsync(solution, symbolAndProjectId, newName, optionSet, filter: null, cancellationToken: cancellationToken);
return RenameSymbolAsync(solution, symbolAndProjectId, newName, optionSet, nonConflictSymbols: null, cancellationToken);
}
internal static Task<RenameLocations> GetRenameLocationsAsync(
......@@ -54,29 +52,17 @@ public static class Renamer
internal static async Task<Solution> RenameAsync(
RenameLocations locations,
string newName,
Func<Location, bool> filter = null,
Func<IEnumerable<ISymbol>, bool?> hasConflict = null,
ImmutableHashSet<ISymbol> nonConflictSymbols = null,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(newName))
{
throw new ArgumentException(nameof(newName));
}
cancellationToken.ThrowIfCancellationRequested();
var symbolAndProjectId = locations.SymbolAndProjectId;
if (filter != null)
{
locations = new RenameLocations(
locations.Locations.Where(loc => filter(loc.Location)).ToSet(),
symbolAndProjectId, locations.Solution,
locations.ReferencedSymbols, locations.ImplicitLocations.Where(loc => filter(loc.Location)),
locations.Options);
}
var conflictResolution = await ConflictResolver.ResolveConflictsAsync(
locations, symbolAndProjectId.Symbol.Name, newName, locations.Options, hasConflict, cancellationToken).ConfigureAwait(false);
locations, locations.SymbolAndProjectId.Symbol.Name, newName,
locations.Options, nonConflictSymbols, cancellationToken).ConfigureAwait(false);
return conflictResolution.NewSolution;
}
......@@ -86,25 +72,20 @@ public static class Renamer
SymbolAndProjectId symbolAndProjectId,
string newName,
OptionSet options,
Func<Location, bool> filter,
Func<IEnumerable<ISymbol>, bool?> hasConflict = null,
ImmutableHashSet<ISymbol> nonConflictSymbols = null,
CancellationToken cancellationToken = default)
{
if (solution == null)
{
throw new ArgumentNullException(nameof(solution));
}
if (symbolAndProjectId.Symbol == null)
{
throw new ArgumentNullException(nameof(symbolAndProjectId));
}
cancellationToken.ThrowIfCancellationRequested();
options ??= solution.Workspace.Options;
var renameLocations = await GetRenameLocationsAsync(solution, symbolAndProjectId, options, cancellationToken).ConfigureAwait(false);
return await RenameAsync(renameLocations, newName, filter, hasConflict, cancellationToken).ConfigureAwait(false);
return await RenameAsync(renameLocations, newName, nonConflictSymbols, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -4,6 +4,7 @@
#nullable enable
using System.Diagnostics;
using System.Threading;
using Roslyn.Utilities;
......@@ -39,5 +40,11 @@ public static bool IsVisibleSourceLocation(this Location loc)
var tree = loc.SourceTree;
return !(tree == null || tree.IsHiddenPosition(loc.SourceSpan.Start));
}
public static bool IntersectsWith(this Location loc1, Location loc2)
{
Debug.Assert(loc1.IsInSource && loc2.IsInSource);
return loc1.SourceTree == loc2.SourceTree && loc1.SourceSpan.IntersectsWith(loc2.SourceSpan);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册