public IEnumerable<Location> ComputePossibleImplicitUsageConflicts( ISymbol renamedSymbol, SemanticModel semanticModel, Location originalDeclarationLocation, int newDeclarationLocationStartingPosition, CancellationToken cancellationToken) { // TODO: support other implicitly used methods like dispose if ((renamedSymbol.Name == "MoveNext" || renamedSymbol.Name == "GetEnumerator" || renamedSymbol.Name == "Current") && renamedSymbol.GetAllTypeArguments().Length == 0) { // TODO: partial methods currently only show the location where the rename happens as a conflict. // Consider showing both locations as a conflict. var baseType = renamedSymbol.ContainingType.GetBaseTypes().FirstOrDefault(); if (baseType != null) { var implicitSymbols = semanticModel.LookupSymbols( newDeclarationLocationStartingPosition, baseType, renamedSymbol.Name) .Where(sym => !sym.Equals(renamedSymbol)); foreach (var symbol in implicitSymbols) { if (symbol.GetAllTypeArguments().Length != 0) { continue; } if (symbol.Kind == SymbolKind.Method) { var method = (IMethodSymbol)symbol; if (symbol.Name == "MoveNext") { if (!method.ReturnsVoid && !method.Parameters.Any() && method.ReturnType.SpecialType == SpecialType.System_Boolean) { return SpecializedCollections.SingletonEnumerable(originalDeclarationLocation); } } else if (symbol.Name == "GetEnumerator") { // we are a bit pessimistic here. // To be sure we would need to check if the returned type is having a MoveNext and Current as required by foreach if (!method.ReturnsVoid && !method.Parameters.Any()) { return SpecializedCollections.SingletonEnumerable(originalDeclarationLocation); } } } else if (symbol.Kind == SymbolKind.Property && symbol.Name == "Current") { var property = (IPropertySymbol)symbol; if (!property.Parameters.Any() && !property.IsWriteOnly) { return SpecializedCollections.SingletonEnumerable(originalDeclarationLocation); } } } } } return SpecializedCollections.EmptyEnumerable<Location>(); }