| Index: pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
|
| diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
|
| index c2deaa12f8a3840858d06d185ae8b998e45a0f7f..22aa8eeb4ab42c1e5800508109daf79f4dc95835 100644
|
| --- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
|
| +++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
|
| @@ -14,17 +14,20 @@ import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
|
| import 'package:analysis_server/src/services/refactoring/rename.dart';
|
| import 'package:analysis_server/src/services/search/hierarchy.dart';
|
| import 'package:analysis_server/src/services/search/search_engine.dart';
|
| -import 'package:analyzer/dart/ast/ast.dart' show Identifier;
|
| +import 'package:analyzer/dart/ast/ast.dart';
|
| +import 'package:analyzer/dart/ast/visitor.dart';
|
| import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/src/dart/element/ast_provider.dart';
|
| import 'package:analyzer/src/generated/java_core.dart';
|
|
|
| /**
|
| * Checks if creating a method with the given [name] in [classElement] will
|
| * cause any conflicts.
|
| */
|
| -Future<RefactoringStatus> validateCreateMethod(
|
| - SearchEngine searchEngine, ClassElement classElement, String name) {
|
| - return new _ClassMemberValidator.forCreate(searchEngine, classElement, name)
|
| +Future<RefactoringStatus> validateCreateMethod(SearchEngine searchEngine,
|
| + AstProvider astProvider, ClassElement classElement, String name) {
|
| + return new _ClassMemberValidator.forCreate(
|
| + searchEngine, astProvider, classElement, name)
|
| .validate();
|
| }
|
|
|
| @@ -32,9 +35,12 @@ Future<RefactoringStatus> validateCreateMethod(
|
| * A [Refactoring] for renaming class member [Element]s.
|
| */
|
| class RenameClassMemberRefactoringImpl extends RenameRefactoringImpl {
|
| + final AstProvider astProvider;
|
| +
|
| _ClassMemberValidator _validator;
|
|
|
| - RenameClassMemberRefactoringImpl(SearchEngine searchEngine, Element element)
|
| + RenameClassMemberRefactoringImpl(
|
| + SearchEngine searchEngine, this.astProvider, Element element)
|
| : super(searchEngine, element);
|
|
|
| @override
|
| @@ -50,8 +56,8 @@ class RenameClassMemberRefactoringImpl extends RenameRefactoringImpl {
|
|
|
| @override
|
| Future<RefactoringStatus> checkFinalConditions() {
|
| - _validator =
|
| - new _ClassMemberValidator.forRename(searchEngine, element, newName);
|
| + _validator = new _ClassMemberValidator.forRename(
|
| + searchEngine, astProvider, element, newName);
|
| return _validator.validate();
|
| }
|
|
|
| @@ -122,6 +128,7 @@ class RenameClassMemberRefactoringImpl extends RenameRefactoringImpl {
|
| */
|
| class _ClassMemberValidator {
|
| final SearchEngine searchEngine;
|
| + final ResolvedUnitCache unitCache;
|
| final LibraryElement library;
|
| final Element element;
|
| final ClassElement elementClass;
|
| @@ -134,14 +141,17 @@ class _ClassMemberValidator {
|
| List<SearchMatch> references = <SearchMatch>[];
|
|
|
| _ClassMemberValidator.forCreate(
|
| - this.searchEngine, this.elementClass, this.name)
|
| - : isRename = false,
|
| + this.searchEngine, AstProvider astProvider, this.elementClass, this.name)
|
| + : unitCache = new ResolvedUnitCache(astProvider),
|
| + isRename = false,
|
| library = null,
|
| element = null,
|
| elementKind = ElementKind.METHOD;
|
|
|
| - _ClassMemberValidator.forRename(this.searchEngine, Element element, this.name)
|
| - : isRename = true,
|
| + _ClassMemberValidator.forRename(
|
| + this.searchEngine, AstProvider astProvider, Element element, this.name)
|
| + : unitCache = new ResolvedUnitCache(astProvider),
|
| + isRename = true,
|
| library = element.library,
|
| element = element,
|
| elementClass = element.enclosingElement,
|
| @@ -188,7 +198,7 @@ class _ClassMemberValidator {
|
| }
|
| // usage of the renamed Element is shadowed by a local element
|
| {
|
| - _MatchShadowedByLocal conflict = _getShadowingLocalElement();
|
| + _MatchShadowedByLocal conflict = await _getShadowingLocalElement();
|
| if (conflict != null) {
|
| LocalElement localElement = conflict.localElement;
|
| result.addError(
|
| @@ -237,25 +247,31 @@ class _ClassMemberValidator {
|
| return result;
|
| }
|
|
|
| - _MatchShadowedByLocal _getShadowingLocalElement() {
|
| + Future<_MatchShadowedByLocal> _getShadowingLocalElement() async {
|
| + var localElementMap = <CompilationUnitElement, List<LocalElement>>{};
|
| + Future<List<LocalElement>> getLocalElements(Element element) async {
|
| + var unitElement = unitCache.getUnitElement(element);
|
| + var localElements = localElementMap[unitElement];
|
| + if (localElements == null) {
|
| + var unit = await unitCache.getUnit(unitElement);
|
| + var collector = new _LocalElementsCollector(name);
|
| + unit.accept(collector);
|
| + localElements = collector.elements;
|
| + localElementMap[unitElement] = localElements;
|
| + }
|
| + return localElements;
|
| + }
|
| +
|
| for (SearchMatch match in references) {
|
| - // qualified reference cannot be shadowed by a local element
|
| + // Qualified reference cannot be shadowed by local elements.
|
| if (match.isQualified) {
|
| continue;
|
| }
|
| - // check local elements of the enclosing executable
|
| - Element containingElement = match.element;
|
| - if (containingElement is ExecutableElement) {
|
| - Iterable<LocalElement> localElements = <Iterable<LocalElement>>[
|
| - containingElement.functions,
|
| - containingElement.localVariables,
|
| - containingElement.parameters
|
| - ].expand((Iterable<LocalElement> x) => x);
|
| - for (LocalElement localElement in localElements) {
|
| - if (localElement.displayName == name &&
|
| - localElement.visibleRange.intersects(match.sourceRange)) {
|
| - return new _MatchShadowedByLocal(match, localElement);
|
| - }
|
| + // Check local elements that might shadow the reference.
|
| + var localElements = await getLocalElements(match.element);
|
| + for (LocalElement localElement in localElements) {
|
| + if (localElement.visibleRange.intersects(match.sourceRange)) {
|
| + return new _MatchShadowedByLocal(match, localElement);
|
| }
|
| }
|
| }
|
| @@ -307,6 +323,20 @@ class _ClassMemberValidator {
|
| }
|
| }
|
|
|
| +class _LocalElementsCollector extends GeneralizingAstVisitor<Null> {
|
| + final String name;
|
| + final List<LocalElement> elements = [];
|
| +
|
| + _LocalElementsCollector(this.name);
|
| +
|
| + visitSimpleIdentifier(SimpleIdentifier node) {
|
| + Element element = node.staticElement;
|
| + if (element is LocalElement && element.name == name) {
|
| + elements.add(element);
|
| + }
|
| + }
|
| +}
|
| +
|
| class _MatchShadowedByLocal {
|
| final SearchMatch match;
|
| final LocalElement localElement;
|
|
|