| 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 | 6 |
| 7 import 'package:analysis_server/src/protocol_server.dart' hide Element; | 7 import 'package:analysis_server/src/protocol_server.dart' hide Element; |
| 8 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; | 8 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; |
| 9 import 'package:analysis_server/src/services/correction/selection_analyzer.dart'
; | 9 import 'package:analysis_server/src/services/correction/selection_analyzer.dart'
; |
| 10 import 'package:analysis_server/src/services/correction/statement_analyzer.dart'
; | 10 import 'package:analysis_server/src/services/correction/statement_analyzer.dart'
; |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 if (_staticContext) { | 316 if (_staticContext) { |
| 317 annotations = 'static '; | 317 annotations = 'static '; |
| 318 } | 318 } |
| 319 } | 319 } |
| 320 // prepare declaration source | 320 // prepare declaration source |
| 321 String declarationSource = null; | 321 String declarationSource = null; |
| 322 { | 322 { |
| 323 String returnExpressionSource = _getMethodBodySource(); | 323 String returnExpressionSource = _getMethodBodySource(); |
| 324 // closure | 324 // closure |
| 325 if (_selectionFunctionExpression != null) { | 325 if (_selectionFunctionExpression != null) { |
| 326 declarationSource = '$name$returnExpressionSource'; | 326 String returnTypeCode = _getExpectedClosureReturnTypeCode(); |
| 327 declarationSource = '$returnTypeCode$name$returnExpressionSource'; |
| 327 if (_selectionFunctionExpression.body is ExpressionFunctionBody) { | 328 if (_selectionFunctionExpression.body is ExpressionFunctionBody) { |
| 328 declarationSource += ';'; | 329 declarationSource += ';'; |
| 329 } | 330 } |
| 330 } | 331 } |
| 331 // optional 'async' body modifier | 332 // optional 'async' body modifier |
| 332 String asyncKeyword = _hasAwait ? ' async' : ''; | 333 String asyncKeyword = _hasAwait ? ' async' : ''; |
| 333 // expression | 334 // expression |
| 334 if (_selectionExpression != null) { | 335 if (_selectionExpression != null) { |
| 335 // add return type | 336 // add return type |
| 336 if (returnType.isNotEmpty) { | 337 if (returnType.isNotEmpty) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 } | 422 } |
| 422 // OK | 423 // OK |
| 423 return new Future<RefactoringStatus>.value(result); | 424 return new Future<RefactoringStatus>.value(result); |
| 424 } | 425 } |
| 425 | 426 |
| 426 /** | 427 /** |
| 427 * Checks if [selectionRange] selects [Expression] which can be extracted, and | 428 * Checks if [selectionRange] selects [Expression] which can be extracted, and |
| 428 * location of this [DartExpression] in AST allows extracting. | 429 * location of this [DartExpression] in AST allows extracting. |
| 429 */ | 430 */ |
| 430 RefactoringStatus _checkSelection() { | 431 RefactoringStatus _checkSelection() { |
| 432 // Check for implicitly selected closure. |
| 433 { |
| 434 FunctionExpression function = _findFunctionExpression(); |
| 435 if (function != null) { |
| 436 _selectionFunctionExpression = function; |
| 437 selectionRange = range.node(function); |
| 438 _parentMember = getEnclosingClassOrUnitMember(function); |
| 439 return new RefactoringStatus(); |
| 440 } |
| 441 } |
| 442 |
| 431 _ExtractMethodAnalyzer selectionAnalyzer = | 443 _ExtractMethodAnalyzer selectionAnalyzer = |
| 432 new _ExtractMethodAnalyzer(unit, selectionRange); | 444 new _ExtractMethodAnalyzer(unit, selectionRange); |
| 433 unit.accept(selectionAnalyzer); | 445 unit.accept(selectionAnalyzer); |
| 434 // may be fatal error | 446 // May be a fatal error. |
| 435 { | 447 { |
| 436 RefactoringStatus status = selectionAnalyzer.status; | 448 RefactoringStatus status = selectionAnalyzer.status; |
| 437 if (status.hasFatalError) { | 449 if (status.hasFatalError) { |
| 438 return status; | 450 return status; |
| 439 } | 451 } |
| 440 } | 452 } |
| 441 // check selected nodes | |
| 442 List<AstNode> selectedNodes = selectionAnalyzer.selectedNodes; | 453 List<AstNode> selectedNodes = selectionAnalyzer.selectedNodes; |
| 454 |
| 455 // Check selected nodes. |
| 443 if (!selectedNodes.isEmpty) { | 456 if (!selectedNodes.isEmpty) { |
| 444 AstNode coveringNode = selectionAnalyzer.coveringNode; | 457 AstNode selectedNode = selectedNodes.first; |
| 445 _parentMember = getEnclosingClassOrUnitMember(coveringNode); | 458 _parentMember = getEnclosingClassOrUnitMember(selectedNode); |
| 446 // single expression selected | 459 // single expression selected |
| 447 if (selectedNodes.length == 1 && | 460 if (selectedNodes.length == 1) { |
| 448 !utils.selectionIncludesNonWhitespaceOutsideNode( | 461 if (!utils.selectionIncludesNonWhitespaceOutsideNode( |
| 449 selectionRange, selectionAnalyzer.firstSelectedNode)) { | 462 selectionRange, selectedNode)) { |
| 450 AstNode selectedNode = selectionAnalyzer.firstSelectedNode; | 463 if (selectedNode is Expression) { |
| 451 if (selectedNode is Expression) { | 464 _selectionExpression = selectedNode; |
| 452 _selectionExpression = selectedNode; | 465 // additional check for closure |
| 453 // additional check for closure | 466 if (_selectionExpression is FunctionExpression) { |
| 454 if (_selectionExpression is FunctionExpression) { | 467 _selectionFunctionExpression = |
| 455 _selectionFunctionExpression = | 468 _selectionExpression as FunctionExpression; |
| 456 _selectionExpression as FunctionExpression; | 469 _selectionExpression = null; |
| 457 _selectionExpression = null; | 470 } |
| 471 // OK |
| 472 return new RefactoringStatus(); |
| 458 } | 473 } |
| 459 // OK | |
| 460 return new RefactoringStatus(); | |
| 461 } | 474 } |
| 462 } | 475 } |
| 463 // statements selected | 476 // statements selected |
| 464 { | 477 { |
| 465 List<Statement> selectedStatements = []; | 478 List<Statement> selectedStatements = []; |
| 466 for (AstNode selectedNode in selectedNodes) { | 479 for (AstNode selectedNode in selectedNodes) { |
| 467 if (selectedNode is Statement) { | 480 if (selectedNode is Statement) { |
| 468 selectedStatements.add(selectedNode); | 481 selectedStatements.add(selectedNode); |
| 469 } | 482 } |
| 470 } | 483 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 499 } | 512 } |
| 500 // doesn't return a value | 513 // doesn't return a value |
| 501 if (_selectionStatements != null) { | 514 if (_selectionStatements != null) { |
| 502 return returnType != 'void'; | 515 return returnType != 'void'; |
| 503 } | 516 } |
| 504 // OK | 517 // OK |
| 505 return true; | 518 return true; |
| 506 } | 519 } |
| 507 | 520 |
| 508 /** | 521 /** |
| 522 * If the [selectionRange] is associated with a [FunctionExpression], return |
| 523 * this [FunctionExpression]. |
| 524 */ |
| 525 FunctionExpression _findFunctionExpression() { |
| 526 if (selectionRange.length != 0) { |
| 527 return null; |
| 528 } |
| 529 int offset = selectionRange.offset; |
| 530 AstNode node = new NodeLocator2(offset, offset).searchWithin(unit); |
| 531 |
| 532 // Check for the parameter list of a FunctionExpression. |
| 533 { |
| 534 FunctionExpression function = |
| 535 node?.getAncestor((n) => n is FunctionExpression); |
| 536 if (function != null && |
| 537 function.parameters != null && |
| 538 range.node(function.parameters).contains(offset)) { |
| 539 return function; |
| 540 } |
| 541 } |
| 542 |
| 543 // Check for the name of the named argument with the closure expression. |
| 544 if (node is SimpleIdentifier && |
| 545 node.parent is Label && |
| 546 node.parent.parent is NamedExpression) { |
| 547 NamedExpression namedExpression = node.parent.parent; |
| 548 Expression expression = namedExpression.expression; |
| 549 if (expression is FunctionExpression) { |
| 550 return expression; |
| 551 } |
| 552 } |
| 553 |
| 554 return null; |
| 555 } |
| 556 |
| 557 /** |
| 558 * If the selected closure (i.e. [_selectionFunctionExpression]) is an |
| 559 * argument for a function typed parameter (as it should be), and the |
| 560 * function type has the return type specified, return this return type's |
| 561 * code. Otherwise return the empty string. |
| 562 */ |
| 563 String _getExpectedClosureReturnTypeCode() { |
| 564 Expression argument = _selectionFunctionExpression; |
| 565 if (argument.parent is NamedExpression) { |
| 566 argument = argument.parent as NamedExpression; |
| 567 } |
| 568 ParameterElement parameter = argument.bestParameterElement; |
| 569 if (parameter != null) { |
| 570 DartType parameterType = parameter.type; |
| 571 if (parameterType is FunctionType) { |
| 572 String typeCode = _getTypeCode(parameterType.returnType); |
| 573 if (typeCode != 'dynamic') { |
| 574 return typeCode + ' '; |
| 575 } |
| 576 } |
| 577 } |
| 578 return ''; |
| 579 } |
| 580 |
| 581 /** |
| 509 * Returns the selected [Expression] source, with applying new parameter | 582 * Returns the selected [Expression] source, with applying new parameter |
| 510 * names. | 583 * names. |
| 511 */ | 584 */ |
| 512 String _getMethodBodySource() { | 585 String _getMethodBodySource() { |
| 513 String source = utils.getRangeText(selectionRange); | 586 String source = utils.getRangeText(selectionRange); |
| 514 // prepare operations to replace variables with parameters | 587 // prepare operations to replace variables with parameters |
| 515 List<SourceEdit> replaceEdits = []; | 588 List<SourceEdit> replaceEdits = []; |
| 516 for (RefactoringMethodParameter parameter in _parameters) { | 589 for (RefactoringMethodParameter parameter in _parameters) { |
| 517 List<SourceRange> ranges = _parameterReferencesMap[parameter.id]; | 590 List<SourceRange> ranges = _parameterReferencesMap[parameter.id]; |
| 518 if (ranges != null) { | 591 if (ranges != null) { |
| (...skipping 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 return false; | 1323 return false; |
| 1251 } | 1324 } |
| 1252 for (int i = 0; i < parameterTypes.length; i++) { | 1325 for (int i = 0; i < parameterTypes.length; i++) { |
| 1253 if (other.parameterTypes[i] != parameterTypes[i]) { | 1326 if (other.parameterTypes[i] != parameterTypes[i]) { |
| 1254 return false; | 1327 return false; |
| 1255 } | 1328 } |
| 1256 } | 1329 } |
| 1257 return true; | 1330 return true; |
| 1258 } | 1331 } |
| 1259 } | 1332 } |
| OLD | NEW |