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

Side by Side Diff: analyzer/lib/src/generated/element_resolver.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « analyzer/lib/src/generated/element_handle.dart ('k') | analyzer/lib/src/generated/engine.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « analyzer/lib/src/generated/element_handle.dart ('k') | analyzer/lib/src/generated/engine.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698