| 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.extract_method; | 5 library services.src.refactoring.extract_method; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_server/src/protocol.dart' hide Element; | 9 import 'package:analysis_server/src/protocol.dart' hide Element; |
| 10 import 'package:analysis_server/src/services/correction/selection_analyzer.dart'
; | 10 import 'package:analysis_server/src/services/correction/selection_analyzer.dart'
; |
| 11 import 'package:analysis_server/src/services/correction/source_range.dart'; | 11 import 'package:analysis_server/src/services/correction/source_range.dart'; |
| 12 import 'package:analysis_server/src/services/correction/statement_analyzer.dart'
; | 12 import 'package:analysis_server/src/services/correction/statement_analyzer.dart'
; |
| 13 import 'package:analysis_server/src/services/correction/status.dart'; | 13 import 'package:analysis_server/src/services/correction/status.dart'; |
| 14 import 'package:analysis_server/src/services/correction/util.dart'; | 14 import 'package:analysis_server/src/services/correction/util.dart'; |
| 15 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart
'; | 15 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart
'; |
| 16 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; | 16 import 'package:analysis_server/src/services/refactoring/refactoring.dart'; |
| 17 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
rt'; | 17 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da
rt'; |
| 18 import 'package:analysis_server/src/services/refactoring/rename_class_member.dar
t'; |
| 19 import 'package:analysis_server/src/services/refactoring/rename_unit_member.dart
'; |
| 18 import 'package:analysis_server/src/services/search/search_engine.dart'; | 20 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 19 import 'package:analyzer/src/generated/ast.dart'; | 21 import 'package:analyzer/src/generated/ast.dart'; |
| 20 import 'package:analyzer/src/generated/element.dart'; | 22 import 'package:analyzer/src/generated/element.dart'; |
| 21 import 'package:analyzer/src/generated/java_core.dart'; | 23 import 'package:analyzer/src/generated/java_core.dart'; |
| 22 import 'package:analyzer/src/generated/scanner.dart'; | 24 import 'package:analyzer/src/generated/scanner.dart'; |
| 23 import 'package:analyzer/src/generated/source.dart'; | 25 import 'package:analyzer/src/generated/source.dart'; |
| 24 | 26 |
| 25 | 27 |
| 26 const String _TOKEN_SEPARATOR = "\uFFFF"; | 28 const String _TOKEN_SEPARATOR = '\uFFFF'; |
| 27 | 29 |
| 28 | 30 |
| 29 /** | 31 /** |
| 30 * Returns the "normalized" version of the given source, which is reconstructed | 32 * Returns the "normalized" version of the given source, which is reconstructed |
| 31 * from tokens, so ignores all the comments and spaces. | 33 * from tokens, so ignores all the comments and spaces. |
| 32 */ | 34 */ |
| 33 String _getNormalizedSource(String src) { | 35 String _getNormalizedSource(String src) { |
| 34 List<Token> selectionTokens = TokenUtils.getTokens(src); | 36 List<Token> selectionTokens = TokenUtils.getTokens(src); |
| 35 return StringUtils.join(selectionTokens, _TOKEN_SEPARATOR); | 37 return StringUtils.join(selectionTokens, _TOKEN_SEPARATOR); |
| 36 } | 38 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 if (_selectionExpression is AssignmentExpression) { | 101 if (_selectionExpression is AssignmentExpression) { |
| 100 return false; | 102 return false; |
| 101 } | 103 } |
| 102 } | 104 } |
| 103 if (_selectionStatements != null) { | 105 if (_selectionStatements != null) { |
| 104 return returnType != null; | 106 return returnType != null; |
| 105 } | 107 } |
| 106 return true; | 108 return true; |
| 107 } | 109 } |
| 108 | 110 |
| 109 /** | |
| 110 * @return the selected [DartExpression] source, with applying new parameter n
ames. | |
| 111 */ | |
| 112 String get methodBodySource { | |
| 113 String source = utils.getRangeText(selectionRange); | |
| 114 // prepare ReplaceEdit operations to replace variables with parameters | |
| 115 // TODO: implement parameters | |
| 116 List<SourceEdit> replaceEdits = []; | |
| 117 // for (Parameter parameter in _parametersMap.values) { | |
| 118 // List<SourceRange> ranges = _parameterReferencesMap[parameter.oldName]; | |
| 119 // if (ranges != null) { | |
| 120 // for (SourceRange range in ranges) { | |
| 121 // replaceEdits.add(new SourceEdit(range.offset - selectionRange.offset
, range.length, parameter.newName)); | |
| 122 // } | |
| 123 // } | |
| 124 // } | |
| 125 // apply replacements | |
| 126 source = SourceEdit.applySequence(source, replaceEdits); | |
| 127 // change indentation | |
| 128 if (_selectionFunctionExpression != null) { | |
| 129 AstNode baseNode = | |
| 130 _selectionFunctionExpression.getAncestor((node) => node is Statement); | |
| 131 if (baseNode != null) { | |
| 132 String baseIndent = utils.getNodePrefix(baseNode); | |
| 133 String targetIndent = utils.getNodePrefix(_parentMember); | |
| 134 source = utils.replaceSourceIndent(source, baseIndent, targetIndent); | |
| 135 source = source.trim(); | |
| 136 } | |
| 137 } | |
| 138 if (_selectionStatements != null) { | |
| 139 String selectionIndent = utils.getNodePrefix(_selectionStatements[0]); | |
| 140 String targetIndent = utils.getNodePrefix(_parentMember) + ' '; | |
| 141 source = utils.replaceSourceIndent(source, selectionIndent, targetIndent); | |
| 142 } | |
| 143 // done | |
| 144 return source; | |
| 145 } | |
| 146 | |
| 147 @override | 111 @override |
| 148 List<RefactoringMethodParameter> get parameters => _parameters; | 112 List<RefactoringMethodParameter> get parameters => _parameters; |
| 149 | 113 |
| 150 @override | 114 @override |
| 151 void set parameters(List<RefactoringMethodParameter> parameters) { | 115 void set parameters(List<RefactoringMethodParameter> parameters) { |
| 152 // TODO: implement parameters | 116 _parameters = parameters.toList(); |
| 153 } | 117 } |
| 154 | 118 |
| 155 @override | 119 @override |
| 156 String get refactoringName { | 120 String get refactoringName { |
| 157 AstNode node = new NodeLocator.con1(selectionOffset).searchWithin(unit); | 121 AstNode node = new NodeLocator.con1(selectionOffset).searchWithin(unit); |
| 158 if (node != null && | 122 if (node != null && |
| 159 node.getAncestor((node) => node is ClassDeclaration) != null) { | 123 node.getAncestor((node) => node is ClassDeclaration) != null) { |
| 160 return 'Extract Method'; | 124 return 'Extract Method'; |
| 161 } | 125 } |
| 162 return 'Extract Function'; | 126 return 'Extract Function'; |
| 163 } | 127 } |
| 164 | 128 |
| 165 String get signature { | 129 String get signature { |
| 166 StringBuffer sb = new StringBuffer(); | 130 StringBuffer sb = new StringBuffer(); |
| 167 if (createGetter) { | 131 if (createGetter) { |
| 168 sb.write("get "); | 132 sb.write('get '); |
| 169 sb.write(name); | 133 sb.write(name); |
| 170 } else { | 134 } else { |
| 171 sb.write(name); | 135 sb.write(name); |
| 172 sb.write("("); | 136 sb.write('('); |
| 173 // add all parameters | 137 // add all parameters |
| 174 bool firstParameter = true; | 138 bool firstParameter = true; |
| 175 for (RefactoringMethodParameter parameter in _parameters) { | 139 for (RefactoringMethodParameter parameter in _parameters) { |
| 176 // may be comma | 140 // may be comma |
| 177 if (firstParameter) { | 141 if (firstParameter) { |
| 178 firstParameter = false; | 142 firstParameter = false; |
| 179 } else { | 143 } else { |
| 180 sb.write(', '); | 144 sb.write(', '); |
| 181 } | 145 } |
| 182 // type | 146 // type |
| 183 { | 147 { |
| 184 String typeSource = parameter.type; | 148 String typeSource = parameter.type; |
| 185 if ('dynamic' != typeSource && '' != typeSource) { | 149 if ('dynamic' != typeSource && '' != typeSource) { |
| 186 sb.write(typeSource); | 150 sb.write(typeSource); |
| 187 sb.write(" "); | 151 sb.write(' '); |
| 188 } | 152 } |
| 189 } | 153 } |
| 190 // name | 154 // name |
| 191 sb.write(parameter.name); | 155 sb.write(parameter.name); |
| 192 } | 156 } |
| 193 sb.write(")"); | 157 sb.write(')'); |
| 194 } | 158 } |
| 195 // done | 159 // done |
| 196 return sb.toString(); | 160 return sb.toString(); |
| 197 } | 161 } |
| 198 | 162 |
| 199 @override | 163 @override |
| 200 Future<RefactoringStatus> checkFinalConditions() { | 164 Future<RefactoringStatus> checkFinalConditions() { |
| 201 RefactoringStatus result = new RefactoringStatus(); | 165 RefactoringStatus result = new RefactoringStatus(); |
| 166 result.addStatus(validateMethodName(name)); |
| 167 result.addStatus(_checkParameterNames()); |
| 168 // TODO: implement checkFinalConditions |
| 169 return _checkPossibleConflicts().then((status) { |
| 170 result.addStatus(status); |
| 171 return result; |
| 172 }); |
| 202 return new Future.value(result); | 173 return new Future.value(result); |
| 203 // TODO: implement checkFinalConditions | |
| 204 } | 174 } |
| 205 | 175 |
| 176 |
| 206 @override | 177 @override |
| 207 Future<RefactoringStatus> checkInitialConditions() { | 178 Future<RefactoringStatus> checkInitialConditions() { |
| 208 RefactoringStatus result = new RefactoringStatus(); | 179 RefactoringStatus result = new RefactoringStatus(); |
| 209 // selection | 180 // selection |
| 210 result.addStatus(_checkSelection()); | 181 result.addStatus(_checkSelection()); |
| 211 if (result.hasFatalError) { | 182 if (result.hasFatalError) { |
| 212 return new Future.value(result); | 183 return new Future.value(result); |
| 213 } | 184 } |
| 214 // prepare parts | 185 // prepare parts |
| 215 result.addStatus(_initializeParameters()); | 186 result.addStatus(_initializeParameters()); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 // assign the return value | 237 // assign the return value |
| 267 sb.write(occurrenceName); | 238 sb.write(occurrenceName); |
| 268 sb.write(' = '); | 239 sb.write(' = '); |
| 269 } else { | 240 } else { |
| 270 sb.write('return '); | 241 sb.write('return '); |
| 271 } | 242 } |
| 272 } | 243 } |
| 273 // invocation itself | 244 // invocation itself |
| 274 sb.write(name); | 245 sb.write(name); |
| 275 if (!createGetter) { | 246 if (!createGetter) { |
| 276 sb.write("("); | 247 sb.write('('); |
| 277 bool firstParameter = true; | 248 bool firstParameter = true; |
| 278 for (RefactoringMethodParameter parameter in _parameters) { | 249 for (RefactoringMethodParameter parameter in _parameters) { |
| 279 // may be comma | 250 // may be comma |
| 280 if (firstParameter) { | 251 if (firstParameter) { |
| 281 firstParameter = false; | 252 firstParameter = false; |
| 282 } else { | 253 } else { |
| 283 sb.write(', '); | 254 sb.write(', '); |
| 284 } | 255 } |
| 285 // argument name | 256 // argument name |
| 286 { | 257 { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 300 // add replace edit | 271 // add replace edit |
| 301 SourceEdit edit = new SourceEdit.range(range, invocationSource); | 272 SourceEdit edit = new SourceEdit.range(range, invocationSource); |
| 302 change.addEdit(file, edit); | 273 change.addEdit(file, edit); |
| 303 } | 274 } |
| 304 // add method declaration | 275 // add method declaration |
| 305 { | 276 { |
| 306 // prepare environment | 277 // prepare environment |
| 307 String prefix = utils.getNodePrefix(_parentMember); | 278 String prefix = utils.getNodePrefix(_parentMember); |
| 308 String eol = utils.endOfLine; | 279 String eol = utils.endOfLine; |
| 309 // prepare annotations | 280 // prepare annotations |
| 310 String annotations = ""; | 281 String annotations = ''; |
| 311 { | 282 { |
| 312 // may be "static" | 283 // may be "static" |
| 313 if (_staticContext) { | 284 if (_staticContext) { |
| 314 annotations = 'static '; | 285 annotations = 'static '; |
| 315 } | 286 } |
| 316 } | 287 } |
| 317 // prepare declaration source | 288 // prepare declaration source |
| 318 String declarationSource = null; | 289 String declarationSource = null; |
| 319 { | 290 { |
| 320 String returnExpressionSource = methodBodySource; | 291 String returnExpressionSource = _getMethodBodySource(); |
| 321 // closure | 292 // closure |
| 322 if (_selectionFunctionExpression != null) { | 293 if (_selectionFunctionExpression != null) { |
| 323 declarationSource = "${name}${returnExpressionSource}"; | 294 declarationSource = '${name}${returnExpressionSource}'; |
| 324 if (_selectionFunctionExpression.body is ExpressionFunctionBody) { | 295 if (_selectionFunctionExpression.body is ExpressionFunctionBody) { |
| 325 declarationSource += ';'; | 296 declarationSource += ';'; |
| 326 } | 297 } |
| 327 } | 298 } |
| 328 // expression | 299 // expression |
| 329 if (_selectionExpression != null) { | 300 if (_selectionExpression != null) { |
| 330 // add return type | 301 // add return type |
| 331 String returnTypeName = | 302 String returnTypeName = |
| 332 utils.getExpressionTypeSource(_selectionExpression); | 303 utils.getExpressionTypeSource(_selectionExpression); |
| 333 if (returnTypeName != null && returnTypeName != "dynamic") { | 304 if (returnTypeName != null && returnTypeName != 'dynamic') { |
| 334 annotations += "${returnTypeName} "; | 305 annotations += '${returnTypeName} '; |
| 335 } | 306 } |
| 336 // just return expression | 307 // just return expression |
| 337 declarationSource = | 308 declarationSource = |
| 338 "${annotations}${signature} => ${returnExpressionSource};"; | 309 '${annotations}${signature} => ${returnExpressionSource};'; |
| 339 } | 310 } |
| 340 // statements | 311 // statements |
| 341 if (_selectionStatements != null) { | 312 if (_selectionStatements != null) { |
| 342 if (returnType != null) { | 313 if (returnType != null) { |
| 343 if (returnType.isNotEmpty) { | 314 if (returnType.isNotEmpty) { |
| 344 annotations += returnType + ' '; | 315 annotations += returnType + ' '; |
| 345 } | 316 } |
| 346 } else { | 317 } else { |
| 347 annotations += 'void '; | 318 annotations += 'void '; |
| 348 } | 319 } |
| 349 declarationSource = "${annotations}${signature} {${eol}"; | 320 declarationSource = '${annotations}${signature} {${eol}'; |
| 350 declarationSource += returnExpressionSource; | 321 declarationSource += returnExpressionSource; |
| 351 if (_returnVariableName != null) { | 322 if (_returnVariableName != null) { |
| 352 declarationSource += | 323 declarationSource += |
| 353 '${prefix} return ${_returnVariableName};$eol'; | 324 '${prefix} return ${_returnVariableName};$eol'; |
| 354 } | 325 } |
| 355 declarationSource += '${prefix}}'; | 326 declarationSource += '${prefix}}'; |
| 356 } | 327 } |
| 357 } | 328 } |
| 358 // insert declaration | 329 // insert declaration |
| 359 if (declarationSource != null) { | 330 if (declarationSource != null) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 375 */ | 346 */ |
| 376 void _addParameterReference(String name, SourceRange range) { | 347 void _addParameterReference(String name, SourceRange range) { |
| 377 List<SourceRange> references = _parameterReferencesMap[name]; | 348 List<SourceRange> references = _parameterReferencesMap[name]; |
| 378 if (references == null) { | 349 if (references == null) { |
| 379 references = []; | 350 references = []; |
| 380 _parameterReferencesMap[name] = references; | 351 _parameterReferencesMap[name] = references; |
| 381 } | 352 } |
| 382 references.add(range); | 353 references.add(range); |
| 383 } | 354 } |
| 384 | 355 |
| 356 RefactoringStatus _checkParameterNames() { |
| 357 RefactoringStatus result = new RefactoringStatus(); |
| 358 for (RefactoringMethodParameter parameter in _parameters) { |
| 359 result.addStatus(validateParameterName(parameter.name)); |
| 360 for (RefactoringMethodParameter other in _parameters) { |
| 361 if (!identical(parameter, other) && other.name == parameter.name) { |
| 362 result.addError( |
| 363 format("Parameter '{0}' already exists", parameter.name)); |
| 364 return result; |
| 365 } |
| 366 } |
| 367 if (_usedNames.contains(parameter.name)) { |
| 368 result.addError( |
| 369 format("'{0}' is already used as a name in the selected code", param
eter.name)); |
| 370 return result; |
| 371 } |
| 372 } |
| 373 return result; |
| 374 } |
| 375 |
| 376 /** |
| 377 * Checks if created method will shadow or will be shadowed by other elements. |
| 378 */ |
| 379 Future<RefactoringStatus> _checkPossibleConflicts() { |
| 380 RefactoringStatus result = new RefactoringStatus(); |
| 381 AstNode parent = _parentMember.parent; |
| 382 // top-level function |
| 383 if (parent is CompilationUnit) { |
| 384 LibraryElement libraryElement = parent.element.library; |
| 385 return validateCreateFunction(searchEngine, libraryElement, name); |
| 386 } |
| 387 // method of class |
| 388 if (parent is ClassDeclaration) { |
| 389 ClassElement classElement = parent.element; |
| 390 return validateCreateMethod(searchEngine, classElement, name); |
| 391 } |
| 392 // OK |
| 393 return new Future.value(result); |
| 394 } |
| 395 |
| 385 /** | 396 /** |
| 386 * Checks if [selectionRange] selects [Expression] which can be extracted, and | 397 * Checks if [selectionRange] selects [Expression] which can be extracted, and |
| 387 * location of this [DartExpression] in AST allows extracting. | 398 * location of this [DartExpression] in AST allows extracting. |
| 388 */ | 399 */ |
| 389 RefactoringStatus _checkSelection() { | 400 RefactoringStatus _checkSelection() { |
| 390 _ExtractMethodAnalyzer selectionAnalyzer = | 401 _ExtractMethodAnalyzer selectionAnalyzer = |
| 391 new _ExtractMethodAnalyzer(unit, selectionRange); | 402 new _ExtractMethodAnalyzer(unit, selectionRange); |
| 392 unit.accept(selectionAnalyzer); | 403 unit.accept(selectionAnalyzer); |
| 393 // may be fatal error | 404 // may be fatal error |
| 394 { | 405 { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 _selectionStatements = selectedStatements; | 443 _selectionStatements = selectedStatements; |
| 433 return new RefactoringStatus(); | 444 return new RefactoringStatus(); |
| 434 } | 445 } |
| 435 } | 446 } |
| 436 } | 447 } |
| 437 // invalid selection | 448 // invalid selection |
| 438 return new RefactoringStatus.fatal( | 449 return new RefactoringStatus.fatal( |
| 439 'Can only extract a single expression or a set of statements.'); | 450 'Can only extract a single expression or a set of statements.'); |
| 440 } | 451 } |
| 441 | 452 |
| 453 /** |
| 454 * @return the selected [DartExpression] source, with applying new parameter n
ames. |
| 455 */ |
| 456 String _getMethodBodySource() { |
| 457 String source = utils.getRangeText(selectionRange); |
| 458 // prepare operations to replace variables with parameters |
| 459 List<SourceEdit> replaceEdits = []; |
| 460 for (RefactoringMethodParameter parameter in _parametersMap.values) { |
| 461 List<SourceRange> ranges = _parameterReferencesMap[parameter.id]; |
| 462 if (ranges != null) { |
| 463 for (SourceRange range in ranges) { |
| 464 replaceEdits.add( |
| 465 new SourceEdit( |
| 466 range.offset - selectionRange.offset, |
| 467 range.length, |
| 468 parameter.name)); |
| 469 } |
| 470 } |
| 471 } |
| 472 replaceEdits.sort((a, b) => b.offset - a.offset); |
| 473 // apply replacements |
| 474 source = SourceEdit.applySequence(source, replaceEdits); |
| 475 // change indentation |
| 476 if (_selectionFunctionExpression != null) { |
| 477 AstNode baseNode = |
| 478 _selectionFunctionExpression.getAncestor((node) => node is Statement); |
| 479 if (baseNode != null) { |
| 480 String baseIndent = utils.getNodePrefix(baseNode); |
| 481 String targetIndent = utils.getNodePrefix(_parentMember); |
| 482 source = utils.replaceSourceIndent(source, baseIndent, targetIndent); |
| 483 source = source.trim(); |
| 484 } |
| 485 } |
| 486 if (_selectionStatements != null) { |
| 487 String selectionIndent = utils.getNodePrefix(_selectionStatements[0]); |
| 488 String targetIndent = utils.getNodePrefix(_parentMember) + ' '; |
| 489 source = utils.replaceSourceIndent(source, selectionIndent, targetIndent); |
| 490 } |
| 491 // done |
| 492 return source; |
| 493 } |
| 494 |
| 442 _SourcePattern _getSourcePattern(SourceRange range) { | 495 _SourcePattern _getSourcePattern(SourceRange range) { |
| 443 String originalSource = utils.getText(range.offset, range.length); | 496 String originalSource = utils.getText(range.offset, range.length); |
| 444 _SourcePattern pattern = new _SourcePattern(); | 497 _SourcePattern pattern = new _SourcePattern(); |
| 445 List<SourceEdit> replaceEdits = <SourceEdit>[]; | 498 List<SourceEdit> replaceEdits = <SourceEdit>[]; |
| 446 unit.accept(new _GetSourcePatternVisitor(range, pattern, replaceEdits)); | 499 unit.accept(new _GetSourcePatternVisitor(range, pattern, replaceEdits)); |
| 447 replaceEdits = replaceEdits.reversed.toList(); | 500 replaceEdits = replaceEdits.reversed.toList(); |
| 448 pattern.patternSource = | 501 pattern.patternSource = |
| 449 SourceEdit.applySequence(originalSource, replaceEdits); | 502 SourceEdit.applySequence(originalSource, replaceEdits); |
| 450 return pattern; | 503 return pattern; |
| 451 } | 504 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 477 // don't allow cycles | 530 // don't allow cycles |
| 478 statement.accept(new _ResetCanCreateGetterVisitor(this)); | 531 statement.accept(new _ResetCanCreateGetterVisitor(this)); |
| 479 } | 532 } |
| 480 } | 533 } |
| 481 } | 534 } |
| 482 | 535 |
| 483 /** | 536 /** |
| 484 * Fills [_occurrences] field. | 537 * Fills [_occurrences] field. |
| 485 */ | 538 */ |
| 486 void _initializeOccurrences() { | 539 void _initializeOccurrences() { |
| 540 _occurrences.clear(); |
| 487 // prepare selection | 541 // prepare selection |
| 488 _SourcePattern selectionPattern = _getSourcePattern(selectionRange); | 542 _SourcePattern selectionPattern = _getSourcePattern(selectionRange); |
| 489 String selectionSource = | 543 String selectionSource = |
| 490 _getNormalizedSource(selectionPattern.patternSource); | 544 _getNormalizedSource(selectionPattern.patternSource); |
| 491 Map<String, String> patternToSelectionName = | 545 Map<String, String> patternToSelectionName = |
| 492 _inverseMap(selectionPattern.originalToPatternNames); | 546 _inverseMap(selectionPattern.originalToPatternNames); |
| 493 // prepare an enclosing parent - class or unit | 547 // prepare an enclosing parent - class or unit |
| 494 AstNode enclosingMemberParent = _parentMember.parent; | 548 AstNode enclosingMemberParent = _parentMember.parent; |
| 495 // visit nodes which will able to access extracted method | 549 // visit nodes which will able to access extracted method |
| 496 enclosingMemberParent.accept( | 550 enclosingMemberParent.accept( |
| (...skipping 23 matching lines...) Expand all Loading... |
| 520 if (expression != null) { | 574 if (expression != null) { |
| 521 _returnType = expression.bestType; | 575 _returnType = expression.bestType; |
| 522 } | 576 } |
| 523 } | 577 } |
| 524 } | 578 } |
| 525 // may be single variable to return | 579 // may be single variable to return |
| 526 if (assignedUsedVariables.length == 1) { | 580 if (assignedUsedVariables.length == 1) { |
| 527 // we cannot both return variable and have explicit return statement | 581 // we cannot both return variable and have explicit return statement |
| 528 if (_returnType != null) { | 582 if (_returnType != null) { |
| 529 result.addFatalError( | 583 result.addFatalError( |
| 530 "Ambiguous return value: Selected block contains assignment(s) to " | 584 'Ambiguous return value: Selected block contains assignment(s) to ' |
| 531 "local variables and return statement."); | 585 'local variables and return statement.'); |
| 532 return result; | 586 return result; |
| 533 } | 587 } |
| 534 // prepare to return an assigned variable | 588 // prepare to return an assigned variable |
| 535 VariableElement returnVariable = assignedUsedVariables[0]; | 589 VariableElement returnVariable = assignedUsedVariables[0]; |
| 536 _returnType = returnVariable.type; | 590 _returnType = returnVariable.type; |
| 537 _returnVariableName = returnVariable.displayName; | 591 _returnVariableName = returnVariable.displayName; |
| 538 } | 592 } |
| 539 // fatal, if multiple variables assigned and used after selection | 593 // fatal, if multiple variables assigned and used after selection |
| 540 if (assignedUsedVariables.length > 1) { | 594 if (assignedUsedVariables.length > 1) { |
| 541 StringBuffer sb = new StringBuffer(); | 595 StringBuffer sb = new StringBuffer(); |
| 542 for (VariableElement variable in assignedUsedVariables) { | 596 for (VariableElement variable in assignedUsedVariables) { |
| 543 sb.write(variable.displayName); | 597 sb.write(variable.displayName); |
| 544 sb.write("\n"); | 598 sb.write('\n'); |
| 545 } | 599 } |
| 546 result.addFatalError( | 600 result.addFatalError( |
| 547 format( | 601 format( |
| 548 "Ambiguous return value: Selected block contains more than one " | 602 'Ambiguous return value: Selected block contains more than one ' |
| 549 "assignment to local variables. Affected variables are:\n\n{0}
", | 603 'assignment to local variables. Affected variables are:\n\n{0}
', |
| 550 sb.toString().trim())); | 604 sb.toString().trim())); |
| 551 } | 605 } |
| 552 // done | 606 // done |
| 553 return result; | 607 return result; |
| 554 } | 608 } |
| 555 | 609 |
| 556 void _initializeReturnType() { | 610 void _initializeReturnType() { |
| 557 if (_returnType == null) { | 611 if (_returnType == null) { |
| 558 returnType = null; | 612 returnType = null; |
| 559 } else { | 613 } else { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 610 @override | 664 @override |
| 611 void handleNextSelectedNode(AstNode node) { | 665 void handleNextSelectedNode(AstNode node) { |
| 612 super.handleNextSelectedNode(node); | 666 super.handleNextSelectedNode(node); |
| 613 _checkParent(node); | 667 _checkParent(node); |
| 614 } | 668 } |
| 615 | 669 |
| 616 @override | 670 @override |
| 617 void handleSelectionEndsIn(AstNode node) { | 671 void handleSelectionEndsIn(AstNode node) { |
| 618 super.handleSelectionEndsIn(node); | 672 super.handleSelectionEndsIn(node); |
| 619 invalidSelection( | 673 invalidSelection( |
| 620 "The selection does not cover a set of statements or an expression. " | 674 'The selection does not cover a set of statements or an expression. ' |
| 621 "Extend selection to a valid range."); | 675 'Extend selection to a valid range.'); |
| 622 } | 676 } |
| 623 | 677 |
| 624 @override | 678 @override |
| 625 Object visitAssignmentExpression(AssignmentExpression node) { | 679 Object visitAssignmentExpression(AssignmentExpression node) { |
| 626 super.visitAssignmentExpression(node); | 680 super.visitAssignmentExpression(node); |
| 627 Expression lhs = node.leftHandSide; | 681 Expression lhs = node.leftHandSide; |
| 628 if (_isFirstSelectedNode(lhs)) { | 682 if (_isFirstSelectedNode(lhs)) { |
| 629 invalidSelection( | 683 invalidSelection( |
| 630 'Cannot extract the left-hand side of an assignment.', | 684 'Cannot extract the left-hand side of an assignment.', |
| 631 new Location.fromNode(lhs)); | 685 new Location.fromNode(lhs)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 656 } | 710 } |
| 657 return null; | 711 return null; |
| 658 } | 712 } |
| 659 | 713 |
| 660 @override | 714 @override |
| 661 Object visitSimpleIdentifier(SimpleIdentifier node) { | 715 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 662 super.visitSimpleIdentifier(node); | 716 super.visitSimpleIdentifier(node); |
| 663 if (_isFirstSelectedNode(node)) { | 717 if (_isFirstSelectedNode(node)) { |
| 664 // name of declaration | 718 // name of declaration |
| 665 if (node.inDeclarationContext()) { | 719 if (node.inDeclarationContext()) { |
| 666 invalidSelection("Cannot extract the name part of a declaration."); | 720 invalidSelection('Cannot extract the name part of a declaration.'); |
| 667 } | 721 } |
| 668 // method name | 722 // method name |
| 669 Element element = node.bestElement; | 723 Element element = node.bestElement; |
| 670 if (element is FunctionElement || element is MethodElement) { | 724 if (element is FunctionElement || element is MethodElement) { |
| 671 invalidSelection("Cannot extract a single method name."); | 725 invalidSelection('Cannot extract a single method name.'); |
| 672 } | 726 } |
| 673 // name in property access | 727 // name in property access |
| 674 if (node.parent is PrefixedIdentifier && | 728 if (node.parent is PrefixedIdentifier && |
| 675 (node.parent as PrefixedIdentifier).identifier == node) { | 729 (node.parent as PrefixedIdentifier).identifier == node) { |
| 676 invalidSelection("Can not extract name part of a property access."); | 730 invalidSelection('Can not extract name part of a property access.'); |
| 677 } | 731 } |
| 678 } | 732 } |
| 679 return null; | 733 return null; |
| 680 } | 734 } |
| 681 | 735 |
| 682 @override | 736 @override |
| 683 Object visitTypeName(TypeName node) { | 737 Object visitTypeName(TypeName node) { |
| 684 super.visitTypeName(node); | 738 super.visitTypeName(node); |
| 685 if (_isFirstSelectedNode(node)) { | 739 if (_isFirstSelectedNode(node)) { |
| 686 invalidSelection("Cannot extract a single type reference."); | 740 invalidSelection('Cannot extract a single type reference.'); |
| 687 } | 741 } |
| 688 return null; | 742 return null; |
| 689 } | 743 } |
| 690 | 744 |
| 691 @override | 745 @override |
| 692 Object visitVariableDeclaration(VariableDeclaration node) { | 746 Object visitVariableDeclaration(VariableDeclaration node) { |
| 693 super.visitVariableDeclaration(node); | 747 super.visitVariableDeclaration(node); |
| 694 if (_isFirstSelectedNode(node)) { | 748 if (_isFirstSelectedNode(node)) { |
| 695 invalidSelection( | 749 invalidSelection( |
| 696 "Cannot extract a variable declaration fragment. " | 750 'Cannot extract a variable declaration fragment. ' |
| 697 "Select whole declaration statement.", | 751 'Select whole declaration statement.', |
| 698 new Location.fromNode(node)); | 752 new Location.fromNode(node)); |
| 699 } | 753 } |
| 700 return null; | 754 return null; |
| 701 } | 755 } |
| 702 | 756 |
| 703 void _checkParent(AstNode node) { | 757 void _checkParent(AstNode node) { |
| 704 AstNode firstParent = firstSelectedNode.parent; | 758 AstNode firstParent = firstSelectedNode.parent; |
| 705 do { | 759 do { |
| 706 node = node.parent; | 760 node = node.parent; |
| 707 if (identical(node, firstParent)) { | 761 if (identical(node, firstParent)) { |
| 708 return; | 762 return; |
| 709 } | 763 } |
| 710 } while (node != null); | 764 } while (node != null); |
| 711 invalidSelection( | 765 invalidSelection( |
| 712 "Not all selected statements are enclosed by the same parent statement."
); | 766 'Not all selected statements are enclosed by the same parent statement.'
); |
| 713 } | 767 } |
| 714 | 768 |
| 715 bool _isFirstSelectedNode(AstNode node) => identical(firstSelectedNode, node); | 769 bool _isFirstSelectedNode(AstNode node) => identical(firstSelectedNode, node); |
| 716 } | 770 } |
| 717 | 771 |
| 718 | 772 |
| 719 class _GetSourcePatternVisitor extends GeneralizingAstVisitor { | 773 class _GetSourcePatternVisitor extends GeneralizingAstVisitor { |
| 720 final SourceRange partRange; | 774 final SourceRange partRange; |
| 721 final _SourcePattern pattern; | 775 final _SourcePattern pattern; |
| 722 final List<SourceEdit> replaceEdits; | 776 final List<SourceEdit> replaceEdits; |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 996 | 1050 |
| 997 /** | 1051 /** |
| 998 * Generalized version of some source, in which references to the specific | 1052 * Generalized version of some source, in which references to the specific |
| 999 * variables are replaced with pattern variables, with back mapping from the | 1053 * variables are replaced with pattern variables, with back mapping from the |
| 1000 * pattern to the original variable names. | 1054 * pattern to the original variable names. |
| 1001 */ | 1055 */ |
| 1002 class _SourcePattern { | 1056 class _SourcePattern { |
| 1003 String patternSource; | 1057 String patternSource; |
| 1004 Map<String, String> originalToPatternNames = {}; | 1058 Map<String, String> originalToPatternNames = {}; |
| 1005 } | 1059 } |
| OLD | NEW |