| 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' hide Element, | 9 import 'package:analysis_server/src/protocol_server.dart' hide Element, |
| 10 ElementKind; | 10 ElementKind; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 if (element is FieldElement) { | 75 if (element is FieldElement) { |
| 76 result.addStatus(validateFieldName(newName)); | 76 result.addStatus(validateFieldName(newName)); |
| 77 } | 77 } |
| 78 if (element is MethodElement) { | 78 if (element is MethodElement) { |
| 79 result.addStatus(validateMethodName(newName)); | 79 result.addStatus(validateMethodName(newName)); |
| 80 } | 80 } |
| 81 return result; | 81 return result; |
| 82 } | 82 } |
| 83 | 83 |
| 84 @override | 84 @override |
| 85 Future fillChange() { | 85 Future fillChange() async { |
| 86 // update declarations | 86 // update declarations |
| 87 for (Element renameElement in _validator.elements) { | 87 for (Element renameElement in _validator.elements) { |
| 88 if (renameElement.isSynthetic && renameElement is FieldElement) { | 88 if (renameElement.isSynthetic && renameElement is FieldElement) { |
| 89 addDeclarationEdit(renameElement.getter); | 89 addDeclarationEdit(renameElement.getter); |
| 90 addDeclarationEdit(renameElement.setter); | 90 addDeclarationEdit(renameElement.setter); |
| 91 } else { | 91 } else { |
| 92 addDeclarationEdit(renameElement); | 92 addDeclarationEdit(renameElement); |
| 93 } | 93 } |
| 94 } | 94 } |
| 95 // update references | 95 // update references |
| 96 addReferenceEdits(_validator.references); | 96 addReferenceEdits(_validator.references); |
| 97 // potential matches | 97 // potential matches |
| 98 return searchEngine.searchMemberReferences(oldName).then((nameMatches) { | 98 List<SearchMatch> nameMatches = |
| 99 List<SourceReference> nameRefs = getSourceReferences(nameMatches); | 99 await searchEngine.searchMemberReferences(oldName); |
| 100 for (SourceReference reference in nameRefs) { | 100 List<SourceReference> nameRefs = getSourceReferences(nameMatches); |
| 101 // ignore resolved reference, we have already updated it | 101 for (SourceReference reference in nameRefs) { |
| 102 if (reference.isResolved) { | 102 // ignore resolved reference, we have already updated it |
| 103 if (reference.isResolved) { |
| 104 continue; |
| 105 } |
| 106 // check the element being renamed is accessible |
| 107 { |
| 108 LibraryElement whereLibrary = reference.element.library; |
| 109 if (!element.isAccessibleIn(whereLibrary)) { |
| 103 continue; | 110 continue; |
| 104 } | 111 } |
| 105 // check the element being renamed is accessible | |
| 106 { | |
| 107 LibraryElement whereLibrary = reference.element.library; | |
| 108 if (!element.isAccessibleIn(whereLibrary)) { | |
| 109 continue; | |
| 110 } | |
| 111 } | |
| 112 // add edit | |
| 113 reference.addEdit(change, newName, id: _newPotentialId()); | |
| 114 } | 112 } |
| 115 }); | 113 // add edit |
| 114 reference.addEdit(change, newName, id: _newPotentialId()); |
| 115 } |
| 116 } | 116 } |
| 117 | 117 |
| 118 String _newPotentialId() { | 118 String _newPotentialId() { |
| 119 String id = potentialEditIds.length.toString(); | 119 String id = potentialEditIds.length.toString(); |
| 120 potentialEditIds.add(id); | 120 potentialEditIds.add(id); |
| 121 return id; | 121 return id; |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 | 124 |
| 125 | 125 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 142 : isRename = false, | 142 : isRename = false, |
| 143 element = null, | 143 element = null, |
| 144 elementKind = ElementKind.METHOD; | 144 elementKind = ElementKind.METHOD; |
| 145 | 145 |
| 146 _ClassMemberValidator.forRename(this.searchEngine, Element element, this.name) | 146 _ClassMemberValidator.forRename(this.searchEngine, Element element, this.name) |
| 147 : isRename = true, | 147 : isRename = true, |
| 148 element = element, | 148 element = element, |
| 149 elementClass = element.enclosingElement, | 149 elementClass = element.enclosingElement, |
| 150 elementKind = element.kind; | 150 elementKind = element.kind; |
| 151 | 151 |
| 152 Future<RefactoringStatus> validate() { | 152 Future<RefactoringStatus> validate() async { |
| 153 RefactoringStatus result = new RefactoringStatus(); | 153 RefactoringStatus result = new RefactoringStatus(); |
| 154 // check if there is a member with "newName" in the same ClassElement | 154 // check if there is a member with "newName" in the same ClassElement |
| 155 for (Element newNameMember in getChildren(elementClass, name)) { | 155 for (Element newNameMember in getChildren(elementClass, name)) { |
| 156 result.addError( | 156 result.addError( |
| 157 format( | 157 format( |
| 158 "Class '{0}' already declares {1} with name '{2}'.", | 158 "Class '{0}' already declares {1} with name '{2}'.", |
| 159 elementClass.displayName, | 159 elementClass.displayName, |
| 160 getElementKindName(newNameMember), | 160 getElementKindName(newNameMember), |
| 161 name), | 161 name), |
| 162 newLocation_fromElement(newNameMember)); | 162 newLocation_fromElement(newNameMember)); |
| 163 } | 163 } |
| 164 // do chained computations | 164 // do chained computations |
| 165 Set<ClassElement> superClasses = getSuperClasses(elementClass); | 165 Set<ClassElement> superClasses = getSuperClasses(elementClass); |
| 166 Set<ClassElement> subClasses; | 166 await _prepareReferences(); |
| 167 return _prepareReferences().then((_) { | 167 Set<ClassElement> subClasses = |
| 168 return getSubClasses(searchEngine, elementClass).then((_subs) { | 168 await getSubClasses(searchEngine, elementClass); |
| 169 subClasses = _subs; | 169 // check shadowing in hierarchy |
| 170 }); | 170 List<SearchMatch> declarations = |
| 171 }).then((_) { | 171 await searchEngine.searchElementDeclarations(name); |
| 172 // check shadowing in hierarchy | 172 for (SearchMatch declaration in declarations) { |
| 173 return searchEngine.searchElementDeclarations(name).then((decls) { | 173 Element nameElement = getSyntheticAccessorVariable(declaration.element); |
| 174 for (SearchMatch decl in decls) { | 174 Element nameClass = nameElement.enclosingElement; |
| 175 Element nameElement = getSyntheticAccessorVariable(decl.element); | 175 // renamed Element shadows member of superclass |
| 176 Element nameClass = nameElement.enclosingElement; | 176 if (superClasses.contains(nameClass)) { |
| 177 // renamed Element shadows member of superclass | 177 result.addError( |
| 178 if (superClasses.contains(nameClass)) { | 178 format( |
| 179 result.addError( | 179 isRename ? |
| 180 format( | 180 "Renamed {0} will shadow {1} '{2}'." : |
| 181 isRename ? | 181 "Created {0} will shadow {1} '{2}'.", |
| 182 "Renamed {0} will shadow {1} '{2}'." : | 182 elementKind.displayName, |
| 183 "Created {0} will shadow {1} '{2}'.", | 183 getElementKindName(nameElement), |
| 184 elementKind.displayName, | 184 getElementQualifiedName(nameElement)), |
| 185 getElementKindName(nameElement), | 185 newLocation_fromElement(nameElement)); |
| 186 getElementQualifiedName(nameElement)), | 186 } |
| 187 newLocation_fromElement(nameElement)); | 187 // renamed Element is shadowed by member of subclass |
| 188 } | 188 if (isRename && subClasses.contains(nameClass)) { |
| 189 // renamed Element is shadowed by member of subclass | 189 result.addError( |
| 190 if (isRename && subClasses.contains(nameClass)) { | 190 format( |
| 191 result.addError( | 191 "Renamed {0} will be shadowed by {1} '{2}'.", |
| 192 format( | 192 elementKind.displayName, |
| 193 "Renamed {0} will be shadowed by {1} '{2}'.", | 193 getElementKindName(nameElement), |
| 194 elementKind.displayName, | 194 getElementQualifiedName(nameElement)), |
| 195 getElementKindName(nameElement), | 195 newLocation_fromElement(nameElement)); |
| 196 getElementQualifiedName(nameElement)), | 196 } |
| 197 newLocation_fromElement(nameElement)); | 197 // renamed Element is shadowed by local |
| 198 } | 198 if (nameElement is LocalElement) { |
| 199 // renamed Element is shadowed by local | 199 LocalElement localElement = nameElement; |
| 200 if (nameElement is LocalElement) { | 200 ClassElement enclosingClass = |
| 201 LocalElement localElement = nameElement; | 201 nameElement.getAncestor((element) => element is ClassElement); |
| 202 ClassElement enclosingClass = | 202 if (enclosingClass == elementClass || |
| 203 nameElement.getAncestor((element) => element is ClassElement); | 203 subClasses.contains(enclosingClass)) { |
| 204 if (enclosingClass == elementClass || | 204 for (SearchMatch reference in references) { |
| 205 subClasses.contains(enclosingClass)) { | 205 if (isReferenceInLocalRange(localElement, reference)) { |
| 206 for (SearchMatch reference in references) { | 206 result.addError( |
| 207 if (isReferenceInLocalRange(localElement, reference)) { | 207 format( |
| 208 result.addError( | 208 "Usage of renamed {0} will be shadowed by {1} '{2}'.", |
| 209 format( | 209 elementKind.displayName, |
| 210 "Usage of renamed {0} will be shadowed by {1} '{2}'.", | 210 getElementKindName(localElement), |
| 211 elementKind.displayName, | 211 localElement.displayName), |
| 212 getElementKindName(localElement), | 212 newLocation_fromMatch(reference)); |
| 213 localElement.displayName), | |
| 214 newLocation_fromMatch(reference)); | |
| 215 } | |
| 216 } | |
| 217 } | 213 } |
| 218 } | 214 } |
| 219 } | 215 } |
| 220 }); | 216 } |
| 221 }).then((_) => result); | 217 } |
| 218 // done |
| 219 return result; |
| 222 } | 220 } |
| 223 | 221 |
| 224 /** | 222 /** |
| 225 * Fills [elements] with [Element]s to rename. | 223 * Fills [elements] with [Element]s to rename. |
| 226 */ | 224 */ |
| 227 Future _prepareElements() { | 225 Future _prepareElements() async { |
| 228 if (element is ClassMemberElement) { | 226 if (element is ClassMemberElement) { |
| 229 return getHierarchyMembers( | 227 elements = await getHierarchyMembers(searchEngine, element); |
| 230 searchEngine, | |
| 231 element).then((Set<Element> elements) { | |
| 232 this.elements = elements; | |
| 233 }); | |
| 234 } else { | 228 } else { |
| 235 elements = new Set.from([element]); | 229 elements = new Set.from([element]); |
| 236 return new Future.value(); | |
| 237 } | 230 } |
| 238 } | 231 } |
| 239 | 232 |
| 240 /** | 233 /** |
| 241 * Fills [references] with all references to [elements]. | 234 * Fills [references] with all references to [elements]. |
| 242 */ | 235 */ |
| 243 Future _prepareReferences() { | 236 Future _prepareReferences() async { |
| 244 if (!isRename) { | 237 if (!isRename) { |
| 245 return new Future.value(); | 238 return new Future.value(); |
| 246 } | 239 } |
| 247 return _prepareElements().then((_) { | 240 await _prepareElements(); |
| 248 return Future.forEach(elements, (Element element) { | 241 await Future.forEach(elements, (Element element) async { |
| 249 return searchEngine.searchReferences(element).then((references) { | 242 List<SearchMatch> elementReferences = |
| 250 this.references.addAll(references); | 243 await searchEngine.searchReferences(element); |
| 251 }); | 244 references.addAll(elementReferences); |
| 252 }); | |
| 253 }); | 245 }); |
| 254 } | 246 } |
| 255 } | 247 } |
| OLD | NEW |