Chromium Code Reviews| 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.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/protocol.dart' show SourceEdit; | 9 import 'package:analysis_server/src/protocol.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 Loading... | |
| 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 * If the given [AstNode] is in a [ClassDeclaration], returns the | |
| 98 * [ClassElement]. Otherwise returns `null`. | |
| 99 */ | |
| 100 ClassElement getEnclosingClassElement(AstNode node) { | |
| 101 ClassDeclaration enclosingClassNode = | |
| 102 node.getAncestor((node) => node is ClassDeclaration); | |
| 103 if (enclosingClassNode != null) { | |
| 104 return enclosingClassNode.element; | |
| 105 } | |
| 106 return null; | |
| 107 } | |
| 108 | |
| 109 | |
| 110 | |
| 111 /** | |
| 97 * Returns a class or an unit member enclosing the given [node]. | 112 * Returns a class or an unit member enclosing the given [node]. |
| 98 */ | 113 */ |
| 99 AstNode getEnclosingClassOrUnitMember(AstNode node) { | 114 AstNode getEnclosingClassOrUnitMember(AstNode node) { |
| 100 AstNode member = node; | 115 AstNode member = node; |
| 101 while (node != null) { | 116 while (node != null) { |
| 102 if (node is ClassDeclaration) { | 117 if (node is ClassDeclaration) { |
| 103 return member; | 118 return member; |
| 104 } | 119 } |
| 105 if (node is CompilationUnit) { | 120 if (node is CompilationUnit) { |
| 106 return member; | 121 return member; |
| 107 } | 122 } |
| 108 member = node; | 123 member = node; |
| 109 node = node.parent; | 124 node = node.parent; |
| 110 } | 125 } |
| 111 return null; | 126 return null; |
| 112 } | 127 } |
| 113 | 128 |
| 114 | |
| 115 | |
| 116 /** | 129 /** |
| 117 * @return the [ExecutableElement] of the enclosing executable [AstNode]. | 130 * @return the [ExecutableElement] of the enclosing executable [AstNode]. |
| 118 */ | 131 */ |
| 119 ExecutableElement getEnclosingExecutableElement(AstNode node) { | 132 ExecutableElement getEnclosingExecutableElement(AstNode node) { |
| 120 while (node != null) { | 133 while (node != null) { |
| 121 if (node is FunctionDeclaration) { | 134 if (node is FunctionDeclaration) { |
| 122 return node.element; | 135 return node.element; |
| 123 } | 136 } |
| 124 if (node is ConstructorDeclaration) { | 137 if (node is ConstructorDeclaration) { |
| 125 return node.element; | 138 return node.element; |
| 126 } | 139 } |
| 127 if (node is MethodDeclaration) { | 140 if (node is MethodDeclaration) { |
| 128 return node.element; | 141 return node.element; |
| 129 } | 142 } |
| 130 node = node.parent; | 143 node = node.parent; |
| 131 } | 144 } |
| 132 return null; | 145 return null; |
| 133 } | 146 } |
| 134 | 147 |
| 148 | |
| 135 /** | 149 /** |
| 136 * @return the enclosing executable [AstNode]. | 150 * @return the enclosing executable [AstNode]. |
| 137 */ | 151 */ |
| 138 AstNode getEnclosingExecutableNode(AstNode node) { | 152 AstNode getEnclosingExecutableNode(AstNode node) { |
| 139 while (node != null) { | 153 while (node != null) { |
| 140 if (node is FunctionDeclaration) { | 154 if (node is FunctionDeclaration) { |
| 141 return node; | 155 return node; |
| 142 } | 156 } |
| 143 if (node is ConstructorDeclaration) { | 157 if (node is ConstructorDeclaration) { |
| 144 return node; | 158 return node; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 171 * Returns the precedence of [node] it is an [Expression], negative otherwise. | 185 * Returns the precedence of [node] it is an [Expression], negative otherwise. |
| 172 */ | 186 */ |
| 173 int getExpressionPrecedence(AstNode node) { | 187 int getExpressionPrecedence(AstNode node) { |
| 174 if (node is Expression) { | 188 if (node is Expression) { |
| 175 return node.precedence; | 189 return node.precedence; |
| 176 } | 190 } |
| 177 return -1000; | 191 return -1000; |
| 178 } | 192 } |
| 179 | 193 |
| 180 | 194 |
| 195 | |
| 181 /** | 196 /** |
| 182 * Returns the namespace of the given [ImportElement]. | 197 * Returns the namespace of the given [ImportElement]. |
| 183 */ | 198 */ |
| 184 Map<String, Element> getImportNamespace(ImportElement imp) { | 199 Map<String, Element> getImportNamespace(ImportElement imp) { |
| 185 NamespaceBuilder builder = new NamespaceBuilder(); | 200 NamespaceBuilder builder = new NamespaceBuilder(); |
| 186 Namespace namespace = builder.createImportNamespaceForDirective(imp); | 201 Namespace namespace = builder.createImportNamespaceForDirective(imp); |
| 187 return namespace.definedNames; | 202 return namespace.definedNames; |
| 188 } | 203 } |
| 189 | 204 |
| 190 | 205 |
| 206 /** | |
| 207 * Returns the line prefix from the given source, i.e. basically just a | |
| 208 * whitespace prefix of the given [String]. | |
| 209 */ | |
| 210 String getLinesPrefix(String lines) { | |
|
Brian Wilkerson
2014/08/31 15:59:56
Should "lines" be "line"?
scheglov
2014/08/31 16:43:23
Acknowledged.
| |
| 211 int index = 0; | |
| 212 while (index < lines.length) { | |
| 213 int c = lines.codeUnitAt(index); | |
| 214 if (!isWhitespace(c)) { | |
| 215 break; | |
| 216 } | |
| 217 index++; | |
| 218 } | |
| 219 return lines.substring(0, index); | |
| 220 } | |
| 221 | |
| 191 | 222 |
| 192 /** | 223 /** |
| 193 * @return the [LocalVariableElement] or [ParameterElement] if given | 224 * @return the [LocalVariableElement] or [ParameterElement] if given |
| 194 * [SimpleIdentifier] is the reference to local variable or parameter, o r | 225 * [SimpleIdentifier] is the reference to local variable or parameter, o r |
| 195 * <code>null</code> in the other case. | 226 * <code>null</code> in the other case. |
| 196 */ | 227 */ |
| 197 VariableElement getLocalOrParameterVariableElement(SimpleIdentifier node) { | 228 VariableElement getLocalOrParameterVariableElement(SimpleIdentifier node) { |
| 198 Element element = node.staticElement; | 229 Element element = node.staticElement; |
| 199 if (element is LocalVariableElement) { | 230 if (element is LocalVariableElement) { |
| 200 return element; | 231 return element; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 211 * local variable, or <code>null</code> in the other case. | 242 * local variable, or <code>null</code> in the other case. |
| 212 */ | 243 */ |
| 213 LocalVariableElement getLocalVariableElement(SimpleIdentifier node) { | 244 LocalVariableElement getLocalVariableElement(SimpleIdentifier node) { |
| 214 Element element = node.staticElement; | 245 Element element = node.staticElement; |
| 215 if (element is LocalVariableElement) { | 246 if (element is LocalVariableElement) { |
| 216 return element; | 247 return element; |
| 217 } | 248 } |
| 218 return null; | 249 return null; |
| 219 } | 250 } |
| 220 | 251 |
| 221 | |
| 222 /** | 252 /** |
| 223 * @return the nearest common ancestor [AstNode] of the given [AstNode]s. | 253 * @return the nearest common ancestor [AstNode] of the given [AstNode]s. |
| 224 */ | 254 */ |
| 225 AstNode getNearestCommonAncestor(List<AstNode> nodes) { | 255 AstNode getNearestCommonAncestor(List<AstNode> nodes) { |
| 226 // may be no nodes | 256 // may be no nodes |
| 227 if (nodes.isEmpty) { | 257 if (nodes.isEmpty) { |
| 228 return null; | 258 return null; |
| 229 } | 259 } |
| 230 // prepare parents | 260 // prepare parents |
| 231 List<List<AstNode>> parents = []; | 261 List<List<AstNode>> parents = []; |
| 232 for (AstNode node in nodes) { | 262 for (AstNode node in nodes) { |
| 233 parents.add(getParents(node)); | 263 parents.add(getParents(node)); |
| 234 } | 264 } |
| 235 // find min length | 265 // find min length |
| 236 int minLength = 1 << 20; | 266 int minLength = 1 << 20; |
| 237 for (List<AstNode> parentList in parents) { | 267 for (List<AstNode> parentList in parents) { |
| 238 minLength = min(minLength, parentList.length); | 268 minLength = min(minLength, parentList.length); |
| 239 } | 269 } |
| 240 // find deepest parent | 270 // find deepest parent |
| 241 int i = 0; | 271 int i = 0; |
| 242 for ( ; i < minLength; i++) { | 272 for ( ; i < minLength; i++) { |
| 243 if (!allListsIdentical(parents, i)) { | 273 if (!allListsIdentical(parents, i)) { |
| 244 break; | 274 break; |
| 245 } | 275 } |
| 246 } | 276 } |
| 247 return parents[0][i - 1]; | 277 return parents[0][i - 1]; |
| 248 } | 278 } |
| 249 | 279 |
| 280 /** | |
| 281 * Returns the [Expression] qualifier if given node is the name part of a | |
| 282 * [PropertyAccess] or a [PrefixedIdentifier]. Maybe `null`. | |
| 283 */ | |
| 284 Expression getNodeQualifier(SimpleIdentifier node) { | |
| 285 AstNode parent = node.parent; | |
| 286 if (parent is PropertyAccess) { | |
| 287 PropertyAccess propertyAccess = parent; | |
| 288 if (identical(propertyAccess.propertyName, node)) { | |
| 289 return propertyAccess.target; | |
| 290 } | |
| 291 } | |
| 292 if (parent is PrefixedIdentifier) { | |
| 293 PrefixedIdentifier prefixed = parent; | |
| 294 if (identical(prefixed.identifier, node)) { | |
| 295 return prefixed.prefix; | |
| 296 } | |
| 297 } | |
| 298 return null; | |
| 299 } | |
| 300 | |
| 301 | |
| 302 /** | |
| 303 * Returns the [ParameterElement] if the given [SimpleIdentifier] is a reference | |
| 304 * to a parameter, or `null` in the other case. | |
| 305 */ | |
| 306 ParameterElement getParameterElement(SimpleIdentifier node) { | |
| 307 Element element = node.staticElement; | |
| 308 if (element is ParameterElement) { | |
| 309 return element; | |
| 310 } | |
| 311 return null; | |
| 312 } | |
| 313 | |
| 250 | 314 |
| 251 /** | 315 /** |
| 252 * @return parent [AstNode]s from [CompilationUnit] (at index "0") to the given one. | 316 * @return parent [AstNode]s from [CompilationUnit] (at index "0") to the given one. |
| 253 */ | 317 */ |
| 254 List<AstNode> getParents(AstNode node) { | 318 List<AstNode> getParents(AstNode node) { |
| 255 // prepare number of parents | 319 // prepare number of parents |
| 256 int numParents = 0; | 320 int numParents = 0; |
| 257 { | 321 { |
| 258 AstNode current = node.parent; | 322 AstNode current = node.parent; |
| 259 while (current != null) { | 323 while (current != null) { |
| 260 numParents++; | 324 numParents++; |
| 261 current = current.parent; | 325 current = current.parent; |
| 262 } | 326 } |
| 263 } | 327 } |
| 264 // fill array of parents | 328 // fill array of parents |
| 265 List<AstNode> parents = new List<AstNode>(numParents); | 329 List<AstNode> parents = new List<AstNode>(numParents); |
| 266 AstNode current = node.parent; | 330 AstNode current = node.parent; |
| 267 int index = numParents; | 331 int index = numParents; |
| 268 while (current != null) { | 332 while (current != null) { |
| 269 parents[--index] = current; | 333 parents[--index] = current; |
| 270 current = current.parent; | 334 current = current.parent; |
| 271 } | 335 } |
| 272 return parents; | 336 return parents; |
| 273 } | 337 } |
| 274 | 338 |
| 339 | |
| 340 /** | |
| 341 * Returns a [PropertyAccessorElement] if the given [SimpleIdentifier] is a | |
| 342 * reference to a property, or `null` in the other case. | |
| 343 */ | |
| 344 PropertyAccessorElement getPropertyAccessorElement(SimpleIdentifier node) { | |
| 345 Element element = node.staticElement; | |
| 346 if (element is PropertyAccessorElement) { | |
| 347 return element; | |
| 348 } | |
| 349 return null; | |
| 350 } | |
| 351 | |
| 352 | |
| 275 /** | 353 /** |
| 276 * If given [AstNode] is name of qualified property extraction, returns target f rom which | 354 * If given [AstNode] is name of qualified property extraction, returns target f rom which |
| 277 * this property is extracted. Otherwise `null`. | 355 * this property is extracted. Otherwise `null`. |
| 278 */ | 356 */ |
| 279 Expression getQualifiedPropertyTarget(AstNode node) { | 357 Expression getQualifiedPropertyTarget(AstNode node) { |
| 280 AstNode parent = node.parent; | 358 AstNode parent = node.parent; |
| 281 if (parent is PrefixedIdentifier) { | 359 if (parent is PrefixedIdentifier) { |
| 282 PrefixedIdentifier prefixed = parent; | 360 PrefixedIdentifier prefixed = parent; |
| 283 if (prefixed.identifier == node) { | 361 if (prefixed.identifier == node) { |
| 284 return parent.prefix; | 362 return parent.prefix; |
| 285 } | 363 } |
| 286 } | 364 } |
| 287 if (parent is PropertyAccess) { | 365 if (parent is PropertyAccess) { |
| 288 PropertyAccess access = parent; | 366 PropertyAccess access = parent; |
| 289 if (access.propertyName == node) { | 367 if (access.propertyName == node) { |
| 290 return access.realTarget; | 368 return access.realTarget; |
| 291 } | 369 } |
| 292 } | 370 } |
| 293 return null; | 371 return null; |
| 294 } | 372 } |
| 295 | 373 |
| 374 | |
| 296 /** | 375 /** |
| 297 * Returns the given [Statement] if not a [Block], or the first child | 376 * Returns the given [Statement] if not a [Block], or the first child |
| 298 * [Statement] if a [Block], or `null` if more than one child. | 377 * [Statement] if a [Block], or `null` if more than one child. |
| 299 */ | 378 */ |
| 300 Statement getSingleStatement(Statement statement) { | 379 Statement getSingleStatement(Statement statement) { |
| 301 if (statement is Block) { | 380 if (statement is Block) { |
| 302 List<Statement> blockStatements = statement.statements; | 381 List<Statement> blockStatements = statement.statements; |
| 303 if (blockStatements.length != 1) { | 382 if (blockStatements.length != 1) { |
| 304 return null; | 383 return null; |
| 305 } | 384 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 332 /** | 411 /** |
| 333 * Checks if the given [Element]'s display name equals to the given name. | 412 * Checks if the given [Element]'s display name equals to the given name. |
| 334 */ | 413 */ |
| 335 bool hasDisplayName(Element element, String name) { | 414 bool hasDisplayName(Element element, String name) { |
| 336 if (element == null) { | 415 if (element == null) { |
| 337 return false; | 416 return false; |
| 338 } | 417 } |
| 339 return element.displayName == name; | 418 return element.displayName == name; |
| 340 } | 419 } |
| 341 | 420 |
| 421 /** | |
| 422 * Returns `true` if the given [PropertyAccessorElement] is an accessor of | |
| 423 * some [FieldElement]. | |
| 424 */ | |
| 425 bool isFieldAccessorElement(PropertyAccessorElement accessor) { | |
| 426 return accessor != null && | |
| 427 accessor.variable is FieldElement && | |
| 428 accessor.variable.enclosingElement is ClassElement; | |
|
Brian Wilkerson
2014/08/31 15:59:56
Do we have field elements whose parent is not a cl
scheglov
2014/08/31 16:43:23
Yes, we do.
Although we are not interested in it f
| |
| 429 } | |
| 430 | |
| 342 | 431 |
| 343 /** | 432 /** |
| 344 * @return <code>true</code> if given [DartNode] is left hand side of assignment , or | 433 * @return <code>true</code> if given [DartNode] is left hand side of assignment , or |
| 345 * declaration of the variable. | 434 * declaration of the variable. |
| 346 */ | 435 */ |
| 347 bool isLeftHandOfAssignment(SimpleIdentifier node) { | 436 bool isLeftHandOfAssignment(SimpleIdentifier node) { |
| 348 if (node.inSetterContext()) { | 437 if (node.inSetterContext()) { |
| 349 return true; | 438 return true; |
| 350 } | 439 } |
| 351 return node.parent is VariableDeclaration && | 440 return node.parent is VariableDeclaration && |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 406 */ | 495 */ |
| 407 SourceEdit createIndentEdit(SourceRange range, String oldIndent, | 496 SourceEdit createIndentEdit(SourceRange range, String oldIndent, |
| 408 String newIndent) { | 497 String newIndent) { |
| 409 String newSource = replaceSourceRangeIndent(range, oldIndent, newIndent); | 498 String newSource = replaceSourceRangeIndent(range, oldIndent, newIndent); |
| 410 return new SourceEdit(range.offset, range.length, newSource); | 499 return new SourceEdit(range.offset, range.length, newSource); |
| 411 } | 500 } |
| 412 | 501 |
| 413 /** | 502 /** |
| 414 * Returns the [AstNode] that encloses the given offset. | 503 * Returns the [AstNode] that encloses the given offset. |
| 415 */ | 504 */ |
| 416 AstNode findNode(int offset) => new NodeLocator.con1(offset).searchWithin(unit ); | 505 AstNode findNode(int offset) => |
| 506 new NodeLocator.con1(offset).searchWithin(unit); | |
| 417 | 507 |
| 418 /** | 508 /** |
| 419 * Returns the actual type source of the given [Expression], may be `null` | 509 * Returns the actual type source of the given [Expression], may be `null` |
| 420 * if can not be resolved, should be treated as the `dynamic` type. | 510 * if can not be resolved, should be treated as the `dynamic` type. |
| 421 */ | 511 */ |
| 422 String getExpressionTypeSource(Expression expression) { | 512 String getExpressionTypeSource(Expression expression) { |
| 423 if (expression == null) { | 513 if (expression == null) { |
| 424 return null; | 514 return null; |
| 425 } | 515 } |
| 426 DartType type = expression.bestType; | 516 DartType type = expression.bestType; |
| (...skipping 792 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1219 } | 1309 } |
| 1220 | 1310 |
| 1221 /** | 1311 /** |
| 1222 * @return <code>true</code> if given [Token]s contain only single [Token] wit h given | 1312 * @return <code>true</code> if given [Token]s contain only single [Token] wit h given |
| 1223 * [TokenType]. | 1313 * [TokenType]. |
| 1224 */ | 1314 */ |
| 1225 static bool hasOnly(List<Token> tokens, TokenType type) => | 1315 static bool hasOnly(List<Token> tokens, TokenType type) => |
| 1226 tokens.length == 1 && tokens[0].type == type; | 1316 tokens.length == 1 && tokens[0].type == type; |
| 1227 } | 1317 } |
| 1228 | 1318 |
| 1319 | |
| 1229 /** | 1320 /** |
| 1230 * A container with a source and its precedence. | 1321 * A container with a source and its precedence. |
| 1231 */ | 1322 */ |
| 1232 class _InvertedCondition { | 1323 class _InvertedCondition { |
| 1233 final int _precedence; | 1324 final int _precedence; |
| 1234 | 1325 |
| 1235 final String _source; | 1326 final String _source; |
| 1236 | 1327 |
| 1237 _InvertedCondition(this._precedence, this._source); | 1328 _InvertedCondition(this._precedence, this._source); |
| 1238 | 1329 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1278 | 1369 |
| 1279 @override | 1370 @override |
| 1280 Object visitExpression(Expression node) { | 1371 Object visitExpression(Expression node) { |
| 1281 if (node is BinaryExpression && node.operator.type == groupOperatorType) { | 1372 if (node is BinaryExpression && node.operator.type == groupOperatorType) { |
| 1282 return super.visitNode(node); | 1373 return super.visitNode(node); |
| 1283 } | 1374 } |
| 1284 operands.add(node); | 1375 operands.add(node); |
| 1285 return null; | 1376 return null; |
| 1286 } | 1377 } |
| 1287 } | 1378 } |
| OLD | NEW |