private static async Task AddImplicitConflictsAsync( ISymbol renamedSymbol, ISymbol originalSymbol, IEnumerable <ReferenceLocation> implicitReferenceLocations, SemanticModel semanticModel, Location originalDeclarationLocation, int newDeclarationLocationStartingPosition, MutableConflictResolution conflictResolution, CancellationToken cancellationToken) { { var renameRewriterService = conflictResolution.CurrentSolution.Workspace.Services.GetLanguageServices(renamedSymbol.Language) .GetRequiredService <IRenameRewriterLanguageService>(); var implicitUsageConflicts = renameRewriterService.ComputePossibleImplicitUsageConflicts(renamedSymbol, semanticModel, originalDeclarationLocation, newDeclarationLocationStartingPosition, cancellationToken); foreach (var implicitUsageConflict in implicitUsageConflicts) { Contract.ThrowIfNull(implicitUsageConflict.SourceTree); conflictResolution.AddOrReplaceRelatedLocation(new RelatedLocation( implicitUsageConflict.SourceSpan, conflictResolution.OldSolution.GetRequiredDocument(implicitUsageConflict.SourceTree).Id, RelatedLocationType.UnresolvableConflict)); } } if (implicitReferenceLocations.IsEmpty()) { return; } foreach (var implicitReferenceLocationsPerLanguage in implicitReferenceLocations.GroupBy(loc => loc.Document.Project.Language)) { // the location of the implicit reference defines the language rules to check. // E.g. foreach in C# using a MoveNext in VB that is renamed to MOVENEXT (within VB) var renameRewriterService = implicitReferenceLocationsPerLanguage.First().Document.Project.LanguageServices.GetRequiredService <IRenameRewriterLanguageService>(); var implicitConflicts = await renameRewriterService.ComputeImplicitReferenceConflictsAsync( originalSymbol, renamedSymbol, implicitReferenceLocationsPerLanguage, cancellationToken).ConfigureAwait(false); foreach (var implicitConflict in implicitConflicts) { Contract.ThrowIfNull(implicitConflict.SourceTree); conflictResolution.AddRelatedLocation(new RelatedLocation( implicitConflict.SourceSpan, conflictResolution.OldSolution.GetRequiredDocument(implicitConflict.SourceTree).Id, RelatedLocationType.UnresolvableConflict)); } } }
private static void AddConflictingSymbolLocations(IEnumerable <ISymbol> conflictingSymbols, MutableConflictResolution conflictResolution, IDictionary <Location, Location> reverseMappedLocations) { foreach (var newSymbol in conflictingSymbols) { foreach (var newLocation in newSymbol.Locations) { if (newLocation.IsInSource) { if (reverseMappedLocations.TryGetValue(newLocation, out var oldLocation)) { conflictResolution.AddOrReplaceRelatedLocation(new RelatedLocation(oldLocation.SourceSpan, conflictResolution.OldSolution.GetDocument(oldLocation.SourceTree).Id, RelatedLocationType.UnresolvableConflict)); } } } } }
/// <summary> /// Computes an adds conflicts relating to declarations, which are independent of /// location-based checks. Examples of these types of conflicts include renaming a member to /// the same name as another member of a type: binding doesn't change (at least from the /// perspective of find all references), but we still need to track it. /// </summary> private static async Task AddDeclarationConflictsAsync( ISymbol renamedSymbol, ISymbol renameSymbol, IEnumerable <ISymbol> referencedSymbols, MutableConflictResolution conflictResolution, IDictionary <Location, Location> reverseMappedLocations, CancellationToken cancellationToken) { try { var project = conflictResolution.CurrentSolution.GetProject(renamedSymbol.ContainingAssembly, cancellationToken); if (renamedSymbol.ContainingSymbol.IsKind(SymbolKind.NamedType)) { var otherThingsNamedTheSame = renamedSymbol.ContainingType.GetMembers(renamedSymbol.Name) .Where(s => !s.Equals(renamedSymbol) && string.Equals(s.MetadataName, renamedSymbol.MetadataName, StringComparison.Ordinal)); IEnumerable <ISymbol> otherThingsNamedTheSameExcludeMethodAndParameterizedProperty; // Possibly overloaded symbols are excluded here and handled elsewhere var semanticFactsService = project.LanguageServices.GetService <ISemanticFactsService>(); if (semanticFactsService.SupportsParameterizedProperties) { otherThingsNamedTheSameExcludeMethodAndParameterizedProperty = otherThingsNamedTheSame .Where(s => !s.MatchesKind(SymbolKind.Method, SymbolKind.Property) || !renamedSymbol.MatchesKind(SymbolKind.Method, SymbolKind.Property)); } else { otherThingsNamedTheSameExcludeMethodAndParameterizedProperty = otherThingsNamedTheSame .Where(s => s.Kind != SymbolKind.Method || renamedSymbol.Kind != SymbolKind.Method); } AddConflictingSymbolLocations(otherThingsNamedTheSameExcludeMethodAndParameterizedProperty, conflictResolution, reverseMappedLocations); } if (renamedSymbol.IsKind(SymbolKind.Namespace) && renamedSymbol.ContainingSymbol.IsKind(SymbolKind.Namespace)) { var otherThingsNamedTheSame = ((INamespaceSymbol)renamedSymbol.ContainingSymbol).GetMembers(renamedSymbol.Name) .Where(s => !s.Equals(renamedSymbol) && !s.IsKind(SymbolKind.Namespace) && string.Equals(s.MetadataName, renamedSymbol.MetadataName, StringComparison.Ordinal)); AddConflictingSymbolLocations(otherThingsNamedTheSame, conflictResolution, reverseMappedLocations); } if (renamedSymbol.IsKind(SymbolKind.NamedType) && renamedSymbol.ContainingSymbol is INamespaceOrTypeSymbol) { var otherThingsNamedTheSame = ((INamespaceOrTypeSymbol)renamedSymbol.ContainingSymbol).GetMembers(renamedSymbol.Name) .Where(s => !s.Equals(renamedSymbol) && string.Equals(s.MetadataName, renamedSymbol.MetadataName, StringComparison.Ordinal)); var conflictingSymbolLocations = otherThingsNamedTheSame.Where(s => !s.IsKind(SymbolKind.Namespace)); if (otherThingsNamedTheSame.Any(s => s.IsKind(SymbolKind.Namespace))) { conflictingSymbolLocations = conflictingSymbolLocations.Concat(renamedSymbol); } AddConflictingSymbolLocations(conflictingSymbolLocations, conflictResolution, reverseMappedLocations); } // Some types of symbols (namespaces, cref stuff, etc) might not have ContainingAssemblies if (renamedSymbol.ContainingAssembly != null) { // There also might be language specific rules we need to include var languageRenameService = project.LanguageServices.GetService <IRenameRewriterLanguageService>(); var languageConflicts = await languageRenameService.ComputeDeclarationConflictsAsync( conflictResolution.ReplacementText, renamedSymbol, renameSymbol, referencedSymbols, conflictResolution.OldSolution, conflictResolution.CurrentSolution, reverseMappedLocations, cancellationToken).ConfigureAwait(false); foreach (var languageConflict in languageConflicts) { conflictResolution.AddOrReplaceRelatedLocation(new RelatedLocation(languageConflict.SourceSpan, conflictResolution.OldSolution.GetDocument(languageConflict.SourceTree).Id, RelatedLocationType.UnresolvableConflict)); } } } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { // A NullReferenceException is happening in this method, but the dumps do not // contain information about this stack frame because this method is async and // therefore the exception filter in IdentifyConflictsAsync is insufficient. // See https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=378642 throw ExceptionUtilities.Unreachable; } }
private static bool IsRenameValid(MutableConflictResolution conflictResolution, ISymbol renamedSymbol) { // if we rename an identifier and it now binds to a symbol from metadata this should be treated as // an invalid rename. return(conflictResolution.ReplacementTextValid && renamedSymbol != null && renamedSymbol.Locations.Any(loc => loc.IsInSource)); }