| 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_services/correction/change.dart'; | 9 import 'package:analysis_services/correction/change.dart'; |
| 10 import 'package:analysis_services/correction/status.dart'; | 10 import 'package:analysis_services/correction/status.dart'; |
| 11 import 'package:analysis_services/refactoring/refactoring.dart'; | 11 import 'package:analysis_services/refactoring/refactoring.dart'; |
| 12 import 'package:analysis_services/search/hierarchy.dart'; | 12 import 'package:analysis_services/search/hierarchy.dart'; |
| 13 import 'package:analysis_services/search/search_engine.dart'; | 13 import 'package:analysis_services/search/search_engine.dart'; |
| 14 import 'package:analysis_services/src/correction/util.dart'; |
| 14 import 'package:analysis_services/src/refactoring/naming_conventions.dart'; | 15 import 'package:analysis_services/src/refactoring/naming_conventions.dart'; |
| 15 import 'package:analysis_services/src/refactoring/rename.dart'; | 16 import 'package:analysis_services/src/refactoring/rename.dart'; |
| 16 import 'package:analyzer/src/generated/element.dart'; | 17 import 'package:analyzer/src/generated/element.dart'; |
| 18 import 'package:analyzer/src/generated/java_core.dart'; |
| 17 | 19 |
| 18 | 20 |
| 19 /** | 21 /** |
| 20 * A [Refactoring] for renaming class member [Element]s. | 22 * A [Refactoring] for renaming class member [Element]s. |
| 21 */ | 23 */ |
| 22 class RenameClassMemberRefactoringImpl extends RenameRefactoringImpl { | 24 class RenameClassMemberRefactoringImpl extends RenameRefactoringImpl { |
| 23 _RenameClassMemberValidator _validator; | 25 _RenameClassMemberValidator _validator; |
| 24 | 26 |
| 25 RenameClassMemberRefactoringImpl(SearchEngine searchEngine, Element element) | 27 RenameClassMemberRefactoringImpl(SearchEngine searchEngine, Element element) |
| 26 : super(searchEngine, element); | 28 : super(searchEngine, element); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 /** | 125 /** |
| 124 * Helper to check if renaming of an [Element] to the given name will cause any | 126 * Helper to check if renaming of an [Element] to the given name will cause any |
| 125 * problems. | 127 * problems. |
| 126 */ | 128 */ |
| 127 class _RenameClassMemberValidator { | 129 class _RenameClassMemberValidator { |
| 128 final SearchEngine searchEngine; | 130 final SearchEngine searchEngine; |
| 129 final Element element; | 131 final Element element; |
| 130 final String oldName; | 132 final String oldName; |
| 131 final String newName; | 133 final String newName; |
| 132 | 134 |
| 133 // Set<ClassElement> _superClasses; | |
| 134 // Set<ClassElement> _subClasses; | |
| 135 | |
| 136 Set<Element> elements = new Set(); | 135 Set<Element> elements = new Set(); |
| 137 List<SearchMatch> references = []; | 136 List<SearchMatch> references = []; |
| 138 | 137 |
| 139 _RenameClassMemberValidator(this.searchEngine, Element element, this.newName) | 138 _RenameClassMemberValidator(this.searchEngine, Element element, this.newName) |
| 140 : element = element, | 139 : element = element, |
| 141 oldName = element.displayName; | 140 oldName = element.displayName; |
| 142 | 141 |
| 143 Future<RefactoringStatus> validate() { | 142 Future<RefactoringStatus> validate() { |
| 144 RefactoringStatus result = new RefactoringStatus(); | 143 RefactoringStatus result = new RefactoringStatus(); |
| 145 ClassElement elementClass = element.enclosingElement; | 144 ClassElement elementClass = element.enclosingElement; |
| 146 return _prepareElements().then((_) { | 145 // check if there is a member with "newName" in the same ClassElement |
| 147 return Future.forEach(elements, (Element element) { | 146 for (Element newNameMember in getChildren(elementClass, newName)) { |
| 148 return searchEngine.searchReferences(element).then((references) { | 147 result.addError( |
| 149 this.references.addAll(references); | 148 format( |
| 150 }); | 149 "Class '{0}' already declares {1} with name '{2}'.", |
| 150 elementClass.displayName, |
| 151 getElementKindName(newNameMember), |
| 152 newName), |
| 153 new RefactoringStatusContext.forElement(newNameMember)); |
| 154 } |
| 155 // do chained computations |
| 156 Set<ClassElement> superClasses = getSuperClasses(elementClass); |
| 157 Set<ClassElement> subClasses; |
| 158 return _prepareReferences().then((_) { |
| 159 return getSubClasses(searchEngine, elementClass).then((_subs) { |
| 160 subClasses = _subs; |
| 151 }); | 161 }); |
| 152 }).then((_) { | 162 }).then((_) { |
| 153 return new RefactoringStatus(); | 163 // check shadowing in hierarchy |
| 154 }); | 164 return searchEngine.searchElementDeclarations(newName).then((decls) { |
| 155 // _superClasses = getSuperClasses(elementClass); | 165 for (SearchMatch decl in decls) { |
| 156 // TODO(scheglov) validate | 166 Element nameElement = getSyntheticAccessorVariable(decl.element); |
| 167 Element nameClass = nameElement.enclosingElement; |
| 168 // renamed Element shadows member of superclass |
| 169 if (superClasses.contains(nameClass)) { |
| 170 result.addError( |
| 171 format( |
| 172 "Renamed {0} will shadow {1} '{2}'.", |
| 173 getElementKindName(element), |
| 174 getElementKindName(nameElement), |
| 175 getElementQualifiedName(nameElement)), |
| 176 new RefactoringStatusContext.forElement(nameElement)); |
| 177 } |
| 178 // renamed Element is shadowed by member of subclass |
| 179 if (subClasses.contains(nameClass)) { |
| 180 result.addError( |
| 181 format( |
| 182 "Renamed {0} will be shadowed by {1} '{2}'.", |
| 183 getElementKindName(element), |
| 184 getElementKindName(nameElement), |
| 185 getElementQualifiedName(nameElement)), |
| 186 new RefactoringStatusContext.forElement(nameElement)); |
| 187 } |
| 188 // renamed Element is shadowed by local |
| 189 if (nameElement is LocalElement) { |
| 190 LocalElement localElement = nameElement; |
| 191 ClassElement enclosingClass = |
| 192 nameElement.getAncestor((element) => element is ClassElement); |
| 193 if (enclosingClass == elementClass || |
| 194 subClasses.contains(enclosingClass)) { |
| 195 for (SearchMatch reference in references) { |
| 196 if (isReferenceInLocalRange(localElement, reference)) { |
| 197 result.addError( |
| 198 format( |
| 199 "Usage of renamed {0} will be shadowed by {1} '{2}'.", |
| 200 getElementKindName(element), |
| 201 getElementKindName(localElement), |
| 202 localElement.displayName), |
| 203 new RefactoringStatusContext.forMatch(reference)); |
| 204 } |
| 205 } |
| 206 } |
| 207 } |
| 208 } |
| 209 }); |
| 210 }).then((_) => result); |
| 157 } | 211 } |
| 158 | 212 |
| 159 /** | 213 /** |
| 160 * Fills [elements] with [Element]s to rename. | 214 * Fills [elements] with [Element]s to rename. |
| 161 */ | 215 */ |
| 162 Future _prepareElements() { | 216 Future _prepareElements() { |
| 163 if (element is ClassMemberElement) { | 217 if (element is ClassMemberElement) { |
| 164 return getHierarchyMembers( | 218 return getHierarchyMembers( |
| 165 searchEngine, | 219 searchEngine, |
| 166 element).then((Set<Element> elements) { | 220 element).then((Set<Element> elements) { |
| 167 this.elements = elements; | 221 this.elements = elements; |
| 168 }); | 222 }); |
| 169 } else { | 223 } else { |
| 170 elements = new Set.from([element]); | 224 elements = new Set.from([element]); |
| 171 return new Future.value(); | 225 return new Future.value(); |
| 172 } | 226 } |
| 173 } | 227 } |
| 228 |
| 229 /** |
| 230 * Fills [references] with all references to [elements]. |
| 231 */ |
| 232 Future _prepareReferences() { |
| 233 return _prepareElements().then((_) { |
| 234 return Future.forEach(elements, (Element element) { |
| 235 return searchEngine.searchReferences(element).then((references) { |
| 236 this.references.addAll(references); |
| 237 }); |
| 238 }); |
| 239 }); |
| 240 } |
| 174 } | 241 } |
| OLD | NEW |