| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 library analyzer.src.generated.declaration_resolver; |
| 6 |
| 7 import 'dart:collection'; |
| 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart'; |
| 11 import 'package:analyzer/dart/ast/visitor.dart'; |
| 12 import 'package:analyzer/dart/element/element.dart'; |
| 13 import 'package:analyzer/dart/element/visitor.dart'; |
| 14 import 'package:analyzer/exception/exception.dart'; |
| 15 import 'package:analyzer/src/dart/element/element.dart'; |
| 16 |
| 17 /** |
| 18 * A visitor that resolves declarations in an AST structure to already built |
| 19 * elements. |
| 20 * |
| 21 * The resulting AST must have everything resolved that would have been resolved |
| 22 * by a [CompilationUnitBuilder] (that is, must be a valid [RESOLVED_UNIT1]). |
| 23 * This class must not assume that the [CompilationUnitElement] passed to it is |
| 24 * any more complete than a [COMPILATION_UNIT_ELEMENT]. |
| 25 */ |
| 26 class DeclarationResolver extends RecursiveAstVisitor<Object> |
| 27 with _ExistingElementResolver { |
| 28 /** |
| 29 * The elements that are reachable from the compilation unit element. When a |
| 30 * compilation unit has been resolved, this set should be empty. |
| 31 */ |
| 32 Set<Element> _expectedElements; |
| 33 |
| 34 /** |
| 35 * The function type alias containing the AST nodes being visited, or `null` |
| 36 * if we are not in the scope of a function type alias. |
| 37 */ |
| 38 FunctionTypeAliasElement _enclosingAlias; |
| 39 |
| 40 /** |
| 41 * The class containing the AST nodes being visited, or `null` if we are not |
| 42 * in the scope of a class. |
| 43 */ |
| 44 ClassElement _enclosingClass; |
| 45 |
| 46 /** |
| 47 * The method or function containing the AST nodes being visited, or `null` if |
| 48 * we are not in the scope of a method or function. |
| 49 */ |
| 50 ExecutableElement _enclosingExecutable; |
| 51 |
| 52 /** |
| 53 * The parameter containing the AST nodes being visited, or `null` if we are |
| 54 * not in the scope of a parameter. |
| 55 */ |
| 56 ParameterElement _enclosingParameter; |
| 57 |
| 58 /** |
| 59 * Resolve the declarations within the given compilation [unit] to the |
| 60 * elements rooted at the given [element]. Throw an [ElementMismatchException] |
| 61 * if the element model and compilation unit do not match each other. |
| 62 */ |
| 63 void resolve(CompilationUnit unit, CompilationUnitElement element) { |
| 64 _ElementGatherer gatherer = new _ElementGatherer(); |
| 65 element.accept(gatherer); |
| 66 _expectedElements = gatherer.elements; |
| 67 _enclosingUnit = element; |
| 68 _expectedElements.remove(element); |
| 69 unit.element = element; |
| 70 unit.accept(this); |
| 71 _validateResolution(); |
| 72 } |
| 73 |
| 74 @override |
| 75 Object visitCatchClause(CatchClause node) { |
| 76 SimpleIdentifier exceptionParameter = node.exceptionParameter; |
| 77 if (exceptionParameter != null) { |
| 78 List<LocalVariableElement> localVariables = |
| 79 _enclosingExecutable.localVariables; |
| 80 _findIdentifier(localVariables, exceptionParameter); |
| 81 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; |
| 82 if (stackTraceParameter != null) { |
| 83 _findIdentifier(localVariables, stackTraceParameter); |
| 84 } |
| 85 } |
| 86 return super.visitCatchClause(node); |
| 87 } |
| 88 |
| 89 @override |
| 90 Object visitClassDeclaration(ClassDeclaration node) { |
| 91 ClassElement outerClass = _enclosingClass; |
| 92 try { |
| 93 SimpleIdentifier className = node.name; |
| 94 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); |
| 95 super.visitClassDeclaration(node); |
| 96 _resolveMetadata(node, node.metadata, _enclosingClass); |
| 97 return null; |
| 98 } finally { |
| 99 _enclosingClass = outerClass; |
| 100 } |
| 101 } |
| 102 |
| 103 @override |
| 104 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 105 ClassElement outerClass = _enclosingClass; |
| 106 try { |
| 107 SimpleIdentifier className = node.name; |
| 108 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); |
| 109 super.visitClassTypeAlias(node); |
| 110 _resolveMetadata(node, node.metadata, _enclosingClass); |
| 111 return null; |
| 112 } finally { |
| 113 _enclosingClass = outerClass; |
| 114 } |
| 115 } |
| 116 |
| 117 @override |
| 118 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 119 ExecutableElement outerExecutable = _enclosingExecutable; |
| 120 try { |
| 121 SimpleIdentifier constructorName = node.name; |
| 122 if (constructorName == null) { |
| 123 _enclosingExecutable = _enclosingClass.unnamedConstructor; |
| 124 if (_enclosingExecutable == null) { |
| 125 _mismatch('Could not find default constructor', node); |
| 126 } |
| 127 } else { |
| 128 _enclosingExecutable = |
| 129 _enclosingClass.getNamedConstructor(constructorName.name); |
| 130 if (_enclosingExecutable == null) { |
| 131 _mismatch( |
| 132 'Could not find constructor element with name "${constructorName.n
ame}', |
| 133 node); |
| 134 } |
| 135 constructorName.staticElement = _enclosingExecutable; |
| 136 } |
| 137 _expectedElements.remove(_enclosingExecutable); |
| 138 node.element = _enclosingExecutable as ConstructorElement; |
| 139 super.visitConstructorDeclaration(node); |
| 140 _resolveMetadata(node, node.metadata, _enclosingExecutable); |
| 141 return null; |
| 142 } finally { |
| 143 _enclosingExecutable = outerExecutable; |
| 144 } |
| 145 } |
| 146 |
| 147 @override |
| 148 Object visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 149 SimpleIdentifier variableName = node.identifier; |
| 150 Element element = |
| 151 _findIdentifier(_enclosingExecutable.localVariables, variableName); |
| 152 super.visitDeclaredIdentifier(node); |
| 153 _resolveMetadata(node, node.metadata, element); |
| 154 return null; |
| 155 } |
| 156 |
| 157 @override |
| 158 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 159 SimpleIdentifier parameterName = node.parameter.identifier; |
| 160 ParameterElement element = _getElementForParameter(node, parameterName); |
| 161 Expression defaultValue = node.defaultValue; |
| 162 if (defaultValue != null) { |
| 163 ExecutableElement outerExecutable = _enclosingExecutable; |
| 164 try { |
| 165 _enclosingExecutable = element.initializer; |
| 166 defaultValue.accept(this); |
| 167 } finally { |
| 168 _enclosingExecutable = outerExecutable; |
| 169 } |
| 170 } |
| 171 ParameterElement outerParameter = _enclosingParameter; |
| 172 try { |
| 173 _enclosingParameter = element; |
| 174 super.visitDefaultFormalParameter(node); |
| 175 _resolveMetadata(node, node.metadata, element); |
| 176 return null; |
| 177 } finally { |
| 178 _enclosingParameter = outerParameter; |
| 179 } |
| 180 } |
| 181 |
| 182 @override |
| 183 Object visitEnumDeclaration(EnumDeclaration node) { |
| 184 ClassElement enclosingEnum = |
| 185 _findIdentifier(_enclosingUnit.enums, node.name); |
| 186 List<FieldElement> constants = enclosingEnum.fields; |
| 187 for (EnumConstantDeclaration constant in node.constants) { |
| 188 _findIdentifier(constants, constant.name); |
| 189 } |
| 190 super.visitEnumDeclaration(node); |
| 191 _resolveMetadata(node, node.metadata, enclosingEnum); |
| 192 return null; |
| 193 } |
| 194 |
| 195 @override |
| 196 Object visitExportDirective(ExportDirective node) { |
| 197 super.visitExportDirective(node); |
| 198 _resolveAnnotations( |
| 199 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 200 return null; |
| 201 } |
| 202 |
| 203 @override |
| 204 Object visitFieldDeclaration(FieldDeclaration node) { |
| 205 super.visitFieldDeclaration(node); |
| 206 _resolveMetadata(node, node.metadata, node.fields.variables[0].element); |
| 207 return null; |
| 208 } |
| 209 |
| 210 @override |
| 211 Object visitFieldFormalParameter(FieldFormalParameter node) { |
| 212 if (node.parent is! DefaultFormalParameter) { |
| 213 SimpleIdentifier parameterName = node.identifier; |
| 214 ParameterElement element = _getElementForParameter(node, parameterName); |
| 215 ParameterElement outerParameter = _enclosingParameter; |
| 216 try { |
| 217 _enclosingParameter = element; |
| 218 super.visitFieldFormalParameter(node); |
| 219 _resolveMetadata(node, node.metadata, element); |
| 220 return null; |
| 221 } finally { |
| 222 _enclosingParameter = outerParameter; |
| 223 } |
| 224 } else { |
| 225 return super.visitFieldFormalParameter(node); |
| 226 } |
| 227 } |
| 228 |
| 229 @override |
| 230 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 231 ExecutableElement outerExecutable = _enclosingExecutable; |
| 232 try { |
| 233 SimpleIdentifier functionName = node.name; |
| 234 Token property = node.propertyKeyword; |
| 235 if (property == null) { |
| 236 if (_enclosingExecutable != null) { |
| 237 _enclosingExecutable = |
| 238 _findIdentifier(_enclosingExecutable.functions, functionName); |
| 239 } else { |
| 240 _enclosingExecutable = |
| 241 _findIdentifier(_enclosingUnit.functions, functionName); |
| 242 } |
| 243 } else { |
| 244 if (_enclosingExecutable != null) { |
| 245 _enclosingExecutable = |
| 246 _findIdentifier(_enclosingExecutable.functions, functionName); |
| 247 } else { |
| 248 List<PropertyAccessorElement> accessors; |
| 249 if (_enclosingClass != null) { |
| 250 accessors = _enclosingClass.accessors; |
| 251 } else { |
| 252 accessors = _enclosingUnit.accessors; |
| 253 } |
| 254 PropertyAccessorElement accessor; |
| 255 if (property.keyword == Keyword.GET) { |
| 256 accessor = _findIdentifier(accessors, functionName); |
| 257 } else if (property.keyword == Keyword.SET) { |
| 258 accessor = _findWithNameAndOffset(accessors, functionName, |
| 259 functionName.name + '=', functionName.offset); |
| 260 _expectedElements.remove(accessor); |
| 261 functionName.staticElement = accessor; |
| 262 } |
| 263 _enclosingExecutable = accessor; |
| 264 } |
| 265 } |
| 266 node.functionExpression.element = _enclosingExecutable; |
| 267 super.visitFunctionDeclaration(node); |
| 268 _resolveMetadata(node, node.metadata, _enclosingExecutable); |
| 269 return null; |
| 270 } finally { |
| 271 _enclosingExecutable = outerExecutable; |
| 272 } |
| 273 } |
| 274 |
| 275 @override |
| 276 Object visitFunctionExpression(FunctionExpression node) { |
| 277 if (node.parent is! FunctionDeclaration) { |
| 278 FunctionElement element = _findAtOffset( |
| 279 _enclosingExecutable.functions, node, node.beginToken.offset); |
| 280 _expectedElements.remove(element); |
| 281 node.element = element; |
| 282 } |
| 283 ExecutableElement outerExecutable = _enclosingExecutable; |
| 284 try { |
| 285 _enclosingExecutable = node.element; |
| 286 return super.visitFunctionExpression(node); |
| 287 } finally { |
| 288 _enclosingExecutable = outerExecutable; |
| 289 } |
| 290 } |
| 291 |
| 292 @override |
| 293 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 294 FunctionTypeAliasElement outerAlias = _enclosingAlias; |
| 295 try { |
| 296 SimpleIdentifier aliasName = node.name; |
| 297 _enclosingAlias = |
| 298 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName); |
| 299 super.visitFunctionTypeAlias(node); |
| 300 _resolveMetadata(node, node.metadata, _enclosingAlias); |
| 301 return null; |
| 302 } finally { |
| 303 _enclosingAlias = outerAlias; |
| 304 } |
| 305 } |
| 306 |
| 307 @override |
| 308 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 309 if (node.parent is! DefaultFormalParameter) { |
| 310 SimpleIdentifier parameterName = node.identifier; |
| 311 ParameterElement element = _getElementForParameter(node, parameterName); |
| 312 ParameterElement outerParameter = _enclosingParameter; |
| 313 try { |
| 314 _enclosingParameter = element; |
| 315 super.visitFunctionTypedFormalParameter(node); |
| 316 _resolveMetadata(node, node.metadata, _enclosingParameter); |
| 317 return null; |
| 318 } finally { |
| 319 _enclosingParameter = outerParameter; |
| 320 } |
| 321 } else { |
| 322 return super.visitFunctionTypedFormalParameter(node); |
| 323 } |
| 324 } |
| 325 |
| 326 @override |
| 327 Object visitImportDirective(ImportDirective node) { |
| 328 super.visitImportDirective(node); |
| 329 _resolveAnnotations( |
| 330 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 331 return null; |
| 332 } |
| 333 |
| 334 @override |
| 335 Object visitLabeledStatement(LabeledStatement node) { |
| 336 for (Label label in node.labels) { |
| 337 SimpleIdentifier labelName = label.label; |
| 338 _findIdentifier(_enclosingExecutable.labels, labelName); |
| 339 } |
| 340 return super.visitLabeledStatement(node); |
| 341 } |
| 342 |
| 343 @override |
| 344 Object visitLibraryDirective(LibraryDirective node) { |
| 345 super.visitLibraryDirective(node); |
| 346 _resolveAnnotations( |
| 347 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 348 return null; |
| 349 } |
| 350 |
| 351 @override |
| 352 Object visitMethodDeclaration(MethodDeclaration node) { |
| 353 ExecutableElement outerExecutable = _enclosingExecutable; |
| 354 try { |
| 355 Token property = node.propertyKeyword; |
| 356 SimpleIdentifier methodName = node.name; |
| 357 String nameOfMethod = methodName.name; |
| 358 if (property == null) { |
| 359 String elementName = nameOfMethod == '-' && |
| 360 node.parameters != null && |
| 361 node.parameters.parameters.isEmpty |
| 362 ? 'unary-' |
| 363 : nameOfMethod; |
| 364 _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods, |
| 365 methodName, elementName, methodName.offset); |
| 366 _expectedElements.remove(_enclosingExecutable); |
| 367 methodName.staticElement = _enclosingExecutable; |
| 368 } else { |
| 369 PropertyAccessorElement accessor; |
| 370 if (property.keyword == Keyword.GET) { |
| 371 accessor = _findIdentifier(_enclosingClass.accessors, methodName); |
| 372 } else if (property.keyword == Keyword.SET) { |
| 373 accessor = _findWithNameAndOffset(_enclosingClass.accessors, |
| 374 methodName, nameOfMethod + '=', methodName.offset); |
| 375 _expectedElements.remove(accessor); |
| 376 methodName.staticElement = accessor; |
| 377 } |
| 378 _enclosingExecutable = accessor; |
| 379 } |
| 380 super.visitMethodDeclaration(node); |
| 381 _resolveMetadata(node, node.metadata, _enclosingExecutable); |
| 382 return null; |
| 383 } finally { |
| 384 _enclosingExecutable = outerExecutable; |
| 385 } |
| 386 } |
| 387 |
| 388 @override |
| 389 Object visitPartDirective(PartDirective node) { |
| 390 super.visitPartDirective(node); |
| 391 _resolveAnnotations( |
| 392 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 393 return null; |
| 394 } |
| 395 |
| 396 @override |
| 397 Object visitPartOfDirective(PartOfDirective node) { |
| 398 node.element = _enclosingUnit.library; |
| 399 return super.visitPartOfDirective(node); |
| 400 } |
| 401 |
| 402 @override |
| 403 Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 404 if (node.parent is! DefaultFormalParameter) { |
| 405 SimpleIdentifier parameterName = node.identifier; |
| 406 ParameterElement element = _getElementForParameter(node, parameterName); |
| 407 ParameterElement outerParameter = _enclosingParameter; |
| 408 try { |
| 409 _enclosingParameter = element; |
| 410 super.visitSimpleFormalParameter(node); |
| 411 _resolveMetadata(node, node.metadata, element); |
| 412 return null; |
| 413 } finally { |
| 414 _enclosingParameter = outerParameter; |
| 415 } |
| 416 } else {} |
| 417 return super.visitSimpleFormalParameter(node); |
| 418 } |
| 419 |
| 420 @override |
| 421 Object visitSwitchCase(SwitchCase node) { |
| 422 for (Label label in node.labels) { |
| 423 SimpleIdentifier labelName = label.label; |
| 424 _findIdentifier(_enclosingExecutable.labels, labelName); |
| 425 } |
| 426 return super.visitSwitchCase(node); |
| 427 } |
| 428 |
| 429 @override |
| 430 Object visitSwitchDefault(SwitchDefault node) { |
| 431 for (Label label in node.labels) { |
| 432 SimpleIdentifier labelName = label.label; |
| 433 _findIdentifier(_enclosingExecutable.labels, labelName); |
| 434 } |
| 435 return super.visitSwitchDefault(node); |
| 436 } |
| 437 |
| 438 @override |
| 439 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 440 super.visitTopLevelVariableDeclaration(node); |
| 441 _resolveMetadata(node, node.metadata, node.variables.variables[0].element); |
| 442 return null; |
| 443 } |
| 444 |
| 445 @override |
| 446 Object visitTypeParameter(TypeParameter node) { |
| 447 SimpleIdentifier parameterName = node.name; |
| 448 Element element = null; |
| 449 if (_enclosingExecutable != null) { |
| 450 element = _findIdentifier( |
| 451 _enclosingExecutable.typeParameters, parameterName, |
| 452 required: false); |
| 453 } |
| 454 if (element == null) { |
| 455 if (_enclosingClass != null) { |
| 456 element = |
| 457 _findIdentifier(_enclosingClass.typeParameters, parameterName); |
| 458 } else if (_enclosingAlias != null) { |
| 459 element = |
| 460 _findIdentifier(_enclosingAlias.typeParameters, parameterName); |
| 461 } |
| 462 } |
| 463 if (element == null) { |
| 464 String name = parameterName.name; |
| 465 int offset = parameterName.offset; |
| 466 _mismatch( |
| 467 'Could not find type parameter with name "$name" at $offset', node); |
| 468 } |
| 469 super.visitTypeParameter(node); |
| 470 _resolveMetadata(node, node.metadata, element); |
| 471 return null; |
| 472 } |
| 473 |
| 474 @override |
| 475 Object visitVariableDeclaration(VariableDeclaration node) { |
| 476 VariableElement element = null; |
| 477 SimpleIdentifier variableName = node.name; |
| 478 if (_enclosingExecutable != null) { |
| 479 element = _findIdentifier( |
| 480 _enclosingExecutable.localVariables, variableName, |
| 481 required: false); |
| 482 } |
| 483 if (element == null && _enclosingClass != null) { |
| 484 element = _findIdentifier(_enclosingClass.fields, variableName, |
| 485 required: false); |
| 486 } |
| 487 if (element == null && _enclosingUnit != null) { |
| 488 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName); |
| 489 } |
| 490 Expression initializer = node.initializer; |
| 491 if (initializer != null) { |
| 492 ExecutableElement outerExecutable = _enclosingExecutable; |
| 493 try { |
| 494 _enclosingExecutable = element.initializer; |
| 495 return super.visitVariableDeclaration(node); |
| 496 } finally { |
| 497 _enclosingExecutable = outerExecutable; |
| 498 } |
| 499 } |
| 500 return super.visitVariableDeclaration(node); |
| 501 } |
| 502 |
| 503 @override |
| 504 Object visitVariableDeclarationList(VariableDeclarationList node) { |
| 505 super.visitVariableDeclarationList(node); |
| 506 if (node.parent is! FieldDeclaration && |
| 507 node.parent is! TopLevelVariableDeclaration) { |
| 508 _resolveMetadata(node, node.metadata, node.variables[0].element); |
| 509 } |
| 510 return null; |
| 511 } |
| 512 |
| 513 /** |
| 514 * Return the element in the given list of [elements] that was created for the |
| 515 * declaration at the given [offset]. Throw an [ElementMismatchException] if |
| 516 * an element at that offset cannot be found. |
| 517 * |
| 518 * This method should only be used when there is no name associated with the |
| 519 * node. |
| 520 */ |
| 521 Element _findAtOffset(List<Element> elements, AstNode node, int offset) => |
| 522 _findWithNameAndOffset(elements, node, '', offset); |
| 523 |
| 524 /** |
| 525 * Return the element in the given list of [elements] that was created for the |
| 526 * declaration with the given [identifier]. As a side-effect, associate the |
| 527 * returned element with the identifier. Throw an [ElementMismatchException] |
| 528 * if an element corresponding to the identifier cannot be found unless |
| 529 * [required] is `false`, in which case return `null`. |
| 530 */ |
| 531 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier, |
| 532 {bool required: true}) { |
| 533 Element element = _findWithNameAndOffset( |
| 534 elements, identifier, identifier.name, identifier.offset, |
| 535 required: required); |
| 536 _expectedElements.remove(element); |
| 537 identifier.staticElement = element; |
| 538 return element; |
| 539 } |
| 540 |
| 541 /** |
| 542 * Return the element in the given list of [elements] that was created for the |
| 543 * declaration with the given [name] at the given [offset]. Throw an |
| 544 * [ElementMismatchException] if an element corresponding to the identifier |
| 545 * cannot be found unless [required] is `false`, in which case return `null`. |
| 546 */ |
| 547 Element _findWithNameAndOffset( |
| 548 List<Element> elements, AstNode node, String name, int offset, |
| 549 {bool required: true}) { |
| 550 int length = elements.length; |
| 551 for (int i = 0; i < length; i++) { |
| 552 Element element = elements[i]; |
| 553 if (element.nameOffset == offset && element.name == name) { |
| 554 return element; |
| 555 } |
| 556 } |
| 557 if (!required) { |
| 558 return null; |
| 559 } |
| 560 for (int i = 0; i < length; i++) { |
| 561 Element element = elements[i]; |
| 562 if (element.name == name) { |
| 563 _mismatch( |
| 564 'Found element with name "$name" at ${element.nameOffset}, ' |
| 565 'but expected offset of $offset', |
| 566 node); |
| 567 } |
| 568 if (element.nameOffset == offset) { |
| 569 _mismatch( |
| 570 'Found element with name "${element.name}" at $offset, ' |
| 571 'but expected element with name "$name"', |
| 572 node); |
| 573 } |
| 574 } |
| 575 _mismatch('Could not find element with name "$name" at $offset', node); |
| 576 return null; // Never reached |
| 577 } |
| 578 |
| 579 /** |
| 580 * Search the most closely enclosing list of parameter elements for a |
| 581 * parameter, defined by the given [node], with the given [parameterName]. |
| 582 * Return the element that was found, or throw an [ElementMismatchException] |
| 583 * if an element corresponding to the identifier cannot be found. |
| 584 */ |
| 585 ParameterElement _getElementForParameter( |
| 586 FormalParameter node, SimpleIdentifier parameterName) { |
| 587 List<ParameterElement> parameters = null; |
| 588 if (_enclosingParameter != null) { |
| 589 parameters = _enclosingParameter.parameters; |
| 590 } |
| 591 if (parameters == null && _enclosingExecutable != null) { |
| 592 parameters = _enclosingExecutable.parameters; |
| 593 } |
| 594 if (parameters == null && _enclosingAlias != null) { |
| 595 parameters = _enclosingAlias.parameters; |
| 596 } |
| 597 if (parameters == null) { |
| 598 StringBuffer buffer = new StringBuffer(); |
| 599 buffer.writeln('Could not find parameter in enclosing scope'); |
| 600 buffer.writeln( |
| 601 '(_enclosingParameter == null) == ${_enclosingParameter == null}'); |
| 602 buffer.writeln( |
| 603 '(_enclosingExecutable == null) == ${_enclosingExecutable == null}'); |
| 604 buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}'); |
| 605 _mismatch(buffer.toString(), parameterName); |
| 606 } |
| 607 return _findIdentifier(parameters, parameterName); |
| 608 } |
| 609 |
| 610 /** |
| 611 * Associate each of the annotation [nodes] with the corresponding |
| 612 * [ElementAnnotation] in [annotations]. If there is a problem, report it |
| 613 * against the given [parent] node. |
| 614 */ |
| 615 void _resolveAnnotations(AstNode parent, NodeList<Annotation> nodes, |
| 616 List<ElementAnnotation> annotations) { |
| 617 int nodeCount = nodes.length; |
| 618 if (nodeCount != annotations.length) { |
| 619 _mismatch( |
| 620 'Found $nodeCount annotation nodes and ' |
| 621 '${annotations.length} element annotations', |
| 622 parent); |
| 623 } |
| 624 for (int i = 0; i < nodeCount; i++) { |
| 625 nodes[i].elementAnnotation = annotations[i]; |
| 626 } |
| 627 } |
| 628 |
| 629 /** |
| 630 * If [element] is not `null`, associate each of the annotation [nodes] with |
| 631 * the corresponding [ElementAnnotation] in [element.metadata]. If there is a |
| 632 * problem, report it against the given [parent] node. |
| 633 * |
| 634 * If [element] is `null`, do nothing--this allows us to be robust in the |
| 635 * case where we are operating on an element model that hasn't been fully |
| 636 * built. |
| 637 */ |
| 638 void _resolveMetadata( |
| 639 AstNode parent, NodeList<Annotation> nodes, Element element) { |
| 640 if (element != null) { |
| 641 _resolveAnnotations(parent, nodes, element.metadata); |
| 642 } |
| 643 } |
| 644 |
| 645 /** |
| 646 * Throw an exception if there are non-synthetic elements in the element model |
| 647 * that were not associated with an AST node. |
| 648 */ |
| 649 void _validateResolution() { |
| 650 if (_expectedElements.isNotEmpty) { |
| 651 StringBuffer buffer = new StringBuffer(); |
| 652 buffer.write(_expectedElements.length); |
| 653 buffer.writeln(' unmatched elements found:'); |
| 654 for (Element element in _expectedElements) { |
| 655 buffer.write(' '); |
| 656 buffer.writeln(element); |
| 657 } |
| 658 throw new _ElementMismatchException(buffer.toString()); |
| 659 } |
| 660 } |
| 661 } |
| 662 |
| 663 /** |
| 664 * A visitor that can be used to collect all of the non-synthetic elements in an |
| 665 * element model. |
| 666 */ |
| 667 class _ElementGatherer extends GeneralizingElementVisitor { |
| 668 /** |
| 669 * The set in which the elements are collected. |
| 670 */ |
| 671 final Set<Element> elements = new HashSet<Element>(); |
| 672 |
| 673 /** |
| 674 * Initialize the visitor. |
| 675 */ |
| 676 _ElementGatherer(); |
| 677 |
| 678 @override |
| 679 void visitElement(Element element) { |
| 680 if (!element.isSynthetic) { |
| 681 elements.add(element); |
| 682 } |
| 683 super.visitElement(element); |
| 684 } |
| 685 } |
| 686 |
| 687 class _ElementMismatchException extends AnalysisException { |
| 688 /** |
| 689 * Initialize a newly created exception to have the given [message] and |
| 690 * [cause]. |
| 691 */ |
| 692 _ElementMismatchException(String message, [CaughtException cause = null]) |
| 693 : super(message, cause); |
| 694 } |
| 695 |
| 696 /** |
| 697 * A mixin for classes that use an existing element model to resolve a portion |
| 698 * of an AST structure. |
| 699 */ |
| 700 class _ExistingElementResolver { |
| 701 /** |
| 702 * The compilation unit containing the AST nodes being visited. |
| 703 */ |
| 704 CompilationUnitElementImpl _enclosingUnit; |
| 705 |
| 706 /** |
| 707 * Throw an [ElementMismatchException] to report that the element model and th
e |
| 708 * AST do not match. The [message] will have the path to the given [node] |
| 709 * appended to it. |
| 710 */ |
| 711 void _mismatch(String message, AstNode node) { |
| 712 StringBuffer buffer = new StringBuffer(); |
| 713 buffer.write('Mismatch in '); |
| 714 buffer.write(runtimeType); |
| 715 buffer.write(' while resolving '); |
| 716 buffer.writeln(_enclosingUnit?.source?.fullName); |
| 717 buffer.writeln(message); |
| 718 buffer.write('Path to root:'); |
| 719 String separator = ' '; |
| 720 AstNode parent = node; |
| 721 while (parent != null) { |
| 722 buffer.write(separator); |
| 723 buffer.write(parent.runtimeType.toString()); |
| 724 separator = ', '; |
| 725 parent = parent.parent; |
| 726 } |
| 727 throw new _ElementMismatchException(buffer.toString()); |
| 728 } |
| 729 } |
| OLD | NEW |