Pass target elements being renamed into validator.

R=brianwilkerson@google.com
BUG=

Review-Url: https://codereview.chromium.org/2963173002 .
This commit is contained in:
Konstantin Shcheglov 2017-06-29 13:41:23 -07:00
parent 501688de4c
commit f6b7fd307a
2 changed files with 27 additions and 33 deletions

View file

@ -17,25 +17,6 @@ import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
import 'package:path/path.dart' as pathos;
/**
* Returns `true` if two given [Element]s are [LocalElement]s and have
* intersecting with visibility ranges.
*/
bool haveIntersectingRanges(LocalElement localElement, Element element) {
if (element is! LocalElement) {
return false;
}
LocalElement localElement2 = element as LocalElement;
Source localSource = localElement.source;
Source localSource2 = localElement2.source;
SourceRange localRange = localElement.visibleRange;
SourceRange localRange2 = localElement2.visibleRange;
return localSource2 == localSource &&
localRange != null &&
localRange2 != null &&
localRange2.intersects(localRange);
}
/**
* Checks if [element] is defined in the library containing [source].
*/

View file

@ -4,7 +4,8 @@
import 'dart:async';
import 'package:analysis_server/src/protocol_server.dart' hide Element;
import 'package:analysis_server/src/protocol_server.dart'
hide Element, ElementKind;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
@ -54,8 +55,7 @@ class RenameLocalRefactoringImpl extends RenameRefactoringImpl {
for (LocalElement element in elements) {
CompilationUnit unit = await unitCache.getUnit(element);
if (unit != null) {
SourceRange elementRange = element.visibleRange;
unit.accept(new _ConflictValidatorVisitor(this, result, elementRange));
unit.accept(new _ConflictValidatorVisitor(result, newName, element));
}
}
return result;
@ -111,21 +111,19 @@ class RenameLocalRefactoringImpl extends RenameRefactoringImpl {
}
class _ConflictValidatorVisitor extends RecursiveAstVisitor {
final RenameLocalRefactoringImpl refactoring;
final RefactoringStatus result;
final SourceRange elementRange;
final String newName;
final LocalElement target;
final Set<Element> conflictingLocals = new Set<Element>();
_ConflictValidatorVisitor(this.refactoring, this.result, this.elementRange);
_ConflictValidatorVisitor(this.result, this.newName, this.target);
@override
visitSimpleIdentifier(SimpleIdentifier node) {
Element nodeElement = node.bestElement;
String newName = refactoring.newName;
if (nodeElement != null && nodeElement.name == newName) {
// duplicate declaration
if (node.inDeclarationContext() &&
haveIntersectingRanges(refactoring.element, nodeElement)) {
// Duplicate declaration.
if (node.inDeclarationContext() && _isVisibleWithTarget(nodeElement)) {
conflictingLocals.add(nodeElement);
String nodeKind = nodeElement.kind.displayName;
String message = "Duplicate $nodeKind '$newName'.";
@ -135,16 +133,17 @@ class _ConflictValidatorVisitor extends RecursiveAstVisitor {
if (conflictingLocals.contains(nodeElement)) {
return;
}
// shadowing referenced element
if (elementRange != null &&
elementRange.contains(node.offset) &&
// Shadowing by the target element.
SourceRange targetRange = target.visibleRange;
if (targetRange != null &&
targetRange.contains(node.offset) &&
!node.isQualified &&
!_isNamedExpressionName(node)) {
nodeElement = getSyntheticAccessorVariable(nodeElement);
String nodeKind = nodeElement.kind.displayName;
String nodeName = getElementQualifiedName(nodeElement);
String nameElementSourceName = nodeElement.source.shortName;
String refKind = refactoring.element.kind.displayName;
String refKind = target.kind.displayName;
String message = 'Usage of $nodeKind "$nodeName" declared in '
'"$nameElementSourceName" will be shadowed by renamed $refKind.';
result.addError(message, newLocation_fromNode(node));
@ -152,6 +151,20 @@ class _ConflictValidatorVisitor extends RecursiveAstVisitor {
}
}
/**
* Returns whether [element] and [target] are visible together.
*/
bool _isVisibleWithTarget(Element element) {
if (element is LocalElement) {
SourceRange targetRange = target.visibleRange;
SourceRange elementRange = element.visibleRange;
return targetRange != null &&
elementRange != null &&
elementRange.intersects(targetRange);
}
return false;
}
static bool _isNamedExpressionName(SimpleIdentifier node) {
return node.parent is Label && node.parent.parent is NamedExpression;
}