OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 | 6 |
7 import 'package:analysis_server/src/protocol_server.dart' hide Element; | 7 import 'package:analysis_server/src/protocol_server.dart' |
| 8 hide Element, ElementKind; |
8 import 'package:analysis_server/src/services/correction/status.dart'; | 9 import 'package:analysis_server/src/services/correction/status.dart'; |
9 import 'package:analysis_server/src/services/correction/util.dart'; | 10 import 'package:analysis_server/src/services/correction/util.dart'; |
10 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart
'; | 11 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart
'; |
11 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; | 12 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; |
12 import 'package:analysis_server/src/services/refactoring/rename.dart'; | 13 import 'package:analysis_server/src/services/refactoring/rename.dart'; |
13 import 'package:analysis_server/src/services/search/hierarchy.dart'; | 14 import 'package:analysis_server/src/services/search/hierarchy.dart'; |
14 import 'package:analysis_server/src/services/search/search_engine.dart'; | 15 import 'package:analysis_server/src/services/search/search_engine.dart'; |
15 import 'package:analyzer/dart/ast/ast.dart'; | 16 import 'package:analyzer/dart/ast/ast.dart'; |
16 import 'package:analyzer/dart/ast/visitor.dart'; | 17 import 'package:analyzer/dart/ast/visitor.dart'; |
17 import 'package:analyzer/dart/element/element.dart'; | 18 import 'package:analyzer/dart/element/element.dart'; |
(...skipping 29 matching lines...) Expand all Loading... |
47 return "Rename Local Variable"; | 48 return "Rename Local Variable"; |
48 } | 49 } |
49 | 50 |
50 @override | 51 @override |
51 Future<RefactoringStatus> checkFinalConditions() async { | 52 Future<RefactoringStatus> checkFinalConditions() async { |
52 RefactoringStatus result = new RefactoringStatus(); | 53 RefactoringStatus result = new RefactoringStatus(); |
53 await _prepareElements(); | 54 await _prepareElements(); |
54 for (LocalElement element in elements) { | 55 for (LocalElement element in elements) { |
55 CompilationUnit unit = await unitCache.getUnit(element); | 56 CompilationUnit unit = await unitCache.getUnit(element); |
56 if (unit != null) { | 57 if (unit != null) { |
57 SourceRange elementRange = element.visibleRange; | 58 unit.accept(new _ConflictValidatorVisitor(result, newName, element)); |
58 unit.accept(new _ConflictValidatorVisitor(this, result, elementRange)); | |
59 } | 59 } |
60 } | 60 } |
61 return result; | 61 return result; |
62 } | 62 } |
63 | 63 |
64 @override | 64 @override |
65 RefactoringStatus checkNewName() { | 65 RefactoringStatus checkNewName() { |
66 RefactoringStatus result = super.checkNewName(); | 66 RefactoringStatus result = super.checkNewName(); |
67 if (element is LocalVariableElement) { | 67 if (element is LocalVariableElement) { |
68 result.addStatus(validateVariableName(newName)); | 68 result.addStatus(validateVariableName(newName)); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 } | 104 } |
105 } | 105 } |
106 } | 106 } |
107 } else { | 107 } else { |
108 elements = new Set.from([element]); | 108 elements = new Set.from([element]); |
109 } | 109 } |
110 } | 110 } |
111 } | 111 } |
112 | 112 |
113 class _ConflictValidatorVisitor extends RecursiveAstVisitor { | 113 class _ConflictValidatorVisitor extends RecursiveAstVisitor { |
114 final RenameLocalRefactoringImpl refactoring; | |
115 final RefactoringStatus result; | 114 final RefactoringStatus result; |
116 final SourceRange elementRange; | 115 final String newName; |
| 116 final LocalElement target; |
117 final Set<Element> conflictingLocals = new Set<Element>(); | 117 final Set<Element> conflictingLocals = new Set<Element>(); |
118 | 118 |
119 _ConflictValidatorVisitor(this.refactoring, this.result, this.elementRange); | 119 _ConflictValidatorVisitor(this.result, this.newName, this.target); |
120 | 120 |
121 @override | 121 @override |
122 visitSimpleIdentifier(SimpleIdentifier node) { | 122 visitSimpleIdentifier(SimpleIdentifier node) { |
123 Element nodeElement = node.bestElement; | 123 Element nodeElement = node.bestElement; |
124 String newName = refactoring.newName; | |
125 if (nodeElement != null && nodeElement.name == newName) { | 124 if (nodeElement != null && nodeElement.name == newName) { |
126 // duplicate declaration | 125 // Duplicate declaration. |
127 if (node.inDeclarationContext() && | 126 if (node.inDeclarationContext() && _isVisibleWithTarget(nodeElement)) { |
128 haveIntersectingRanges(refactoring.element, nodeElement)) { | |
129 conflictingLocals.add(nodeElement); | 127 conflictingLocals.add(nodeElement); |
130 String nodeKind = nodeElement.kind.displayName; | 128 String nodeKind = nodeElement.kind.displayName; |
131 String message = "Duplicate $nodeKind '$newName'."; | 129 String message = "Duplicate $nodeKind '$newName'."; |
132 result.addError(message, newLocation_fromElement(nodeElement)); | 130 result.addError(message, newLocation_fromElement(nodeElement)); |
133 return; | 131 return; |
134 } | 132 } |
135 if (conflictingLocals.contains(nodeElement)) { | 133 if (conflictingLocals.contains(nodeElement)) { |
136 return; | 134 return; |
137 } | 135 } |
138 // shadowing referenced element | 136 // Shadowing by the target element. |
139 if (elementRange != null && | 137 SourceRange targetRange = target.visibleRange; |
140 elementRange.contains(node.offset) && | 138 if (targetRange != null && |
| 139 targetRange.contains(node.offset) && |
141 !node.isQualified && | 140 !node.isQualified && |
142 !_isNamedExpressionName(node)) { | 141 !_isNamedExpressionName(node)) { |
143 nodeElement = getSyntheticAccessorVariable(nodeElement); | 142 nodeElement = getSyntheticAccessorVariable(nodeElement); |
144 String nodeKind = nodeElement.kind.displayName; | 143 String nodeKind = nodeElement.kind.displayName; |
145 String nodeName = getElementQualifiedName(nodeElement); | 144 String nodeName = getElementQualifiedName(nodeElement); |
146 String nameElementSourceName = nodeElement.source.shortName; | 145 String nameElementSourceName = nodeElement.source.shortName; |
147 String refKind = refactoring.element.kind.displayName; | 146 String refKind = target.kind.displayName; |
148 String message = 'Usage of $nodeKind "$nodeName" declared in ' | 147 String message = 'Usage of $nodeKind "$nodeName" declared in ' |
149 '"$nameElementSourceName" will be shadowed by renamed $refKind.'; | 148 '"$nameElementSourceName" will be shadowed by renamed $refKind.'; |
150 result.addError(message, newLocation_fromNode(node)); | 149 result.addError(message, newLocation_fromNode(node)); |
151 } | 150 } |
152 } | 151 } |
153 } | 152 } |
154 | 153 |
| 154 /** |
| 155 * Returns whether [element] and [target] are visible together. |
| 156 */ |
| 157 bool _isVisibleWithTarget(Element element) { |
| 158 if (element is LocalElement) { |
| 159 SourceRange targetRange = target.visibleRange; |
| 160 SourceRange elementRange = element.visibleRange; |
| 161 return targetRange != null && |
| 162 elementRange != null && |
| 163 elementRange.intersects(targetRange); |
| 164 } |
| 165 return false; |
| 166 } |
| 167 |
155 static bool _isNamedExpressionName(SimpleIdentifier node) { | 168 static bool _isNamedExpressionName(SimpleIdentifier node) { |
156 return node.parent is Label && node.parent.parent is NamedExpression; | 169 return node.parent is Label && node.parent.parent is NamedExpression; |
157 } | 170 } |
158 } | 171 } |
OLD | NEW |