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

Side by Side Diff: pkg/analysis_server/lib/src/services/correction/util.dart

Issue 498763003: Initial 'Extract Method' refactoring implementation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 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 | Annotate | Revision Log
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.correction.util; 5 library services.src.correction.util;
6 6
7 import 'dart:math'; 7 import 'dart:math';
8 8
9 import 'package:analysis_server/src/protocol2.dart' show SourceEdit; 9 import 'package:analysis_server/src/protocol2.dart' show SourceEdit;
10 import 'package:analysis_server/src/services/correction/source_range.dart'; 10 import 'package:analysis_server/src/services/correction/source_range.dart';
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 ElementKind kind = element.kind; 87 ElementKind kind = element.kind;
88 if (kind == ElementKind.FIELD || kind == ElementKind.METHOD) { 88 if (kind == ElementKind.FIELD || kind == ElementKind.METHOD) {
89 return '${element.enclosingElement.displayName}.${element.displayName}'; 89 return '${element.enclosingElement.displayName}.${element.displayName}';
90 } else { 90 } else {
91 return element.displayName; 91 return element.displayName;
92 } 92 }
93 } 93 }
94 94
95 95
96 /** 96 /**
97 * Returns a class or an unit member enclosing the given [node].
98 */
99 AstNode getEnclosingClassOrUnitMember(AstNode node) {
100 AstNode member = node;
101 while (node != null) {
102 if (node is ClassDeclaration) {
103 return member;
104 }
105 if (node is CompilationUnit) {
106 return member;
107 }
108 member = node;
109 node = node.parent;
110 }
111 return null;
112 }
113
114
115
116 /**
97 * @return the [ExecutableElement] of the enclosing executable [AstNode]. 117 * @return the [ExecutableElement] of the enclosing executable [AstNode].
98 */ 118 */
99 ExecutableElement getEnclosingExecutableElement(AstNode node) { 119 ExecutableElement getEnclosingExecutableElement(AstNode node) {
100 while (node != null) { 120 while (node != null) {
101 if (node is FunctionDeclaration) { 121 if (node is FunctionDeclaration) {
102 return node.element; 122 return node.element;
103 } 123 }
104 if (node is ConstructorDeclaration) { 124 if (node is ConstructorDeclaration) {
105 return node.element; 125 return node.element;
106 } 126 }
107 if (node is MethodDeclaration) { 127 if (node is MethodDeclaration) {
108 return node.element; 128 return node.element;
109 } 129 }
110 node = node.parent; 130 node = node.parent;
111 } 131 }
112 return null; 132 return null;
113 } 133 }
114 134
115
116 /** 135 /**
117 * @return the enclosing executable [AstNode]. 136 * @return the enclosing executable [AstNode].
118 */ 137 */
119 AstNode getEnclosingExecutableNode(AstNode node) { 138 AstNode getEnclosingExecutableNode(AstNode node) {
120 while (node != null) { 139 while (node != null) {
121 if (node is FunctionDeclaration) { 140 if (node is FunctionDeclaration) {
122 return node; 141 return node;
123 } 142 }
124 if (node is ConstructorDeclaration) { 143 if (node is ConstructorDeclaration) {
125 return node; 144 return node;
126 } 145 }
127 if (node is MethodDeclaration) { 146 if (node is MethodDeclaration) {
128 return node; 147 return node;
129 } 148 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 180
162 /** 181 /**
163 * Returns the namespace of the given [ImportElement]. 182 * Returns the namespace of the given [ImportElement].
164 */ 183 */
165 Map<String, Element> getImportNamespace(ImportElement imp) { 184 Map<String, Element> getImportNamespace(ImportElement imp) {
166 NamespaceBuilder builder = new NamespaceBuilder(); 185 NamespaceBuilder builder = new NamespaceBuilder();
167 Namespace namespace = builder.createImportNamespaceForDirective(imp); 186 Namespace namespace = builder.createImportNamespaceForDirective(imp);
168 return namespace.definedNames; 187 return namespace.definedNames;
169 } 188 }
170 189
190
191
192 /**
193 * @return the [LocalVariableElement] or [ParameterElement] if given
194 * [SimpleIdentifier] is the reference to local variable or parameter, o r
195 * <code>null</code> in the other case.
196 */
197 VariableElement getLocalOrParameterVariableElement(SimpleIdentifier node) {
198 Element element = node.staticElement;
199 if (element is LocalVariableElement) {
200 return element;
201 }
202 if (element is ParameterElement) {
203 return element;
204 }
205 return null;
206 }
207
208
209 /**
210 * @return the [LocalVariableElement] if given [SimpleIdentifier] is the referen ce to
211 * local variable, or <code>null</code> in the other case.
212 */
213 LocalVariableElement getLocalVariableElement(SimpleIdentifier node) {
214 Element element = node.staticElement;
215 if (element is LocalVariableElement) {
216 return element;
217 }
218 return null;
219 }
220
221
171 /** 222 /**
172 * @return the nearest common ancestor [AstNode] of the given [AstNode]s. 223 * @return the nearest common ancestor [AstNode] of the given [AstNode]s.
173 */ 224 */
174 AstNode getNearestCommonAncestor(List<AstNode> nodes) { 225 AstNode getNearestCommonAncestor(List<AstNode> nodes) {
175 // may be no nodes 226 // may be no nodes
176 if (nodes.isEmpty) { 227 if (nodes.isEmpty) {
177 return null; 228 return null;
178 } 229 }
179 // prepare parents 230 // prepare parents
180 List<List<AstNode>> parents = []; 231 List<List<AstNode>> parents = [];
181 for (AstNode node in nodes) { 232 for (AstNode node in nodes) {
182 parents.add(getParents(node)); 233 parents.add(getParents(node));
183 } 234 }
184 // find min length 235 // find min length
185 int minLength = 1 << 20; 236 int minLength = 1 << 20;
186 for (List<AstNode> parentList in parents) { 237 for (List<AstNode> parentList in parents) {
187 minLength = min(minLength, parentList.length); 238 minLength = min(minLength, parentList.length);
188 } 239 }
189 // find deepest parent 240 // find deepest parent
190 int i = 0; 241 int i = 0;
191 for (; i < minLength; i++) { 242 for ( ; i < minLength; i++) {
192 if (!allListsIdentical(parents, i)) { 243 if (!allListsIdentical(parents, i)) {
193 break; 244 break;
194 } 245 }
195 } 246 }
196 return parents[0][i - 1]; 247 return parents[0][i - 1];
197 } 248 }
198 249
250
199 /** 251 /**
200 * @return parent [AstNode]s from [CompilationUnit] (at index "0") to the given one. 252 * @return parent [AstNode]s from [CompilationUnit] (at index "0") to the given one.
201 */ 253 */
202 List<AstNode> getParents(AstNode node) { 254 List<AstNode> getParents(AstNode node) {
203 // prepare number of parents 255 // prepare number of parents
204 int numParents = 0; 256 int numParents = 0;
205 { 257 {
206 AstNode current = node.parent; 258 AstNode current = node.parent;
207 while (current != null) { 259 while (current != null) {
208 numParents++; 260 numParents++;
209 current = current.parent; 261 current = current.parent;
210 } 262 }
211 } 263 }
212 // fill array of parents 264 // fill array of parents
213 List<AstNode> parents = new List<AstNode>(numParents); 265 List<AstNode> parents = new List<AstNode>(numParents);
214 AstNode current = node.parent; 266 AstNode current = node.parent;
215 int index = numParents; 267 int index = numParents;
216 while (current != null) { 268 while (current != null) {
217 parents[--index] = current; 269 parents[--index] = current;
218 current = current.parent; 270 current = current.parent;
219 } 271 }
220 return parents; 272 return parents;
221 } 273 }
222 274
223
224 /** 275 /**
225 * If given [AstNode] is name of qualified property extraction, returns target f rom which 276 * If given [AstNode] is name of qualified property extraction, returns target f rom which
226 * this property is extracted. Otherwise `null`. 277 * this property is extracted. Otherwise `null`.
227 */ 278 */
228 Expression getQualifiedPropertyTarget(AstNode node) { 279 Expression getQualifiedPropertyTarget(AstNode node) {
229 AstNode parent = node.parent; 280 AstNode parent = node.parent;
230 if (parent is PrefixedIdentifier) { 281 if (parent is PrefixedIdentifier) {
231 PrefixedIdentifier prefixed = parent; 282 PrefixedIdentifier prefixed = parent;
232 if (prefixed.identifier == node) { 283 if (prefixed.identifier == node) {
233 return parent.prefix; 284 return parent.prefix;
234 } 285 }
235 } 286 }
236 if (parent is PropertyAccess) { 287 if (parent is PropertyAccess) {
237 PropertyAccess access = parent; 288 PropertyAccess access = parent;
238 if (access.propertyName == node) { 289 if (access.propertyName == node) {
239 return access.realTarget; 290 return access.realTarget;
240 } 291 }
241 } 292 }
242 return null; 293 return null;
243 } 294 }
244 295
245
246 /** 296 /**
247 * Returns the given [Statement] if not a [Block], or the first child 297 * Returns the given [Statement] if not a [Block], or the first child
248 * [Statement] if a [Block], or `null` if more than one child. 298 * [Statement] if a [Block], or `null` if more than one child.
249 */ 299 */
250 Statement getSingleStatement(Statement statement) { 300 Statement getSingleStatement(Statement statement) {
251 if (statement is Block) { 301 if (statement is Block) {
252 List<Statement> blockStatements = statement.statements; 302 List<Statement> blockStatements = statement.statements;
253 if (blockStatements.length != 1) { 303 if (blockStatements.length != 1) {
254 return null; 304 return null;
255 } 305 }
(...skipping 27 matching lines...) Expand all
283 * Checks if the given [Element]'s display name equals to the given name. 333 * Checks if the given [Element]'s display name equals to the given name.
284 */ 334 */
285 bool hasDisplayName(Element element, String name) { 335 bool hasDisplayName(Element element, String name) {
286 if (element == null) { 336 if (element == null) {
287 return false; 337 return false;
288 } 338 }
289 return element.displayName == name; 339 return element.displayName == name;
290 } 340 }
291 341
292 342
343 /**
344 * @return <code>true</code> if given [DartNode] is left hand side of assignment , or
345 * declaration of the variable.
346 */
347 bool isLeftHandOfAssignment(SimpleIdentifier node) {
348 if (node.inSetterContext()) {
349 return true;
350 }
351 return node.parent is VariableDeclaration &&
352 (node.parent as VariableDeclaration).name == node;
Brian Wilkerson 2014/08/25 07:44:00 Does this also want to ensure that there is an ini
scheglov 2014/08/25 15:36:29 I's not very useful to extract an empty variable d
353 }
354
355
356 /**
357 * @return `true` if the given [SimpleIdentifier] is the name of the
358 * [NamedExpression].
359 */
360 bool isNamedExpressionName(SimpleIdentifier node) {
361 AstNode parent = node.parent;
362 if (parent is Label) {
363 Label label = parent;
364 if (identical(label.label, node)) {
365 AstNode parent2 = label.parent;
366 if (parent2 is NamedExpression) {
367 return identical(parent2.name, label);
368 }
369 }
370 }
371 return false;
372 }
373
374
293 class CorrectionUtils { 375 class CorrectionUtils {
294 final CompilationUnit unit; 376 final CompilationUnit unit;
295 377
296 LibraryElement _library; 378 LibraryElement _library;
297 String _buffer; 379 String _buffer;
298 String _endOfLine; 380 String _endOfLine;
299 381
300 CorrectionUtils(this.unit) { 382 CorrectionUtils(this.unit) {
301 CompilationUnitElement unitElement = unit.element; 383 CompilationUnitElement unitElement = unit.element;
302 this._library = unitElement.library; 384 this._library = unitElement.library;
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 861
780 /** 862 /**
781 * Returns the source with indentation changed from [oldIndent] to 863 * Returns the source with indentation changed from [oldIndent] to
782 * [newIndent], keeping indentation of lines relative to each other. 864 * [newIndent], keeping indentation of lines relative to each other.
783 */ 865 */
784 String replaceSourceIndent(String source, String oldIndent, 866 String replaceSourceIndent(String source, String oldIndent,
785 String newIndent) { 867 String newIndent) {
786 // prepare STRING token ranges 868 // prepare STRING token ranges
787 List<SourceRange> lineRanges = []; 869 List<SourceRange> lineRanges = [];
788 { 870 {
789 var token = unit.beginToken; 871 List<Token> tokens = TokenUtils.getTokens(source);
790 while (token != null && token.type != TokenType.EOF) { 872 for (Token token in tokens) {
791 if (token.type == TokenType.STRING) { 873 if (token.type == TokenType.STRING) {
792 lineRanges.add(rangeToken(token)); 874 lineRanges.add(rangeToken(token));
793 } 875 }
794 token = token.next; 876 token = token.next;
795 } 877 }
796 } 878 }
797 // re-indent lines 879 // re-indent lines
798 StringBuffer sb = new StringBuffer(); 880 StringBuffer sb = new StringBuffer();
799 String eol = endOfLine; 881 String eol = endOfLine;
800 List<String> lines = source.split(eol); 882 List<String> lines = source.split(eol);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 bool selectionIncludesNonWhitespaceOutsideNode(SourceRange selection, 927 bool selectionIncludesNonWhitespaceOutsideNode(SourceRange selection,
846 AstNode node) { 928 AstNode node) {
847 return _selectionIncludesNonWhitespaceOutsideRange( 929 return _selectionIncludesNonWhitespaceOutsideRange(
848 selection, 930 selection,
849 rangeNode(node)); 931 rangeNode(node));
850 } 932 }
851 933
852 /** 934 /**
853 * @return <code>true</code> if given range of [BinaryExpression] can be extra cted. 935 * @return <code>true</code> if given range of [BinaryExpression] can be extra cted.
854 */ 936 */
855 bool validateBinaryExpressionRange(BinaryExpression binaryExpression, SourceRa nge range) { 937 bool validateBinaryExpressionRange(BinaryExpression binaryExpression,
938 SourceRange range) {
856 // only parts of associative expression are safe to extract 939 // only parts of associative expression are safe to extract
857 if (!binaryExpression.operator.type.isAssociativeOperator) { 940 if (!binaryExpression.operator.type.isAssociativeOperator) {
858 return false; 941 return false;
859 } 942 }
860 // prepare selected operands 943 // prepare selected operands
861 List<Expression> operands = _getOperandsInOrderFor(binaryExpression); 944 List<Expression> operands = _getOperandsInOrderFor(binaryExpression);
862 List<Expression> subOperands = _getOperandsForSourceRange(operands, range); 945 List<Expression> subOperands = _getOperandsForSourceRange(operands, range);
863 // if empty, then something wrong with selection 946 // if empty, then something wrong with selection
864 if (subOperands.isEmpty) { 947 if (subOperands.isEmpty) {
865 return false; 948 return false;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
970 } 1053 }
971 return _invertCondition0(innerExpresion); 1054 return _invertCondition0(innerExpresion);
972 } 1055 }
973 DartType type = expression.bestType; 1056 DartType type = expression.bestType;
974 if (type.displayName == "bool") { 1057 if (type.displayName == "bool") {
975 return _InvertedCondition._simple("!${getNodeText(expression)}"); 1058 return _InvertedCondition._simple("!${getNodeText(expression)}");
976 } 1059 }
977 return _InvertedCondition._simple(getNodeText(expression)); 1060 return _InvertedCondition._simple(getNodeText(expression));
978 } 1061 }
979 1062
980 bool _selectionIncludesNonWhitespaceOutsideOperands(SourceRange selection, Lis t<Expression> operands) { 1063 bool _selectionIncludesNonWhitespaceOutsideOperands(SourceRange selection,
981 return _selectionIncludesNonWhitespaceOutsideRange(selection, rangeNodes(ope rands)); 1064 List<Expression> operands) {
1065 return _selectionIncludesNonWhitespaceOutsideRange(
1066 selection,
1067 rangeNodes(operands));
982 } 1068 }
983 1069
984 /** 1070 /**
985 * @return <code>true</code> if "selection" covers "range" and there are any n on-whitespace tokens 1071 * @return <code>true</code> if "selection" covers "range" and there are any n on-whitespace tokens
986 * between "selection" and "range" start/end. 1072 * between "selection" and "range" start/end.
987 */ 1073 */
988 bool _selectionIncludesNonWhitespaceOutsideRange(SourceRange selection, 1074 bool _selectionIncludesNonWhitespaceOutsideRange(SourceRange selection,
989 SourceRange range) { 1075 SourceRange range) {
990 // selection should cover range 1076 // selection should cover range
991 if (!selection.covers(range)) { 1077 if (!selection.covers(range)) {
992 return false; 1078 return false;
993 } 1079 }
994 // non-whitespace between selection start and range start 1080 // non-whitespace between selection start and range start
995 if (!isJustWhitespaceOrComment(rangeStartStart(selection, range))) { 1081 if (!isJustWhitespaceOrComment(rangeStartStart(selection, range))) {
996 return true; 1082 return true;
997 } 1083 }
998 // non-whitespace after range 1084 // non-whitespace after range
999 if (!isJustWhitespaceOrComment(rangeEndEnd(range, selection))) { 1085 if (!isJustWhitespaceOrComment(rangeEndEnd(range, selection))) {
1000 return true; 1086 return true;
1001 } 1087 }
1002 // only whitespace in selection around range 1088 // only whitespace in selection around range
1003 return false; 1089 return false;
1004 } 1090 }
1005 1091
1006 /** 1092 /**
1007 * @return [Expression]s from <code>operands</code> which are completely cover ed by given 1093 * @return [Expression]s from <code>operands</code> which are completely cover ed by given
1008 * [SourceRange]. Range should start and end between given [Expression ]s. 1094 * [SourceRange]. Range should start and end between given [Expression ]s.
1009 */ 1095 */
1010 static List<Expression> _getOperandsForSourceRange(List<Expression> operands, SourceRange range) { 1096 static List<Expression> _getOperandsForSourceRange(List<Expression> operands,
1097 SourceRange range) {
1011 assert(!operands.isEmpty); 1098 assert(!operands.isEmpty);
1012 List<Expression> subOperands = []; 1099 List<Expression> subOperands = [];
1013 // track range enter/exit 1100 // track range enter/exit
1014 bool entered = false; 1101 bool entered = false;
1015 bool exited = false; 1102 bool exited = false;
1016 // may be range starts before or on first operand 1103 // may be range starts before or on first operand
1017 if (range.offset <= operands[0].offset) { 1104 if (range.offset <= operands[0].offset) {
1018 entered = true; 1105 entered = true;
1019 } 1106 }
1020 // iterate over gaps between operands 1107 // iterate over gaps between operands
1021 for (int i = 0; i < operands.length - 1; i++) { 1108 for (int i = 0; i < operands.length - 1; i++) {
1022 Expression operand = operands[i]; 1109 Expression operand = operands[i];
1023 Expression nextOperand = operands[i + 1]; 1110 Expression nextOperand = operands[i + 1];
1024 SourceRange inclusiveGap = rangeEndStart(operand, nextOperand).getMoveEnd( 1); 1111 SourceRange inclusiveGap =
1112 rangeEndStart(operand, nextOperand).getMoveEnd(1);
1025 // add operand, if already entered range 1113 // add operand, if already entered range
1026 if (entered) { 1114 if (entered) {
1027 subOperands.add(operand); 1115 subOperands.add(operand);
1028 // may be last operand in range 1116 // may be last operand in range
1029 if (range.endsIn(inclusiveGap)) { 1117 if (range.endsIn(inclusiveGap)) {
1030 exited = true; 1118 exited = true;
1031 } 1119 }
1032 } else { 1120 } else {
1033 // may be first operand in range 1121 // may be first operand in range
1034 if (range.startsIn(inclusiveGap)) { 1122 if (range.startsIn(inclusiveGap)) {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
1185 1273
1186 @override 1274 @override
1187 Object visitExpression(Expression node) { 1275 Object visitExpression(Expression node) {
1188 if (node is BinaryExpression && node.operator.type == groupOperatorType) { 1276 if (node is BinaryExpression && node.operator.type == groupOperatorType) {
1189 return super.visitNode(node); 1277 return super.visitNode(node);
1190 } 1278 }
1191 operands.add(node); 1279 operands.add(node);
1192 return null; 1280 return null;
1193 } 1281 }
1194 } 1282 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698