| 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 SourceChange, |
| 10 SourceEdit; |
| 10 import 'package:analysis_server/src/services/correction/source_range.dart'; | 11 import 'package:analysis_server/src/services/correction/source_range.dart'; |
| 11 import 'package:analysis_server/src/services/correction/strings.dart'; | 12 import 'package:analysis_server/src/services/correction/strings.dart'; |
| 12 import 'package:analyzer/src/generated/ast.dart'; | 13 import 'package:analyzer/src/generated/ast.dart'; |
| 13 import 'package:analyzer/src/generated/element.dart'; | 14 import 'package:analyzer/src/generated/element.dart'; |
| 14 import 'package:analyzer/src/generated/engine.dart'; | 15 import 'package:analyzer/src/generated/engine.dart'; |
| 15 import 'package:analyzer/src/generated/resolver.dart'; | 16 import 'package:analyzer/src/generated/resolver.dart'; |
| 16 import 'package:analyzer/src/generated/scanner.dart'; | 17 import 'package:analyzer/src/generated/scanner.dart'; |
| 17 import 'package:analyzer/src/generated/source.dart'; | 18 import 'package:analyzer/src/generated/source.dart'; |
| 18 | 19 |
| 19 | 20 |
| 21 void addElementSourceChange(SourceChange change, Element element, |
| 22 SourceEdit edit) { |
| 23 AnalysisContext context = element.context; |
| 24 Source source = element.source; |
| 25 addSourceChange(change, context, source, edit); |
| 26 } |
| 27 |
| 28 |
| 29 void addSourceChange(SourceChange change, AnalysisContext context, |
| 30 Source source, SourceEdit edit) { |
| 31 String file = source.fullName; |
| 32 int fileStamp = context.getModificationStamp(source); |
| 33 change.addEdit(file, fileStamp, edit); |
| 34 } |
| 35 |
| 36 |
| 20 /** | 37 /** |
| 21 * @return <code>true</code> if given [List]s are identical at given position. | 38 * @return <code>true</code> if given [List]s are identical at given position. |
| 22 */ | 39 */ |
| 23 bool allListsIdentical(List<List> lists, int position) { | 40 bool allListsIdentical(List<List> lists, int position) { |
| 24 Object element = lists[0][position]; | 41 Object element = lists[0][position]; |
| 25 for (List list in lists) { | 42 for (List list in lists) { |
| 26 if (list[position] != element) { | 43 if (list[position] != element) { |
| 27 return false; | 44 return false; |
| 28 } | 45 } |
| 29 } | 46 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 | 90 |
| 74 | 91 |
| 75 /** | 92 /** |
| 76 * Return the name of the [Element] kind. | 93 * Return the name of the [Element] kind. |
| 77 */ | 94 */ |
| 78 String getElementKindName(Element element) { | 95 String getElementKindName(Element element) { |
| 79 return element.kind.displayName; | 96 return element.kind.displayName; |
| 80 } | 97 } |
| 81 | 98 |
| 82 | 99 |
| 100 |
| 83 /** | 101 /** |
| 84 * Returns the name to display in the UI for the given [Element]. | 102 * Returns the name to display in the UI for the given [Element]. |
| 85 */ | 103 */ |
| 86 String getElementQualifiedName(Element element) { | 104 String getElementQualifiedName(Element element) { |
| 87 ElementKind kind = element.kind; | 105 ElementKind kind = element.kind; |
| 88 if (kind == ElementKind.FIELD || kind == ElementKind.METHOD) { | 106 if (kind == ElementKind.FIELD || kind == ElementKind.METHOD) { |
| 89 return '${element.enclosingElement.displayName}.${element.displayName}'; | 107 return '${element.enclosingElement.displayName}.${element.displayName}'; |
| 90 } else { | 108 } else { |
| 91 return element.displayName; | 109 return element.displayName; |
| 92 } | 110 } |
| 93 } | 111 } |
| 94 | 112 |
| 95 | |
| 96 /** | 113 /** |
| 97 * If the given [AstNode] is in a [ClassDeclaration], returns the | 114 * If the given [AstNode] is in a [ClassDeclaration], returns the |
| 98 * [ClassElement]. Otherwise returns `null`. | 115 * [ClassElement]. Otherwise returns `null`. |
| 99 */ | 116 */ |
| 100 ClassElement getEnclosingClassElement(AstNode node) { | 117 ClassElement getEnclosingClassElement(AstNode node) { |
| 101 ClassDeclaration enclosingClassNode = | 118 ClassDeclaration enclosingClassNode = |
| 102 node.getAncestor((node) => node is ClassDeclaration); | 119 node.getAncestor((node) => node is ClassDeclaration); |
| 103 if (enclosingClassNode != null) { | 120 if (enclosingClassNode != null) { |
| 104 return enclosingClassNode.element; | 121 return enclosingClassNode.element; |
| 105 } | 122 } |
| 106 return null; | 123 return null; |
| 107 } | 124 } |
| 108 | 125 |
| 109 | 126 |
| 110 | |
| 111 /** | 127 /** |
| 112 * Returns a class or an unit member enclosing the given [node]. | 128 * Returns a class or an unit member enclosing the given [node]. |
| 113 */ | 129 */ |
| 114 AstNode getEnclosingClassOrUnitMember(AstNode node) { | 130 AstNode getEnclosingClassOrUnitMember(AstNode node) { |
| 115 AstNode member = node; | 131 AstNode member = node; |
| 116 while (node != null) { | 132 while (node != null) { |
| 117 if (node is ClassDeclaration) { | 133 if (node is ClassDeclaration) { |
| 118 return member; | 134 return member; |
| 119 } | 135 } |
| 120 if (node is CompilationUnit) { | 136 if (node is CompilationUnit) { |
| 121 return member; | 137 return member; |
| 122 } | 138 } |
| 123 member = node; | 139 member = node; |
| 124 node = node.parent; | 140 node = node.parent; |
| 125 } | 141 } |
| 126 return null; | 142 return null; |
| 127 } | 143 } |
| 128 | 144 |
| 145 |
| 129 /** | 146 /** |
| 130 * @return the [ExecutableElement] of the enclosing executable [AstNode]. | 147 * @return the [ExecutableElement] of the enclosing executable [AstNode]. |
| 131 */ | 148 */ |
| 132 ExecutableElement getEnclosingExecutableElement(AstNode node) { | 149 ExecutableElement getEnclosingExecutableElement(AstNode node) { |
| 133 while (node != null) { | 150 while (node != null) { |
| 134 if (node is FunctionDeclaration) { | 151 if (node is FunctionDeclaration) { |
| 135 return node.element; | 152 return node.element; |
| 136 } | 153 } |
| 137 if (node is ConstructorDeclaration) { | 154 if (node is ConstructorDeclaration) { |
| 138 return node.element; | 155 return node.element; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 159 } | 176 } |
| 160 if (node is MethodDeclaration) { | 177 if (node is MethodDeclaration) { |
| 161 return node; | 178 return node; |
| 162 } | 179 } |
| 163 node = node.parent; | 180 node = node.parent; |
| 164 } | 181 } |
| 165 return null; | 182 return null; |
| 166 } | 183 } |
| 167 | 184 |
| 168 | 185 |
| 186 |
| 169 /** | 187 /** |
| 170 * Returns [getExpressionPrecedence] for the parent of [node], | 188 * Returns [getExpressionPrecedence] for the parent of [node], |
| 171 * or `0` if the parent node is [ParenthesizedExpression]. | 189 * or `0` if the parent node is [ParenthesizedExpression]. |
| 172 * | 190 * |
| 173 * The reason is that `(expr)` is always executed after `expr`. | 191 * The reason is that `(expr)` is always executed after `expr`. |
| 174 */ | 192 */ |
| 175 int getExpressionParentPrecedence(AstNode node) { | 193 int getExpressionParentPrecedence(AstNode node) { |
| 176 AstNode parent = node.parent; | 194 AstNode parent = node.parent; |
| 177 if (parent is ParenthesizedExpression) { | 195 if (parent is ParenthesizedExpression) { |
| 178 return 0; | 196 return 0; |
| 179 } | 197 } |
| 180 return getExpressionPrecedence(parent); | 198 return getExpressionPrecedence(parent); |
| 181 } | 199 } |
| 182 | 200 |
| 183 | 201 |
| 184 /** | 202 /** |
| 185 * Returns the precedence of [node] it is an [Expression], negative otherwise. | 203 * Returns the precedence of [node] it is an [Expression], negative otherwise. |
| 186 */ | 204 */ |
| 187 int getExpressionPrecedence(AstNode node) { | 205 int getExpressionPrecedence(AstNode node) { |
| 188 if (node is Expression) { | 206 if (node is Expression) { |
| 189 return node.precedence; | 207 return node.precedence; |
| 190 } | 208 } |
| 191 return -1000; | 209 return -1000; |
| 192 } | 210 } |
| 193 | 211 |
| 194 | 212 |
| 195 | |
| 196 /** | 213 /** |
| 197 * Returns the namespace of the given [ImportElement]. | 214 * Returns the namespace of the given [ImportElement]. |
| 198 */ | 215 */ |
| 199 Map<String, Element> getImportNamespace(ImportElement imp) { | 216 Map<String, Element> getImportNamespace(ImportElement imp) { |
| 200 NamespaceBuilder builder = new NamespaceBuilder(); | 217 NamespaceBuilder builder = new NamespaceBuilder(); |
| 201 Namespace namespace = builder.createImportNamespaceForDirective(imp); | 218 Namespace namespace = builder.createImportNamespaceForDirective(imp); |
| 202 return namespace.definedNames; | 219 return namespace.definedNames; |
| 203 } | 220 } |
| 204 | 221 |
| 205 | 222 |
| 206 /** | 223 /** |
| 207 * Returns the line prefix from the given source, i.e. basically just a | 224 * Returns the line prefix from the given source, i.e. basically just a |
| 208 * whitespace prefix of the given [String]. | 225 * whitespace prefix of the given [String]. |
| 209 */ | 226 */ |
| 210 String getLinePrefix(String line) { | 227 String getLinePrefix(String line) { |
| 211 int index = 0; | 228 int index = 0; |
| 212 while (index < line.length) { | 229 while (index < line.length) { |
| 213 int c = line.codeUnitAt(index); | 230 int c = line.codeUnitAt(index); |
| 214 if (!isWhitespace(c)) { | 231 if (!isWhitespace(c)) { |
| 215 break; | 232 break; |
| 216 } | 233 } |
| 217 index++; | 234 index++; |
| 218 } | 235 } |
| 219 return line.substring(0, index); | 236 return line.substring(0, index); |
| 220 } | 237 } |
| 221 | 238 |
| 222 | |
| 223 /** | 239 /** |
| 224 * @return the [LocalVariableElement] or [ParameterElement] if given | 240 * @return the [LocalVariableElement] or [ParameterElement] if given |
| 225 * [SimpleIdentifier] is the reference to local variable or parameter, o
r | 241 * [SimpleIdentifier] is the reference to local variable or parameter, o
r |
| 226 * <code>null</code> in the other case. | 242 * <code>null</code> in the other case. |
| 227 */ | 243 */ |
| 228 VariableElement getLocalOrParameterVariableElement(SimpleIdentifier node) { | 244 VariableElement getLocalOrParameterVariableElement(SimpleIdentifier node) { |
| 229 Element element = node.staticElement; | 245 Element element = node.staticElement; |
| 230 if (element is LocalVariableElement) { | 246 if (element is LocalVariableElement) { |
| 231 return element; | 247 return element; |
| 232 } | 248 } |
| 233 if (element is ParameterElement) { | 249 if (element is ParameterElement) { |
| 234 return element; | 250 return element; |
| 235 } | 251 } |
| 236 return null; | 252 return null; |
| 237 } | 253 } |
| 238 | 254 |
| 239 | |
| 240 /** | 255 /** |
| 241 * @return the [LocalVariableElement] if given [SimpleIdentifier] is the referen
ce to | 256 * @return the [LocalVariableElement] if given [SimpleIdentifier] is the referen
ce to |
| 242 * local variable, or <code>null</code> in the other case. | 257 * local variable, or <code>null</code> in the other case. |
| 243 */ | 258 */ |
| 244 LocalVariableElement getLocalVariableElement(SimpleIdentifier node) { | 259 LocalVariableElement getLocalVariableElement(SimpleIdentifier node) { |
| 245 Element element = node.staticElement; | 260 Element element = node.staticElement; |
| 246 if (element is LocalVariableElement) { | 261 if (element is LocalVariableElement) { |
| 247 return element; | 262 return element; |
| 248 } | 263 } |
| 249 return null; | 264 return null; |
| 250 } | 265 } |
| 251 | 266 |
| 267 |
| 252 /** | 268 /** |
| 253 * @return the nearest common ancestor [AstNode] of the given [AstNode]s. | 269 * @return the nearest common ancestor [AstNode] of the given [AstNode]s. |
| 254 */ | 270 */ |
| 255 AstNode getNearestCommonAncestor(List<AstNode> nodes) { | 271 AstNode getNearestCommonAncestor(List<AstNode> nodes) { |
| 256 // may be no nodes | 272 // may be no nodes |
| 257 if (nodes.isEmpty) { | 273 if (nodes.isEmpty) { |
| 258 return null; | 274 return null; |
| 259 } | 275 } |
| 260 // prepare parents | 276 // prepare parents |
| 261 List<List<AstNode>> parents = []; | 277 List<List<AstNode>> parents = []; |
| 262 for (AstNode node in nodes) { | 278 for (AstNode node in nodes) { |
| 263 parents.add(getParents(node)); | 279 parents.add(getParents(node)); |
| 264 } | 280 } |
| 265 // find min length | 281 // find min length |
| 266 int minLength = 1 << 20; | 282 int minLength = 1 << 20; |
| 267 for (List<AstNode> parentList in parents) { | 283 for (List<AstNode> parentList in parents) { |
| 268 minLength = min(minLength, parentList.length); | 284 minLength = min(minLength, parentList.length); |
| 269 } | 285 } |
| 270 // find deepest parent | 286 // find deepest parent |
| 271 int i = 0; | 287 int i = 0; |
| 272 for ( ; i < minLength; i++) { | 288 for ( ; i < minLength; i++) { |
| 273 if (!allListsIdentical(parents, i)) { | 289 if (!allListsIdentical(parents, i)) { |
| 274 break; | 290 break; |
| 275 } | 291 } |
| 276 } | 292 } |
| 277 return parents[0][i - 1]; | 293 return parents[0][i - 1]; |
| 278 } | 294 } |
| 279 | 295 |
| 296 |
| 280 /** | 297 /** |
| 281 * Returns the [Expression] qualifier if given node is the name part of a | 298 * Returns the [Expression] qualifier if given node is the name part of a |
| 282 * [PropertyAccess] or a [PrefixedIdentifier]. Maybe `null`. | 299 * [PropertyAccess] or a [PrefixedIdentifier]. Maybe `null`. |
| 283 */ | 300 */ |
| 284 Expression getNodeQualifier(SimpleIdentifier node) { | 301 Expression getNodeQualifier(SimpleIdentifier node) { |
| 285 AstNode parent = node.parent; | 302 AstNode parent = node.parent; |
| 286 if (parent is PropertyAccess) { | 303 if (parent is PropertyAccess) { |
| 287 PropertyAccess propertyAccess = parent; | 304 PropertyAccess propertyAccess = parent; |
| 288 if (identical(propertyAccess.propertyName, node)) { | 305 if (identical(propertyAccess.propertyName, node)) { |
| 289 return propertyAccess.target; | 306 return propertyAccess.target; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 } | 405 } |
| 389 | 406 |
| 390 | 407 |
| 391 /** | 408 /** |
| 392 * Returns the [String] content of the given [Source]. | 409 * Returns the [String] content of the given [Source]. |
| 393 */ | 410 */ |
| 394 String getSourceContent(AnalysisContext context, Source source) { | 411 String getSourceContent(AnalysisContext context, Source source) { |
| 395 return context.getContents(source).data; | 412 return context.getContents(source).data; |
| 396 } | 413 } |
| 397 | 414 |
| 398 | |
| 399 /** | 415 /** |
| 400 * Returns the given [Statement] if not a [Block], or all the children | 416 * Returns the given [Statement] if not a [Block], or all the children |
| 401 * [Statement]s if a [Block]. | 417 * [Statement]s if a [Block]. |
| 402 */ | 418 */ |
| 403 List<Statement> getStatements(Statement statement) { | 419 List<Statement> getStatements(Statement statement) { |
| 404 if (statement is Block) { | 420 if (statement is Block) { |
| 405 return statement.statements; | 421 return statement.statements; |
| 406 } | 422 } |
| 407 return [statement]; | 423 return [statement]; |
| 408 } | 424 } |
| 409 | 425 |
| 410 | 426 |
| 411 /** | 427 /** |
| 412 * Checks if the given [Element]'s display name equals to the given name. | 428 * Checks if the given [Element]'s display name equals to the given name. |
| 413 */ | 429 */ |
| 414 bool hasDisplayName(Element element, String name) { | 430 bool hasDisplayName(Element element, String name) { |
| 415 if (element == null) { | 431 if (element == null) { |
| 416 return false; | 432 return false; |
| 417 } | 433 } |
| 418 return element.displayName == name; | 434 return element.displayName == name; |
| 419 } | 435 } |
| 420 | 436 |
| 437 |
| 421 /** | 438 /** |
| 422 * Checks if the given [PropertyAccessorElement] is an accessor of a | 439 * Checks if the given [PropertyAccessorElement] is an accessor of a |
| 423 * [FieldElement]. | 440 * [FieldElement]. |
| 424 */ | 441 */ |
| 425 bool isFieldAccessorElement(PropertyAccessorElement accessor) { | 442 bool isFieldAccessorElement(PropertyAccessorElement accessor) { |
| 426 return accessor != null && accessor.variable is FieldElement; | 443 return accessor != null && accessor.variable is FieldElement; |
| 427 } | 444 } |
| 428 | 445 |
| 429 | 446 |
| 430 /** | 447 /** |
| (...skipping 951 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1382 | 1399 |
| 1383 @override | 1400 @override |
| 1384 Object visitExpression(Expression node) { | 1401 Object visitExpression(Expression node) { |
| 1385 if (node is BinaryExpression && node.operator.type == groupOperatorType) { | 1402 if (node is BinaryExpression && node.operator.type == groupOperatorType) { |
| 1386 return super.visitNode(node); | 1403 return super.visitNode(node); |
| 1387 } | 1404 } |
| 1388 operands.add(node); | 1405 operands.add(node); |
| 1389 return null; | 1406 return null; |
| 1390 } | 1407 } |
| 1391 } | 1408 } |
| OLD | NEW |