Chromium Code Reviews| 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.inline_method; | 5 library services.src.refactoring.inline_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/source_range.dart'; | 10 import 'package:analysis_server/src/services/correction/source_range.dart'; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 final int offset; | 172 final int offset; |
| 173 String file; | 173 String file; |
| 174 CorrectionUtils utils; | 174 CorrectionUtils utils; |
| 175 SourceChange change; | 175 SourceChange change; |
| 176 | 176 |
| 177 bool isDeclaration = false; | 177 bool isDeclaration = false; |
| 178 bool deleteSource = false; | 178 bool deleteSource = false; |
| 179 bool inlineAll = true; | 179 bool inlineAll = true; |
| 180 | 180 |
| 181 ExecutableElement _methodElement; | 181 ExecutableElement _methodElement; |
| 182 bool _isAccessor; | |
| 182 String _methodFile; | 183 String _methodFile; |
| 183 CompilationUnit _methodUnit; | 184 CompilationUnit _methodUnit; |
| 184 CorrectionUtils _methodUtils; | 185 CorrectionUtils _methodUtils; |
| 185 AstNode _methodNode; | 186 AstNode _methodNode; |
| 186 FormalParameterList _methodParameters; | 187 FormalParameterList _methodParameters; |
| 187 FunctionBody _methodBody; | 188 FunctionBody _methodBody; |
| 188 Expression _methodExpression; | 189 Expression _methodExpression; |
| 189 _SourcePart _methodExpressionPart; | 190 _SourcePart _methodExpressionPart; |
| 190 _SourcePart _methodStatementsPart; | 191 _SourcePart _methodStatementsPart; |
| 191 List<_ReferenceProcessor> _referenceProcessors = []; | 192 List<_ReferenceProcessor> _referenceProcessors = []; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 294 | 295 |
| 295 /** | 296 /** |
| 296 * Initializes [_methodElement] and related fields. | 297 * Initializes [_methodElement] and related fields. |
| 297 */ | 298 */ |
| 298 RefactoringStatus _prepareMethod() { | 299 RefactoringStatus _prepareMethod() { |
| 299 _methodElement = null; | 300 _methodElement = null; |
| 300 _methodParameters = null; | 301 _methodParameters = null; |
| 301 _methodBody = null; | 302 _methodBody = null; |
| 302 deleteSource = false; | 303 deleteSource = false; |
| 303 inlineAll = false; | 304 inlineAll = false; |
| 305 // prepare for failure | |
| 306 RefactoringStatus fatalStatus = new RefactoringStatus.fatal( | |
| 307 'Method declaration or reference must be selected to activate this refac toring.'); | |
| 304 // prepare selected SimpleIdentifier | 308 // prepare selected SimpleIdentifier |
| 305 AstNode selectedNode = new NodeLocator.con1(offset).searchWithin(unit); | 309 AstNode node = new NodeLocator.con1(offset).searchWithin(unit); |
| 306 if (selectedNode is! SimpleIdentifier) { | 310 if (node is! SimpleIdentifier) { |
| 307 return new RefactoringStatus.fatal( | 311 return fatalStatus; |
| 308 'Method declaration or reference must be selected to activate this ref actoring.'); | |
| 309 } | 312 } |
| 310 SimpleIdentifier selectedIdentifier = selectedNode as SimpleIdentifier; | 313 SimpleIdentifier identifier = node as SimpleIdentifier; |
| 311 // prepare selected ExecutableElement | 314 // prepare selected ExecutableElement |
| 312 Element selectedElement = selectedIdentifier.bestElement; | 315 Element element = identifier.bestElement; |
| 313 if (selectedElement is! ExecutableElement) { | 316 if (element is! ExecutableElement) { |
| 314 return new RefactoringStatus.fatal( | 317 return fatalStatus; |
| 315 'Method declaration or reference must be selected to activate this ref actoring.'); | |
| 316 } | 318 } |
| 317 _methodElement = selectedElement as ExecutableElement; | 319 _methodElement = element as ExecutableElement; |
| 320 _isAccessor = element is PropertyAccessorElement; | |
| 318 _methodFile = _methodElement.source.fullName; | 321 _methodFile = _methodElement.source.fullName; |
| 319 _methodUnit = selectedElement.unit; | 322 _methodUnit = element.unit; |
| 320 _methodUtils = new CorrectionUtils(_methodUnit); | 323 _methodUtils = new CorrectionUtils(_methodUnit); |
| 321 if (selectedElement is MethodElement || | 324 // class member |
| 322 selectedElement is PropertyAccessorElement) { | 325 bool isClassMember = element.enclosingElement is ClassElement; |
| 323 MethodDeclaration methodDeclaration = | 326 if (element is MethodElement || _isAccessor && isClassMember) { |
| 324 _methodElement.node as MethodDeclaration; | 327 MethodDeclaration methodDeclaration = element.node; |
| 325 _methodNode = methodDeclaration; | 328 _methodNode = methodDeclaration; |
| 326 _methodParameters = methodDeclaration.parameters; | 329 _methodParameters = methodDeclaration.parameters; |
| 327 _methodBody = methodDeclaration.body; | 330 _methodBody = methodDeclaration.body; |
| 328 // prepare mode | 331 // prepare mode |
| 329 isDeclaration = selectedNode == methodDeclaration.name; | 332 isDeclaration = node == methodDeclaration.name; |
| 330 deleteSource = isDeclaration; | 333 deleteSource = isDeclaration; |
| 331 inlineAll = deleteSource; | 334 inlineAll = deleteSource; |
| 335 return new RefactoringStatus(); | |
| 332 } | 336 } |
| 333 if (selectedElement is FunctionElement) { | 337 // unit member |
| 334 FunctionDeclaration functionDeclaration = | 338 bool isUnitMember = element.enclosingElement is CompilationUnitElement; |
| 335 _methodElement.node as FunctionDeclaration; | 339 if (element is FunctionElement || _isAccessor && isUnitMember) { |
| 340 FunctionDeclaration functionDeclaration = element.node; | |
| 336 _methodNode = functionDeclaration; | 341 _methodNode = functionDeclaration; |
| 337 _methodParameters = functionDeclaration.functionExpression.parameters; | 342 _methodParameters = functionDeclaration.functionExpression.parameters; |
| 338 _methodBody = functionDeclaration.functionExpression.body; | 343 _methodBody = functionDeclaration.functionExpression.body; |
| 339 // prepare mode | 344 // prepare mode |
| 340 isDeclaration = selectedNode == functionDeclaration.name; | 345 isDeclaration = node == functionDeclaration.name; |
| 341 deleteSource = isDeclaration; | 346 deleteSource = isDeclaration; |
| 342 inlineAll = deleteSource; | 347 inlineAll = deleteSource; |
| 348 return new RefactoringStatus(); | |
| 343 } | 349 } |
| 344 // OK | 350 // OK |
| 345 return new RefactoringStatus(); | 351 return fatalStatus; |
| 346 } | 352 } |
| 347 | 353 |
| 348 /** | 354 /** |
| 349 * Analyze [_methodBody] to fill [_methodExpressionPart] and | 355 * Analyze [_methodBody] to fill [_methodExpressionPart] and |
| 350 * [_methodStatementsPart]. | 356 * [_methodStatementsPart]. |
| 351 */ | 357 */ |
| 352 RefactoringStatus _prepareMethodParts() { | 358 RefactoringStatus _prepareMethodParts() { |
| 353 RefactoringStatus result = new RefactoringStatus(); | 359 RefactoringStatus result = new RefactoringStatus(); |
| 354 if (_methodBody is ExpressionFunctionBody) { | 360 if (_methodBody is ExpressionFunctionBody) { |
| 355 ExpressionFunctionBody body = _methodBody as ExpressionFunctionBody; | 361 ExpressionFunctionBody body = _methodBody as ExpressionFunctionBody; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 458 AstNode parent3 = parent2.parent; | 464 AstNode parent3 = parent2.parent; |
| 459 return parent3 is VariableDeclarationStatement && | 465 return parent3 is VariableDeclarationStatement && |
| 460 parent3.parent is Block; | 466 parent3.parent is Block; |
| 461 } | 467 } |
| 462 } | 468 } |
| 463 } | 469 } |
| 464 // not in block, cannot inline body | 470 // not in block, cannot inline body |
| 465 return false; | 471 return false; |
| 466 } | 472 } |
| 467 | 473 |
| 468 void _inlineMethodInvocation(RefactoringStatus status, Expression methodUsage, | 474 void _inlineMethodInvocation(RefactoringStatus status, Expression usage, |
| 469 bool cascaded, Expression target, List<Expression> arguments) { | 475 bool cascaded, Expression target, List<Expression> arguments) { |
| 470 // we don't support cascade | 476 // we don't support cascade |
| 471 if (cascaded) { | 477 if (cascaded) { |
| 472 status.addError( | 478 status.addError( |
| 473 'Cannot inline cascade invocation.', | 479 'Cannot inline cascade invocation.', |
| 474 new Location.fromNode(methodUsage)); | 480 new Location.fromNode(usage)); |
| 475 } | 481 } |
| 476 // can we inline method body into "methodUsage" block? | 482 // can we inline method body into "methodUsage" block? |
| 477 if (_canInlineBody(methodUsage)) { | 483 if (_canInlineBody(usage)) { |
| 478 // insert non-return statements | 484 // insert non-return statements |
| 479 if (ref._methodStatementsPart != null) { | 485 if (ref._methodStatementsPart != null) { |
| 480 // prepare statements source for invocation | 486 // prepare statements source for invocation |
| 481 String source = _getMethodSourceForInvocation( | 487 String source = _getMethodSourceForInvocation( |
| 482 ref._methodStatementsPart, | 488 ref._methodStatementsPart, |
| 483 _refUtils, | 489 _refUtils, |
| 484 methodUsage, | 490 usage, |
| 485 target, | 491 target, |
| 486 arguments); | 492 arguments); |
| 487 source = _refUtils.replaceSourceIndent( | 493 source = _refUtils.replaceSourceIndent( |
| 488 source, | 494 source, |
| 489 ref._methodStatementsPart._prefix, | 495 ref._methodStatementsPart._prefix, |
| 490 _refPrefix); | 496 _refPrefix); |
| 491 // do insert | 497 // do insert |
| 492 SourceRange range = rangeStartLength(_refLineRange, 0); | 498 SourceRange range = rangeStartLength(_refLineRange, 0); |
| 493 SourceEdit edit = new SourceEdit.range(range, source); | 499 SourceEdit edit = new SourceEdit.range(range, source); |
| 494 ref.change.addEdit(_refFile, edit); | 500 ref.change.addEdit(_refFile, edit); |
| 495 } | 501 } |
| 496 // replace invocation with return expression | 502 // replace invocation with return expression |
| 497 if (ref._methodExpressionPart != null) { | 503 if (ref._methodExpressionPart != null) { |
| 498 // prepare expression source for invocation | 504 // prepare expression source for invocation |
| 499 String source = _getMethodSourceForInvocation( | 505 String source = _getMethodSourceForInvocation( |
| 500 ref._methodExpressionPart, | 506 ref._methodExpressionPart, |
| 501 _refUtils, | 507 _refUtils, |
| 502 methodUsage, | 508 usage, |
| 503 target, | 509 target, |
| 504 arguments); | 510 arguments); |
| 505 if (getExpressionPrecedence(ref._methodExpression) < | 511 if (getExpressionPrecedence(ref._methodExpression) < |
| 506 getExpressionParentPrecedence(methodUsage)) { | 512 getExpressionParentPrecedence(usage)) { |
| 507 source = "(${source})"; | 513 source = "(${source})"; |
| 508 } | 514 } |
| 509 // do replace | 515 // do replace |
| 510 SourceRange methodUsageRange = rangeNode(methodUsage); | 516 SourceRange methodUsageRange = rangeNode(usage); |
| 511 SourceEdit edit = new SourceEdit.range(methodUsageRange, source); | 517 SourceEdit edit = new SourceEdit.range(methodUsageRange, source); |
| 512 ref.change.addEdit(_refFile, edit); | 518 ref.change.addEdit(_refFile, edit); |
| 513 } else { | 519 } else { |
| 514 SourceEdit edit = new SourceEdit.range(_refLineRange, ""); | 520 SourceEdit edit = new SourceEdit.range(_refLineRange, ""); |
| 515 ref.change.addEdit(_refFile, edit); | 521 ref.change.addEdit(_refFile, edit); |
| 516 } | 522 } |
| 517 return; | 523 return; |
| 518 } | 524 } |
| 519 // inline as closure invocation | 525 // inline as closure invocation |
| 520 String source; | 526 String source; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 552 } else { | 558 } else { |
| 553 // cannot inline reference to method: var v = new A().method; | 559 // cannot inline reference to method: var v = new A().method; |
| 554 if (ref._methodElement is MethodElement) { | 560 if (ref._methodElement is MethodElement) { |
| 555 status.addFatalError( | 561 status.addFatalError( |
| 556 'Cannot inline class method reference.', | 562 'Cannot inline class method reference.', |
| 557 new Location.fromNode(_node)); | 563 new Location.fromNode(_node)); |
| 558 return; | 564 return; |
| 559 } | 565 } |
| 560 // PropertyAccessorElement | 566 // PropertyAccessorElement |
| 561 if (ref._methodElement is PropertyAccessorElement) { | 567 if (ref._methodElement is PropertyAccessorElement) { |
| 568 Expression usage = _node; | |
| 562 Expression target = null; | 569 Expression target = null; |
| 563 bool cascade = false; | 570 bool cascade = false; |
| 564 if (nodeParent is PrefixedIdentifier) { | 571 if (nodeParent is PrefixedIdentifier) { |
| 565 PrefixedIdentifier propertyAccess = nodeParent; | 572 PrefixedIdentifier propertyAccess = nodeParent; |
| 573 usage = propertyAccess; | |
| 566 target = propertyAccess.prefix; | 574 target = propertyAccess.prefix; |
| 567 cascade = false; | 575 cascade = false; |
| 568 } | 576 } |
| 569 if (nodeParent is PropertyAccess) { | 577 if (nodeParent is PropertyAccess) { |
| 570 PropertyAccess propertyAccess = nodeParent; | 578 PropertyAccess propertyAccess = nodeParent; |
| 579 usage = propertyAccess; | |
| 571 target = propertyAccess.realTarget; | 580 target = propertyAccess.realTarget; |
| 572 cascade = propertyAccess.isCascaded; | 581 cascade = propertyAccess.isCascaded; |
| 573 } | 582 } |
| 574 // prepare arguments | 583 // prepare arguments |
| 575 List<Expression> arguments = []; | 584 List<Expression> arguments = []; |
| 576 if ((_node as SimpleIdentifier).inSetterContext()) { | 585 if ((_node as SimpleIdentifier).inSetterContext()) { |
| 577 arguments.add( | 586 AssignmentExpression assignment; |
| 578 (nodeParent.parent as AssignmentExpression).rightHandSide); | 587 if (nodeParent is AssignmentExpression) { |
| 588 assignment = nodeParent; | |
| 589 } else { | |
| 590 assignment = nodeParent.parent; | |
|
Brian Wilkerson
2014/09/12 22:42:31
Are two levels always enough? Consider using getAn
scheglov
2014/09/14 03:17:39
Ah, yes.
Thank you!
| |
| 591 } | |
| 592 arguments.add(assignment.rightHandSide); | |
| 579 } | 593 } |
| 580 // inline body | 594 // inline body |
| 581 _inlineMethodInvocation( | 595 _inlineMethodInvocation(status, usage, cascade, target, arguments); |
| 582 status, | |
| 583 nodeParent as Expression, | |
| 584 cascade, | |
| 585 target, | |
| 586 arguments); | |
| 587 return; | 596 return; |
| 588 } | 597 } |
| 589 // not invocation, just reference to function | 598 // not invocation, just reference to function |
| 590 String source; | 599 String source; |
| 591 { | 600 { |
| 592 source = ref._methodUtils.getRangeText( | 601 source = ref._methodUtils.getRangeText( |
| 593 rangeStartEnd(ref._methodParameters.leftParenthesis, ref._methodNode )); | 602 rangeStartEnd(ref._methodParameters.leftParenthesis, ref._methodNode )); |
| 594 String methodPrefix = | 603 String methodPrefix = |
| 595 ref._methodUtils.getLinePrefix(ref._methodNode.offset); | 604 ref._methodUtils.getLinePrefix(ref._methodNode.offset); |
| 596 source = | 605 source = |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 795 } | 804 } |
| 796 | 805 |
| 797 void _addVariable(SimpleIdentifier node) { | 806 void _addVariable(SimpleIdentifier node) { |
| 798 VariableElement variableElement = getLocalVariableElement(node); | 807 VariableElement variableElement = getLocalVariableElement(node); |
| 799 if (variableElement != null) { | 808 if (variableElement != null) { |
| 800 SourceRange nodeRange = rangeNode(node); | 809 SourceRange nodeRange = rangeNode(node); |
| 801 result.addVariable(variableElement, nodeRange); | 810 result.addVariable(variableElement, nodeRange); |
| 802 } | 811 } |
| 803 } | 812 } |
| 804 } | 813 } |
| OLD | NEW |