| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library engine.resolver.element_resolver; | |
| 6 | |
| 7 import 'dart:collection'; | |
| 8 | |
| 9 import 'ast.dart'; | |
| 10 import 'element.dart'; | |
| 11 import 'engine.dart'; | |
| 12 import 'error.dart'; | |
| 13 import 'resolver.dart'; | |
| 14 import 'scanner.dart' as sc; | |
| 15 import 'utilities_dart.dart'; | |
| 16 | |
| 17 /** | |
| 18 * An object used by instances of [ResolverVisitor] to resolve references within | |
| 19 * the AST structure to the elements being referenced. The requirements for the | |
| 20 * element resolver are: | |
| 21 * | |
| 22 * 1. Every [SimpleIdentifier] should be resolved to the element to which it | |
| 23 * refers. Specifically: | |
| 24 * * An identifier within the declaration of that name should resolve to the | |
| 25 * element being declared. | |
| 26 * * An identifier denoting a prefix should resolve to the element | |
| 27 * representing the import that defines the prefix (an [ImportElement]). | |
| 28 * * An identifier denoting a variable should resolve to the element | |
| 29 * representing the variable (a [VariableElement]). | |
| 30 * * An identifier denoting a parameter should resolve to the element | |
| 31 * representing the parameter (a [ParameterElement]). | |
| 32 * * An identifier denoting a field should resolve to the element | |
| 33 * representing the getter or setter being invoked (a | |
| 34 * [PropertyAccessorElement]). | |
| 35 * * An identifier denoting the name of a method or function being invoked | |
| 36 * should resolve to the element representing the method or function (an | |
| 37 * [ExecutableElement]). | |
| 38 * * An identifier denoting a label should resolve to the element | |
| 39 * representing the label (a [LabelElement]). | |
| 40 * The identifiers within directives are exceptions to this rule and are | |
| 41 * covered below. | |
| 42 * 2. Every node containing a token representing an operator that can be | |
| 43 * overridden ( [BinaryExpression], [PrefixExpression], [PostfixExpression]) | |
| 44 * should resolve to the element representing the method invoked by that | |
| 45 * operator (a [MethodElement]). | |
| 46 * 3. Every [FunctionExpressionInvocation] should resolve to the element | |
| 47 * representing the function being invoked (a [FunctionElement]). This will | |
| 48 * be the same element as that to which the name is resolved if the function | |
| 49 * has a name, but is provided for those cases where an unnamed function is | |
| 50 * being invoked. | |
| 51 * 4. Every [LibraryDirective] and [PartOfDirective] should resolve to the | |
| 52 * element representing the library being specified by the directive (a | |
| 53 * [LibraryElement]) unless, in the case of a part-of directive, the | |
| 54 * specified library does not exist. | |
| 55 * 5. Every [ImportDirective] and [ExportDirective] should resolve to the | |
| 56 * element representing the library being specified by the directive unless | |
| 57 * the specified library does not exist (an [ImportElement] or | |
| 58 * [ExportElement]). | |
| 59 * 6. The identifier representing the prefix in an [ImportDirective] should | |
| 60 * resolve to the element representing the prefix (a [PrefixElement]). | |
| 61 * 7. The identifiers in the hide and show combinators in [ImportDirective]s | |
| 62 * and [ExportDirective]s should resolve to the elements that are being | |
| 63 * hidden or shown, respectively, unless those names are not defined in the | |
| 64 * specified library (or the specified library does not exist). | |
| 65 * 8. Every [PartDirective] should resolve to the element representing the | |
| 66 * compilation unit being specified by the string unless the specified | |
| 67 * compilation unit does not exist (a [CompilationUnitElement]). | |
| 68 * | |
| 69 * Note that AST nodes that would represent elements that are not defined are | |
| 70 * not resolved to anything. This includes such things as references to | |
| 71 * undeclared variables (which is an error) and names in hide and show | |
| 72 * combinators that are not defined in the imported library (which is not an | |
| 73 * error). | |
| 74 */ | |
| 75 class ElementResolver extends SimpleAstVisitor<Object> { | |
| 76 /** | |
| 77 * The resolver driving this participant. | |
| 78 */ | |
| 79 final ResolverVisitor _resolver; | |
| 80 | |
| 81 /** | |
| 82 * The element for the library containing the compilation unit being visited. | |
| 83 */ | |
| 84 LibraryElement _definingLibrary; | |
| 85 | |
| 86 /** | |
| 87 * A flag indicating whether we should generate hints. | |
| 88 */ | |
| 89 bool _enableHints = false; | |
| 90 | |
| 91 /** | |
| 92 * A flag indicating whether we should strictly follow the specification when | |
| 93 * generating warnings on "call" methods (fixes dartbug.com/21938). | |
| 94 */ | |
| 95 bool _enableStrictCallChecks = false; | |
| 96 | |
| 97 /** | |
| 98 * The type representing the type 'dynamic'. | |
| 99 */ | |
| 100 DartType _dynamicType; | |
| 101 | |
| 102 /** | |
| 103 * The type representing the type 'type'. | |
| 104 */ | |
| 105 DartType _typeType; | |
| 106 | |
| 107 /** | |
| 108 * A utility class for the resolver to answer the question of "what are my | |
| 109 * subtypes?". | |
| 110 */ | |
| 111 SubtypeManager _subtypeManager; | |
| 112 | |
| 113 /** | |
| 114 * The object keeping track of which elements have had their types promoted. | |
| 115 */ | |
| 116 TypePromotionManager _promoteManager; | |
| 117 | |
| 118 /** | |
| 119 * Initialize a newly created visitor to work for the given [_resolver] to | |
| 120 * resolve the nodes in a compilation unit. | |
| 121 */ | |
| 122 ElementResolver(this._resolver) { | |
| 123 this._definingLibrary = _resolver.definingLibrary; | |
| 124 AnalysisOptions options = _definingLibrary.context.analysisOptions; | |
| 125 _enableHints = options.hint; | |
| 126 _enableStrictCallChecks = options.enableStrictCallChecks; | |
| 127 _dynamicType = _resolver.typeProvider.dynamicType; | |
| 128 _typeType = _resolver.typeProvider.typeType; | |
| 129 _subtypeManager = new SubtypeManager(); | |
| 130 _promoteManager = _resolver.promoteManager; | |
| 131 } | |
| 132 | |
| 133 /** | |
| 134 * Return `true` iff the current enclosing function is a constant constructor | |
| 135 * declaration. | |
| 136 */ | |
| 137 bool get isInConstConstructor { | |
| 138 ExecutableElement function = _resolver.enclosingFunction; | |
| 139 if (function is ConstructorElement) { | |
| 140 return function.isConst; | |
| 141 } | |
| 142 return false; | |
| 143 } | |
| 144 | |
| 145 @override | |
| 146 Object visitAssignmentExpression(AssignmentExpression node) { | |
| 147 sc.Token operator = node.operator; | |
| 148 sc.TokenType operatorType = operator.type; | |
| 149 if (operatorType != sc.TokenType.EQ && | |
| 150 operatorType != sc.TokenType.QUESTION_QUESTION_EQ) { | |
| 151 operatorType = _operatorFromCompoundAssignment(operatorType); | |
| 152 Expression leftHandSide = node.leftHandSide; | |
| 153 if (leftHandSide != null) { | |
| 154 String methodName = operatorType.lexeme; | |
| 155 DartType staticType = _getStaticType(leftHandSide); | |
| 156 MethodElement staticMethod = | |
| 157 _lookUpMethod(leftHandSide, staticType, methodName); | |
| 158 node.staticElement = staticMethod; | |
| 159 DartType propagatedType = _getPropagatedType(leftHandSide); | |
| 160 MethodElement propagatedMethod = | |
| 161 _lookUpMethod(leftHandSide, propagatedType, methodName); | |
| 162 node.propagatedElement = propagatedMethod; | |
| 163 if (_shouldReportMissingMember(staticType, staticMethod)) { | |
| 164 _recordUndefinedToken(staticType.element, | |
| 165 StaticTypeWarningCode.UNDEFINED_METHOD, operator, [ | |
| 166 methodName, | |
| 167 staticType.displayName | |
| 168 ]); | |
| 169 } else if (_enableHints && | |
| 170 _shouldReportMissingMember(propagatedType, propagatedMethod) && | |
| 171 !_memberFoundInSubclass( | |
| 172 propagatedType.element, methodName, true, false)) { | |
| 173 _recordUndefinedToken(propagatedType.element, | |
| 174 HintCode.UNDEFINED_METHOD, operator, [ | |
| 175 methodName, | |
| 176 propagatedType.displayName | |
| 177 ]); | |
| 178 } | |
| 179 } | |
| 180 } | |
| 181 return null; | |
| 182 } | |
| 183 | |
| 184 @override | |
| 185 Object visitBinaryExpression(BinaryExpression node) { | |
| 186 sc.Token operator = node.operator; | |
| 187 if (operator.isUserDefinableOperator) { | |
| 188 _resolveBinaryExpression(node, operator.lexeme); | |
| 189 } else if (operator.type == sc.TokenType.BANG_EQ) { | |
| 190 _resolveBinaryExpression(node, sc.TokenType.EQ_EQ.lexeme); | |
| 191 } | |
| 192 return null; | |
| 193 } | |
| 194 | |
| 195 @override | |
| 196 Object visitBreakStatement(BreakStatement node) { | |
| 197 node.target = _lookupBreakOrContinueTarget(node, node.label, false); | |
| 198 return null; | |
| 199 } | |
| 200 | |
| 201 @override | |
| 202 Object visitClassDeclaration(ClassDeclaration node) { | |
| 203 setMetadata(node.element, node); | |
| 204 return null; | |
| 205 } | |
| 206 @override | |
| 207 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 208 setMetadata(node.element, node); | |
| 209 return null; | |
| 210 } | |
| 211 | |
| 212 @override | |
| 213 Object visitCommentReference(CommentReference node) { | |
| 214 Identifier identifier = node.identifier; | |
| 215 if (identifier is SimpleIdentifier) { | |
| 216 SimpleIdentifier simpleIdentifier = identifier; | |
| 217 Element element = _resolveSimpleIdentifier(simpleIdentifier); | |
| 218 if (element == null) { | |
| 219 // | |
| 220 // This might be a reference to an imported name that is missing the | |
| 221 // prefix. | |
| 222 // | |
| 223 element = _findImportWithoutPrefix(simpleIdentifier); | |
| 224 if (element is MultiplyDefinedElement) { | |
| 225 // TODO(brianwilkerson) Report this error? | |
| 226 element = null; | |
| 227 } | |
| 228 } | |
| 229 if (element == null) { | |
| 230 // TODO(brianwilkerson) Report this error? | |
| 231 // resolver.reportError( | |
| 232 // StaticWarningCode.UNDEFINED_IDENTIFIER, | |
| 233 // simpleIdentifier, | |
| 234 // simpleIdentifier.getName()); | |
| 235 } else { | |
| 236 if (element.library == null || element.library != _definingLibrary) { | |
| 237 // TODO(brianwilkerson) Report this error? | |
| 238 } | |
| 239 simpleIdentifier.staticElement = element; | |
| 240 if (node.newKeyword != null) { | |
| 241 if (element is ClassElement) { | |
| 242 ConstructorElement constructor = element.unnamedConstructor; | |
| 243 if (constructor == null) { | |
| 244 // TODO(brianwilkerson) Report this error. | |
| 245 } else { | |
| 246 simpleIdentifier.staticElement = constructor; | |
| 247 } | |
| 248 } else { | |
| 249 // TODO(brianwilkerson) Report this error. | |
| 250 } | |
| 251 } | |
| 252 } | |
| 253 } else if (identifier is PrefixedIdentifier) { | |
| 254 PrefixedIdentifier prefixedIdentifier = identifier; | |
| 255 SimpleIdentifier prefix = prefixedIdentifier.prefix; | |
| 256 SimpleIdentifier name = prefixedIdentifier.identifier; | |
| 257 Element element = _resolveSimpleIdentifier(prefix); | |
| 258 if (element == null) { | |
| 259 // resolver.reportError(StaticWarningCode.UNDEFINED_IDENTIFIER, prefix, p
refix.getName()); | |
| 260 } else { | |
| 261 if (element is PrefixElement) { | |
| 262 prefix.staticElement = element; | |
| 263 // TODO(brianwilkerson) Report this error? | |
| 264 element = _resolver.nameScope.lookup(identifier, _definingLibrary); | |
| 265 name.staticElement = element; | |
| 266 return null; | |
| 267 } | |
| 268 LibraryElement library = element.library; | |
| 269 if (library == null) { | |
| 270 // TODO(brianwilkerson) We need to understand how the library could | |
| 271 // ever be null. | |
| 272 AnalysisEngine.instance.logger | |
| 273 .logError("Found element with null library: ${element.name}"); | |
| 274 } else if (library != _definingLibrary) { | |
| 275 // TODO(brianwilkerson) Report this error. | |
| 276 } | |
| 277 name.staticElement = element; | |
| 278 if (node.newKeyword == null) { | |
| 279 if (element is ClassElement) { | |
| 280 Element memberElement = | |
| 281 _lookupGetterOrMethod(element.type, name.name); | |
| 282 if (memberElement == null) { | |
| 283 memberElement = element.getNamedConstructor(name.name); | |
| 284 if (memberElement == null) { | |
| 285 memberElement = _lookUpSetter(prefix, element.type, name.name); | |
| 286 } | |
| 287 } | |
| 288 if (memberElement == null) { | |
| 289 // reportGetterOrSetterNotFound(prefixedIdentifier, name, element.g
etDisplayName()); | |
| 290 } else { | |
| 291 name.staticElement = memberElement; | |
| 292 } | |
| 293 } else { | |
| 294 // TODO(brianwilkerson) Report this error. | |
| 295 } | |
| 296 } else { | |
| 297 if (element is ClassElement) { | |
| 298 ConstructorElement constructor = | |
| 299 element.getNamedConstructor(name.name); | |
| 300 if (constructor == null) { | |
| 301 // TODO(brianwilkerson) Report this error. | |
| 302 } else { | |
| 303 name.staticElement = constructor; | |
| 304 } | |
| 305 } else { | |
| 306 // TODO(brianwilkerson) Report this error. | |
| 307 } | |
| 308 } | |
| 309 } | |
| 310 } | |
| 311 return null; | |
| 312 } | |
| 313 | |
| 314 @override | |
| 315 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 316 super.visitConstructorDeclaration(node); | |
| 317 ConstructorElement element = node.element; | |
| 318 if (element is ConstructorElementImpl) { | |
| 319 ConstructorElementImpl constructorElement = element; | |
| 320 ConstructorName redirectedNode = node.redirectedConstructor; | |
| 321 if (redirectedNode != null) { | |
| 322 // set redirected factory constructor | |
| 323 ConstructorElement redirectedElement = redirectedNode.staticElement; | |
| 324 constructorElement.redirectedConstructor = redirectedElement; | |
| 325 } else { | |
| 326 // set redirected generative constructor | |
| 327 for (ConstructorInitializer initializer in node.initializers) { | |
| 328 if (initializer is RedirectingConstructorInvocation) { | |
| 329 ConstructorElement redirectedElement = initializer.staticElement; | |
| 330 constructorElement.redirectedConstructor = redirectedElement; | |
| 331 } | |
| 332 } | |
| 333 } | |
| 334 setMetadata(constructorElement, node); | |
| 335 } | |
| 336 return null; | |
| 337 } | |
| 338 | |
| 339 @override | |
| 340 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 341 SimpleIdentifier fieldName = node.fieldName; | |
| 342 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 343 FieldElement fieldElement = enclosingClass.getField(fieldName.name); | |
| 344 fieldName.staticElement = fieldElement; | |
| 345 return null; | |
| 346 } | |
| 347 | |
| 348 @override | |
| 349 Object visitConstructorName(ConstructorName node) { | |
| 350 DartType type = node.type.type; | |
| 351 if (type != null && type.isDynamic) { | |
| 352 return null; | |
| 353 } else if (type is! InterfaceType) { | |
| 354 // TODO(brianwilkerson) Report these errors. | |
| 355 // ASTNode parent = node.getParent(); | |
| 356 // if (parent instanceof InstanceCreationExpression) { | |
| 357 // if (((InstanceCreationExpression) parent).isConst()) { | |
| 358 // // CompileTimeErrorCode.CONST_WITH_NON_TYPE | |
| 359 // } else { | |
| 360 // // StaticWarningCode.NEW_WITH_NON_TYPE | |
| 361 // } | |
| 362 // } else { | |
| 363 // // This is part of a redirecting factory constructor; not sure which e
rror code to use | |
| 364 // } | |
| 365 return null; | |
| 366 } | |
| 367 // look up ConstructorElement | |
| 368 ConstructorElement constructor; | |
| 369 SimpleIdentifier name = node.name; | |
| 370 InterfaceType interfaceType = type as InterfaceType; | |
| 371 if (name == null) { | |
| 372 constructor = interfaceType.lookUpConstructor(null, _definingLibrary); | |
| 373 } else { | |
| 374 constructor = | |
| 375 interfaceType.lookUpConstructor(name.name, _definingLibrary); | |
| 376 name.staticElement = constructor; | |
| 377 } | |
| 378 node.staticElement = constructor; | |
| 379 return null; | |
| 380 } | |
| 381 | |
| 382 @override | |
| 383 Object visitContinueStatement(ContinueStatement node) { | |
| 384 node.target = _lookupBreakOrContinueTarget(node, node.label, true); | |
| 385 return null; | |
| 386 } | |
| 387 | |
| 388 @override | |
| 389 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 390 setMetadata(node.element, node); | |
| 391 return null; | |
| 392 } | |
| 393 | |
| 394 @override | |
| 395 Object visitEnumDeclaration(EnumDeclaration node) { | |
| 396 setMetadata(node.element, node); | |
| 397 return null; | |
| 398 } | |
| 399 | |
| 400 @override | |
| 401 Object visitExportDirective(ExportDirective node) { | |
| 402 ExportElement exportElement = node.element; | |
| 403 if (exportElement != null) { | |
| 404 // The element is null when the URI is invalid | |
| 405 // TODO(brianwilkerson) Figure out whether the element can ever be | |
| 406 // something other than an ExportElement | |
| 407 _resolveCombinators(exportElement.exportedLibrary, node.combinators); | |
| 408 setMetadata(exportElement, node); | |
| 409 } | |
| 410 return null; | |
| 411 } | |
| 412 | |
| 413 @override | |
| 414 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 415 _setMetadataForParameter(node.element, node); | |
| 416 return super.visitFieldFormalParameter(node); | |
| 417 } | |
| 418 | |
| 419 @override | |
| 420 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 421 setMetadata(node.element, node); | |
| 422 return null; | |
| 423 } | |
| 424 | |
| 425 @override | |
| 426 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 427 // TODO(brianwilkerson) Can we ever resolve the function being invoked? | |
| 428 Expression expression = node.function; | |
| 429 if (expression is FunctionExpression) { | |
| 430 FunctionExpression functionExpression = expression; | |
| 431 ExecutableElement functionElement = functionExpression.element; | |
| 432 ArgumentList argumentList = node.argumentList; | |
| 433 List<ParameterElement> parameters = | |
| 434 _resolveArgumentsToFunction(false, argumentList, functionElement); | |
| 435 if (parameters != null) { | |
| 436 argumentList.correspondingStaticParameters = parameters; | |
| 437 } | |
| 438 } | |
| 439 return null; | |
| 440 } | |
| 441 | |
| 442 @override | |
| 443 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 444 setMetadata(node.element, node); | |
| 445 return null; | |
| 446 } | |
| 447 | |
| 448 @override | |
| 449 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 450 _setMetadataForParameter(node.element, node); | |
| 451 return null; | |
| 452 } | |
| 453 | |
| 454 @override | |
| 455 Object visitImportDirective(ImportDirective node) { | |
| 456 SimpleIdentifier prefixNode = node.prefix; | |
| 457 if (prefixNode != null) { | |
| 458 String prefixName = prefixNode.name; | |
| 459 for (PrefixElement prefixElement in _definingLibrary.prefixes) { | |
| 460 if (prefixElement.displayName == prefixName) { | |
| 461 prefixNode.staticElement = prefixElement; | |
| 462 break; | |
| 463 } | |
| 464 } | |
| 465 } | |
| 466 ImportElement importElement = node.element; | |
| 467 if (importElement != null) { | |
| 468 // The element is null when the URI is invalid | |
| 469 LibraryElement library = importElement.importedLibrary; | |
| 470 if (library != null) { | |
| 471 _resolveCombinators(library, node.combinators); | |
| 472 } | |
| 473 setMetadata(importElement, node); | |
| 474 } | |
| 475 return null; | |
| 476 } | |
| 477 | |
| 478 @override | |
| 479 Object visitIndexExpression(IndexExpression node) { | |
| 480 Expression target = node.realTarget; | |
| 481 DartType staticType = _getStaticType(target); | |
| 482 DartType propagatedType = _getPropagatedType(target); | |
| 483 String getterMethodName = sc.TokenType.INDEX.lexeme; | |
| 484 String setterMethodName = sc.TokenType.INDEX_EQ.lexeme; | |
| 485 bool isInGetterContext = node.inGetterContext(); | |
| 486 bool isInSetterContext = node.inSetterContext(); | |
| 487 if (isInGetterContext && isInSetterContext) { | |
| 488 // lookup setter | |
| 489 MethodElement setterStaticMethod = | |
| 490 _lookUpMethod(target, staticType, setterMethodName); | |
| 491 MethodElement setterPropagatedMethod = | |
| 492 _lookUpMethod(target, propagatedType, setterMethodName); | |
| 493 // set setter element | |
| 494 node.staticElement = setterStaticMethod; | |
| 495 node.propagatedElement = setterPropagatedMethod; | |
| 496 // generate undefined method warning | |
| 497 _checkForUndefinedIndexOperator(node, target, getterMethodName, | |
| 498 setterStaticMethod, setterPropagatedMethod, staticType, | |
| 499 propagatedType); | |
| 500 // lookup getter method | |
| 501 MethodElement getterStaticMethod = | |
| 502 _lookUpMethod(target, staticType, getterMethodName); | |
| 503 MethodElement getterPropagatedMethod = | |
| 504 _lookUpMethod(target, propagatedType, getterMethodName); | |
| 505 // set getter element | |
| 506 AuxiliaryElements auxiliaryElements = | |
| 507 new AuxiliaryElements(getterStaticMethod, getterPropagatedMethod); | |
| 508 node.auxiliaryElements = auxiliaryElements; | |
| 509 // generate undefined method warning | |
| 510 _checkForUndefinedIndexOperator(node, target, getterMethodName, | |
| 511 getterStaticMethod, getterPropagatedMethod, staticType, | |
| 512 propagatedType); | |
| 513 } else if (isInGetterContext) { | |
| 514 // lookup getter method | |
| 515 MethodElement staticMethod = | |
| 516 _lookUpMethod(target, staticType, getterMethodName); | |
| 517 MethodElement propagatedMethod = | |
| 518 _lookUpMethod(target, propagatedType, getterMethodName); | |
| 519 // set getter element | |
| 520 node.staticElement = staticMethod; | |
| 521 node.propagatedElement = propagatedMethod; | |
| 522 // generate undefined method warning | |
| 523 _checkForUndefinedIndexOperator(node, target, getterMethodName, | |
| 524 staticMethod, propagatedMethod, staticType, propagatedType); | |
| 525 } else if (isInSetterContext) { | |
| 526 // lookup setter method | |
| 527 MethodElement staticMethod = | |
| 528 _lookUpMethod(target, staticType, setterMethodName); | |
| 529 MethodElement propagatedMethod = | |
| 530 _lookUpMethod(target, propagatedType, setterMethodName); | |
| 531 // set setter element | |
| 532 node.staticElement = staticMethod; | |
| 533 node.propagatedElement = propagatedMethod; | |
| 534 // generate undefined method warning | |
| 535 _checkForUndefinedIndexOperator(node, target, setterMethodName, | |
| 536 staticMethod, propagatedMethod, staticType, propagatedType); | |
| 537 } | |
| 538 return null; | |
| 539 } | |
| 540 | |
| 541 @override | |
| 542 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 543 ConstructorElement invokedConstructor = node.constructorName.staticElement; | |
| 544 node.staticElement = invokedConstructor; | |
| 545 ArgumentList argumentList = node.argumentList; | |
| 546 List<ParameterElement> parameters = _resolveArgumentsToFunction( | |
| 547 node.isConst, argumentList, invokedConstructor); | |
| 548 if (parameters != null) { | |
| 549 argumentList.correspondingStaticParameters = parameters; | |
| 550 } | |
| 551 return null; | |
| 552 } | |
| 553 | |
| 554 @override | |
| 555 Object visitLibraryDirective(LibraryDirective node) { | |
| 556 setMetadata(node.element, node); | |
| 557 return null; | |
| 558 } | |
| 559 | |
| 560 @override | |
| 561 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 562 setMetadata(node.element, node); | |
| 563 return null; | |
| 564 } | |
| 565 | |
| 566 @override | |
| 567 Object visitMethodInvocation(MethodInvocation node) { | |
| 568 SimpleIdentifier methodName = node.methodName; | |
| 569 // | |
| 570 // Synthetic identifiers have been already reported during parsing. | |
| 571 // | |
| 572 if (methodName.isSynthetic) { | |
| 573 return null; | |
| 574 } | |
| 575 // | |
| 576 // We have a method invocation of one of two forms: 'e.m(a1, ..., an)' or | |
| 577 // 'm(a1, ..., an)'. The first step is to figure out which executable is | |
| 578 // being invoked, using both the static and the propagated type information. | |
| 579 // | |
| 580 Expression target = node.realTarget; | |
| 581 if (target is SuperExpression && !_isSuperInValidContext(target)) { | |
| 582 return null; | |
| 583 } | |
| 584 Element staticElement; | |
| 585 Element propagatedElement; | |
| 586 DartType staticType = null; | |
| 587 DartType propagatedType = null; | |
| 588 if (target == null) { | |
| 589 staticElement = _resolveInvokedElement(methodName); | |
| 590 propagatedElement = null; | |
| 591 } else if (methodName.name == FunctionElement.LOAD_LIBRARY_NAME && | |
| 592 _isDeferredPrefix(target)) { | |
| 593 if (node.operator.type == sc.TokenType.QUESTION_PERIOD) { | |
| 594 _resolver.reportErrorForNode( | |
| 595 CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, target, | |
| 596 [(target as SimpleIdentifier).name]); | |
| 597 } | |
| 598 LibraryElement importedLibrary = _getImportedLibrary(target); | |
| 599 methodName.staticElement = importedLibrary.loadLibraryFunction; | |
| 600 return null; | |
| 601 } else { | |
| 602 staticType = _getStaticType(target); | |
| 603 propagatedType = _getPropagatedType(target); | |
| 604 // | |
| 605 // If this method invocation is of the form 'C.m' where 'C' is a class, | |
| 606 // then we don't call resolveInvokedElement(...) which walks up the class | |
| 607 // hierarchy, instead we just look for the member in the type only. This | |
| 608 // does not apply to conditional method invocation (i.e. 'C?.m(...)'). | |
| 609 // | |
| 610 bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD; | |
| 611 ClassElementImpl typeReference = getTypeReference(target, isConditional); | |
| 612 if (typeReference != null) { | |
| 613 staticElement = | |
| 614 propagatedElement = _resolveElement(typeReference, methodName); | |
| 615 } else { | |
| 616 staticElement = _resolveInvokedElementWithTarget( | |
| 617 target, staticType, methodName, isConditional); | |
| 618 propagatedElement = _resolveInvokedElementWithTarget( | |
| 619 target, propagatedType, methodName, isConditional); | |
| 620 } | |
| 621 } | |
| 622 staticElement = _convertSetterToGetter(staticElement); | |
| 623 propagatedElement = _convertSetterToGetter(propagatedElement); | |
| 624 // | |
| 625 // Record the results. | |
| 626 // | |
| 627 methodName.staticElement = staticElement; | |
| 628 methodName.propagatedElement = propagatedElement; | |
| 629 ArgumentList argumentList = node.argumentList; | |
| 630 if (staticElement != null) { | |
| 631 List<ParameterElement> parameters = | |
| 632 _computeCorrespondingParameters(argumentList, staticElement); | |
| 633 if (parameters != null) { | |
| 634 argumentList.correspondingStaticParameters = parameters; | |
| 635 } | |
| 636 } | |
| 637 if (propagatedElement != null) { | |
| 638 List<ParameterElement> parameters = | |
| 639 _computeCorrespondingParameters(argumentList, propagatedElement); | |
| 640 if (parameters != null) { | |
| 641 argumentList.correspondingPropagatedParameters = parameters; | |
| 642 } | |
| 643 } | |
| 644 // | |
| 645 // Then check for error conditions. | |
| 646 // | |
| 647 ErrorCode errorCode = _checkForInvocationError(target, true, staticElement); | |
| 648 bool generatedWithTypePropagation = false; | |
| 649 if (_enableHints && errorCode == null && staticElement == null) { | |
| 650 // The method lookup may have failed because there were multiple | |
| 651 // incompatible choices. In this case we don't want to generate a hint. | |
| 652 errorCode = _checkForInvocationError(target, false, propagatedElement); | |
| 653 if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) { | |
| 654 ClassElement classElementContext = null; | |
| 655 if (target == null) { | |
| 656 classElementContext = _resolver.enclosingClass; | |
| 657 } else { | |
| 658 DartType type = _getBestType(target); | |
| 659 if (type != null) { | |
| 660 if (type.element is ClassElement) { | |
| 661 classElementContext = type.element as ClassElement; | |
| 662 } | |
| 663 } | |
| 664 } | |
| 665 if (classElementContext != null) { | |
| 666 _subtypeManager.ensureLibraryVisited(_definingLibrary); | |
| 667 HashSet<ClassElement> subtypeElements = | |
| 668 _subtypeManager.computeAllSubtypes(classElementContext); | |
| 669 for (ClassElement subtypeElement in subtypeElements) { | |
| 670 if (subtypeElement.getMethod(methodName.name) != null) { | |
| 671 errorCode = null; | |
| 672 } | |
| 673 } | |
| 674 } | |
| 675 } | |
| 676 generatedWithTypePropagation = true; | |
| 677 } | |
| 678 if (errorCode == null) { | |
| 679 return null; | |
| 680 } | |
| 681 if (identical( | |
| 682 errorCode, StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) || | |
| 683 identical(errorCode, | |
| 684 CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT) || | |
| 685 identical(errorCode, StaticTypeWarningCode.UNDEFINED_FUNCTION)) { | |
| 686 _resolver.reportErrorForNode(errorCode, methodName, [methodName.name]); | |
| 687 } else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) { | |
| 688 String targetTypeName; | |
| 689 if (target == null) { | |
| 690 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 691 targetTypeName = enclosingClass.displayName; | |
| 692 ErrorCode proxyErrorCode = (generatedWithTypePropagation | |
| 693 ? HintCode.UNDEFINED_METHOD | |
| 694 : StaticTypeWarningCode.UNDEFINED_METHOD); | |
| 695 _recordUndefinedNode(_resolver.enclosingClass, proxyErrorCode, | |
| 696 methodName, [methodName.name, targetTypeName]); | |
| 697 } else { | |
| 698 // ignore Function "call" | |
| 699 // (if we are about to create a hint using type propagation, | |
| 700 // then we can use type propagation here as well) | |
| 701 DartType targetType = null; | |
| 702 if (!generatedWithTypePropagation) { | |
| 703 targetType = _getStaticType(target); | |
| 704 } else { | |
| 705 // choose the best type | |
| 706 targetType = _getPropagatedType(target); | |
| 707 if (targetType == null) { | |
| 708 targetType = _getStaticType(target); | |
| 709 } | |
| 710 } | |
| 711 if (!_enableStrictCallChecks && | |
| 712 targetType != null && | |
| 713 targetType.isDartCoreFunction && | |
| 714 methodName.name == FunctionElement.CALL_METHOD_NAME) { | |
| 715 // TODO(brianwilkerson) Can we ever resolve the function being | |
| 716 // invoked? | |
| 717 // resolveArgumentsToParameters(node.getArgumentList(), invokedFunction
); | |
| 718 return null; | |
| 719 } | |
| 720 targetTypeName = targetType == null ? null : targetType.displayName; | |
| 721 ErrorCode proxyErrorCode = (generatedWithTypePropagation | |
| 722 ? HintCode.UNDEFINED_METHOD | |
| 723 : StaticTypeWarningCode.UNDEFINED_METHOD); | |
| 724 _recordUndefinedNode(targetType.element, proxyErrorCode, methodName, [ | |
| 725 methodName.name, | |
| 726 targetTypeName | |
| 727 ]); | |
| 728 } | |
| 729 } else if (identical( | |
| 730 errorCode, StaticTypeWarningCode.UNDEFINED_SUPER_METHOD)) { | |
| 731 // Generate the type name. | |
| 732 // The error code will never be generated via type propagation | |
| 733 DartType targetType = _getStaticType(target); | |
| 734 if (targetType is InterfaceType && !targetType.isObject) { | |
| 735 targetType = (targetType as InterfaceType).superclass; | |
| 736 } | |
| 737 String targetTypeName = targetType == null ? null : targetType.name; | |
| 738 _resolver.reportErrorForNode(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, | |
| 739 methodName, [methodName.name, targetTypeName]); | |
| 740 } | |
| 741 return null; | |
| 742 } | |
| 743 | |
| 744 @override | |
| 745 Object visitPartDirective(PartDirective node) { | |
| 746 setMetadata(node.element, node); | |
| 747 return null; | |
| 748 } | |
| 749 | |
| 750 @override | |
| 751 Object visitPartOfDirective(PartOfDirective node) { | |
| 752 setMetadata(node.element, node); | |
| 753 return null; | |
| 754 } | |
| 755 | |
| 756 @override | |
| 757 Object visitPostfixExpression(PostfixExpression node) { | |
| 758 Expression operand = node.operand; | |
| 759 String methodName = _getPostfixOperator(node); | |
| 760 DartType staticType = _getStaticType(operand); | |
| 761 MethodElement staticMethod = _lookUpMethod(operand, staticType, methodName); | |
| 762 node.staticElement = staticMethod; | |
| 763 DartType propagatedType = _getPropagatedType(operand); | |
| 764 MethodElement propagatedMethod = | |
| 765 _lookUpMethod(operand, propagatedType, methodName); | |
| 766 node.propagatedElement = propagatedMethod; | |
| 767 if (_shouldReportMissingMember(staticType, staticMethod)) { | |
| 768 if (operand is SuperExpression) { | |
| 769 _recordUndefinedToken(staticType.element, | |
| 770 StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, node.operator, [ | |
| 771 methodName, | |
| 772 staticType.displayName | |
| 773 ]); | |
| 774 } else { | |
| 775 _recordUndefinedToken(staticType.element, | |
| 776 StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [ | |
| 777 methodName, | |
| 778 staticType.displayName | |
| 779 ]); | |
| 780 } | |
| 781 } else if (_enableHints && | |
| 782 _shouldReportMissingMember(propagatedType, propagatedMethod) && | |
| 783 !_memberFoundInSubclass( | |
| 784 propagatedType.element, methodName, true, false)) { | |
| 785 _recordUndefinedToken(propagatedType.element, HintCode.UNDEFINED_OPERATOR, | |
| 786 node.operator, [methodName, propagatedType.displayName]); | |
| 787 } | |
| 788 return null; | |
| 789 } | |
| 790 | |
| 791 @override | |
| 792 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 793 SimpleIdentifier prefix = node.prefix; | |
| 794 SimpleIdentifier identifier = node.identifier; | |
| 795 // | |
| 796 // First, check the "lib.loadLibrary" case | |
| 797 // | |
| 798 if (identifier.name == FunctionElement.LOAD_LIBRARY_NAME && | |
| 799 _isDeferredPrefix(prefix)) { | |
| 800 LibraryElement importedLibrary = _getImportedLibrary(prefix); | |
| 801 identifier.staticElement = importedLibrary.loadLibraryFunction; | |
| 802 return null; | |
| 803 } | |
| 804 // | |
| 805 // Check to see whether the prefix is really a prefix. | |
| 806 // | |
| 807 Element prefixElement = prefix.staticElement; | |
| 808 if (prefixElement is PrefixElement) { | |
| 809 Element element = _resolver.nameScope.lookup(node, _definingLibrary); | |
| 810 if (element == null && identifier.inSetterContext()) { | |
| 811 element = _resolver.nameScope.lookup( | |
| 812 new SyntheticIdentifier("${node.name}=", node), _definingLibrary); | |
| 813 } | |
| 814 if (element == null) { | |
| 815 if (identifier.inSetterContext()) { | |
| 816 _resolver.reportErrorForNode(StaticWarningCode.UNDEFINED_SETTER, | |
| 817 identifier, [identifier.name, prefixElement.name]); | |
| 818 } else if (node.parent is Annotation) { | |
| 819 Annotation annotation = node.parent as Annotation; | |
| 820 _resolver.reportErrorForNode( | |
| 821 CompileTimeErrorCode.INVALID_ANNOTATION, annotation); | |
| 822 return null; | |
| 823 } else { | |
| 824 _resolver.reportErrorForNode(StaticWarningCode.UNDEFINED_GETTER, | |
| 825 identifier, [identifier.name, prefixElement.name]); | |
| 826 } | |
| 827 return null; | |
| 828 } | |
| 829 if (element is PropertyAccessorElement && identifier.inSetterContext()) { | |
| 830 PropertyInducingElement variable = | |
| 831 (element as PropertyAccessorElement).variable; | |
| 832 if (variable != null) { | |
| 833 PropertyAccessorElement setter = variable.setter; | |
| 834 if (setter != null) { | |
| 835 element = setter; | |
| 836 } | |
| 837 } | |
| 838 } | |
| 839 // TODO(brianwilkerson) The prefix needs to be resolved to the element for | |
| 840 // the import that defines the prefix, not the prefix's element. | |
| 841 identifier.staticElement = element; | |
| 842 // Validate annotation element. | |
| 843 if (node.parent is Annotation) { | |
| 844 Annotation annotation = node.parent as Annotation; | |
| 845 _resolveAnnotationElement(annotation); | |
| 846 return null; | |
| 847 } | |
| 848 return null; | |
| 849 } | |
| 850 // May be annotation, resolve invocation of "const" constructor. | |
| 851 if (node.parent is Annotation) { | |
| 852 Annotation annotation = node.parent as Annotation; | |
| 853 _resolveAnnotationElement(annotation); | |
| 854 } | |
| 855 // | |
| 856 // Otherwise, the prefix is really an expression that happens to be a simple | |
| 857 // identifier and this is really equivalent to a property access node. | |
| 858 // | |
| 859 _resolvePropertyAccess(prefix, identifier, false); | |
| 860 return null; | |
| 861 } | |
| 862 | |
| 863 @override | |
| 864 Object visitPrefixExpression(PrefixExpression node) { | |
| 865 sc.Token operator = node.operator; | |
| 866 sc.TokenType operatorType = operator.type; | |
| 867 if (operatorType.isUserDefinableOperator || | |
| 868 operatorType == sc.TokenType.PLUS_PLUS || | |
| 869 operatorType == sc.TokenType.MINUS_MINUS) { | |
| 870 Expression operand = node.operand; | |
| 871 String methodName = _getPrefixOperator(node); | |
| 872 DartType staticType = _getStaticType(operand); | |
| 873 MethodElement staticMethod = | |
| 874 _lookUpMethod(operand, staticType, methodName); | |
| 875 node.staticElement = staticMethod; | |
| 876 DartType propagatedType = _getPropagatedType(operand); | |
| 877 MethodElement propagatedMethod = | |
| 878 _lookUpMethod(operand, propagatedType, methodName); | |
| 879 node.propagatedElement = propagatedMethod; | |
| 880 if (_shouldReportMissingMember(staticType, staticMethod)) { | |
| 881 if (operand is SuperExpression) { | |
| 882 _recordUndefinedToken(staticType.element, | |
| 883 StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, operator, [ | |
| 884 methodName, | |
| 885 staticType.displayName | |
| 886 ]); | |
| 887 } else { | |
| 888 _recordUndefinedToken(staticType.element, | |
| 889 StaticTypeWarningCode.UNDEFINED_OPERATOR, operator, [ | |
| 890 methodName, | |
| 891 staticType.displayName | |
| 892 ]); | |
| 893 } | |
| 894 } else if (_enableHints && | |
| 895 _shouldReportMissingMember(propagatedType, propagatedMethod) && | |
| 896 !_memberFoundInSubclass( | |
| 897 propagatedType.element, methodName, true, false)) { | |
| 898 _recordUndefinedToken(propagatedType.element, | |
| 899 HintCode.UNDEFINED_OPERATOR, operator, [ | |
| 900 methodName, | |
| 901 propagatedType.displayName | |
| 902 ]); | |
| 903 } | |
| 904 } | |
| 905 return null; | |
| 906 } | |
| 907 | |
| 908 @override | |
| 909 Object visitPropertyAccess(PropertyAccess node) { | |
| 910 Expression target = node.realTarget; | |
| 911 if (target is SuperExpression && !_isSuperInValidContext(target)) { | |
| 912 return null; | |
| 913 } | |
| 914 SimpleIdentifier propertyName = node.propertyName; | |
| 915 _resolvePropertyAccess(target, propertyName, | |
| 916 node.operator.type == sc.TokenType.QUESTION_PERIOD); | |
| 917 return null; | |
| 918 } | |
| 919 | |
| 920 @override | |
| 921 Object visitRedirectingConstructorInvocation( | |
| 922 RedirectingConstructorInvocation node) { | |
| 923 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 924 if (enclosingClass == null) { | |
| 925 // TODO(brianwilkerson) Report this error. | |
| 926 return null; | |
| 927 } | |
| 928 SimpleIdentifier name = node.constructorName; | |
| 929 ConstructorElement element; | |
| 930 if (name == null) { | |
| 931 element = enclosingClass.unnamedConstructor; | |
| 932 } else { | |
| 933 element = enclosingClass.getNamedConstructor(name.name); | |
| 934 } | |
| 935 if (element == null) { | |
| 936 // TODO(brianwilkerson) Report this error and decide what element to | |
| 937 // associate with the node. | |
| 938 return null; | |
| 939 } | |
| 940 if (name != null) { | |
| 941 name.staticElement = element; | |
| 942 } | |
| 943 node.staticElement = element; | |
| 944 ArgumentList argumentList = node.argumentList; | |
| 945 List<ParameterElement> parameters = | |
| 946 _resolveArgumentsToFunction(false, argumentList, element); | |
| 947 if (parameters != null) { | |
| 948 argumentList.correspondingStaticParameters = parameters; | |
| 949 } | |
| 950 return null; | |
| 951 } | |
| 952 | |
| 953 @override | |
| 954 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 955 _setMetadataForParameter(node.element, node); | |
| 956 return null; | |
| 957 } | |
| 958 | |
| 959 @override | |
| 960 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 961 // | |
| 962 // Synthetic identifiers have been already reported during parsing. | |
| 963 // | |
| 964 if (node.isSynthetic) { | |
| 965 return null; | |
| 966 } | |
| 967 // | |
| 968 // We ignore identifiers that have already been resolved, such as | |
| 969 // identifiers representing the name in a declaration. | |
| 970 // | |
| 971 if (node.staticElement != null) { | |
| 972 return null; | |
| 973 } | |
| 974 // | |
| 975 // The name dynamic denotes a Type object even though dynamic is not a | |
| 976 // class. | |
| 977 // | |
| 978 if (node.name == _dynamicType.name) { | |
| 979 node.staticElement = _dynamicType.element; | |
| 980 node.staticType = _typeType; | |
| 981 return null; | |
| 982 } | |
| 983 // | |
| 984 // Otherwise, the node should be resolved. | |
| 985 // | |
| 986 Element element = _resolveSimpleIdentifier(node); | |
| 987 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 988 if (_isFactoryConstructorReturnType(node) && | |
| 989 !identical(element, enclosingClass)) { | |
| 990 _resolver.reportErrorForNode( | |
| 991 CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node); | |
| 992 } else if (_isConstructorReturnType(node) && | |
| 993 !identical(element, enclosingClass)) { | |
| 994 _resolver.reportErrorForNode( | |
| 995 CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node); | |
| 996 element = null; | |
| 997 } else if (element == null || | |
| 998 (element is PrefixElement && !_isValidAsPrefix(node))) { | |
| 999 // TODO(brianwilkerson) Recover from this error. | |
| 1000 if (_isConstructorReturnType(node)) { | |
| 1001 _resolver.reportErrorForNode( | |
| 1002 CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node); | |
| 1003 } else if (node.parent is Annotation) { | |
| 1004 Annotation annotation = node.parent as Annotation; | |
| 1005 _resolver.reportErrorForNode( | |
| 1006 CompileTimeErrorCode.INVALID_ANNOTATION, annotation); | |
| 1007 } else if (element is PrefixElement) { | |
| 1008 _resolver.reportErrorForNode( | |
| 1009 CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, node, | |
| 1010 [element.name]); | |
| 1011 } else { | |
| 1012 _recordUndefinedNode(_resolver.enclosingClass, | |
| 1013 StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]); | |
| 1014 } | |
| 1015 } | |
| 1016 node.staticElement = element; | |
| 1017 if (node.inSetterContext() && | |
| 1018 node.inGetterContext() && | |
| 1019 enclosingClass != null) { | |
| 1020 InterfaceType enclosingType = enclosingClass.type; | |
| 1021 AuxiliaryElements auxiliaryElements = new AuxiliaryElements( | |
| 1022 _lookUpGetter(null, enclosingType, node.name), null); | |
| 1023 node.auxiliaryElements = auxiliaryElements; | |
| 1024 } | |
| 1025 // | |
| 1026 // Validate annotation element. | |
| 1027 // | |
| 1028 if (node.parent is Annotation) { | |
| 1029 Annotation annotation = node.parent as Annotation; | |
| 1030 _resolveAnnotationElement(annotation); | |
| 1031 } | |
| 1032 return null; | |
| 1033 } | |
| 1034 | |
| 1035 @override | |
| 1036 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 1037 ClassElementImpl enclosingClass = _resolver.enclosingClass; | |
| 1038 if (enclosingClass == null) { | |
| 1039 // TODO(brianwilkerson) Report this error. | |
| 1040 return null; | |
| 1041 } | |
| 1042 InterfaceType superType = enclosingClass.supertype; | |
| 1043 if (superType == null) { | |
| 1044 // TODO(brianwilkerson) Report this error. | |
| 1045 return null; | |
| 1046 } | |
| 1047 SimpleIdentifier name = node.constructorName; | |
| 1048 String superName = name != null ? name.name : null; | |
| 1049 ConstructorElement element = | |
| 1050 superType.lookUpConstructor(superName, _definingLibrary); | |
| 1051 if (element == null || | |
| 1052 (!enclosingClass.doesMixinLackConstructors && | |
| 1053 !enclosingClass.isSuperConstructorAccessible(element))) { | |
| 1054 if (name != null) { | |
| 1055 _resolver.reportErrorForNode( | |
| 1056 CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [ | |
| 1057 superType.displayName, | |
| 1058 name | |
| 1059 ]); | |
| 1060 } else { | |
| 1061 _resolver.reportErrorForNode( | |
| 1062 CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, | |
| 1063 node, [superType.displayName]); | |
| 1064 } | |
| 1065 return null; | |
| 1066 } else { | |
| 1067 if (element.isFactory) { | |
| 1068 _resolver.reportErrorForNode( | |
| 1069 CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]); | |
| 1070 } | |
| 1071 } | |
| 1072 if (name != null) { | |
| 1073 name.staticElement = element; | |
| 1074 } | |
| 1075 node.staticElement = element; | |
| 1076 ArgumentList argumentList = node.argumentList; | |
| 1077 List<ParameterElement> parameters = _resolveArgumentsToFunction( | |
| 1078 isInConstConstructor, argumentList, element); | |
| 1079 if (parameters != null) { | |
| 1080 argumentList.correspondingStaticParameters = parameters; | |
| 1081 } | |
| 1082 return null; | |
| 1083 } | |
| 1084 | |
| 1085 @override | |
| 1086 Object visitSuperExpression(SuperExpression node) { | |
| 1087 if (!_isSuperInValidContext(node)) { | |
| 1088 _resolver.reportErrorForNode( | |
| 1089 CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node); | |
| 1090 } | |
| 1091 return super.visitSuperExpression(node); | |
| 1092 } | |
| 1093 | |
| 1094 @override | |
| 1095 Object visitTypeParameter(TypeParameter node) { | |
| 1096 setMetadata(node.element, node); | |
| 1097 return null; | |
| 1098 } | |
| 1099 | |
| 1100 @override | |
| 1101 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 1102 setMetadata(node.element, node); | |
| 1103 return null; | |
| 1104 } | |
| 1105 | |
| 1106 /** | |
| 1107 * Given that we have found code to invoke the given [element], return the | |
| 1108 * error code that should be reported, or `null` if no error should be | |
| 1109 * reported. The [target] is the target of the invocation, or `null` if there | |
| 1110 * was no target. The flag [useStaticContext] should be `true` if the | |
| 1111 * invocation is in a static constant (does not have access to instance state. | |
| 1112 */ | |
| 1113 ErrorCode _checkForInvocationError( | |
| 1114 Expression target, bool useStaticContext, Element element) { | |
| 1115 // Prefix is not declared, instead "prefix.id" are declared. | |
| 1116 if (element is PrefixElement) { | |
| 1117 return CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT; | |
| 1118 } | |
| 1119 if (element is PropertyAccessorElement) { | |
| 1120 // | |
| 1121 // This is really a function expression invocation. | |
| 1122 // | |
| 1123 // TODO(brianwilkerson) Consider the possibility of re-writing the AST. | |
| 1124 FunctionType getterType = element.type; | |
| 1125 if (getterType != null) { | |
| 1126 DartType returnType = getterType.returnType; | |
| 1127 if (!_isExecutableType(returnType)) { | |
| 1128 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 1129 } | |
| 1130 } | |
| 1131 } else if (element is ExecutableElement) { | |
| 1132 return null; | |
| 1133 } else if (element is MultiplyDefinedElement) { | |
| 1134 // The error has already been reported | |
| 1135 return null; | |
| 1136 } else if (element == null && target is SuperExpression) { | |
| 1137 // TODO(jwren) We should split the UNDEFINED_METHOD into two error codes, | |
| 1138 // this one, and a code that describes the situation where the method was | |
| 1139 // found, but it was not accessible from the current library. | |
| 1140 return StaticTypeWarningCode.UNDEFINED_SUPER_METHOD; | |
| 1141 } else { | |
| 1142 // | |
| 1143 // This is really a function expression invocation. | |
| 1144 // | |
| 1145 // TODO(brianwilkerson) Consider the possibility of re-writing the AST. | |
| 1146 if (element is PropertyInducingElement) { | |
| 1147 PropertyAccessorElement getter = element.getter; | |
| 1148 FunctionType getterType = getter.type; | |
| 1149 if (getterType != null) { | |
| 1150 DartType returnType = getterType.returnType; | |
| 1151 if (!_isExecutableType(returnType)) { | |
| 1152 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 1153 } | |
| 1154 } | |
| 1155 } else if (element is VariableElement) { | |
| 1156 DartType variableType = element.type; | |
| 1157 if (!_isExecutableType(variableType)) { | |
| 1158 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 1159 } | |
| 1160 } else { | |
| 1161 if (target == null) { | |
| 1162 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 1163 if (enclosingClass == null) { | |
| 1164 return StaticTypeWarningCode.UNDEFINED_FUNCTION; | |
| 1165 } else if (element == null) { | |
| 1166 // Proxy-conditional warning, based on state of | |
| 1167 // resolver.getEnclosingClass() | |
| 1168 return StaticTypeWarningCode.UNDEFINED_METHOD; | |
| 1169 } else { | |
| 1170 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 1171 } | |
| 1172 } else { | |
| 1173 DartType targetType; | |
| 1174 if (useStaticContext) { | |
| 1175 targetType = _getStaticType(target); | |
| 1176 } else { | |
| 1177 // Compute and use the propagated type, if it is null, then it may | |
| 1178 // be the case that static type is some type, in which the static | |
| 1179 // type should be used. | |
| 1180 targetType = _getBestType(target); | |
| 1181 } | |
| 1182 if (targetType == null) { | |
| 1183 return StaticTypeWarningCode.UNDEFINED_FUNCTION; | |
| 1184 } else if (!targetType.isDynamic && !targetType.isBottom) { | |
| 1185 // Proxy-conditional warning, based on state of | |
| 1186 // targetType.getElement() | |
| 1187 return StaticTypeWarningCode.UNDEFINED_METHOD; | |
| 1188 } | |
| 1189 } | |
| 1190 } | |
| 1191 } | |
| 1192 return null; | |
| 1193 } | |
| 1194 | |
| 1195 /** | |
| 1196 * Check that the given index [expression] was resolved, otherwise a | |
| 1197 * [StaticTypeWarningCode.UNDEFINED_OPERATOR] is generated. The [target] is | |
| 1198 * the target of the expression. The [methodName] is the name of the operator | |
| 1199 * associated with the context of using of the given index expression. | |
| 1200 */ | |
| 1201 bool _checkForUndefinedIndexOperator(IndexExpression expression, | |
| 1202 Expression target, String methodName, MethodElement staticMethod, | |
| 1203 MethodElement propagatedMethod, DartType staticType, | |
| 1204 DartType propagatedType) { | |
| 1205 bool shouldReportMissingMember_static = | |
| 1206 _shouldReportMissingMember(staticType, staticMethod); | |
| 1207 bool shouldReportMissingMember_propagated = | |
| 1208 !shouldReportMissingMember_static && | |
| 1209 _enableHints && | |
| 1210 _shouldReportMissingMember(propagatedType, propagatedMethod) && | |
| 1211 !_memberFoundInSubclass( | |
| 1212 propagatedType.element, methodName, true, false); | |
| 1213 if (shouldReportMissingMember_static || | |
| 1214 shouldReportMissingMember_propagated) { | |
| 1215 sc.Token leftBracket = expression.leftBracket; | |
| 1216 sc.Token rightBracket = expression.rightBracket; | |
| 1217 ErrorCode errorCode; | |
| 1218 if (shouldReportMissingMember_static) { | |
| 1219 if (target is SuperExpression) { | |
| 1220 errorCode = StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR; | |
| 1221 } else { | |
| 1222 errorCode = StaticTypeWarningCode.UNDEFINED_OPERATOR; | |
| 1223 } | |
| 1224 } else { | |
| 1225 errorCode = HintCode.UNDEFINED_OPERATOR; | |
| 1226 } | |
| 1227 DartType type = | |
| 1228 shouldReportMissingMember_static ? staticType : propagatedType; | |
| 1229 if (leftBracket == null || rightBracket == null) { | |
| 1230 _recordUndefinedNode(type.element, errorCode, expression, [ | |
| 1231 methodName, | |
| 1232 type.displayName | |
| 1233 ]); | |
| 1234 } else { | |
| 1235 int offset = leftBracket.offset; | |
| 1236 int length = rightBracket.offset - offset + 1; | |
| 1237 _recordUndefinedOffset(type.element, errorCode, offset, length, [ | |
| 1238 methodName, | |
| 1239 type.displayName | |
| 1240 ]); | |
| 1241 } | |
| 1242 return true; | |
| 1243 } | |
| 1244 return false; | |
| 1245 } | |
| 1246 | |
| 1247 /** | |
| 1248 * Given an [argumentList] and the executable [element] that will be invoked | |
| 1249 * using those arguments, compute the list of parameters that correspond to | |
| 1250 * the list of arguments. Return the parameters that correspond to the | |
| 1251 * arguments, or `null` if no correspondence could be computed. | |
| 1252 */ | |
| 1253 List<ParameterElement> _computeCorrespondingParameters( | |
| 1254 ArgumentList argumentList, Element element) { | |
| 1255 if (element is PropertyAccessorElement) { | |
| 1256 // | |
| 1257 // This is an invocation of the call method defined on the value returned | |
| 1258 // by the getter. | |
| 1259 // | |
| 1260 FunctionType getterType = element.type; | |
| 1261 if (getterType != null) { | |
| 1262 DartType getterReturnType = getterType.returnType; | |
| 1263 if (getterReturnType is InterfaceType) { | |
| 1264 MethodElement callMethod = getterReturnType.lookUpMethod( | |
| 1265 FunctionElement.CALL_METHOD_NAME, _definingLibrary); | |
| 1266 if (callMethod != null) { | |
| 1267 return _resolveArgumentsToFunction(false, argumentList, callMethod); | |
| 1268 } | |
| 1269 } else if (getterReturnType is FunctionType) { | |
| 1270 List<ParameterElement> parameters = getterReturnType.parameters; | |
| 1271 return _resolveArgumentsToParameters(false, argumentList, parameters); | |
| 1272 } | |
| 1273 } | |
| 1274 } else if (element is ExecutableElement) { | |
| 1275 return _resolveArgumentsToFunction(false, argumentList, element); | |
| 1276 } else if (element is VariableElement) { | |
| 1277 VariableElement variable = element; | |
| 1278 DartType type = _promoteManager.getStaticType(variable); | |
| 1279 if (type is FunctionType) { | |
| 1280 FunctionType functionType = type; | |
| 1281 List<ParameterElement> parameters = functionType.parameters; | |
| 1282 return _resolveArgumentsToParameters(false, argumentList, parameters); | |
| 1283 } else if (type is InterfaceType) { | |
| 1284 // "call" invocation | |
| 1285 MethodElement callMethod = type.lookUpMethod( | |
| 1286 FunctionElement.CALL_METHOD_NAME, _definingLibrary); | |
| 1287 if (callMethod != null) { | |
| 1288 List<ParameterElement> parameters = callMethod.parameters; | |
| 1289 return _resolveArgumentsToParameters(false, argumentList, parameters); | |
| 1290 } | |
| 1291 } | |
| 1292 } | |
| 1293 return null; | |
| 1294 } | |
| 1295 | |
| 1296 /** | |
| 1297 * If the given [element] is a setter, return the getter associated with it. | |
| 1298 * Otherwise, return the element unchanged. | |
| 1299 */ | |
| 1300 Element _convertSetterToGetter(Element element) { | |
| 1301 // TODO(brianwilkerson) Determine whether and why the element could ever be | |
| 1302 // a setter. | |
| 1303 if (element is PropertyAccessorElement) { | |
| 1304 return element.variable.getter; | |
| 1305 } | |
| 1306 return element; | |
| 1307 } | |
| 1308 | |
| 1309 /** | |
| 1310 * Return `true` if the given [element] is not a proxy. See | |
| 1311 * [ClassElement.isOrInheritsProxy]. | |
| 1312 */ | |
| 1313 bool _doesntHaveProxy(Element element) => | |
| 1314 !(element is ClassElement && element.isOrInheritsProxy); | |
| 1315 | |
| 1316 /** | |
| 1317 * Look for any declarations of the given [identifier] that are imported using | |
| 1318 * a prefix. Return the element that was found, or `null` if the name is not | |
| 1319 * imported using a prefix. | |
| 1320 */ | |
| 1321 Element _findImportWithoutPrefix(SimpleIdentifier identifier) { | |
| 1322 Element element = null; | |
| 1323 Scope nameScope = _resolver.nameScope; | |
| 1324 for (ImportElement importElement in _definingLibrary.imports) { | |
| 1325 PrefixElement prefixElement = importElement.prefix; | |
| 1326 if (prefixElement != null) { | |
| 1327 Identifier prefixedIdentifier = new SyntheticIdentifier( | |
| 1328 "${prefixElement.name}.${identifier.name}", identifier); | |
| 1329 Element importedElement = | |
| 1330 nameScope.lookup(prefixedIdentifier, _definingLibrary); | |
| 1331 if (importedElement != null) { | |
| 1332 if (element == null) { | |
| 1333 element = importedElement; | |
| 1334 } else { | |
| 1335 element = MultiplyDefinedElementImpl.fromElements( | |
| 1336 _definingLibrary.context, element, importedElement); | |
| 1337 } | |
| 1338 } | |
| 1339 } | |
| 1340 } | |
| 1341 return element; | |
| 1342 } | |
| 1343 | |
| 1344 /** | |
| 1345 * Return the best type of the given [expression] that is to be used for | |
| 1346 * type analysis. | |
| 1347 */ | |
| 1348 DartType _getBestType(Expression expression) { | |
| 1349 DartType bestType = _resolveTypeParameter(expression.bestType); | |
| 1350 if (bestType is FunctionType) { | |
| 1351 // | |
| 1352 // All function types are subtypes of 'Function', which is itself a | |
| 1353 // subclass of 'Object'. | |
| 1354 // | |
| 1355 bestType = _resolver.typeProvider.functionType; | |
| 1356 } | |
| 1357 return bestType; | |
| 1358 } | |
| 1359 | |
| 1360 /** | |
| 1361 * Assuming that the given [expression] is a prefix for a deferred import, | |
| 1362 * return the library that is being imported. | |
| 1363 */ | |
| 1364 LibraryElement _getImportedLibrary(Expression expression) { | |
| 1365 PrefixElement prefixElement = | |
| 1366 (expression as SimpleIdentifier).staticElement as PrefixElement; | |
| 1367 List<ImportElement> imports = | |
| 1368 prefixElement.enclosingElement.getImportsWithPrefix(prefixElement); | |
| 1369 return imports[0].importedLibrary; | |
| 1370 } | |
| 1371 | |
| 1372 /** | |
| 1373 * Return the name of the method invoked by the given postfix [expression]. | |
| 1374 */ | |
| 1375 String _getPostfixOperator(PostfixExpression expression) => | |
| 1376 (expression.operator.type == sc.TokenType.PLUS_PLUS) | |
| 1377 ? sc.TokenType.PLUS.lexeme | |
| 1378 : sc.TokenType.MINUS.lexeme; | |
| 1379 | |
| 1380 /** | |
| 1381 * Return the name of the method invoked by the given postfix [expression]. | |
| 1382 */ | |
| 1383 String _getPrefixOperator(PrefixExpression expression) { | |
| 1384 sc.Token operator = expression.operator; | |
| 1385 sc.TokenType operatorType = operator.type; | |
| 1386 if (operatorType == sc.TokenType.PLUS_PLUS) { | |
| 1387 return sc.TokenType.PLUS.lexeme; | |
| 1388 } else if (operatorType == sc.TokenType.MINUS_MINUS) { | |
| 1389 return sc.TokenType.MINUS.lexeme; | |
| 1390 } else if (operatorType == sc.TokenType.MINUS) { | |
| 1391 return "unary-"; | |
| 1392 } else { | |
| 1393 return operator.lexeme; | |
| 1394 } | |
| 1395 } | |
| 1396 | |
| 1397 /** | |
| 1398 * Return the propagated type of the given [expression] that is to be used for | |
| 1399 * type analysis. | |
| 1400 */ | |
| 1401 DartType _getPropagatedType(Expression expression) { | |
| 1402 DartType propagatedType = _resolveTypeParameter(expression.propagatedType); | |
| 1403 if (propagatedType is FunctionType) { | |
| 1404 // | |
| 1405 // All function types are subtypes of 'Function', which is itself a | |
| 1406 // subclass of 'Object'. | |
| 1407 // | |
| 1408 propagatedType = _resolver.typeProvider.functionType; | |
| 1409 } | |
| 1410 return propagatedType; | |
| 1411 } | |
| 1412 | |
| 1413 /** | |
| 1414 * Return the static type of the given [expression] that is to be used for | |
| 1415 * type analysis. | |
| 1416 */ | |
| 1417 DartType _getStaticType(Expression expression) { | |
| 1418 if (expression is NullLiteral) { | |
| 1419 return _resolver.typeProvider.bottomType; | |
| 1420 } | |
| 1421 DartType staticType = _resolveTypeParameter(expression.staticType); | |
| 1422 if (staticType is FunctionType) { | |
| 1423 // | |
| 1424 // All function types are subtypes of 'Function', which is itself a | |
| 1425 // subclass of 'Object'. | |
| 1426 // | |
| 1427 staticType = _resolver.typeProvider.functionType; | |
| 1428 } | |
| 1429 return staticType; | |
| 1430 } | |
| 1431 | |
| 1432 /** | |
| 1433 * Return `true` if the given [expression] is a prefix for a deferred import. | |
| 1434 */ | |
| 1435 bool _isDeferredPrefix(Expression expression) { | |
| 1436 if (expression is! SimpleIdentifier) { | |
| 1437 return false; | |
| 1438 } | |
| 1439 Element element = (expression as SimpleIdentifier).staticElement; | |
| 1440 if (element is! PrefixElement) { | |
| 1441 return false; | |
| 1442 } | |
| 1443 PrefixElement prefixElement = element as PrefixElement; | |
| 1444 List<ImportElement> imports = | |
| 1445 prefixElement.enclosingElement.getImportsWithPrefix(prefixElement); | |
| 1446 if (imports.length != 1) { | |
| 1447 return false; | |
| 1448 } | |
| 1449 return imports[0].isDeferred; | |
| 1450 } | |
| 1451 | |
| 1452 /** | |
| 1453 * Return `true` if the given [type] represents an object that could be | |
| 1454 * invoked using the call operator '()'. | |
| 1455 */ | |
| 1456 bool _isExecutableType(DartType type) { | |
| 1457 if (type.isDynamic || type is FunctionType) { | |
| 1458 return true; | |
| 1459 } else if (!_enableStrictCallChecks && | |
| 1460 (type.isDartCoreFunction || type.isObject)) { | |
| 1461 return true; | |
| 1462 } else if (type is InterfaceType) { | |
| 1463 ClassElement classElement = type.element; | |
| 1464 // 16078 from Gilad: If the type is a Functor with the @proxy annotation, | |
| 1465 // treat it as an executable type. | |
| 1466 // example code: NonErrorResolverTest. | |
| 1467 // test_invocationOfNonFunction_proxyOnFunctionClass() | |
| 1468 if (classElement.isProxy && | |
| 1469 type.isSubtypeOf(_resolver.typeProvider.functionType)) { | |
| 1470 return true; | |
| 1471 } | |
| 1472 MethodElement methodElement = classElement.lookUpMethod( | |
| 1473 FunctionElement.CALL_METHOD_NAME, _definingLibrary); | |
| 1474 return methodElement != null; | |
| 1475 } | |
| 1476 return false; | |
| 1477 } | |
| 1478 | |
| 1479 /** | |
| 1480 * Return `true` if the given [element] is a static element. | |
| 1481 */ | |
| 1482 bool _isStatic(Element element) { | |
| 1483 if (element is ExecutableElement) { | |
| 1484 return element.isStatic; | |
| 1485 } else if (element is PropertyInducingElement) { | |
| 1486 return element.isStatic; | |
| 1487 } | |
| 1488 return false; | |
| 1489 } | |
| 1490 | |
| 1491 /** | |
| 1492 * Return `true` if the given [node] can validly be resolved to a prefix: | |
| 1493 * * it is the prefix in an import directive, or | |
| 1494 * * it is the prefix in a prefixed identifier. | |
| 1495 */ | |
| 1496 bool _isValidAsPrefix(SimpleIdentifier node) { | |
| 1497 AstNode parent = node.parent; | |
| 1498 if (parent is ImportDirective) { | |
| 1499 return identical(parent.prefix, node); | |
| 1500 } else if (parent is PrefixedIdentifier) { | |
| 1501 return true; | |
| 1502 } else if (parent is MethodInvocation) { | |
| 1503 return identical(parent.target, node); | |
| 1504 } | |
| 1505 return false; | |
| 1506 } | |
| 1507 | |
| 1508 /** | |
| 1509 * Return the target of a break or continue statement, and update the static | |
| 1510 * element of its label (if any). The [parentNode] is the AST node of the | |
| 1511 * break or continue statement. The [labelNode] is the label contained in that | |
| 1512 * statement (if any). The flag [isContinue] is `true` if the node being | |
| 1513 * visited is a continue statement. | |
| 1514 */ | |
| 1515 AstNode _lookupBreakOrContinueTarget( | |
| 1516 AstNode parentNode, SimpleIdentifier labelNode, bool isContinue) { | |
| 1517 if (labelNode == null) { | |
| 1518 return _resolver.implicitLabelScope.getTarget(isContinue); | |
| 1519 } else { | |
| 1520 LabelScope labelScope = _resolver.labelScope; | |
| 1521 if (labelScope == null) { | |
| 1522 // There are no labels in scope, so by definition the label is | |
| 1523 // undefined. | |
| 1524 _resolver.reportErrorForNode( | |
| 1525 CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]); | |
| 1526 return null; | |
| 1527 } | |
| 1528 LabelScope definingScope = labelScope.lookup(labelNode.name); | |
| 1529 if (definingScope == null) { | |
| 1530 // No definition of the given label name could be found in any | |
| 1531 // enclosing scope. | |
| 1532 _resolver.reportErrorForNode( | |
| 1533 CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]); | |
| 1534 return null; | |
| 1535 } | |
| 1536 // The target has been found. | |
| 1537 labelNode.staticElement = definingScope.element; | |
| 1538 ExecutableElement labelContainer = definingScope.element | |
| 1539 .getAncestor((element) => element is ExecutableElement); | |
| 1540 if (!identical(labelContainer, _resolver.enclosingFunction)) { | |
| 1541 _resolver.reportErrorForNode(CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE, | |
| 1542 labelNode, [labelNode.name]); | |
| 1543 } | |
| 1544 return definingScope.node; | |
| 1545 } | |
| 1546 } | |
| 1547 | |
| 1548 /** | |
| 1549 * Look up the getter with the given [getterName] in the given [type]. Return | |
| 1550 * the element representing the getter that was found, or `null` if there is | |
| 1551 * no getter with the given name. The [target] is the target of the | |
| 1552 * invocation, or `null` if there is no target. | |
| 1553 */ | |
| 1554 PropertyAccessorElement _lookUpGetter( | |
| 1555 Expression target, DartType type, String getterName) { | |
| 1556 type = _resolveTypeParameter(type); | |
| 1557 if (type is InterfaceType) { | |
| 1558 InterfaceType interfaceType = type; | |
| 1559 PropertyAccessorElement accessor; | |
| 1560 if (target is SuperExpression) { | |
| 1561 accessor = interfaceType.lookUpGetterInSuperclass( | |
| 1562 getterName, _definingLibrary); | |
| 1563 } else { | |
| 1564 accessor = interfaceType.lookUpGetter(getterName, _definingLibrary); | |
| 1565 } | |
| 1566 if (accessor != null) { | |
| 1567 return accessor; | |
| 1568 } | |
| 1569 return _lookUpGetterInInterfaces( | |
| 1570 interfaceType, false, getterName, new HashSet<ClassElement>()); | |
| 1571 } | |
| 1572 return null; | |
| 1573 } | |
| 1574 | |
| 1575 /** | |
| 1576 * Look up the getter with the given [getterName] in the interfaces | |
| 1577 * implemented by the given [targetType], either directly or indirectly. | |
| 1578 * Return the element representing the getter that was found, or `null` if | |
| 1579 * there is no getter with the given name. The flag [includeTargetType] should | |
| 1580 * be `true` if the search should include the target type. The | |
| 1581 * [visitedInterfaces] is a set containing all of the interfaces that have | |
| 1582 * been examined, used to prevent infinite recursion and to optimize the | |
| 1583 * search. | |
| 1584 */ | |
| 1585 PropertyAccessorElement _lookUpGetterInInterfaces(InterfaceType targetType, | |
| 1586 bool includeTargetType, String getterName, | |
| 1587 HashSet<ClassElement> visitedInterfaces) { | |
| 1588 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the | |
| 1589 // specification (titled "Inheritance and Overriding" under "Interfaces") | |
| 1590 // describes a much more complex scheme for finding the inherited member. | |
| 1591 // We need to follow that scheme. The code below should cover the 80% case. | |
| 1592 ClassElement targetClass = targetType.element; | |
| 1593 if (visitedInterfaces.contains(targetClass)) { | |
| 1594 return null; | |
| 1595 } | |
| 1596 visitedInterfaces.add(targetClass); | |
| 1597 if (includeTargetType) { | |
| 1598 PropertyAccessorElement getter = targetType.getGetter(getterName); | |
| 1599 if (getter != null && getter.isAccessibleIn(_definingLibrary)) { | |
| 1600 return getter; | |
| 1601 } | |
| 1602 } | |
| 1603 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 1604 PropertyAccessorElement getter = _lookUpGetterInInterfaces( | |
| 1605 interfaceType, true, getterName, visitedInterfaces); | |
| 1606 if (getter != null) { | |
| 1607 return getter; | |
| 1608 } | |
| 1609 } | |
| 1610 for (InterfaceType mixinType in targetType.mixins.reversed) { | |
| 1611 PropertyAccessorElement getter = _lookUpGetterInInterfaces( | |
| 1612 mixinType, true, getterName, visitedInterfaces); | |
| 1613 if (getter != null) { | |
| 1614 return getter; | |
| 1615 } | |
| 1616 } | |
| 1617 InterfaceType superclass = targetType.superclass; | |
| 1618 if (superclass == null) { | |
| 1619 return null; | |
| 1620 } | |
| 1621 return _lookUpGetterInInterfaces( | |
| 1622 superclass, true, getterName, visitedInterfaces); | |
| 1623 } | |
| 1624 | |
| 1625 /** | |
| 1626 * Look up the method or getter with the given [memberName] in the given | |
| 1627 * [type]. Return the element representing the method or getter that was | |
| 1628 * found, or `null` if there is no method or getter with the given name. | |
| 1629 */ | |
| 1630 ExecutableElement _lookupGetterOrMethod(DartType type, String memberName) { | |
| 1631 type = _resolveTypeParameter(type); | |
| 1632 if (type is InterfaceType) { | |
| 1633 InterfaceType interfaceType = type; | |
| 1634 ExecutableElement member = | |
| 1635 interfaceType.lookUpMethod(memberName, _definingLibrary); | |
| 1636 if (member != null) { | |
| 1637 return member; | |
| 1638 } | |
| 1639 member = interfaceType.lookUpGetter(memberName, _definingLibrary); | |
| 1640 if (member != null) { | |
| 1641 return member; | |
| 1642 } | |
| 1643 return _lookUpGetterOrMethodInInterfaces( | |
| 1644 interfaceType, false, memberName, new HashSet<ClassElement>()); | |
| 1645 } | |
| 1646 return null; | |
| 1647 } | |
| 1648 | |
| 1649 /** | |
| 1650 * Look up the method or getter with the given [memberName] in the interfaces | |
| 1651 * implemented by the given [targetType], either directly or indirectly. | |
| 1652 * Return the element representing the method or getter that was found, or | |
| 1653 * `null` if there is no method or getter with the given name. The flag | |
| 1654 * [includeTargetType] should be `true` if the search should include the | |
| 1655 * target type. The [visitedInterfaces] is a set containing all of the | |
| 1656 * interfaces that have been examined, used to prevent infinite recursion and | |
| 1657 * to optimize the search. | |
| 1658 */ | |
| 1659 ExecutableElement _lookUpGetterOrMethodInInterfaces(InterfaceType targetType, | |
| 1660 bool includeTargetType, String memberName, | |
| 1661 HashSet<ClassElement> visitedInterfaces) { | |
| 1662 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the | |
| 1663 // specification (titled "Inheritance and Overriding" under "Interfaces") | |
| 1664 // describes a much more complex scheme for finding the inherited member. | |
| 1665 // We need to follow that scheme. The code below should cover the 80% case. | |
| 1666 ClassElement targetClass = targetType.element; | |
| 1667 if (visitedInterfaces.contains(targetClass)) { | |
| 1668 return null; | |
| 1669 } | |
| 1670 visitedInterfaces.add(targetClass); | |
| 1671 if (includeTargetType) { | |
| 1672 ExecutableElement member = targetType.getMethod(memberName); | |
| 1673 if (member != null) { | |
| 1674 return member; | |
| 1675 } | |
| 1676 member = targetType.getGetter(memberName); | |
| 1677 if (member != null) { | |
| 1678 return member; | |
| 1679 } | |
| 1680 } | |
| 1681 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 1682 ExecutableElement member = _lookUpGetterOrMethodInInterfaces( | |
| 1683 interfaceType, true, memberName, visitedInterfaces); | |
| 1684 if (member != null) { | |
| 1685 return member; | |
| 1686 } | |
| 1687 } | |
| 1688 for (InterfaceType mixinType in targetType.mixins.reversed) { | |
| 1689 ExecutableElement member = _lookUpGetterOrMethodInInterfaces( | |
| 1690 mixinType, true, memberName, visitedInterfaces); | |
| 1691 if (member != null) { | |
| 1692 return member; | |
| 1693 } | |
| 1694 } | |
| 1695 InterfaceType superclass = targetType.superclass; | |
| 1696 if (superclass == null) { | |
| 1697 return null; | |
| 1698 } | |
| 1699 return _lookUpGetterOrMethodInInterfaces( | |
| 1700 superclass, true, memberName, visitedInterfaces); | |
| 1701 } | |
| 1702 | |
| 1703 /** | |
| 1704 * Look up the method with the given [methodName] in the given [type]. Return | |
| 1705 * the element representing the method that was found, or `null` if there is | |
| 1706 * no method with the given name. The [target] is the target of the | |
| 1707 * invocation, or `null` if there is no target. | |
| 1708 */ | |
| 1709 MethodElement _lookUpMethod( | |
| 1710 Expression target, DartType type, String methodName) { | |
| 1711 type = _resolveTypeParameter(type); | |
| 1712 if (type is InterfaceType) { | |
| 1713 InterfaceType interfaceType = type; | |
| 1714 MethodElement method; | |
| 1715 if (target is SuperExpression) { | |
| 1716 method = interfaceType.lookUpMethodInSuperclass( | |
| 1717 methodName, _definingLibrary); | |
| 1718 } else { | |
| 1719 method = interfaceType.lookUpMethod(methodName, _definingLibrary); | |
| 1720 } | |
| 1721 if (method != null) { | |
| 1722 return method; | |
| 1723 } | |
| 1724 return _lookUpMethodInInterfaces( | |
| 1725 interfaceType, false, methodName, new HashSet<ClassElement>()); | |
| 1726 } | |
| 1727 return null; | |
| 1728 } | |
| 1729 | |
| 1730 /** | |
| 1731 * Look up the method with the given [methodName] in the interfaces | |
| 1732 * implemented by the given [targetType], either directly or indirectly. | |
| 1733 * Return the element representing the method that was found, or `null` if | |
| 1734 * there is no method with the given name. The flag [includeTargetType] should | |
| 1735 * be `true` if the search should include the target type. The | |
| 1736 * [visitedInterfaces] is a set containing all of the interfaces that have | |
| 1737 * been examined, used to prevent infinite recursion and to optimize the | |
| 1738 * search. | |
| 1739 */ | |
| 1740 MethodElement _lookUpMethodInInterfaces(InterfaceType targetType, | |
| 1741 bool includeTargetType, String methodName, | |
| 1742 HashSet<ClassElement> visitedInterfaces) { | |
| 1743 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the | |
| 1744 // specification (titled "Inheritance and Overriding" under "Interfaces") | |
| 1745 // describes a much more complex scheme for finding the inherited member. | |
| 1746 // We need to follow that scheme. The code below should cover the 80% case. | |
| 1747 ClassElement targetClass = targetType.element; | |
| 1748 if (visitedInterfaces.contains(targetClass)) { | |
| 1749 return null; | |
| 1750 } | |
| 1751 visitedInterfaces.add(targetClass); | |
| 1752 if (includeTargetType) { | |
| 1753 MethodElement method = targetType.getMethod(methodName); | |
| 1754 if (method != null && method.isAccessibleIn(_definingLibrary)) { | |
| 1755 return method; | |
| 1756 } | |
| 1757 } | |
| 1758 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 1759 MethodElement method = _lookUpMethodInInterfaces( | |
| 1760 interfaceType, true, methodName, visitedInterfaces); | |
| 1761 if (method != null) { | |
| 1762 return method; | |
| 1763 } | |
| 1764 } | |
| 1765 for (InterfaceType mixinType in targetType.mixins.reversed) { | |
| 1766 MethodElement method = _lookUpMethodInInterfaces( | |
| 1767 mixinType, true, methodName, visitedInterfaces); | |
| 1768 if (method != null) { | |
| 1769 return method; | |
| 1770 } | |
| 1771 } | |
| 1772 InterfaceType superclass = targetType.superclass; | |
| 1773 if (superclass == null) { | |
| 1774 return null; | |
| 1775 } | |
| 1776 return _lookUpMethodInInterfaces( | |
| 1777 superclass, true, methodName, visitedInterfaces); | |
| 1778 } | |
| 1779 | |
| 1780 /** | |
| 1781 * Look up the setter with the given [setterName] in the given [type]. Return | |
| 1782 * the element representing the setter that was found, or `null` if there is | |
| 1783 * no setter with the given name. The [target] is the target of the | |
| 1784 * invocation, or `null` if there is no target. | |
| 1785 */ | |
| 1786 PropertyAccessorElement _lookUpSetter( | |
| 1787 Expression target, DartType type, String setterName) { | |
| 1788 type = _resolveTypeParameter(type); | |
| 1789 if (type is InterfaceType) { | |
| 1790 InterfaceType interfaceType = type; | |
| 1791 PropertyAccessorElement accessor; | |
| 1792 if (target is SuperExpression) { | |
| 1793 accessor = interfaceType.lookUpSetterInSuperclass( | |
| 1794 setterName, _definingLibrary); | |
| 1795 } else { | |
| 1796 accessor = interfaceType.lookUpSetter(setterName, _definingLibrary); | |
| 1797 } | |
| 1798 if (accessor != null) { | |
| 1799 return accessor; | |
| 1800 } | |
| 1801 return _lookUpSetterInInterfaces( | |
| 1802 interfaceType, false, setterName, new HashSet<ClassElement>()); | |
| 1803 } | |
| 1804 return null; | |
| 1805 } | |
| 1806 | |
| 1807 /** | |
| 1808 * Look up the setter with the given [setterName] in the interfaces | |
| 1809 * implemented by the given [targetType], either directly or indirectly. | |
| 1810 * Return the element representing the setter that was found, or `null` if | |
| 1811 * there is no setter with the given name. The [targetType] is the type in | |
| 1812 * which the setter might be defined. The flag [includeTargetType] should be | |
| 1813 * `true` if the search should include the target type. The | |
| 1814 * [visitedInterfaces] is a set containing all of the interfaces that have | |
| 1815 * been examined, used to prevent infinite recursion and to optimize the | |
| 1816 * search. | |
| 1817 */ | |
| 1818 PropertyAccessorElement _lookUpSetterInInterfaces(InterfaceType targetType, | |
| 1819 bool includeTargetType, String setterName, | |
| 1820 HashSet<ClassElement> visitedInterfaces) { | |
| 1821 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the | |
| 1822 // specification (titled "Inheritance and Overriding" under "Interfaces") | |
| 1823 // describes a much more complex scheme for finding the inherited member. | |
| 1824 // We need to follow that scheme. The code below should cover the 80% case. | |
| 1825 ClassElement targetClass = targetType.element; | |
| 1826 if (visitedInterfaces.contains(targetClass)) { | |
| 1827 return null; | |
| 1828 } | |
| 1829 visitedInterfaces.add(targetClass); | |
| 1830 if (includeTargetType) { | |
| 1831 PropertyAccessorElement setter = targetType.getSetter(setterName); | |
| 1832 if (setter != null && setter.isAccessibleIn(_definingLibrary)) { | |
| 1833 return setter; | |
| 1834 } | |
| 1835 } | |
| 1836 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 1837 PropertyAccessorElement setter = _lookUpSetterInInterfaces( | |
| 1838 interfaceType, true, setterName, visitedInterfaces); | |
| 1839 if (setter != null) { | |
| 1840 return setter; | |
| 1841 } | |
| 1842 } | |
| 1843 for (InterfaceType mixinType in targetType.mixins.reversed) { | |
| 1844 PropertyAccessorElement setter = _lookUpSetterInInterfaces( | |
| 1845 mixinType, true, setterName, visitedInterfaces); | |
| 1846 if (setter != null) { | |
| 1847 return setter; | |
| 1848 } | |
| 1849 } | |
| 1850 InterfaceType superclass = targetType.superclass; | |
| 1851 if (superclass == null) { | |
| 1852 return null; | |
| 1853 } | |
| 1854 return _lookUpSetterInInterfaces( | |
| 1855 superclass, true, setterName, visitedInterfaces); | |
| 1856 } | |
| 1857 | |
| 1858 /** | |
| 1859 * Given some class [element], this method uses [_subtypeManager] to find the | |
| 1860 * set of all subtypes; the subtypes are then searched for a member (method, | |
| 1861 * getter, or setter), that has the given [memberName]. The flag [asMethod] | |
| 1862 * should be `true` if the methods should be searched for in the subtypes. The | |
| 1863 * flag [asAccessor] should be `true` if the accessors (getters and setters) | |
| 1864 * should be searched for in the subtypes. | |
| 1865 */ | |
| 1866 bool _memberFoundInSubclass( | |
| 1867 Element element, String memberName, bool asMethod, bool asAccessor) { | |
| 1868 if (element is ClassElement) { | |
| 1869 _subtypeManager.ensureLibraryVisited(_definingLibrary); | |
| 1870 HashSet<ClassElement> subtypeElements = | |
| 1871 _subtypeManager.computeAllSubtypes(element); | |
| 1872 for (ClassElement subtypeElement in subtypeElements) { | |
| 1873 if (asMethod && subtypeElement.getMethod(memberName) != null) { | |
| 1874 return true; | |
| 1875 } else if (asAccessor && | |
| 1876 (subtypeElement.getGetter(memberName) != null || | |
| 1877 subtypeElement.getSetter(memberName) != null)) { | |
| 1878 return true; | |
| 1879 } | |
| 1880 } | |
| 1881 } | |
| 1882 return false; | |
| 1883 } | |
| 1884 | |
| 1885 /** | |
| 1886 * Return the binary operator that is invoked by the given compound assignment | |
| 1887 * [operator]. | |
| 1888 */ | |
| 1889 sc.TokenType _operatorFromCompoundAssignment(sc.TokenType operator) { | |
| 1890 while (true) { | |
| 1891 if (operator == sc.TokenType.AMPERSAND_EQ) { | |
| 1892 return sc.TokenType.AMPERSAND; | |
| 1893 } else if (operator == sc.TokenType.BAR_EQ) { | |
| 1894 return sc.TokenType.BAR; | |
| 1895 } else if (operator == sc.TokenType.CARET_EQ) { | |
| 1896 return sc.TokenType.CARET; | |
| 1897 } else if (operator == sc.TokenType.GT_GT_EQ) { | |
| 1898 return sc.TokenType.GT_GT; | |
| 1899 } else if (operator == sc.TokenType.LT_LT_EQ) { | |
| 1900 return sc.TokenType.LT_LT; | |
| 1901 } else if (operator == sc.TokenType.MINUS_EQ) { | |
| 1902 return sc.TokenType.MINUS; | |
| 1903 } else if (operator == sc.TokenType.PERCENT_EQ) { | |
| 1904 return sc.TokenType.PERCENT; | |
| 1905 } else if (operator == sc.TokenType.PLUS_EQ) { | |
| 1906 return sc.TokenType.PLUS; | |
| 1907 } else if (operator == sc.TokenType.SLASH_EQ) { | |
| 1908 return sc.TokenType.SLASH; | |
| 1909 } else if (operator == sc.TokenType.STAR_EQ) { | |
| 1910 return sc.TokenType.STAR; | |
| 1911 } else if (operator == sc.TokenType.TILDE_SLASH_EQ) { | |
| 1912 return sc.TokenType.TILDE_SLASH; | |
| 1913 } else { | |
| 1914 // Internal error: Unmapped assignment operator. | |
| 1915 AnalysisEngine.instance.logger.logError( | |
| 1916 "Failed to map ${operator.lexeme} to it's corresponding operator"); | |
| 1917 return operator; | |
| 1918 } | |
| 1919 break; | |
| 1920 } | |
| 1921 } | |
| 1922 | |
| 1923 /** | |
| 1924 * Record that the given [node] is undefined, causing an error to be reported | |
| 1925 * if appropriate. The [declaringElement] is the element inside which no | |
| 1926 * declaration was found. If this element is a proxy, no error will be | |
| 1927 * reported. If null, then an error will always be reported. The [errorCode] | |
| 1928 * is the error code to report. The [arguments] are the arguments to the error | |
| 1929 * message. | |
| 1930 */ | |
| 1931 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode, | |
| 1932 AstNode node, List<Object> arguments) { | |
| 1933 if (_doesntHaveProxy(declaringElement)) { | |
| 1934 _resolver.reportErrorForNode(errorCode, node, arguments); | |
| 1935 } | |
| 1936 } | |
| 1937 | |
| 1938 /** | |
| 1939 * Record that the given [offset]/[length] is undefined, causing an error to | |
| 1940 * be reported if appropriate. The [declaringElement] is the element inside | |
| 1941 * which no declaration was found. If this element is a proxy, no error will | |
| 1942 * be reported. If null, then an error will always be reported. The | |
| 1943 * [errorCode] is the error code to report. The [arguments] are arguments to | |
| 1944 * the error message. | |
| 1945 */ | |
| 1946 void _recordUndefinedOffset(Element declaringElement, ErrorCode errorCode, | |
| 1947 int offset, int length, List<Object> arguments) { | |
| 1948 if (_doesntHaveProxy(declaringElement)) { | |
| 1949 _resolver.reportErrorForOffset(errorCode, offset, length, arguments); | |
| 1950 } | |
| 1951 } | |
| 1952 | |
| 1953 /** | |
| 1954 * Record that the given [token] is undefined, causing an error to be reported | |
| 1955 * if appropriate. The [declaringElement] is the element inside which no | |
| 1956 * declaration was found. If this element is a proxy, no error will be | |
| 1957 * reported. If null, then an error will always be reported. The [errorCode] | |
| 1958 * is the error code to report. The [arguments] are arguments to the error | |
| 1959 * message. | |
| 1960 */ | |
| 1961 void _recordUndefinedToken(Element declaringElement, ErrorCode errorCode, | |
| 1962 sc.Token token, List<Object> arguments) { | |
| 1963 if (_doesntHaveProxy(declaringElement)) { | |
| 1964 _resolver.reportErrorForToken(errorCode, token, arguments); | |
| 1965 } | |
| 1966 } | |
| 1967 | |
| 1968 void _resolveAnnotationConstructorInvocationArguments( | |
| 1969 Annotation annotation, ConstructorElement constructor) { | |
| 1970 ArgumentList argumentList = annotation.arguments; | |
| 1971 // error will be reported in ConstantVerifier | |
| 1972 if (argumentList == null) { | |
| 1973 return; | |
| 1974 } | |
| 1975 // resolve arguments to parameters | |
| 1976 List<ParameterElement> parameters = | |
| 1977 _resolveArgumentsToFunction(true, argumentList, constructor); | |
| 1978 if (parameters != null) { | |
| 1979 argumentList.correspondingStaticParameters = parameters; | |
| 1980 } | |
| 1981 } | |
| 1982 | |
| 1983 /** | |
| 1984 * Continues resolution of the given [annotation]. | |
| 1985 */ | |
| 1986 void _resolveAnnotationElement(Annotation annotation) { | |
| 1987 SimpleIdentifier nameNode1; | |
| 1988 SimpleIdentifier nameNode2; | |
| 1989 { | |
| 1990 Identifier annName = annotation.name; | |
| 1991 if (annName is PrefixedIdentifier) { | |
| 1992 PrefixedIdentifier prefixed = annName; | |
| 1993 nameNode1 = prefixed.prefix; | |
| 1994 nameNode2 = prefixed.identifier; | |
| 1995 } else { | |
| 1996 nameNode1 = annName as SimpleIdentifier; | |
| 1997 nameNode2 = null; | |
| 1998 } | |
| 1999 } | |
| 2000 SimpleIdentifier nameNode3 = annotation.constructorName; | |
| 2001 ConstructorElement constructor = null; | |
| 2002 // | |
| 2003 // CONST or Class(args) | |
| 2004 // | |
| 2005 if (nameNode1 != null && nameNode2 == null && nameNode3 == null) { | |
| 2006 Element element1 = nameNode1.staticElement; | |
| 2007 // CONST | |
| 2008 if (element1 is PropertyAccessorElement) { | |
| 2009 _resolveAnnotationElementGetter(annotation, element1); | |
| 2010 return; | |
| 2011 } | |
| 2012 // Class(args) | |
| 2013 if (element1 is ClassElement) { | |
| 2014 ClassElement classElement = element1; | |
| 2015 constructor = new InterfaceTypeImpl(classElement).lookUpConstructor( | |
| 2016 null, _definingLibrary); | |
| 2017 } | |
| 2018 } | |
| 2019 // | |
| 2020 // prefix.CONST or prefix.Class() or Class.CONST or Class.constructor(args) | |
| 2021 // | |
| 2022 if (nameNode1 != null && nameNode2 != null && nameNode3 == null) { | |
| 2023 Element element1 = nameNode1.staticElement; | |
| 2024 Element element2 = nameNode2.staticElement; | |
| 2025 // Class.CONST - not resolved yet | |
| 2026 if (element1 is ClassElement) { | |
| 2027 ClassElement classElement = element1; | |
| 2028 element2 = classElement.lookUpGetter(nameNode2.name, _definingLibrary); | |
| 2029 } | |
| 2030 // prefix.CONST or Class.CONST | |
| 2031 if (element2 is PropertyAccessorElement) { | |
| 2032 nameNode2.staticElement = element2; | |
| 2033 annotation.element = element2; | |
| 2034 _resolveAnnotationElementGetter(annotation, element2); | |
| 2035 return; | |
| 2036 } | |
| 2037 // prefix.Class() | |
| 2038 if (element2 is ClassElement) { | |
| 2039 constructor = element2.unnamedConstructor; | |
| 2040 } | |
| 2041 // Class.constructor(args) | |
| 2042 if (element1 is ClassElement) { | |
| 2043 ClassElement classElement = element1; | |
| 2044 constructor = new InterfaceTypeImpl(classElement).lookUpConstructor( | |
| 2045 nameNode2.name, _definingLibrary); | |
| 2046 nameNode2.staticElement = constructor; | |
| 2047 } | |
| 2048 } | |
| 2049 // | |
| 2050 // prefix.Class.CONST or prefix.Class.constructor(args) | |
| 2051 // | |
| 2052 if (nameNode1 != null && nameNode2 != null && nameNode3 != null) { | |
| 2053 Element element2 = nameNode2.staticElement; | |
| 2054 // element2 should be ClassElement | |
| 2055 if (element2 is ClassElement) { | |
| 2056 ClassElement classElement = element2; | |
| 2057 String name3 = nameNode3.name; | |
| 2058 // prefix.Class.CONST | |
| 2059 PropertyAccessorElement getter = | |
| 2060 classElement.lookUpGetter(name3, _definingLibrary); | |
| 2061 if (getter != null) { | |
| 2062 nameNode3.staticElement = getter; | |
| 2063 annotation.element = element2; | |
| 2064 _resolveAnnotationElementGetter(annotation, getter); | |
| 2065 return; | |
| 2066 } | |
| 2067 // prefix.Class.constructor(args) | |
| 2068 constructor = new InterfaceTypeImpl(classElement).lookUpConstructor( | |
| 2069 name3, _definingLibrary); | |
| 2070 nameNode3.staticElement = constructor; | |
| 2071 } | |
| 2072 } | |
| 2073 // we need constructor | |
| 2074 if (constructor == null) { | |
| 2075 _resolver.reportErrorForNode( | |
| 2076 CompileTimeErrorCode.INVALID_ANNOTATION, annotation); | |
| 2077 return; | |
| 2078 } | |
| 2079 // record element | |
| 2080 annotation.element = constructor; | |
| 2081 // resolve arguments | |
| 2082 _resolveAnnotationConstructorInvocationArguments(annotation, constructor); | |
| 2083 } | |
| 2084 | |
| 2085 void _resolveAnnotationElementGetter( | |
| 2086 Annotation annotation, PropertyAccessorElement accessorElement) { | |
| 2087 // accessor should be synthetic | |
| 2088 if (!accessorElement.isSynthetic) { | |
| 2089 _resolver.reportErrorForNode( | |
| 2090 CompileTimeErrorCode.INVALID_ANNOTATION, annotation); | |
| 2091 return; | |
| 2092 } | |
| 2093 // variable should be constant | |
| 2094 VariableElement variableElement = accessorElement.variable; | |
| 2095 if (!variableElement.isConst) { | |
| 2096 _resolver.reportErrorForNode( | |
| 2097 CompileTimeErrorCode.INVALID_ANNOTATION, annotation); | |
| 2098 } | |
| 2099 // OK | |
| 2100 return; | |
| 2101 } | |
| 2102 | |
| 2103 /** | |
| 2104 * Given an [argumentList] and the [executableElement] that will be invoked | |
| 2105 * using those argument, compute the list of parameters that correspond to the | |
| 2106 * list of arguments. An error will be reported if any of the arguments cannot | |
| 2107 * be matched to a parameter. The flag [reportError] should be `true` if a | |
| 2108 * compile-time error should be reported; or `false` if a compile-time warning | |
| 2109 * should be reported. Return the parameters that correspond to the arguments, | |
| 2110 * or `null` if no correspondence could be computed. | |
| 2111 */ | |
| 2112 List<ParameterElement> _resolveArgumentsToFunction(bool reportError, | |
| 2113 ArgumentList argumentList, ExecutableElement executableElement) { | |
| 2114 if (executableElement == null) { | |
| 2115 return null; | |
| 2116 } | |
| 2117 List<ParameterElement> parameters = executableElement.parameters; | |
| 2118 return _resolveArgumentsToParameters(reportError, argumentList, parameters); | |
| 2119 } | |
| 2120 | |
| 2121 /** | |
| 2122 * Given an [argumentList] and the [parameters] related to the element that | |
| 2123 * will be invoked using those arguments, compute the list of parameters that | |
| 2124 * correspond to the list of arguments. An error will be reported if any of | |
| 2125 * the arguments cannot be matched to a parameter. The flag [reportError] | |
| 2126 * should be `true` if a compile-time error should be reported; or `false` if | |
| 2127 * a compile-time warning should be reported. Return the parameters that | |
| 2128 * correspond to the arguments. | |
| 2129 */ | |
| 2130 List<ParameterElement> _resolveArgumentsToParameters(bool reportError, | |
| 2131 ArgumentList argumentList, List<ParameterElement> parameters) { | |
| 2132 List<ParameterElement> requiredParameters = new List<ParameterElement>(); | |
| 2133 List<ParameterElement> positionalParameters = new List<ParameterElement>(); | |
| 2134 HashMap<String, ParameterElement> namedParameters = | |
| 2135 new HashMap<String, ParameterElement>(); | |
| 2136 for (ParameterElement parameter in parameters) { | |
| 2137 ParameterKind kind = parameter.parameterKind; | |
| 2138 if (kind == ParameterKind.REQUIRED) { | |
| 2139 requiredParameters.add(parameter); | |
| 2140 } else if (kind == ParameterKind.POSITIONAL) { | |
| 2141 positionalParameters.add(parameter); | |
| 2142 } else { | |
| 2143 namedParameters[parameter.name] = parameter; | |
| 2144 } | |
| 2145 } | |
| 2146 List<ParameterElement> unnamedParameters = | |
| 2147 new List<ParameterElement>.from(requiredParameters); | |
| 2148 unnamedParameters.addAll(positionalParameters); | |
| 2149 int unnamedParameterCount = unnamedParameters.length; | |
| 2150 int unnamedIndex = 0; | |
| 2151 NodeList<Expression> arguments = argumentList.arguments; | |
| 2152 int argumentCount = arguments.length; | |
| 2153 List<ParameterElement> resolvedParameters = | |
| 2154 new List<ParameterElement>(argumentCount); | |
| 2155 int positionalArgumentCount = 0; | |
| 2156 HashSet<String> usedNames = new HashSet<String>(); | |
| 2157 bool noBlankArguments = true; | |
| 2158 for (int i = 0; i < argumentCount; i++) { | |
| 2159 Expression argument = arguments[i]; | |
| 2160 if (argument is NamedExpression) { | |
| 2161 SimpleIdentifier nameNode = argument.name.label; | |
| 2162 String name = nameNode.name; | |
| 2163 ParameterElement element = namedParameters[name]; | |
| 2164 if (element == null) { | |
| 2165 ErrorCode errorCode = (reportError | |
| 2166 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER | |
| 2167 : StaticWarningCode.UNDEFINED_NAMED_PARAMETER); | |
| 2168 _resolver.reportErrorForNode(errorCode, nameNode, [name]); | |
| 2169 } else { | |
| 2170 resolvedParameters[i] = element; | |
| 2171 nameNode.staticElement = element; | |
| 2172 } | |
| 2173 if (!usedNames.add(name)) { | |
| 2174 _resolver.reportErrorForNode( | |
| 2175 CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]); | |
| 2176 } | |
| 2177 } else { | |
| 2178 if (argument is SimpleIdentifier && argument.name.isEmpty) { | |
| 2179 noBlankArguments = false; | |
| 2180 } | |
| 2181 positionalArgumentCount++; | |
| 2182 if (unnamedIndex < unnamedParameterCount) { | |
| 2183 resolvedParameters[i] = unnamedParameters[unnamedIndex++]; | |
| 2184 } | |
| 2185 } | |
| 2186 } | |
| 2187 if (positionalArgumentCount < requiredParameters.length && | |
| 2188 noBlankArguments) { | |
| 2189 ErrorCode errorCode = (reportError | |
| 2190 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS | |
| 2191 : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS); | |
| 2192 _resolver.reportErrorForNode(errorCode, argumentList, [ | |
| 2193 requiredParameters.length, | |
| 2194 positionalArgumentCount | |
| 2195 ]); | |
| 2196 } else if (positionalArgumentCount > unnamedParameterCount && | |
| 2197 noBlankArguments) { | |
| 2198 ErrorCode errorCode = (reportError | |
| 2199 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS | |
| 2200 : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS); | |
| 2201 _resolver.reportErrorForNode(errorCode, argumentList, [ | |
| 2202 unnamedParameterCount, | |
| 2203 positionalArgumentCount | |
| 2204 ]); | |
| 2205 } | |
| 2206 return resolvedParameters; | |
| 2207 } | |
| 2208 | |
| 2209 void _resolveBinaryExpression(BinaryExpression node, String methodName) { | |
| 2210 Expression leftOperand = node.leftOperand; | |
| 2211 if (leftOperand != null) { | |
| 2212 DartType staticType = _getStaticType(leftOperand); | |
| 2213 MethodElement staticMethod = | |
| 2214 _lookUpMethod(leftOperand, staticType, methodName); | |
| 2215 node.staticElement = staticMethod; | |
| 2216 DartType propagatedType = _getPropagatedType(leftOperand); | |
| 2217 MethodElement propagatedMethod = | |
| 2218 _lookUpMethod(leftOperand, propagatedType, methodName); | |
| 2219 node.propagatedElement = propagatedMethod; | |
| 2220 if (_shouldReportMissingMember(staticType, staticMethod)) { | |
| 2221 if (leftOperand is SuperExpression) { | |
| 2222 _recordUndefinedToken(staticType.element, | |
| 2223 StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, node.operator, [ | |
| 2224 methodName, | |
| 2225 staticType.displayName | |
| 2226 ]); | |
| 2227 } else { | |
| 2228 _recordUndefinedToken(staticType.element, | |
| 2229 StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [ | |
| 2230 methodName, | |
| 2231 staticType.displayName | |
| 2232 ]); | |
| 2233 } | |
| 2234 } else if (_enableHints && | |
| 2235 _shouldReportMissingMember(propagatedType, propagatedMethod) && | |
| 2236 !_memberFoundInSubclass( | |
| 2237 propagatedType.element, methodName, true, false)) { | |
| 2238 _recordUndefinedToken(propagatedType.element, | |
| 2239 HintCode.UNDEFINED_OPERATOR, node.operator, [ | |
| 2240 methodName, | |
| 2241 propagatedType.displayName | |
| 2242 ]); | |
| 2243 } | |
| 2244 } | |
| 2245 } | |
| 2246 | |
| 2247 /** | |
| 2248 * Resolve the names in the given [combinators] in the scope of the given | |
| 2249 * [library]. | |
| 2250 */ | |
| 2251 void _resolveCombinators( | |
| 2252 LibraryElement library, NodeList<Combinator> combinators) { | |
| 2253 if (library == null) { | |
| 2254 // | |
| 2255 // The library will be null if the directive containing the combinators | |
| 2256 // has a URI that is not valid. | |
| 2257 // | |
| 2258 return; | |
| 2259 } | |
| 2260 Namespace namespace = | |
| 2261 new NamespaceBuilder().createExportNamespaceForLibrary(library); | |
| 2262 for (Combinator combinator in combinators) { | |
| 2263 NodeList<SimpleIdentifier> names; | |
| 2264 if (combinator is HideCombinator) { | |
| 2265 names = combinator.hiddenNames; | |
| 2266 } else { | |
| 2267 names = (combinator as ShowCombinator).shownNames; | |
| 2268 } | |
| 2269 for (SimpleIdentifier name in names) { | |
| 2270 String nameStr = name.name; | |
| 2271 Element element = namespace.get(nameStr); | |
| 2272 if (element == null) { | |
| 2273 element = namespace.get("$nameStr="); | |
| 2274 } | |
| 2275 if (element != null) { | |
| 2276 // Ensure that the name always resolves to a top-level variable | |
| 2277 // rather than a getter or setter | |
| 2278 if (element is PropertyAccessorElement) { | |
| 2279 element = (element as PropertyAccessorElement).variable; | |
| 2280 } | |
| 2281 name.staticElement = element; | |
| 2282 } | |
| 2283 } | |
| 2284 } | |
| 2285 } | |
| 2286 | |
| 2287 /** | |
| 2288 * Given that we are accessing a property of the given [classElement] with the | |
| 2289 * given [propertyName], return the element that represents the property. | |
| 2290 */ | |
| 2291 Element _resolveElement( | |
| 2292 ClassElementImpl classElement, SimpleIdentifier propertyName) { | |
| 2293 String name = propertyName.name; | |
| 2294 Element element = null; | |
| 2295 if (propertyName.inSetterContext()) { | |
| 2296 element = classElement.getSetter(name); | |
| 2297 } | |
| 2298 if (element == null) { | |
| 2299 element = classElement.getGetter(name); | |
| 2300 } | |
| 2301 if (element == null) { | |
| 2302 element = classElement.getMethod(name); | |
| 2303 } | |
| 2304 if (element != null && element.isAccessibleIn(_definingLibrary)) { | |
| 2305 return element; | |
| 2306 } | |
| 2307 return null; | |
| 2308 } | |
| 2309 | |
| 2310 /** | |
| 2311 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the | |
| 2312 * element being invoked. If the returned element is a method, then the method | |
| 2313 * will be invoked. If the returned element is a getter, the getter will be | |
| 2314 * invoked without arguments and the result of that invocation will then be | |
| 2315 * invoked with the arguments. The [methodName] is the name of the method | |
| 2316 * being invoked ('m'). | |
| 2317 */ | |
| 2318 Element _resolveInvokedElement(SimpleIdentifier methodName) { | |
| 2319 // | |
| 2320 // Look first in the lexical scope. | |
| 2321 // | |
| 2322 Element element = _resolver.nameScope.lookup(methodName, _definingLibrary); | |
| 2323 if (element == null) { | |
| 2324 // | |
| 2325 // If it isn't defined in the lexical scope, and the invocation is within | |
| 2326 // a class, then look in the inheritance scope. | |
| 2327 // | |
| 2328 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 2329 if (enclosingClass != null) { | |
| 2330 InterfaceType enclosingType = enclosingClass.type; | |
| 2331 element = _lookUpMethod(null, enclosingType, methodName.name); | |
| 2332 if (element == null) { | |
| 2333 // | |
| 2334 // If there's no method, then it's possible that 'm' is a getter that | |
| 2335 // returns a function. | |
| 2336 // | |
| 2337 element = _lookUpGetter(null, enclosingType, methodName.name); | |
| 2338 } | |
| 2339 } | |
| 2340 } | |
| 2341 // TODO(brianwilkerson) Report this error. | |
| 2342 return element; | |
| 2343 } | |
| 2344 | |
| 2345 /** | |
| 2346 * Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the | |
| 2347 * element being invoked. If the returned element is a method, then the method | |
| 2348 * will be invoked. If the returned element is a getter, the getter will be | |
| 2349 * invoked without arguments and the result of that invocation will then be | |
| 2350 * invoked with the arguments. The [target] is the target of the invocation | |
| 2351 * ('e'). The [targetType] is the type of the target. The [methodName] is th | |
| 2352 * name of the method being invoked ('m'). [isConditional] indicates | |
| 2353 * whether the invocatoin uses a '?.' operator. | |
| 2354 */ | |
| 2355 Element _resolveInvokedElementWithTarget(Expression target, | |
| 2356 DartType targetType, SimpleIdentifier methodName, bool isConditional) { | |
| 2357 if (targetType is InterfaceType) { | |
| 2358 Element element = _lookUpMethod(target, targetType, methodName.name); | |
| 2359 if (element == null) { | |
| 2360 // | |
| 2361 // If there's no method, then it's possible that 'm' is a getter that | |
| 2362 // returns a function. | |
| 2363 // | |
| 2364 // TODO (collinsn): need to add union type support here too, in the | |
| 2365 // style of [lookUpMethod]. | |
| 2366 element = _lookUpGetter(target, targetType, methodName.name); | |
| 2367 } | |
| 2368 return element; | |
| 2369 } else if (target is SimpleIdentifier) { | |
| 2370 Element targetElement = target.staticElement; | |
| 2371 if (targetElement is PrefixElement) { | |
| 2372 if (isConditional) { | |
| 2373 _resolver.reportErrorForNode( | |
| 2374 CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, | |
| 2375 target, [target.name]); | |
| 2376 } | |
| 2377 // | |
| 2378 // Look to see whether the name of the method is really part of a | |
| 2379 // prefixed identifier for an imported top-level function or top-level | |
| 2380 // getter that returns a function. | |
| 2381 // | |
| 2382 String name = "${target.name}.$methodName"; | |
| 2383 Identifier functionName = new SyntheticIdentifier(name, methodName); | |
| 2384 Element element = | |
| 2385 _resolver.nameScope.lookup(functionName, _definingLibrary); | |
| 2386 if (element != null) { | |
| 2387 // TODO(brianwilkerson) This isn't a method invocation, it's a | |
| 2388 // function invocation where the function name is a prefixed | |
| 2389 // identifier. Consider re-writing the AST. | |
| 2390 return element; | |
| 2391 } | |
| 2392 } | |
| 2393 } | |
| 2394 // TODO(brianwilkerson) Report this error. | |
| 2395 return null; | |
| 2396 } | |
| 2397 | |
| 2398 /** | |
| 2399 * Given that we are accessing a property of the given [targetType] with the | |
| 2400 * given [propertyName], return the element that represents the property. The | |
| 2401 * [target] is the target of the invocation ('e'). | |
| 2402 */ | |
| 2403 ExecutableElement _resolveProperty( | |
| 2404 Expression target, DartType targetType, SimpleIdentifier propertyName) { | |
| 2405 ExecutableElement memberElement = null; | |
| 2406 if (propertyName.inSetterContext()) { | |
| 2407 memberElement = _lookUpSetter(target, targetType, propertyName.name); | |
| 2408 } | |
| 2409 if (memberElement == null) { | |
| 2410 memberElement = _lookUpGetter(target, targetType, propertyName.name); | |
| 2411 } | |
| 2412 if (memberElement == null) { | |
| 2413 memberElement = _lookUpMethod(target, targetType, propertyName.name); | |
| 2414 } | |
| 2415 return memberElement; | |
| 2416 } | |
| 2417 | |
| 2418 void _resolvePropertyAccess( | |
| 2419 Expression target, SimpleIdentifier propertyName, bool isConditional) { | |
| 2420 DartType staticType = _getStaticType(target); | |
| 2421 DartType propagatedType = _getPropagatedType(target); | |
| 2422 Element staticElement = null; | |
| 2423 Element propagatedElement = null; | |
| 2424 // | |
| 2425 // If this property access is of the form 'C.m' where 'C' is a class, | |
| 2426 // then we don't call resolveProperty(...) which walks up the class | |
| 2427 // hierarchy, instead we just look for the member in the type only. This | |
| 2428 // does not apply to conditional property accesses (i.e. 'C?.m'). | |
| 2429 // | |
| 2430 ClassElementImpl typeReference = getTypeReference(target, isConditional); | |
| 2431 if (typeReference != null) { | |
| 2432 // TODO(brianwilkerson) Why are we setting the propagated element here? | |
| 2433 // It looks wrong. | |
| 2434 staticElement = | |
| 2435 propagatedElement = _resolveElement(typeReference, propertyName); | |
| 2436 } else { | |
| 2437 staticElement = _resolveProperty(target, staticType, propertyName); | |
| 2438 propagatedElement = | |
| 2439 _resolveProperty(target, propagatedType, propertyName); | |
| 2440 } | |
| 2441 // May be part of annotation, record property element only if exists. | |
| 2442 // Error was already reported in validateAnnotationElement(). | |
| 2443 if (target.parent.parent is Annotation) { | |
| 2444 if (staticElement != null) { | |
| 2445 propertyName.staticElement = staticElement; | |
| 2446 } | |
| 2447 return; | |
| 2448 } | |
| 2449 propertyName.staticElement = staticElement; | |
| 2450 propertyName.propagatedElement = propagatedElement; | |
| 2451 bool shouldReportMissingMember_static = | |
| 2452 _shouldReportMissingMember(staticType, staticElement); | |
| 2453 bool shouldReportMissingMember_propagated = | |
| 2454 !shouldReportMissingMember_static && | |
| 2455 _enableHints && | |
| 2456 _shouldReportMissingMember(propagatedType, propagatedElement) && | |
| 2457 !_memberFoundInSubclass( | |
| 2458 propagatedType.element, propertyName.name, false, true); | |
| 2459 if (shouldReportMissingMember_static || | |
| 2460 shouldReportMissingMember_propagated) { | |
| 2461 DartType staticOrPropagatedType = | |
| 2462 shouldReportMissingMember_static ? staticType : propagatedType; | |
| 2463 Element staticOrPropagatedEnclosingElt = staticOrPropagatedType.element; | |
| 2464 bool isStaticProperty = _isStatic(staticOrPropagatedEnclosingElt); | |
| 2465 DartType displayType = staticOrPropagatedType != null | |
| 2466 ? staticOrPropagatedType | |
| 2467 : propagatedType != null ? propagatedType : staticType; | |
| 2468 // Special getter cases. | |
| 2469 if (propertyName.inGetterContext()) { | |
| 2470 if (!isStaticProperty && | |
| 2471 staticOrPropagatedEnclosingElt is ClassElement) { | |
| 2472 ClassElement classElement = staticOrPropagatedEnclosingElt; | |
| 2473 InterfaceType targetType = classElement.type; | |
| 2474 if (!_enableStrictCallChecks && | |
| 2475 targetType != null && | |
| 2476 targetType.isDartCoreFunction && | |
| 2477 propertyName.name == FunctionElement.CALL_METHOD_NAME) { | |
| 2478 // TODO(brianwilkerson) Can we ever resolve the function being | |
| 2479 // invoked? | |
| 2480 // resolveArgumentsToParameters(node.getArgumentList(), invokedFuncti
on); | |
| 2481 return; | |
| 2482 } else if (classElement.isEnum && propertyName.name == "_name") { | |
| 2483 _resolver.reportErrorForNode( | |
| 2484 CompileTimeErrorCode.ACCESS_PRIVATE_ENUM_FIELD, propertyName, | |
| 2485 [propertyName.name]); | |
| 2486 return; | |
| 2487 } | |
| 2488 } | |
| 2489 } | |
| 2490 Element declaringElement = | |
| 2491 staticType.isVoid ? null : staticOrPropagatedEnclosingElt; | |
| 2492 if (propertyName.inSetterContext()) { | |
| 2493 ErrorCode errorCode; | |
| 2494 if (shouldReportMissingMember_static) { | |
| 2495 if (target is SuperExpression) { | |
| 2496 if (isStaticProperty && !staticType.isVoid) { | |
| 2497 errorCode = StaticWarningCode.UNDEFINED_SUPER_SETTER; | |
| 2498 } else { | |
| 2499 errorCode = StaticTypeWarningCode.UNDEFINED_SUPER_SETTER; | |
| 2500 } | |
| 2501 } else { | |
| 2502 if (isStaticProperty && !staticType.isVoid) { | |
| 2503 errorCode = StaticWarningCode.UNDEFINED_SETTER; | |
| 2504 } else { | |
| 2505 errorCode = StaticTypeWarningCode.UNDEFINED_SETTER; | |
| 2506 } | |
| 2507 } | |
| 2508 } else { | |
| 2509 errorCode = HintCode.UNDEFINED_SETTER; | |
| 2510 } | |
| 2511 _recordUndefinedNode(declaringElement, errorCode, propertyName, [ | |
| 2512 propertyName.name, | |
| 2513 displayType.displayName | |
| 2514 ]); | |
| 2515 } else if (propertyName.inGetterContext()) { | |
| 2516 ErrorCode errorCode; | |
| 2517 if (shouldReportMissingMember_static) { | |
| 2518 if (target is SuperExpression) { | |
| 2519 if (isStaticProperty && !staticType.isVoid) { | |
| 2520 errorCode = StaticWarningCode.UNDEFINED_SUPER_GETTER; | |
| 2521 } else { | |
| 2522 errorCode = StaticTypeWarningCode.UNDEFINED_SUPER_GETTER; | |
| 2523 } | |
| 2524 } else { | |
| 2525 if (isStaticProperty && !staticType.isVoid) { | |
| 2526 errorCode = StaticWarningCode.UNDEFINED_GETTER; | |
| 2527 } else { | |
| 2528 errorCode = StaticTypeWarningCode.UNDEFINED_GETTER; | |
| 2529 } | |
| 2530 } | |
| 2531 } else { | |
| 2532 errorCode = HintCode.UNDEFINED_GETTER; | |
| 2533 } | |
| 2534 _recordUndefinedNode(declaringElement, errorCode, propertyName, [ | |
| 2535 propertyName.name, | |
| 2536 displayType.displayName | |
| 2537 ]); | |
| 2538 } else { | |
| 2539 _recordUndefinedNode(declaringElement, | |
| 2540 StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName, | |
| 2541 [propertyName.name]); | |
| 2542 } | |
| 2543 } | |
| 2544 } | |
| 2545 | |
| 2546 /** | |
| 2547 * Resolve the given simple [identifier] if possible. Return the element to | |
| 2548 * which it could be resolved, or `null` if it could not be resolved. This | |
| 2549 * does not record the results of the resolution. | |
| 2550 */ | |
| 2551 Element _resolveSimpleIdentifier(SimpleIdentifier identifier) { | |
| 2552 Element element = _resolver.nameScope.lookup(identifier, _definingLibrary); | |
| 2553 if (element is PropertyAccessorElement && identifier.inSetterContext()) { | |
| 2554 PropertyInducingElement variable = | |
| 2555 (element as PropertyAccessorElement).variable; | |
| 2556 if (variable != null) { | |
| 2557 PropertyAccessorElement setter = variable.setter; | |
| 2558 if (setter == null) { | |
| 2559 // | |
| 2560 // Check to see whether there might be a locally defined getter and | |
| 2561 // an inherited setter. | |
| 2562 // | |
| 2563 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 2564 if (enclosingClass != null) { | |
| 2565 setter = _lookUpSetter(null, enclosingClass.type, identifier.name); | |
| 2566 } | |
| 2567 } | |
| 2568 if (setter != null) { | |
| 2569 element = setter; | |
| 2570 } | |
| 2571 } | |
| 2572 } else if (element == null && | |
| 2573 (identifier.inSetterContext() || | |
| 2574 identifier.parent is CommentReference)) { | |
| 2575 element = _resolver.nameScope.lookup( | |
| 2576 new SyntheticIdentifier("${identifier.name}=", identifier), | |
| 2577 _definingLibrary); | |
| 2578 } | |
| 2579 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 2580 if (element == null && enclosingClass != null) { | |
| 2581 InterfaceType enclosingType = enclosingClass.type; | |
| 2582 if (element == null && | |
| 2583 (identifier.inSetterContext() || | |
| 2584 identifier.parent is CommentReference)) { | |
| 2585 element = _lookUpSetter(null, enclosingType, identifier.name); | |
| 2586 } | |
| 2587 if (element == null && identifier.inGetterContext()) { | |
| 2588 element = _lookUpGetter(null, enclosingType, identifier.name); | |
| 2589 } | |
| 2590 if (element == null) { | |
| 2591 element = _lookUpMethod(null, enclosingType, identifier.name); | |
| 2592 } | |
| 2593 } | |
| 2594 return element; | |
| 2595 } | |
| 2596 | |
| 2597 /** | |
| 2598 * If the given [type] is a type parameter, resolve it to the type that should | |
| 2599 * be used when looking up members. Otherwise, return the original type. | |
| 2600 */ | |
| 2601 DartType _resolveTypeParameter(DartType type) { | |
| 2602 if (type is TypeParameterType) { | |
| 2603 DartType bound = type.element.bound; | |
| 2604 if (bound == null) { | |
| 2605 return _resolver.typeProvider.objectType; | |
| 2606 } | |
| 2607 return bound; | |
| 2608 } | |
| 2609 return type; | |
| 2610 } | |
| 2611 | |
| 2612 /** | |
| 2613 * Given a [node] that can have annotations associated with it and the | |
| 2614 * [element] to which that node has been resolved, create the annotations in | |
| 2615 * the element model representing the annotations on the node. | |
| 2616 */ | |
| 2617 void _setMetadataForParameter(Element element, NormalFormalParameter node) { | |
| 2618 if (element is! ElementImpl) { | |
| 2619 return; | |
| 2620 } | |
| 2621 List<ElementAnnotationImpl> annotationList = | |
| 2622 new List<ElementAnnotationImpl>(); | |
| 2623 _addAnnotations(annotationList, node.metadata); | |
| 2624 if (!annotationList.isEmpty) { | |
| 2625 (element as ElementImpl).metadata = annotationList; | |
| 2626 } | |
| 2627 } | |
| 2628 | |
| 2629 /** | |
| 2630 * Return `true` if we should report an error as a result of looking up a | |
| 2631 * [member] in the given [type] and not finding any member. | |
| 2632 */ | |
| 2633 bool _shouldReportMissingMember(DartType type, Element member) { | |
| 2634 if (member != null || type == null || type.isDynamic || type.isBottom) { | |
| 2635 return false; | |
| 2636 } | |
| 2637 return true; | |
| 2638 } | |
| 2639 | |
| 2640 /** | |
| 2641 * Checks whether the given [expression] is a reference to a class. If it is | |
| 2642 * then the element representing the class is returned, otherwise `null` is | |
| 2643 * returned. [isConditional] indicates whether [expression] is to the left | |
| 2644 * of a '?.' opertator. | |
| 2645 */ | |
| 2646 static ClassElementImpl getTypeReference( | |
| 2647 Expression expression, bool isConditional) { | |
| 2648 if (!isConditional && expression is Identifier) { | |
| 2649 Element staticElement = expression.staticElement; | |
| 2650 if (staticElement is ClassElementImpl) { | |
| 2651 return staticElement; | |
| 2652 } | |
| 2653 } | |
| 2654 return null; | |
| 2655 } | |
| 2656 | |
| 2657 /** | |
| 2658 * Given a [node] that can have annotations associated with it and the | |
| 2659 * [element] to which that node has been resolved, create the annotations in | |
| 2660 * the element model representing the annotations on the node. | |
| 2661 */ | |
| 2662 static void setMetadata(Element element, AnnotatedNode node) { | |
| 2663 if (element is! ElementImpl) { | |
| 2664 return; | |
| 2665 } | |
| 2666 List<ElementAnnotationImpl> annotationList = <ElementAnnotationImpl>[]; | |
| 2667 _addAnnotations(annotationList, node.metadata); | |
| 2668 if (node is VariableDeclaration && node.parent is VariableDeclarationList) { | |
| 2669 VariableDeclarationList list = node.parent as VariableDeclarationList; | |
| 2670 _addAnnotations(annotationList, list.metadata); | |
| 2671 if (list.parent is FieldDeclaration) { | |
| 2672 FieldDeclaration fieldDeclaration = list.parent as FieldDeclaration; | |
| 2673 _addAnnotations(annotationList, fieldDeclaration.metadata); | |
| 2674 } else if (list.parent is TopLevelVariableDeclaration) { | |
| 2675 TopLevelVariableDeclaration variableDeclaration = | |
| 2676 list.parent as TopLevelVariableDeclaration; | |
| 2677 _addAnnotations(annotationList, variableDeclaration.metadata); | |
| 2678 } | |
| 2679 } | |
| 2680 if (!annotationList.isEmpty) { | |
| 2681 (element as ElementImpl).metadata = annotationList; | |
| 2682 } | |
| 2683 } | |
| 2684 | |
| 2685 /** | |
| 2686 * Generate annotation elements for each of the annotations in the | |
| 2687 * [annotationList] and add them to the given list of [annotations]. | |
| 2688 */ | |
| 2689 static void _addAnnotations(List<ElementAnnotationImpl> annotationList, | |
| 2690 NodeList<Annotation> annotations) { | |
| 2691 int annotationCount = annotations.length; | |
| 2692 for (int i = 0; i < annotationCount; i++) { | |
| 2693 Annotation annotation = annotations[i]; | |
| 2694 Element resolvedElement = annotation.element; | |
| 2695 if (resolvedElement != null) { | |
| 2696 ElementAnnotationImpl elementAnnotation = | |
| 2697 new ElementAnnotationImpl(resolvedElement); | |
| 2698 annotation.elementAnnotation = elementAnnotation; | |
| 2699 annotationList.add(elementAnnotation); | |
| 2700 } | |
| 2701 } | |
| 2702 } | |
| 2703 | |
| 2704 /** | |
| 2705 * Return `true` if the given [identifier] is the return type of a constructor | |
| 2706 * declaration. | |
| 2707 */ | |
| 2708 static bool _isConstructorReturnType(SimpleIdentifier identifier) { | |
| 2709 AstNode parent = identifier.parent; | |
| 2710 if (parent is ConstructorDeclaration) { | |
| 2711 return identical(parent.returnType, identifier); | |
| 2712 } | |
| 2713 return false; | |
| 2714 } | |
| 2715 | |
| 2716 /** | |
| 2717 * Return `true` if the given [identifier] is the return type of a factory | |
| 2718 * constructor. | |
| 2719 */ | |
| 2720 static bool _isFactoryConstructorReturnType(SimpleIdentifier identifier) { | |
| 2721 AstNode parent = identifier.parent; | |
| 2722 if (parent is ConstructorDeclaration) { | |
| 2723 ConstructorDeclaration constructor = parent; | |
| 2724 return identical(constructor.returnType, identifier) && | |
| 2725 constructor.factoryKeyword != null; | |
| 2726 } | |
| 2727 return false; | |
| 2728 } | |
| 2729 | |
| 2730 /** | |
| 2731 * Return `true` if the given 'super' [expression] is used in a valid context. | |
| 2732 */ | |
| 2733 static bool _isSuperInValidContext(SuperExpression expression) { | |
| 2734 for (AstNode node = expression; node != null; node = node.parent) { | |
| 2735 if (node is CompilationUnit) { | |
| 2736 return false; | |
| 2737 } | |
| 2738 if (node is ConstructorDeclaration) { | |
| 2739 return node.factoryKeyword == null; | |
| 2740 } | |
| 2741 if (node is ConstructorFieldInitializer) { | |
| 2742 return false; | |
| 2743 } | |
| 2744 if (node is MethodDeclaration) { | |
| 2745 return !node.isStatic; | |
| 2746 } | |
| 2747 } | |
| 2748 return false; | |
| 2749 } | |
| 2750 } | |
| 2751 | |
| 2752 /** | |
| 2753 * An identifier that can be used to look up names in the lexical scope when | |
| 2754 * there is no identifier in the AST structure. There is no identifier in the | |
| 2755 * AST when the parser could not distinguish between a method invocation and an | |
| 2756 * invocation of a top-level function imported with a prefix. | |
| 2757 */ | |
| 2758 class SyntheticIdentifier extends Identifier { | |
| 2759 /** | |
| 2760 * The name of the synthetic identifier. | |
| 2761 */ | |
| 2762 final String name; | |
| 2763 | |
| 2764 /** | |
| 2765 * The identifier to be highlighted in case of an error | |
| 2766 */ | |
| 2767 final Identifier targetIdentifier; | |
| 2768 | |
| 2769 /** | |
| 2770 * Initialize a newly created synthetic identifier to have the given [name] | |
| 2771 * and [targetIdentifier]. | |
| 2772 */ | |
| 2773 SyntheticIdentifier(this.name, this.targetIdentifier); | |
| 2774 | |
| 2775 @override | |
| 2776 sc.Token get beginToken => null; | |
| 2777 | |
| 2778 @override | |
| 2779 Element get bestElement => null; | |
| 2780 | |
| 2781 @override | |
| 2782 Iterable get childEntities { | |
| 2783 // Should never be called, since a SyntheticIdentifier never appears in the | |
| 2784 // AST--it is just used for lookup. | |
| 2785 assert(false); | |
| 2786 return new ChildEntities(); | |
| 2787 } | |
| 2788 | |
| 2789 @override | |
| 2790 sc.Token get endToken => null; | |
| 2791 | |
| 2792 @override | |
| 2793 int get length => targetIdentifier.length; | |
| 2794 | |
| 2795 @override | |
| 2796 int get offset => targetIdentifier.offset; | |
| 2797 | |
| 2798 @override | |
| 2799 int get precedence => 16; | |
| 2800 | |
| 2801 @override | |
| 2802 Element get propagatedElement => null; | |
| 2803 | |
| 2804 @override | |
| 2805 Element get staticElement => null; | |
| 2806 | |
| 2807 @override | |
| 2808 accept(AstVisitor visitor) => null; | |
| 2809 | |
| 2810 @override | |
| 2811 void visitChildren(AstVisitor visitor) {} | |
| 2812 } | |
| OLD | NEW |