| 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_server.dart' hide Element; | 9 import 'package:analysis_server/src/protocol_server.dart' hide Element; |
| 10 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; | 10 import 'package:analysis_server/src/services/correction/name_suggestion.dart'; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 return new Future.value(result); | 172 return new Future.value(result); |
| 173 } | 173 } |
| 174 // prepare parts | 174 // prepare parts |
| 175 result.addStatus(_initializeParameters()); | 175 result.addStatus(_initializeParameters()); |
| 176 _initializeReturnType(); | 176 _initializeReturnType(); |
| 177 // occurrences | 177 // occurrences |
| 178 _initializeOccurrences(); | 178 _initializeOccurrences(); |
| 179 _prepareOffsetsLengths(); | 179 _prepareOffsetsLengths(); |
| 180 // getter | 180 // getter |
| 181 canCreateGetter = _computeCanCreateGetter(); | 181 canCreateGetter = _computeCanCreateGetter(); |
| 182 _initializeCreateGetter(); | 182 createGetter = |
| 183 canCreateGetter && _isExpressionForGetter(_selectionExpression); |
| 183 // names | 184 // names |
| 184 _prepareExcludedNames(); | 185 _prepareExcludedNames(); |
| 185 _prepareNames(); | 186 _prepareNames(); |
| 186 // closure cannot have parameters | 187 // closure cannot have parameters |
| 187 if (_selectionFunctionExpression != null && !_parameters.isEmpty) { | 188 if (_selectionFunctionExpression != null && !_parameters.isEmpty) { |
| 188 String message = format( | 189 String message = format( |
| 189 'Cannot extract closure as method, it references {0} external variable
(s).', | 190 'Cannot extract closure as method, it references {0} external variable
(s).', |
| 190 _parameters.length); | 191 _parameters.length); |
| 191 RefactoringStatus result = new RefactoringStatus.fatal(message); | 192 RefactoringStatus result = new RefactoringStatus.fatal(message); |
| 192 return new Future.value(result); | 193 return new Future.value(result); |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 String source = SourceEdit.applySequence(originalSource, replaceEdits); | 517 String source = SourceEdit.applySequence(originalSource, replaceEdits); |
| 517 pattern.normalizedSource = _getNormalizedSource(source); | 518 pattern.normalizedSource = _getNormalizedSource(source); |
| 518 return pattern; | 519 return pattern; |
| 519 } | 520 } |
| 520 | 521 |
| 521 String _getTypeCode(DartType type) { | 522 String _getTypeCode(DartType type) { |
| 522 return utils.getTypeSource(type, librariesToImport); | 523 return utils.getTypeSource(type, librariesToImport); |
| 523 } | 524 } |
| 524 | 525 |
| 525 /** | 526 /** |
| 526 * Initializes [createGetter] flag. | |
| 527 */ | |
| 528 void _initializeCreateGetter() { | |
| 529 createGetter = false; | |
| 530 // maybe we cannot at all | |
| 531 if (!canCreateGetter) { | |
| 532 return; | |
| 533 } | |
| 534 // OK, just expression | |
| 535 if (_selectionExpression != null) { | |
| 536 createGetter = !_hasMethodInvocation(_selectionExpression); | |
| 537 return; | |
| 538 } | |
| 539 // allow code blocks without cycles | |
| 540 if (_selectionStatements != null) { | |
| 541 createGetter = true; | |
| 542 for (Statement statement in _selectionStatements) { | |
| 543 // method invocation is something heavy, | |
| 544 // so we don't want to extract it as a part of a getter | |
| 545 if (_hasMethodInvocation(statement)) { | |
| 546 createGetter = false; | |
| 547 return; | |
| 548 } | |
| 549 // don't allow cycles | |
| 550 statement.accept(new _ResetCanCreateGetterVisitor(this)); | |
| 551 } | |
| 552 } | |
| 553 } | |
| 554 | |
| 555 /** | |
| 556 * Fills [_occurrences] field. | 527 * Fills [_occurrences] field. |
| 557 */ | 528 */ |
| 558 void _initializeOccurrences() { | 529 void _initializeOccurrences() { |
| 559 _occurrences.clear(); | 530 _occurrences.clear(); |
| 560 // prepare selection | 531 // prepare selection |
| 561 _SourcePattern selectionPattern = _getSourcePattern(selectionRange); | 532 _SourcePattern selectionPattern = _getSourcePattern(selectionRange); |
| 562 Map<String, String> patternToSelectionName = | 533 Map<String, String> patternToSelectionName = |
| 563 _inverseMap(selectionPattern.originalToPatternNames); | 534 _inverseMap(selectionPattern.originalToPatternNames); |
| 564 // prepare an enclosing parent - class or unit | 535 // prepare an enclosing parent - class or unit |
| 565 AstNode enclosingMemberParent = _parentMember.parent; | 536 AstNode enclosingMemberParent = _parentMember.parent; |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 void _prepareOffsetsLengths() { | 670 void _prepareOffsetsLengths() { |
| 700 offsets.clear(); | 671 offsets.clear(); |
| 701 lengths.clear(); | 672 lengths.clear(); |
| 702 for (_Occurrence occurrence in _occurrences) { | 673 for (_Occurrence occurrence in _occurrences) { |
| 703 offsets.add(occurrence.range.offset); | 674 offsets.add(occurrence.range.offset); |
| 704 lengths.add(occurrence.range.length); | 675 lengths.add(occurrence.range.length); |
| 705 } | 676 } |
| 706 } | 677 } |
| 707 | 678 |
| 708 /** | 679 /** |
| 709 * Checks if [node] has a [MethodInvocation]. | 680 * Checks if the given [expression] is reasonable to extract as a getter. |
| 710 */ | 681 */ |
| 711 static bool _hasMethodInvocation(AstNode node) { | 682 static bool _isExpressionForGetter(Expression expression) { |
| 712 var visitor = new _HasMethodInvocationVisitor(); | 683 if (expression is BinaryExpression) { |
| 713 node.accept(visitor); | 684 return _isExpressionForGetter(expression.leftOperand) && |
| 714 return visitor.result; | 685 _isExpressionForGetter(expression.rightOperand); |
| 686 } |
| 687 if (expression is Literal) { |
| 688 return true; |
| 689 } |
| 690 if (expression is PrefixExpression) { |
| 691 return _isExpressionForGetter(expression.operand); |
| 692 } |
| 693 if (expression is PrefixedIdentifier) { |
| 694 return _isExpressionForGetter(expression.prefix); |
| 695 } |
| 696 if (expression is PropertyAccess) { |
| 697 return _isExpressionForGetter(expression.target); |
| 698 } |
| 699 if (expression is SimpleIdentifier) { |
| 700 return true; |
| 701 } |
| 702 return false; |
| 715 } | 703 } |
| 716 | 704 |
| 717 /** | 705 /** |
| 718 * Returns `true` if the given [statement] may end with a [ReturnStatement]. | 706 * Returns `true` if the given [statement] may end with a [ReturnStatement]. |
| 719 */ | 707 */ |
| 720 static bool _mayEndWithReturnStatement(Statement statement) { | 708 static bool _mayEndWithReturnStatement(Statement statement) { |
| 721 _HasReturnStatementVisitor visitor = new _HasReturnStatementVisitor(); | 709 _HasReturnStatementVisitor visitor = new _HasReturnStatementVisitor(); |
| 722 statement.accept(visitor); | 710 statement.accept(visitor); |
| 723 return visitor.hasReturn; | 711 return visitor.hasReturn; |
| 724 } | 712 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 860 patternName = '__refVar${pattern.originalToPatternNames.length}'; | 848 patternName = '__refVar${pattern.originalToPatternNames.length}'; |
| 861 pattern.originalToPatternNames[originalName] = patternName; | 849 pattern.originalToPatternNames[originalName] = patternName; |
| 862 } | 850 } |
| 863 replaceEdits.add(new SourceEdit(nodeRange.offset - partRange.offset, | 851 replaceEdits.add(new SourceEdit(nodeRange.offset - partRange.offset, |
| 864 nodeRange.length, patternName)); | 852 nodeRange.length, patternName)); |
| 865 } | 853 } |
| 866 } | 854 } |
| 867 } | 855 } |
| 868 } | 856 } |
| 869 | 857 |
| 870 class _HasMethodInvocationVisitor extends RecursiveAstVisitor { | |
| 871 bool result = false; | |
| 872 | |
| 873 @override | |
| 874 visitMethodInvocation(MethodInvocation node) { | |
| 875 result = true; | |
| 876 } | |
| 877 } | |
| 878 | |
| 879 class _HasReturnStatementVisitor extends RecursiveAstVisitor { | 858 class _HasReturnStatementVisitor extends RecursiveAstVisitor { |
| 880 bool hasReturn = false; | 859 bool hasReturn = false; |
| 881 | 860 |
| 882 @override | 861 @override |
| 883 visitBlockFunctionBody(BlockFunctionBody node) {} | 862 visitBlockFunctionBody(BlockFunctionBody node) {} |
| 884 | 863 |
| 885 @override | 864 @override |
| 886 visitReturnStatement(ReturnStatement node) { | 865 visitReturnStatement(ReturnStatement node) { |
| 887 hasReturn = true; | 866 hasReturn = true; |
| 888 } | 867 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 954 return false; | 933 return false; |
| 955 } | 934 } |
| 956 // prepare node source | 935 // prepare node source |
| 957 _SourcePattern nodePattern = ref._getSourcePattern(nodeRange); | 936 _SourcePattern nodePattern = ref._getSourcePattern(nodeRange); |
| 958 // if matches normalized node source, then add as occurrence | 937 // if matches normalized node source, then add as occurrence |
| 959 if (selectionPattern.isCompatible(nodePattern)) { | 938 if (selectionPattern.isCompatible(nodePattern)) { |
| 960 _Occurrence occurrence = | 939 _Occurrence occurrence = |
| 961 new _Occurrence(nodeRange, ref.selectionRange.intersects(nodeRange)); | 940 new _Occurrence(nodeRange, ref.selectionRange.intersects(nodeRange)); |
| 962 ref._occurrences.add(occurrence); | 941 ref._occurrences.add(occurrence); |
| 963 // prepare mapping of parameter names to the occurrence variables | 942 // prepare mapping of parameter names to the occurrence variables |
| 964 nodePattern.originalToPatternNames.forEach( | 943 nodePattern.originalToPatternNames |
| 965 (String originalName, String patternName) { | 944 .forEach((String originalName, String patternName) { |
| 966 String selectionName = patternToSelectionName[patternName]; | 945 String selectionName = patternToSelectionName[patternName]; |
| 967 occurrence._parameterOldToOccurrenceName[selectionName] = originalName; | 946 occurrence._parameterOldToOccurrenceName[selectionName] = originalName; |
| 968 }); | 947 }); |
| 969 // update static | 948 // update static |
| 970 if (forceStatic) { | 949 if (forceStatic) { |
| 971 ref._staticContext = true; | 950 ref._staticContext = true; |
| 972 } | 951 } |
| 973 // we have match | 952 // we have match |
| 974 return true; | 953 return true; |
| 975 } | 954 } |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1072 */ | 1051 */ |
| 1073 class _Occurrence { | 1052 class _Occurrence { |
| 1074 final SourceRange range; | 1053 final SourceRange range; |
| 1075 final bool isSelection; | 1054 final bool isSelection; |
| 1076 | 1055 |
| 1077 Map<String, String> _parameterOldToOccurrenceName = <String, String>{}; | 1056 Map<String, String> _parameterOldToOccurrenceName = <String, String>{}; |
| 1078 | 1057 |
| 1079 _Occurrence(this.range, this.isSelection); | 1058 _Occurrence(this.range, this.isSelection); |
| 1080 } | 1059 } |
| 1081 | 1060 |
| 1082 class _ResetCanCreateGetterVisitor extends RecursiveAstVisitor { | |
| 1083 final ExtractMethodRefactoringImpl ref; | |
| 1084 | |
| 1085 _ResetCanCreateGetterVisitor(this.ref); | |
| 1086 | |
| 1087 @override | |
| 1088 visitDoStatement(DoStatement node) { | |
| 1089 ref.createGetter = false; | |
| 1090 super.visitDoStatement(node); | |
| 1091 } | |
| 1092 | |
| 1093 @override | |
| 1094 visitForEachStatement(ForEachStatement node) { | |
| 1095 ref.createGetter = false; | |
| 1096 super.visitForEachStatement(node); | |
| 1097 } | |
| 1098 | |
| 1099 @override | |
| 1100 visitForStatement(ForStatement node) { | |
| 1101 ref.createGetter = false; | |
| 1102 super.visitForStatement(node); | |
| 1103 } | |
| 1104 | |
| 1105 @override | |
| 1106 visitWhileStatement(WhileStatement node) { | |
| 1107 ref.createGetter = false; | |
| 1108 super.visitWhileStatement(node); | |
| 1109 } | |
| 1110 } | |
| 1111 | |
| 1112 class _ReturnTypeComputer extends RecursiveAstVisitor { | 1061 class _ReturnTypeComputer extends RecursiveAstVisitor { |
| 1113 DartType returnType; | 1062 DartType returnType; |
| 1114 | 1063 |
| 1115 @override | 1064 @override |
| 1116 visitBlockFunctionBody(BlockFunctionBody node) {} | 1065 visitBlockFunctionBody(BlockFunctionBody node) {} |
| 1117 | 1066 |
| 1118 @override | 1067 @override |
| 1119 visitReturnStatement(ReturnStatement node) { | 1068 visitReturnStatement(ReturnStatement node) { |
| 1120 // prepare expression | 1069 // prepare expression |
| 1121 Expression expression = node.expression; | 1070 Expression expression = node.expression; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 return false; | 1107 return false; |
| 1159 } | 1108 } |
| 1160 for (int i = 0; i < parameterTypes.length; i++) { | 1109 for (int i = 0; i < parameterTypes.length; i++) { |
| 1161 if (other.parameterTypes[i] != parameterTypes[i]) { | 1110 if (other.parameterTypes[i] != parameterTypes[i]) { |
| 1162 return false; | 1111 return false; |
| 1163 } | 1112 } |
| 1164 } | 1113 } |
| 1165 return true; | 1114 return true; |
| 1166 } | 1115 } |
| 1167 } | 1116 } |
| OLD | NEW |