| 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 library services.src.refactoring.rename_class_member; | 5 library services.src.refactoring.rename_class_member; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol_server.dart' | 9 import 'package:analysis_server/src/protocol_server.dart' |
| 10 hide Element, ElementKind; | 10 hide Element, ElementKind; |
| 11 import 'package:analysis_server/src/services/correction/status.dart'; | 11 import 'package:analysis_server/src/services/correction/status.dart'; |
| 12 import 'package:analysis_server/src/services/correction/util.dart'; | 12 import 'package:analysis_server/src/services/correction/util.dart'; |
| 13 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart
'; | 13 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart
'; |
| 14 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; | 14 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; |
| 15 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
rt'; | 15 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
rt'; |
| 16 import 'package:analysis_server/src/services/refactoring/rename.dart'; | 16 import 'package:analysis_server/src/services/refactoring/rename.dart'; |
| 17 import 'package:analysis_server/src/services/search/hierarchy.dart'; | 17 import 'package:analysis_server/src/services/search/hierarchy.dart'; |
| 18 import 'package:analysis_server/src/services/search/search_engine.dart'; | 18 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 19 import 'package:analyzer/src/generated/ast.dart' show Identifier; |
| 19 import 'package:analyzer/src/generated/element.dart'; | 20 import 'package:analyzer/src/generated/element.dart'; |
| 20 import 'package:analyzer/src/generated/java_core.dart'; | 21 import 'package:analyzer/src/generated/java_core.dart'; |
| 21 | 22 |
| 22 /** | 23 /** |
| 23 * Checks if creating a method with the given [name] in [classElement] will | 24 * Checks if creating a method with the given [name] in [classElement] will |
| 24 * cause any conflicts. | 25 * cause any conflicts. |
| 25 */ | 26 */ |
| 26 Future<RefactoringStatus> validateCreateMethod( | 27 Future<RefactoringStatus> validateCreateMethod( |
| 27 SearchEngine searchEngine, ClassElement classElement, String name) { | 28 SearchEngine searchEngine, ClassElement classElement, String name) { |
| 28 return new _ClassMemberValidator.forCreate(searchEngine, classElement, name) | 29 return new _ClassMemberValidator.forCreate(searchEngine, classElement, name) |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 potentialEditIds.add(id); | 117 potentialEditIds.add(id); |
| 117 return id; | 118 return id; |
| 118 } | 119 } |
| 119 } | 120 } |
| 120 | 121 |
| 121 /** | 122 /** |
| 122 * Helper to check if the created or renamed [Element] will cause any conflicts. | 123 * Helper to check if the created or renamed [Element] will cause any conflicts. |
| 123 */ | 124 */ |
| 124 class _ClassMemberValidator { | 125 class _ClassMemberValidator { |
| 125 final SearchEngine searchEngine; | 126 final SearchEngine searchEngine; |
| 127 final LibraryElement library; |
| 126 final Element element; | 128 final Element element; |
| 127 final ClassElement elementClass; | 129 final ClassElement elementClass; |
| 128 final ElementKind elementKind; | 130 final ElementKind elementKind; |
| 129 final String name; | 131 final String name; |
| 130 final bool isRename; | 132 final bool isRename; |
| 131 | 133 |
| 134 final RefactoringStatus result = new RefactoringStatus(); |
| 132 Set<Element> elements = new Set<Element>(); | 135 Set<Element> elements = new Set<Element>(); |
| 133 List<SearchMatch> references = <SearchMatch>[]; | 136 List<SearchMatch> references = <SearchMatch>[]; |
| 134 | 137 |
| 135 _ClassMemberValidator.forCreate( | 138 _ClassMemberValidator.forCreate( |
| 136 this.searchEngine, this.elementClass, this.name) | 139 this.searchEngine, this.elementClass, this.name) |
| 137 : isRename = false, | 140 : isRename = false, |
| 141 library = null, |
| 138 element = null, | 142 element = null, |
| 139 elementKind = ElementKind.METHOD; | 143 elementKind = ElementKind.METHOD; |
| 140 | 144 |
| 141 _ClassMemberValidator.forRename(this.searchEngine, Element element, this.name) | 145 _ClassMemberValidator.forRename(this.searchEngine, Element element, this.name) |
| 142 : isRename = true, | 146 : isRename = true, |
| 147 library = element.library, |
| 143 element = element, | 148 element = element, |
| 144 elementClass = element.enclosingElement, | 149 elementClass = element.enclosingElement, |
| 145 elementKind = element.kind; | 150 elementKind = element.kind; |
| 146 | 151 |
| 147 Future<RefactoringStatus> validate() async { | 152 Future<RefactoringStatus> validate() async { |
| 148 RefactoringStatus result = new RefactoringStatus(); | |
| 149 // check if there is a member with "newName" in the same ClassElement | 153 // check if there is a member with "newName" in the same ClassElement |
| 150 for (Element newNameMember in getChildren(elementClass, name)) { | 154 for (Element newNameMember in getChildren(elementClass, name)) { |
| 151 result.addError(format( | 155 result.addError(format( |
| 152 "Class '{0}' already declares {1} with name '{2}'.", | 156 "Class '{0}' already declares {1} with name '{2}'.", |
| 153 elementClass.displayName, getElementKindName(newNameMember), | 157 elementClass.displayName, getElementKindName(newNameMember), |
| 154 name), newLocation_fromElement(newNameMember)); | 158 name), newLocation_fromElement(newNameMember)); |
| 155 } | 159 } |
| 156 // do chained computations | 160 // do chained computations |
| 157 Set<ClassElement> superClasses = getSuperClasses(elementClass); | 161 Set<ClassElement> superClasses = getSuperClasses(elementClass); |
| 158 await _prepareReferences(); | 162 await _prepareReferences(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 if (isReferenceInLocalRange(localElement, reference)) { | 195 if (isReferenceInLocalRange(localElement, reference)) { |
| 192 result.addError(format( | 196 result.addError(format( |
| 193 "Usage of renamed {0} will be shadowed by {1} '{2}'.", | 197 "Usage of renamed {0} will be shadowed by {1} '{2}'.", |
| 194 elementKind.displayName, getElementKindName(localElement), | 198 elementKind.displayName, getElementKindName(localElement), |
| 195 localElement.displayName), newLocation_fromMatch(reference)); | 199 localElement.displayName), newLocation_fromMatch(reference)); |
| 196 } | 200 } |
| 197 } | 201 } |
| 198 } | 202 } |
| 199 } | 203 } |
| 200 } | 204 } |
| 205 // visibility |
| 206 if (isRename) { |
| 207 _validateWillBeInvisible(); |
| 208 } |
| 201 // done | 209 // done |
| 202 return result; | 210 return result; |
| 203 } | 211 } |
| 204 | 212 |
| 205 /** | 213 /** |
| 206 * Fills [elements] with [Element]s to rename. | 214 * Fills [elements] with [Element]s to rename. |
| 207 */ | 215 */ |
| 208 Future _prepareElements() async { | 216 Future _prepareElements() async { |
| 209 if (element is ClassMemberElement) { | 217 if (element is ClassMemberElement) { |
| 210 elements = await getHierarchyMembers(searchEngine, element); | 218 elements = await getHierarchyMembers(searchEngine, element); |
| 211 } else { | 219 } else { |
| 212 elements = new Set.from([element]); | 220 elements = new Set.from([element]); |
| 213 } | 221 } |
| 214 } | 222 } |
| 215 | 223 |
| 216 /** | 224 /** |
| 217 * Fills [references] with all references to [elements]. | 225 * Fills [references] with all references to [elements]. |
| 218 */ | 226 */ |
| 219 Future _prepareReferences() async { | 227 Future _prepareReferences() async { |
| 220 if (!isRename) { | 228 if (!isRename) { |
| 221 return new Future.value(); | 229 return new Future.value(); |
| 222 } | 230 } |
| 223 await _prepareElements(); | 231 await _prepareElements(); |
| 224 await Future.forEach(elements, (Element element) async { | 232 await Future.forEach(elements, (Element element) async { |
| 225 List<SearchMatch> elementReferences = | 233 List<SearchMatch> elementReferences = |
| 226 await searchEngine.searchReferences(element); | 234 await searchEngine.searchReferences(element); |
| 227 references.addAll(elementReferences); | 235 references.addAll(elementReferences); |
| 228 }); | 236 }); |
| 229 } | 237 } |
| 238 |
| 239 /** |
| 240 * Validates if any usage of [element] renamed to [name] will be invisible. |
| 241 */ |
| 242 Future _validateWillBeInvisible() async { |
| 243 if (!Identifier.isPrivateName(name)) { |
| 244 return; |
| 245 } |
| 246 for (SearchMatch reference in references) { |
| 247 Element refElement = reference.element; |
| 248 LibraryElement refLibrary = refElement.library; |
| 249 if (refLibrary != library) { |
| 250 String message = format("Renamed {0} will be invisible in '{1}'.", |
| 251 getElementKindName(element), getElementQualifiedName(refLibrary)); |
| 252 result.addError(message, newLocation_fromMatch(reference)); |
| 253 } |
| 254 } |
| 255 } |
| 230 } | 256 } |
| OLD | NEW |