Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: pkg/analysis_server/lib/src/services/refactoring/extract_method.dart

Issue 1655353002: Issue 25616. Support for extracting methods with function-typed parameters. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698