| 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 13 matching lines...) Expand all Loading... |
| 24 import 'package:analyzer/dart/element/type.dart'; | 24 import 'package:analyzer/dart/element/type.dart'; |
| 25 import 'package:analyzer/src/generated/ast.dart'; | 25 import 'package:analyzer/src/generated/ast.dart'; |
| 26 import 'package:analyzer/src/generated/engine.dart'; | 26 import 'package:analyzer/src/generated/engine.dart'; |
| 27 import 'package:analyzer/src/generated/java_core.dart'; | 27 import 'package:analyzer/src/generated/java_core.dart'; |
| 28 import 'package:analyzer/src/generated/resolver.dart' show ExitDetector; | 28 import 'package:analyzer/src/generated/resolver.dart' show ExitDetector; |
| 29 import 'package:analyzer/src/generated/scanner.dart'; | 29 import 'package:analyzer/src/generated/scanner.dart'; |
| 30 import 'package:analyzer/src/generated/source.dart'; | 30 import 'package:analyzer/src/generated/source.dart'; |
| 31 | 31 |
| 32 const String _TOKEN_SEPARATOR = '\uFFFF'; | 32 const String _TOKEN_SEPARATOR = '\uFFFF'; |
| 33 | 33 |
| 34 Element _getLocalElement(SimpleIdentifier node) { |
| 35 Element element = node.staticElement; |
| 36 if (element is LocalVariableElement || |
| 37 element is ParameterElement || |
| 38 element is FunctionElement && element.visibleRange != null) { |
| 39 return element; |
| 40 } |
| 41 return null; |
| 42 } |
| 43 |
| 34 /** | 44 /** |
| 35 * Returns the "normalized" version of the given source, which is reconstructed | 45 * Returns the "normalized" version of the given source, which is reconstructed |
| 36 * from tokens, so ignores all the comments and spaces. | 46 * from tokens, so ignores all the comments and spaces. |
| 37 */ | 47 */ |
| 38 String _getNormalizedSource(String src) { | 48 String _getNormalizedSource(String src) { |
| 39 List<Token> selectionTokens = TokenUtils.getTokens(src); | 49 List<Token> selectionTokens = TokenUtils.getTokens(src); |
| 40 return StringUtils.join(selectionTokens, _TOKEN_SEPARATOR); | 50 return StringUtils.join(selectionTokens, _TOKEN_SEPARATOR); |
| 41 } | 51 } |
| 42 | 52 |
| 43 /** | 53 /** |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 // type | 164 // type |
| 155 { | 165 { |
| 156 String typeSource = parameter.type; | 166 String typeSource = parameter.type; |
| 157 if ('dynamic' != typeSource && '' != typeSource) { | 167 if ('dynamic' != typeSource && '' != typeSource) { |
| 158 sb.write(typeSource); | 168 sb.write(typeSource); |
| 159 sb.write(' '); | 169 sb.write(' '); |
| 160 } | 170 } |
| 161 } | 171 } |
| 162 // name | 172 // name |
| 163 sb.write(parameter.name); | 173 sb.write(parameter.name); |
| 174 // optional function-typed parameter parameters |
| 175 if (parameter.parameters != null) { |
| 176 sb.write(parameter.parameters); |
| 177 } |
| 164 } | 178 } |
| 165 sb.write(')'); | 179 sb.write(')'); |
| 166 } | 180 } |
| 167 // done | 181 // done |
| 168 return sb.toString(); | 182 return sb.toString(); |
| 169 } | 183 } |
| 170 | 184 |
| 171 @override | 185 @override |
| 172 Future<RefactoringStatus> checkFinalConditions() async { | 186 Future<RefactoringStatus> checkFinalConditions() async { |
| 173 RefactoringStatus result = new RefactoringStatus(); | 187 RefactoringStatus result = new RefactoringStatus(); |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 if (_returnType.element != futureType.element) { | 669 if (_returnType.element != futureType.element) { |
| 656 returnType = _getTypeCode(futureType.substitute4([_returnType])); | 670 returnType = _getTypeCode(futureType.substitute4([_returnType])); |
| 657 } | 671 } |
| 658 } else { | 672 } else { |
| 659 returnType = variableType; | 673 returnType = variableType; |
| 660 } | 674 } |
| 661 } | 675 } |
| 662 } | 676 } |
| 663 | 677 |
| 664 /** | 678 /** |
| 665 * Checks if the given [VariableElement] is declared in [selectionRange]. | 679 * Checks if the given [element] is declared in [selectionRange]. |
| 666 */ | 680 */ |
| 667 bool _isDeclaredInSelection(VariableElement element) { | 681 bool _isDeclaredInSelection(Element element) { |
| 668 return selectionRange.contains(element.nameOffset); | 682 return selectionRange.contains(element.nameOffset); |
| 669 } | 683 } |
| 670 | 684 |
| 671 /** | 685 /** |
| 672 * Checks if it is OK to extract the node with the given [SourceRange]. | 686 * Checks if it is OK to extract the node with the given [SourceRange]. |
| 673 */ | 687 */ |
| 674 bool _isExtractable(SourceRange range) { | 688 bool _isExtractable(SourceRange range) { |
| 675 _ExtractMethodAnalyzer analyzer = new _ExtractMethodAnalyzer(unit, range); | 689 _ExtractMethodAnalyzer analyzer = new _ExtractMethodAnalyzer(unit, range); |
| 676 utils.unit.accept(analyzer); | 690 utils.unit.accept(analyzer); |
| 677 return analyzer.status.isOK; | 691 return analyzer.status.isOK; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 693 } | 707 } |
| 694 if (_unqualifiedNames.contains(name)) { | 708 if (_unqualifiedNames.contains(name)) { |
| 695 return true; | 709 return true; |
| 696 } | 710 } |
| 697 return false; | 711 return false; |
| 698 } | 712 } |
| 699 | 713 |
| 700 /** | 714 /** |
| 701 * Checks if [element] is referenced after [selectionRange]. | 715 * Checks if [element] is referenced after [selectionRange]. |
| 702 */ | 716 */ |
| 703 bool _isUsedAfterSelection(VariableElement element) { | 717 bool _isUsedAfterSelection(Element element) { |
| 704 var visitor = new _IsUsedAfterSelectionVisitor(this, element); | 718 var visitor = new _IsUsedAfterSelectionVisitor(this, element); |
| 705 _parentMember.accept(visitor); | 719 _parentMember.accept(visitor); |
| 706 return visitor.result; | 720 return visitor.result; |
| 707 } | 721 } |
| 708 | 722 |
| 709 /** | 723 /** |
| 710 * Prepare names that are used in the enclosing function, so should not be | 724 * Prepare names that are used in the enclosing function, so should not be |
| 711 * proposed as names of the extracted method. | 725 * proposed as names of the extracted method. |
| 712 */ | 726 */ |
| 713 void _prepareExcludedNames() { | 727 void _prepareExcludedNames() { |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 900 final SourceRange partRange; | 914 final SourceRange partRange; |
| 901 final _SourcePattern pattern; | 915 final _SourcePattern pattern; |
| 902 final List<SourceEdit> replaceEdits; | 916 final List<SourceEdit> replaceEdits; |
| 903 | 917 |
| 904 _GetSourcePatternVisitor(this.partRange, this.pattern, this.replaceEdits); | 918 _GetSourcePatternVisitor(this.partRange, this.pattern, this.replaceEdits); |
| 905 | 919 |
| 906 @override | 920 @override |
| 907 visitSimpleIdentifier(SimpleIdentifier node) { | 921 visitSimpleIdentifier(SimpleIdentifier node) { |
| 908 SourceRange nodeRange = rangeNode(node); | 922 SourceRange nodeRange = rangeNode(node); |
| 909 if (partRange.covers(nodeRange)) { | 923 if (partRange.covers(nodeRange)) { |
| 910 VariableElement variableElement = | 924 Element element = _getLocalElement(node); |
| 911 getLocalOrParameterVariableElement(node); | 925 if (element != null) { |
| 912 if (variableElement != null) { | |
| 913 // name of a named expression | 926 // name of a named expression |
| 914 if (isNamedExpressionName(node)) { | 927 if (isNamedExpressionName(node)) { |
| 915 return; | 928 return; |
| 916 } | 929 } |
| 917 // continue | 930 // continue |
| 918 String originalName = variableElement.displayName; | 931 String originalName = element.displayName; |
| 919 String patternName = pattern.originalToPatternNames[originalName]; | 932 String patternName = pattern.originalToPatternNames[originalName]; |
| 920 if (patternName == null) { | 933 if (patternName == null) { |
| 921 pattern.parameterTypes.add(variableElement.type); | 934 DartType parameterType = _getElementType(element); |
| 935 pattern.parameterTypes.add(parameterType); |
| 922 patternName = '__refVar${pattern.originalToPatternNames.length}'; | 936 patternName = '__refVar${pattern.originalToPatternNames.length}'; |
| 923 pattern.originalToPatternNames[originalName] = patternName; | 937 pattern.originalToPatternNames[originalName] = patternName; |
| 924 } | 938 } |
| 925 replaceEdits.add(new SourceEdit(nodeRange.offset - partRange.offset, | 939 replaceEdits.add(new SourceEdit(nodeRange.offset - partRange.offset, |
| 926 nodeRange.length, patternName)); | 940 nodeRange.length, patternName)); |
| 927 } | 941 } |
| 928 } | 942 } |
| 929 } | 943 } |
| 944 |
| 945 DartType _getElementType(Element element) { |
| 946 if (element is VariableElement) { |
| 947 return element.type; |
| 948 } |
| 949 if (element is FunctionElement) { |
| 950 return element.type; |
| 951 } |
| 952 throw new StateError('Unknown element type: ${element?.runtimeType}'); |
| 953 } |
| 930 } | 954 } |
| 931 | 955 |
| 932 class _HasAwaitVisitor extends GeneralizingAstVisitor { | 956 class _HasAwaitVisitor extends GeneralizingAstVisitor { |
| 933 bool result = false; | 957 bool result = false; |
| 934 | 958 |
| 935 @override | 959 @override |
| 936 visitAwaitExpression(AwaitExpression node) { | 960 visitAwaitExpression(AwaitExpression node) { |
| 937 result = true; | 961 result = true; |
| 938 } | 962 } |
| 939 | 963 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1070 | 1094 |
| 1071 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); | 1095 _InitializeParametersVisitor(this.ref, this.assignedUsedVariables); |
| 1072 | 1096 |
| 1073 @override | 1097 @override |
| 1074 void visitSimpleIdentifier(SimpleIdentifier node) { | 1098 void visitSimpleIdentifier(SimpleIdentifier node) { |
| 1075 SourceRange nodeRange = rangeNode(node); | 1099 SourceRange nodeRange = rangeNode(node); |
| 1076 if (!ref.selectionRange.covers(nodeRange)) { | 1100 if (!ref.selectionRange.covers(nodeRange)) { |
| 1077 return; | 1101 return; |
| 1078 } | 1102 } |
| 1079 String name = node.name; | 1103 String name = node.name; |
| 1080 // analyze local variable | 1104 // analyze local element |
| 1081 VariableElement variableElement = getLocalOrParameterVariableElement(node); | 1105 Element element = _getLocalElement(node); |
| 1082 if (variableElement != null) { | 1106 if (element != null) { |
| 1083 // name of the named expression | 1107 // name of the named expression |
| 1084 if (isNamedExpressionName(node)) { | 1108 if (isNamedExpressionName(node)) { |
| 1085 return; | 1109 return; |
| 1086 } | 1110 } |
| 1087 // if declared outside, add parameter | 1111 // if declared outside, add parameter |
| 1088 if (!ref._isDeclaredInSelection(variableElement)) { | 1112 if (!ref._isDeclaredInSelection(element)) { |
| 1089 // add parameter | 1113 // add parameter |
| 1090 RefactoringMethodParameter parameter = ref._parametersMap[name]; | 1114 RefactoringMethodParameter parameter = ref._parametersMap[name]; |
| 1091 if (parameter == null) { | 1115 if (parameter == null) { |
| 1092 DartType parameterType = node.bestType; | 1116 DartType parameterType = node.bestType; |
| 1093 String parameterTypeCode = ref._getTypeCode(parameterType); | 1117 StringBuffer parametersBuffer = new StringBuffer(); |
| 1118 String parameterTypeCode = ref.utils.getTypeSource( |
| 1119 parameterType, ref.librariesToImport, |
| 1120 parametersBuffer: parametersBuffer); |
| 1121 String parametersCode = |
| 1122 parametersBuffer.isNotEmpty ? parametersBuffer.toString() : null; |
| 1094 parameter = new RefactoringMethodParameter( | 1123 parameter = new RefactoringMethodParameter( |
| 1095 RefactoringMethodParameterKind.REQUIRED, parameterTypeCode, name, | 1124 RefactoringMethodParameterKind.REQUIRED, parameterTypeCode, name, |
| 1096 id: name); | 1125 parameters: parametersCode, id: name); |
| 1097 ref._parameters.add(parameter); | 1126 ref._parameters.add(parameter); |
| 1098 ref._parametersMap[name] = parameter; | 1127 ref._parametersMap[name] = parameter; |
| 1099 } | 1128 } |
| 1100 // add reference to parameter | 1129 // add reference to parameter |
| 1101 ref._addParameterReference(name, nodeRange); | 1130 ref._addParameterReference(name, nodeRange); |
| 1102 } | 1131 } |
| 1103 // remember, if assigned and used after selection | 1132 // remember, if assigned and used after selection |
| 1104 if (isLeftHandOfAssignment(node) && | 1133 if (isLeftHandOfAssignment(node) && ref._isUsedAfterSelection(element)) { |
| 1105 ref._isUsedAfterSelection(variableElement)) { | 1134 if (!assignedUsedVariables.contains(element)) { |
| 1106 if (!assignedUsedVariables.contains(variableElement)) { | 1135 assignedUsedVariables.add(element); |
| 1107 assignedUsedVariables.add(variableElement); | |
| 1108 } | 1136 } |
| 1109 } | 1137 } |
| 1110 } | 1138 } |
| 1111 // remember information for conflicts checking | 1139 // remember information for conflicts checking |
| 1112 if (variableElement is LocalElement) { | 1140 if (element is LocalElement) { |
| 1113 // declared local elements | 1141 // declared local elements |
| 1114 LocalElement localElement = variableElement as LocalElement; | |
| 1115 if (node.inDeclarationContext()) { | 1142 if (node.inDeclarationContext()) { |
| 1116 ref._localNames.putIfAbsent(name, () => <SourceRange>[]); | 1143 ref._localNames.putIfAbsent(name, () => <SourceRange>[]); |
| 1117 ref._localNames[name].add(localElement.visibleRange); | 1144 ref._localNames[name].add(element.visibleRange); |
| 1118 } | 1145 } |
| 1119 } else { | 1146 } else { |
| 1120 // unqualified non-local names | 1147 // unqualified non-local names |
| 1121 if (!node.isQualified) { | 1148 if (!node.isQualified) { |
| 1122 ref._unqualifiedNames.add(name); | 1149 ref._unqualifiedNames.add(name); |
| 1123 } | 1150 } |
| 1124 } | 1151 } |
| 1125 } | 1152 } |
| 1126 } | 1153 } |
| 1127 | 1154 |
| 1128 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { | 1155 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor { |
| 1129 final ExtractMethodRefactoringImpl ref; | 1156 final ExtractMethodRefactoringImpl ref; |
| 1130 final VariableElement element; | 1157 final Element element; |
| 1131 bool result = false; | 1158 bool result = false; |
| 1132 | 1159 |
| 1133 _IsUsedAfterSelectionVisitor(this.ref, this.element); | 1160 _IsUsedAfterSelectionVisitor(this.ref, this.element); |
| 1134 | 1161 |
| 1135 @override | 1162 @override |
| 1136 visitSimpleIdentifier(SimpleIdentifier node) { | 1163 visitSimpleIdentifier(SimpleIdentifier node) { |
| 1137 VariableElement nodeElement = getLocalVariableElement(node); | 1164 Element nodeElement = node.staticElement; |
| 1138 if (identical(nodeElement, element)) { | 1165 if (identical(nodeElement, element)) { |
| 1139 int nodeOffset = node.offset; | 1166 int nodeOffset = node.offset; |
| 1140 if (nodeOffset > ref.selectionRange.end) { | 1167 if (nodeOffset > ref.selectionRange.end) { |
| 1141 result = true; | 1168 result = true; |
| 1142 } | 1169 } |
| 1143 } | 1170 } |
| 1144 } | 1171 } |
| 1145 } | 1172 } |
| 1146 | 1173 |
| 1147 /** | 1174 /** |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1211 return false; | 1238 return false; |
| 1212 } | 1239 } |
| 1213 for (int i = 0; i < parameterTypes.length; i++) { | 1240 for (int i = 0; i < parameterTypes.length; i++) { |
| 1214 if (other.parameterTypes[i] != parameterTypes[i]) { | 1241 if (other.parameterTypes[i] != parameterTypes[i]) { |
| 1215 return false; | 1242 return false; |
| 1216 } | 1243 } |
| 1217 } | 1244 } |
| 1218 return true; | 1245 return true; |
| 1219 } | 1246 } |
| 1220 } | 1247 } |
| OLD | NEW |