Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart

Issue 506753002: Parameters and validation for the 'Extract Method' refactoring. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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_unit_member; 5 library services.src.refactoring.rename_unit_member;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'package:analysis_server/src/protocol.dart' show Location, SourceChange; 9 import 'package:analysis_server/src/protocol.dart' show Location, SourceChange;
10 import 'package:analysis_server/src/services/correction/status.dart'; 10 import 'package:analysis_server/src/services/correction/status.dart';
11 import 'package:analysis_server/src/services/correction/util.dart'; 11 import 'package:analysis_server/src/services/correction/util.dart';
12 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart '; 12 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart ';
13 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; 13 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
14 import 'package:analysis_server/src/services/refactoring/rename.dart'; 14 import 'package:analysis_server/src/services/refactoring/rename.dart';
15 import 'package:analysis_server/src/services/search/element_visitors.dart'; 15 import 'package:analysis_server/src/services/search/element_visitors.dart';
16 import 'package:analysis_server/src/services/search/search_engine.dart'; 16 import 'package:analysis_server/src/services/search/search_engine.dart';
17 import 'package:analyzer/src/generated/element.dart'; 17 import 'package:analyzer/src/generated/element.dart';
18 import 'package:analyzer/src/generated/java_core.dart'; 18 import 'package:analyzer/src/generated/java_core.dart';
19 19
20 20
21 /** 21 /**
22 * Checks if creating a top-level function with the given [name] in [library]
23 * will cause any conflicts.
24 */
25 Future<RefactoringStatus> validateCreateFunction(SearchEngine searchEngine,
26 LibraryElement library, String name) {
27 return new _RenameUnitMemberValidator.forCreate(
28 searchEngine,
29 library,
30 ElementKind.FUNCTION,
31 name).validate();
32 }
33
34
35 /**
36 * Checks if creating a top-level function with the given [name] in [element]
37 * will cause any conflicts.
38 */
39 Future<RefactoringStatus> validateRenameTopLevel(SearchEngine searchEngine,
40 Element element, String name) {
41 return new _RenameUnitMemberValidator.forRename(
42 searchEngine,
43 element,
44 name).validate();
45 }
46
47
48 /**
22 * A [Refactoring] for renaming compilation unit member [Element]s. 49 * A [Refactoring] for renaming compilation unit member [Element]s.
23 */ 50 */
24 class RenameUnitMemberRefactoringImpl extends RenameRefactoringImpl { 51 class RenameUnitMemberRefactoringImpl extends RenameRefactoringImpl {
25 RenameUnitMemberRefactoringImpl(SearchEngine searchEngine, Element element) 52 RenameUnitMemberRefactoringImpl(SearchEngine searchEngine, Element element)
26 : super(searchEngine, element); 53 : super(searchEngine, element);
27 54
28 @override 55 @override
29 String get refactoringName { 56 String get refactoringName {
30 if (element is FunctionElement) { 57 if (element is FunctionElement) {
31 return "Rename Top-Level Function"; 58 return "Rename Top-Level Function";
32 } 59 }
33 if (element is FunctionTypeAliasElement) { 60 if (element is FunctionTypeAliasElement) {
34 return "Rename Function Type Alias"; 61 return "Rename Function Type Alias";
35 } 62 }
36 if (element is TopLevelVariableElement) { 63 if (element is TopLevelVariableElement) {
37 return "Rename Top-Level Variable"; 64 return "Rename Top-Level Variable";
38 } 65 }
39 return "Rename Class"; 66 return "Rename Class";
40 } 67 }
41 68
42 @override 69 @override
43 Future<RefactoringStatus> checkFinalConditions() { 70 Future<RefactoringStatus> checkFinalConditions() {
44 return new RenameUnitMemberValidator( 71 return validateRenameTopLevel(searchEngine, element, newName);
45 searchEngine,
46 element,
47 element.kind,
48 newName,
49 true).validate();
50 } 72 }
51 73
52 @override 74 @override
53 RefactoringStatus checkNewName() { 75 RefactoringStatus checkNewName() {
54 RefactoringStatus result = super.checkNewName(); 76 RefactoringStatus result = super.checkNewName();
55 if (element is TopLevelVariableElement) { 77 if (element is TopLevelVariableElement) {
56 TopLevelVariableElement variable = element as TopLevelVariableElement; 78 TopLevelVariableElement variable = element as TopLevelVariableElement;
57 if (variable.isConst) { 79 if (variable.isConst) {
58 result.addStatus(validateConstantName(newName)); 80 result.addStatus(validateConstantName(newName));
59 } else { 81 } else {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 } 124 }
103 }); 125 });
104 }).then((_) { 126 }).then((_) {
105 return change; 127 return change;
106 }); 128 });
107 } 129 }
108 } 130 }
109 131
110 132
111 /** 133 /**
112 * Helper to check if renaming or creating [Element] with given name will cause any problems. 134 * Helper to check if the created or renamed [Element] will cause any conflicts.
113 */ 135 */
114 class RenameUnitMemberValidator { 136 class _RenameUnitMemberValidator {
115 final SearchEngine searchEngine; 137 final SearchEngine searchEngine;
116 final Element element; 138 LibraryElement library;
117 final ElementKind elementKind; 139 Element element;
118 final String newName; 140 ElementKind elementKind;
119 final bool forRename; 141 final String name;
142 final bool isRename;
120 143
121 final RefactoringStatus result = new RefactoringStatus(); 144 final RefactoringStatus result = new RefactoringStatus();
122 145
123 RenameUnitMemberValidator(this.searchEngine, this.element, this.elementKind, 146 _RenameUnitMemberValidator.forCreate(this.searchEngine, this.library,
124 this.newName, this.forRename); 147 this.elementKind, this.name)
148 : isRename = false;
149
150 _RenameUnitMemberValidator.forRename(this.searchEngine, this.element,
151 this.name)
152 : isRename = true {
153 library = element.getAncestor((e) => e is LibraryElement);
154 elementKind = element.kind;
155 }
125 156
126 Future<RefactoringStatus> validate() { 157 Future<RefactoringStatus> validate() {
127 _validateWillConflict(); 158 _validateWillConflict();
128 List<Future> futures = <Future>[]; 159 List<Future> futures = <Future>[];
129 if (forRename) { 160 if (isRename) {
130 futures.add(_validateWillBeShadowed()); 161 futures.add(_validateWillBeShadowed());
131 } 162 }
132 futures.add(_validateWillShadow()); 163 futures.add(_validateWillShadow());
133 return Future.wait(futures).then((_) { 164 return Future.wait(futures).then((_) {
134 return result; 165 return result;
135 }); 166 });
136 } 167 }
137 168
138 /** 169 /**
139 * Returns `true` if [element] is visible at the given [SearchMatch]. 170 * Returns `true` if [element] is visible at the given [SearchMatch].
140 */ 171 */
141 bool _isVisibleAt(Element element, SearchMatch at) { 172 bool _isVisibleAt(Element element, SearchMatch at) {
142 LibraryElement library = at.element.library; 173 LibraryElement atLibrary = at.element.library;
143 // may be the same library 174 // may be the same library
144 if (element.library == library) { 175 if (library == atLibrary) {
145 return true; 176 return true;
146 } 177 }
147 // check imports 178 // check imports
148 for (ImportElement importElement in library.imports) { 179 for (ImportElement importElement in atLibrary.imports) {
149 // ignore if imported with prefix 180 // ignore if imported with prefix
150 if (importElement.prefix != null) { 181 if (importElement.prefix != null) {
151 continue; 182 continue;
152 } 183 }
153 // check imported elements 184 // check imported elements
154 if (getImportNamespace(importElement).containsValue(element)) { 185 if (getImportNamespace(importElement).containsValue(element)) {
155 return true; 186 return true;
156 } 187 }
157 } 188 }
158 // no, it is not visible 189 // no, it is not visible
159 return false; 190 return false;
160 } 191 }
161 192
162 /** 193 /**
163 * Validates if any usage of [element] renamed to [newName] will be shadowed. 194 * Validates if any usage of [element] renamed to [name] will be shadowed.
164 */ 195 */
165 Future _validateWillBeShadowed() { 196 Future _validateWillBeShadowed() {
197 if (!isRename) {
198 return new Future.value();
199 }
166 return searchEngine.searchReferences(element).then((references) { 200 return searchEngine.searchReferences(element).then((references) {
167 for (SearchMatch reference in references) { 201 for (SearchMatch reference in references) {
168 Element refElement = reference.element; 202 Element refElement = reference.element;
169 ClassElement refClass = 203 ClassElement refClass =
170 refElement.getAncestor((e) => e is ClassElement); 204 refElement.getAncestor((e) => e is ClassElement);
171 if (refClass != null) { 205 if (refClass != null) {
172 visitChildren(refClass, (shadow) { 206 visitChildren(refClass, (shadow) {
173 if (hasDisplayName(shadow, newName)) { 207 if (hasDisplayName(shadow, name)) {
174 String message = format( 208 String message = format(
175 "Reference to renamed {0} will be shadowed by {1} '{2}'.", 209 "Reference to renamed {0} will be shadowed by {1} '{2}'.",
176 getElementKindName(element), 210 getElementKindName(element),
177 getElementKindName(shadow), 211 getElementKindName(shadow),
178 getElementQualifiedName(shadow)); 212 getElementQualifiedName(shadow));
179 result.addError(message, new Location.fromElement(shadow)); 213 result.addError(message, new Location.fromElement(shadow));
180 } 214 }
181 }); 215 });
182 } 216 }
183 } 217 }
184 }); 218 });
185 } 219 }
186 220
187 /** 221 /**
188 * Validates if [element] renamed to [newName] will conflict with another 222 * Validates if [element] renamed to [name] will conflict with another
189 * top-level [Element] in the same library. 223 * top-level [Element] in the same library.
190 */ 224 */
191 void _validateWillConflict() { 225 void _validateWillConflict() {
192 LibraryElement library = element.getAncestor((e) => e is LibraryElement);
193 visitLibraryTopLevelElements(library, (element) { 226 visitLibraryTopLevelElements(library, (element) {
194 if (hasDisplayName(element, newName)) { 227 if (hasDisplayName(element, name)) {
195 String message = format( 228 String message = format(
196 "Library already declares {0} with name '{1}'.", 229 "Library already declares {0} with name '{1}'.",
197 getElementKindName(element), 230 getElementKindName(element),
198 newName); 231 name);
199 result.addError(message, new Location.fromElement(element)); 232 result.addError(message, new Location.fromElement(element));
200 } 233 }
201 }); 234 });
202 } 235 }
203 236
204 /** 237 /**
205 * Validates if renamed [element] will shadow any [Element] named [newName]. 238 * Validates if renamed [element] will shadow any [Element] named [name].
206 */ 239 */
207 Future _validateWillShadow() { 240 Future _validateWillShadow() {
208 return searchEngine.searchMemberDeclarations(newName).then((declarations) { 241 return searchEngine.searchMemberDeclarations(name).then((declarations) {
209 return Future.forEach(declarations, (SearchMatch declaration) { 242 return Future.forEach(declarations, (SearchMatch declaration) {
210 Element member = declaration.element; 243 Element member = declaration.element;
211 ClassElement declaringClass = member.enclosingElement; 244 ClassElement declaringClass = member.enclosingElement;
212 return searchEngine.searchReferences(member).then((memberReferences) { 245 return searchEngine.searchReferences(member).then((memberReferences) {
213 for (SearchMatch memberReference in memberReferences) { 246 for (SearchMatch memberReference in memberReferences) {
214 Element refElement = memberReference.element; 247 Element refElement = memberReference.element;
215 // cannot be shadowed if qualified 248 // cannot be shadowed if qualified
216 if (memberReference.isQualified) { 249 if (memberReference.isQualified) {
217 continue; 250 continue;
218 } 251 }
219 // cannot be shadowed if declared in the same class as reference 252 // cannot be shadowed if declared in the same class as reference
220 ClassElement refClass = 253 ClassElement refClass =
221 refElement.getAncestor((e) => e is ClassElement); 254 refElement.getAncestor((e) => e is ClassElement);
222 if (refClass == declaringClass) { 255 if (refClass == declaringClass) {
223 continue; 256 continue;
224 } 257 }
225 // ignore if not visitble 258 // ignore if not visible
226 if (!_isVisibleAt(element, memberReference)) { 259 if (!_isVisibleAt(element, memberReference)) {
227 continue; 260 continue;
228 } 261 }
229 // OK, reference will be shadowed be the element being renamed 262 // OK, reference will be shadowed be the element being renamed
230 String message = format( 263 String message = format(
231 forRename ? 264 isRename ?
232 "Renamed {0} will shadow {1} '{2}'." : 265 "Renamed {0} will shadow {1} '{2}'." :
233 "Created {0} will shadow {1} '{2}'.", 266 "Created {0} will shadow {1} '{2}'.",
234 getElementKindName(element), 267 elementKind.displayName,
235 getElementKindName(member), 268 getElementKindName(member),
236 getElementQualifiedName(member)); 269 getElementQualifiedName(member));
237 result.addError(message, new Location.fromMatch(memberReference)); 270 result.addError(message, new Location.fromMatch(memberReference));
238 } 271 }
239 }); 272 });
240 }); 273 });
241 }); 274 });
242 } 275 }
243 } 276 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698