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

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

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 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
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);
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);
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 return null;
917 }
918
919 @override
920 Object visitRedirectingConstructorInvocation(
921 RedirectingConstructorInvocation node) {
922 ClassElement enclosingClass = _resolver.enclosingClass;
923 if (enclosingClass == null) {
924 // TODO(brianwilkerson) Report this error.
925 return null;
926 }
927 SimpleIdentifier name = node.constructorName;
928 ConstructorElement element;
929 if (name == null) {
930 element = enclosingClass.unnamedConstructor;
931 } else {
932 element = enclosingClass.getNamedConstructor(name.name);
933 }
934 if (element == null) {
935 // TODO(brianwilkerson) Report this error and decide what element to
936 // associate with the node.
937 return null;
938 }
939 if (name != null) {
940 name.staticElement = element;
941 }
942 node.staticElement = element;
943 ArgumentList argumentList = node.argumentList;
944 List<ParameterElement> parameters =
945 _resolveArgumentsToFunction(false, argumentList, element);
946 if (parameters != null) {
947 argumentList.correspondingStaticParameters = parameters;
948 }
949 return null;
950 }
951
952 @override
953 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
954 _setMetadataForParameter(node.element, node);
955 return null;
956 }
957
958 @override
959 Object visitSimpleIdentifier(SimpleIdentifier node) {
960 //
961 // Synthetic identifiers have been already reported during parsing.
962 //
963 if (node.isSynthetic) {
964 return null;
965 }
966 //
967 // We ignore identifiers that have already been resolved, such as
968 // identifiers representing the name in a declaration.
969 //
970 if (node.staticElement != null) {
971 return null;
972 }
973 //
974 // The name dynamic denotes a Type object even though dynamic is not a
975 // class.
976 //
977 if (node.name == _dynamicType.name) {
978 node.staticElement = _dynamicType.element;
979 node.staticType = _typeType;
980 return null;
981 }
982 //
983 // Otherwise, the node should be resolved.
984 //
985 Element element = _resolveSimpleIdentifier(node);
986 ClassElement enclosingClass = _resolver.enclosingClass;
987 if (_isFactoryConstructorReturnType(node) &&
988 !identical(element, enclosingClass)) {
989 _resolver.reportErrorForNode(
990 CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node);
991 } else if (_isConstructorReturnType(node) &&
992 !identical(element, enclosingClass)) {
993 _resolver.reportErrorForNode(
994 CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node);
995 element = null;
996 } else if (element == null ||
997 (element is PrefixElement && !_isValidAsPrefix(node))) {
998 // TODO(brianwilkerson) Recover from this error.
999 if (_isConstructorReturnType(node)) {
1000 _resolver.reportErrorForNode(
1001 CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node);
1002 } else if (node.parent is Annotation) {
1003 Annotation annotation = node.parent as Annotation;
1004 _resolver.reportErrorForNode(
1005 CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
1006 } else if (element is PrefixElement) {
1007 _resolver.reportErrorForNode(
1008 CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, node,
1009 [element.name]);
1010 } else {
1011 _recordUndefinedNode(_resolver.enclosingClass,
1012 StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
1013 }
1014 }
1015 node.staticElement = element;
1016 if (node.inSetterContext() &&
1017 node.inGetterContext() &&
1018 enclosingClass != null) {
1019 InterfaceType enclosingType = enclosingClass.type;
1020 AuxiliaryElements auxiliaryElements = new AuxiliaryElements(
1021 _lookUpGetter(null, enclosingType, node.name), null);
1022 node.auxiliaryElements = auxiliaryElements;
1023 }
1024 //
1025 // Validate annotation element.
1026 //
1027 if (node.parent is Annotation) {
1028 Annotation annotation = node.parent as Annotation;
1029 _resolveAnnotationElement(annotation);
1030 }
1031 return null;
1032 }
1033
1034 @override
1035 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
1036 ClassElementImpl enclosingClass = _resolver.enclosingClass;
1037 if (enclosingClass == null) {
1038 // TODO(brianwilkerson) Report this error.
1039 return null;
1040 }
1041 InterfaceType superType = enclosingClass.supertype;
1042 if (superType == null) {
1043 // TODO(brianwilkerson) Report this error.
1044 return null;
1045 }
1046 SimpleIdentifier name = node.constructorName;
1047 String superName = name != null ? name.name : null;
1048 ConstructorElement element =
1049 superType.lookUpConstructor(superName, _definingLibrary);
1050 if (element == null ||
1051 (!enclosingClass.doesMixinLackConstructors &&
1052 !enclosingClass.isSuperConstructorAccessible(element))) {
1053 if (name != null) {
1054 _resolver.reportErrorForNode(
1055 CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [
1056 superType.displayName,
1057 name
1058 ]);
1059 } else {
1060 _resolver.reportErrorForNode(
1061 CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT,
1062 node, [superType.displayName]);
1063 }
1064 return null;
1065 } else {
1066 if (element.isFactory) {
1067 _resolver.reportErrorForNode(
1068 CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]);
1069 }
1070 }
1071 if (name != null) {
1072 name.staticElement = element;
1073 }
1074 node.staticElement = element;
1075 ArgumentList argumentList = node.argumentList;
1076 List<ParameterElement> parameters = _resolveArgumentsToFunction(
1077 isInConstConstructor, argumentList, element);
1078 if (parameters != null) {
1079 argumentList.correspondingStaticParameters = parameters;
1080 }
1081 return null;
1082 }
1083
1084 @override
1085 Object visitSuperExpression(SuperExpression node) {
1086 if (!_isSuperInValidContext(node)) {
1087 _resolver.reportErrorForNode(
1088 CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node);
1089 }
1090 return super.visitSuperExpression(node);
1091 }
1092
1093 @override
1094 Object visitTypeParameter(TypeParameter node) {
1095 setMetadata(node.element, node);
1096 return null;
1097 }
1098
1099 @override
1100 Object visitVariableDeclaration(VariableDeclaration node) {
1101 setMetadata(node.element, node);
1102 return null;
1103 }
1104
1105 /**
1106 * Given that we have found code to invoke the given [element], return the
1107 * error code that should be reported, or `null` if no error should be
1108 * reported. The [target] is the target of the invocation, or `null` if there
1109 * was no target. The flag [useStaticContext] should be `true` if the
1110 * invocation is in a static constant (does not have access to instance state.
1111 */
1112 ErrorCode _checkForInvocationError(
1113 Expression target, bool useStaticContext, Element element) {
1114 // Prefix is not declared, instead "prefix.id" are declared.
1115 if (element is PrefixElement) {
1116 return CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT;
1117 }
1118 if (element is PropertyAccessorElement) {
1119 //
1120 // This is really a function expression invocation.
1121 //
1122 // TODO(brianwilkerson) Consider the possibility of re-writing the AST.
1123 FunctionType getterType = element.type;
1124 if (getterType != null) {
1125 DartType returnType = getterType.returnType;
1126 if (!_isExecutableType(returnType)) {
1127 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
1128 }
1129 }
1130 } else if (element is ExecutableElement) {
1131 return null;
1132 } else if (element is MultiplyDefinedElement) {
1133 // The error has already been reported
1134 return null;
1135 } else if (element == null && target is SuperExpression) {
1136 // TODO(jwren) We should split the UNDEFINED_METHOD into two error codes,
1137 // this one, and a code that describes the situation where the method was
1138 // found, but it was not accessible from the current library.
1139 return StaticTypeWarningCode.UNDEFINED_SUPER_METHOD;
1140 } else {
1141 //
1142 // This is really a function expression invocation.
1143 //
1144 // TODO(brianwilkerson) Consider the possibility of re-writing the AST.
1145 if (element is PropertyInducingElement) {
1146 PropertyAccessorElement getter = element.getter;
1147 FunctionType getterType = getter.type;
1148 if (getterType != null) {
1149 DartType returnType = getterType.returnType;
1150 if (!_isExecutableType(returnType)) {
1151 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
1152 }
1153 }
1154 } else if (element is VariableElement) {
1155 DartType variableType = element.type;
1156 if (!_isExecutableType(variableType)) {
1157 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
1158 }
1159 } else {
1160 if (target == null) {
1161 ClassElement enclosingClass = _resolver.enclosingClass;
1162 if (enclosingClass == null) {
1163 return StaticTypeWarningCode.UNDEFINED_FUNCTION;
1164 } else if (element == null) {
1165 // Proxy-conditional warning, based on state of
1166 // resolver.getEnclosingClass()
1167 return StaticTypeWarningCode.UNDEFINED_METHOD;
1168 } else {
1169 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION;
1170 }
1171 } else {
1172 DartType targetType;
1173 if (useStaticContext) {
1174 targetType = _getStaticType(target);
1175 } else {
1176 // Compute and use the propagated type, if it is null, then it may
1177 // be the case that static type is some type, in which the static
1178 // type should be used.
1179 targetType = _getBestType(target);
1180 }
1181 if (targetType == null) {
1182 return StaticTypeWarningCode.UNDEFINED_FUNCTION;
1183 } else if (!targetType.isDynamic && !targetType.isBottom) {
1184 // Proxy-conditional warning, based on state of
1185 // targetType.getElement()
1186 return StaticTypeWarningCode.UNDEFINED_METHOD;
1187 }
1188 }
1189 }
1190 }
1191 return null;
1192 }
1193
1194 /**
1195 * Check that the given index [expression] was resolved, otherwise a
1196 * [StaticTypeWarningCode.UNDEFINED_OPERATOR] is generated. The [target] is
1197 * the target of the expression. The [methodName] is the name of the operator
1198 * associated with the context of using of the given index expression.
1199 */
1200 bool _checkForUndefinedIndexOperator(IndexExpression expression,
1201 Expression target, String methodName, MethodElement staticMethod,
1202 MethodElement propagatedMethod, DartType staticType,
1203 DartType propagatedType) {
1204 bool shouldReportMissingMember_static =
1205 _shouldReportMissingMember(staticType, staticMethod);
1206 bool shouldReportMissingMember_propagated =
1207 !shouldReportMissingMember_static &&
1208 _enableHints &&
1209 _shouldReportMissingMember(propagatedType, propagatedMethod) &&
1210 !_memberFoundInSubclass(
1211 propagatedType.element, methodName, true, false);
1212 if (shouldReportMissingMember_static ||
1213 shouldReportMissingMember_propagated) {
1214 sc.Token leftBracket = expression.leftBracket;
1215 sc.Token rightBracket = expression.rightBracket;
1216 ErrorCode errorCode;
1217 if (shouldReportMissingMember_static) {
1218 if (target is SuperExpression) {
1219 errorCode = StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR;
1220 } else {
1221 errorCode = StaticTypeWarningCode.UNDEFINED_OPERATOR;
1222 }
1223 } else {
1224 errorCode = HintCode.UNDEFINED_OPERATOR;
1225 }
1226 DartType type =
1227 shouldReportMissingMember_static ? staticType : propagatedType;
1228 if (leftBracket == null || rightBracket == null) {
1229 _recordUndefinedNode(type.element, errorCode, expression, [
1230 methodName,
1231 type.displayName
1232 ]);
1233 } else {
1234 int offset = leftBracket.offset;
1235 int length = rightBracket.offset - offset + 1;
1236 _recordUndefinedOffset(type.element, errorCode, offset, length, [
1237 methodName,
1238 type.displayName
1239 ]);
1240 }
1241 return true;
1242 }
1243 return false;
1244 }
1245
1246 /**
1247 * Given an [argumentList] and the executable [element] that will be invoked
1248 * using those arguments, compute the list of parameters that correspond to
1249 * the list of arguments. Return the parameters that correspond to the
1250 * arguments, or `null` if no correspondence could be computed.
1251 */
1252 List<ParameterElement> _computeCorrespondingParameters(
1253 ArgumentList argumentList, Element element) {
1254 if (element is PropertyAccessorElement) {
1255 //
1256 // This is an invocation of the call method defined on the value returned
1257 // by the getter.
1258 //
1259 FunctionType getterType = element.type;
1260 if (getterType != null) {
1261 DartType getterReturnType = getterType.returnType;
1262 if (getterReturnType is InterfaceType) {
1263 MethodElement callMethod = getterReturnType.lookUpMethod(
1264 FunctionElement.CALL_METHOD_NAME, _definingLibrary);
1265 if (callMethod != null) {
1266 return _resolveArgumentsToFunction(false, argumentList, callMethod);
1267 }
1268 } else if (getterReturnType is FunctionType) {
1269 List<ParameterElement> parameters = getterReturnType.parameters;
1270 return _resolveArgumentsToParameters(false, argumentList, parameters);
1271 }
1272 }
1273 } else if (element is ExecutableElement) {
1274 return _resolveArgumentsToFunction(false, argumentList, element);
1275 } else if (element is VariableElement) {
1276 VariableElement variable = element;
1277 DartType type = _promoteManager.getStaticType(variable);
1278 if (type is FunctionType) {
1279 FunctionType functionType = type;
1280 List<ParameterElement> parameters = functionType.parameters;
1281 return _resolveArgumentsToParameters(false, argumentList, parameters);
1282 } else if (type is InterfaceType) {
1283 // "call" invocation
1284 MethodElement callMethod = type.lookUpMethod(
1285 FunctionElement.CALL_METHOD_NAME, _definingLibrary);
1286 if (callMethod != null) {
1287 List<ParameterElement> parameters = callMethod.parameters;
1288 return _resolveArgumentsToParameters(false, argumentList, parameters);
1289 }
1290 }
1291 }
1292 return null;
1293 }
1294
1295 /**
1296 * If the given [element] is a setter, return the getter associated with it.
1297 * Otherwise, return the element unchanged.
1298 */
1299 Element _convertSetterToGetter(Element element) {
1300 // TODO(brianwilkerson) Determine whether and why the element could ever be
1301 // a setter.
1302 if (element is PropertyAccessorElement) {
1303 return element.variable.getter;
1304 }
1305 return element;
1306 }
1307
1308 /**
1309 * Return `true` if the given [element] is not a proxy. See
1310 * [ClassElement.isOrInheritsProxy].
1311 */
1312 bool _doesntHaveProxy(Element element) =>
1313 !(element is ClassElement && element.isOrInheritsProxy);
1314
1315 /**
1316 * Look for any declarations of the given [identifier] that are imported using
1317 * a prefix. Return the element that was found, or `null` if the name is not
1318 * imported using a prefix.
1319 */
1320 Element _findImportWithoutPrefix(SimpleIdentifier identifier) {
1321 Element element = null;
1322 Scope nameScope = _resolver.nameScope;
1323 for (ImportElement importElement in _definingLibrary.imports) {
1324 PrefixElement prefixElement = importElement.prefix;
1325 if (prefixElement != null) {
1326 Identifier prefixedIdentifier = new SyntheticIdentifier(
1327 "${prefixElement.name}.${identifier.name}", identifier);
1328 Element importedElement =
1329 nameScope.lookup(prefixedIdentifier, _definingLibrary);
1330 if (importedElement != null) {
1331 if (element == null) {
1332 element = importedElement;
1333 } else {
1334 element = MultiplyDefinedElementImpl.fromElements(
1335 _definingLibrary.context, element, importedElement);
1336 }
1337 }
1338 }
1339 }
1340 return element;
1341 }
1342
1343 /**
1344 * Return the best type of the given [expression] that is to be used for
1345 * type analysis.
1346 */
1347 DartType _getBestType(Expression expression) {
1348 DartType bestType = _resolveTypeParameter(expression.bestType);
1349 if (bestType is FunctionType) {
1350 //
1351 // All function types are subtypes of 'Function', which is itself a
1352 // subclass of 'Object'.
1353 //
1354 bestType = _resolver.typeProvider.functionType;
1355 }
1356 return bestType;
1357 }
1358
1359 /**
1360 * Assuming that the given [expression] is a prefix for a deferred import,
1361 * return the library that is being imported.
1362 */
1363 LibraryElement _getImportedLibrary(Expression expression) {
1364 PrefixElement prefixElement =
1365 (expression as SimpleIdentifier).staticElement as PrefixElement;
1366 List<ImportElement> imports =
1367 prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
1368 return imports[0].importedLibrary;
1369 }
1370
1371 /**
1372 * Return the name of the method invoked by the given postfix [expression].
1373 */
1374 String _getPostfixOperator(PostfixExpression expression) =>
1375 (expression.operator.type == sc.TokenType.PLUS_PLUS)
1376 ? sc.TokenType.PLUS.lexeme
1377 : sc.TokenType.MINUS.lexeme;
1378
1379 /**
1380 * Return the name of the method invoked by the given postfix [expression].
1381 */
1382 String _getPrefixOperator(PrefixExpression expression) {
1383 sc.Token operator = expression.operator;
1384 sc.TokenType operatorType = operator.type;
1385 if (operatorType == sc.TokenType.PLUS_PLUS) {
1386 return sc.TokenType.PLUS.lexeme;
1387 } else if (operatorType == sc.TokenType.MINUS_MINUS) {
1388 return sc.TokenType.MINUS.lexeme;
1389 } else if (operatorType == sc.TokenType.MINUS) {
1390 return "unary-";
1391 } else {
1392 return operator.lexeme;
1393 }
1394 }
1395
1396 /**
1397 * Return the propagated type of the given [expression] that is to be used for
1398 * type analysis.
1399 */
1400 DartType _getPropagatedType(Expression expression) {
1401 DartType propagatedType = _resolveTypeParameter(expression.propagatedType);
1402 if (propagatedType is FunctionType) {
1403 //
1404 // All function types are subtypes of 'Function', which is itself a
1405 // subclass of 'Object'.
1406 //
1407 propagatedType = _resolver.typeProvider.functionType;
1408 }
1409 return propagatedType;
1410 }
1411
1412 /**
1413 * Return the static type of the given [expression] that is to be used for
1414 * type analysis.
1415 */
1416 DartType _getStaticType(Expression expression) {
1417 if (expression is NullLiteral) {
1418 return _resolver.typeProvider.bottomType;
1419 }
1420 DartType staticType = _resolveTypeParameter(expression.staticType);
1421 if (staticType is FunctionType) {
1422 //
1423 // All function types are subtypes of 'Function', which is itself a
1424 // subclass of 'Object'.
1425 //
1426 staticType = _resolver.typeProvider.functionType;
1427 }
1428 return staticType;
1429 }
1430
1431 /**
1432 * Return `true` if the given [expression] is a prefix for a deferred import.
1433 */
1434 bool _isDeferredPrefix(Expression expression) {
1435 if (expression is! SimpleIdentifier) {
1436 return false;
1437 }
1438 Element element = (expression as SimpleIdentifier).staticElement;
1439 if (element is! PrefixElement) {
1440 return false;
1441 }
1442 PrefixElement prefixElement = element as PrefixElement;
1443 List<ImportElement> imports =
1444 prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
1445 if (imports.length != 1) {
1446 return false;
1447 }
1448 return imports[0].isDeferred;
1449 }
1450
1451 /**
1452 * Return `true` if the given [type] represents an object that could be
1453 * invoked using the call operator '()'.
1454 */
1455 bool _isExecutableType(DartType type) {
1456 if (type.isDynamic || type is FunctionType) {
1457 return true;
1458 } else if (!_enableStrictCallChecks &&
1459 (type.isDartCoreFunction || type.isObject)) {
1460 return true;
1461 } else if (type is InterfaceType) {
1462 ClassElement classElement = type.element;
1463 // 16078 from Gilad: If the type is a Functor with the @proxy annotation,
1464 // treat it as an executable type.
1465 // example code: NonErrorResolverTest.
1466 // test_invocationOfNonFunction_proxyOnFunctionClass()
1467 if (classElement.isProxy &&
1468 type.isSubtypeOf(_resolver.typeProvider.functionType)) {
1469 return true;
1470 }
1471 MethodElement methodElement = classElement.lookUpMethod(
1472 FunctionElement.CALL_METHOD_NAME, _definingLibrary);
1473 return methodElement != null;
1474 }
1475 return false;
1476 }
1477
1478 /**
1479 * Return `true` if the given [element] is a static element.
1480 */
1481 bool _isStatic(Element element) {
1482 if (element is ExecutableElement) {
1483 return element.isStatic;
1484 } else if (element is PropertyInducingElement) {
1485 return element.isStatic;
1486 }
1487 return false;
1488 }
1489
1490 /**
1491 * Return `true` if the given [node] can validly be resolved to a prefix:
1492 * * it is the prefix in an import directive, or
1493 * * it is the prefix in a prefixed identifier.
1494 */
1495 bool _isValidAsPrefix(SimpleIdentifier node) {
1496 AstNode parent = node.parent;
1497 if (parent is ImportDirective) {
1498 return identical(parent.prefix, node);
1499 } else if (parent is PrefixedIdentifier) {
1500 return true;
1501 } else if (parent is MethodInvocation) {
1502 return identical(parent.target, node);
1503 }
1504 return false;
1505 }
1506
1507 /**
1508 * Return the target of a break or continue statement, and update the static
1509 * element of its label (if any). The [parentNode] is the AST node of the
1510 * break or continue statement. The [labelNode] is the label contained in that
1511 * statement (if any). The flag [isContinue] is `true` if the node being
1512 * visited is a continue statement.
1513 */
1514 AstNode _lookupBreakOrContinueTarget(
1515 AstNode parentNode, SimpleIdentifier labelNode, bool isContinue) {
1516 if (labelNode == null) {
1517 return _resolver.implicitLabelScope.getTarget(isContinue);
1518 } else {
1519 LabelScope labelScope = _resolver.labelScope;
1520 if (labelScope == null) {
1521 // There are no labels in scope, so by definition the label is
1522 // undefined.
1523 _resolver.reportErrorForNode(
1524 CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
1525 return null;
1526 }
1527 LabelScope definingScope = labelScope.lookup(labelNode.name);
1528 if (definingScope == null) {
1529 // No definition of the given label name could be found in any
1530 // enclosing scope.
1531 _resolver.reportErrorForNode(
1532 CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
1533 return null;
1534 }
1535 // The target has been found.
1536 labelNode.staticElement = definingScope.element;
1537 ExecutableElement labelContainer = definingScope.element
1538 .getAncestor((element) => element is ExecutableElement);
1539 if (!identical(labelContainer, _resolver.enclosingFunction)) {
1540 _resolver.reportErrorForNode(CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE,
1541 labelNode, [labelNode.name]);
1542 }
1543 return definingScope.node;
1544 }
1545 }
1546
1547 /**
1548 * Look up the getter with the given [getterName] in the given [type]. Return
1549 * the element representing the getter that was found, or `null` if there is
1550 * no getter with the given name. The [target] is the target of the
1551 * invocation, or `null` if there is no target.
1552 */
1553 PropertyAccessorElement _lookUpGetter(
1554 Expression target, DartType type, String getterName) {
1555 type = _resolveTypeParameter(type);
1556 if (type is InterfaceType) {
1557 InterfaceType interfaceType = type;
1558 PropertyAccessorElement accessor;
1559 if (target is SuperExpression) {
1560 accessor = interfaceType.lookUpGetterInSuperclass(
1561 getterName, _definingLibrary);
1562 } else {
1563 accessor = interfaceType.lookUpGetter(getterName, _definingLibrary);
1564 }
1565 if (accessor != null) {
1566 return accessor;
1567 }
1568 return _lookUpGetterInInterfaces(
1569 interfaceType, false, getterName, new HashSet<ClassElement>());
1570 }
1571 return null;
1572 }
1573
1574 /**
1575 * Look up the getter with the given [getterName] in the interfaces
1576 * implemented by the given [targetType], either directly or indirectly.
1577 * Return the element representing the getter that was found, or `null` if
1578 * there is no getter with the given name. The flag [includeTargetType] should
1579 * be `true` if the search should include the target type. The
1580 * [visitedInterfaces] is a set containing all of the interfaces that have
1581 * been examined, used to prevent infinite recursion and to optimize the
1582 * search.
1583 */
1584 PropertyAccessorElement _lookUpGetterInInterfaces(InterfaceType targetType,
1585 bool includeTargetType, String getterName,
1586 HashSet<ClassElement> visitedInterfaces) {
1587 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
1588 // specification (titled "Inheritance and Overriding" under "Interfaces")
1589 // describes a much more complex scheme for finding the inherited member.
1590 // We need to follow that scheme. The code below should cover the 80% case.
1591 ClassElement targetClass = targetType.element;
1592 if (visitedInterfaces.contains(targetClass)) {
1593 return null;
1594 }
1595 visitedInterfaces.add(targetClass);
1596 if (includeTargetType) {
1597 PropertyAccessorElement getter = targetType.getGetter(getterName);
1598 if (getter != null && getter.isAccessibleIn(_definingLibrary)) {
1599 return getter;
1600 }
1601 }
1602 for (InterfaceType interfaceType in targetType.interfaces) {
1603 PropertyAccessorElement getter = _lookUpGetterInInterfaces(
1604 interfaceType, true, getterName, visitedInterfaces);
1605 if (getter != null) {
1606 return getter;
1607 }
1608 }
1609 for (InterfaceType mixinType in targetType.mixins.reversed) {
1610 PropertyAccessorElement getter = _lookUpGetterInInterfaces(
1611 mixinType, true, getterName, visitedInterfaces);
1612 if (getter != null) {
1613 return getter;
1614 }
1615 }
1616 InterfaceType superclass = targetType.superclass;
1617 if (superclass == null) {
1618 return null;
1619 }
1620 return _lookUpGetterInInterfaces(
1621 superclass, true, getterName, visitedInterfaces);
1622 }
1623
1624 /**
1625 * Look up the method or getter with the given [memberName] in the given
1626 * [type]. Return the element representing the method or getter that was
1627 * found, or `null` if there is no method or getter with the given name.
1628 */
1629 ExecutableElement _lookupGetterOrMethod(DartType type, String memberName) {
1630 type = _resolveTypeParameter(type);
1631 if (type is InterfaceType) {
1632 InterfaceType interfaceType = type;
1633 ExecutableElement member =
1634 interfaceType.lookUpMethod(memberName, _definingLibrary);
1635 if (member != null) {
1636 return member;
1637 }
1638 member = interfaceType.lookUpGetter(memberName, _definingLibrary);
1639 if (member != null) {
1640 return member;
1641 }
1642 return _lookUpGetterOrMethodInInterfaces(
1643 interfaceType, false, memberName, new HashSet<ClassElement>());
1644 }
1645 return null;
1646 }
1647
1648 /**
1649 * Look up the method or getter with the given [memberName] in the interfaces
1650 * implemented by the given [targetType], either directly or indirectly.
1651 * Return the element representing the method or getter that was found, or
1652 * `null` if there is no method or getter with the given name. The flag
1653 * [includeTargetType] should be `true` if the search should include the
1654 * target type. The [visitedInterfaces] is a set containing all of the
1655 * interfaces that have been examined, used to prevent infinite recursion and
1656 * to optimize the search.
1657 */
1658 ExecutableElement _lookUpGetterOrMethodInInterfaces(InterfaceType targetType,
1659 bool includeTargetType, String memberName,
1660 HashSet<ClassElement> visitedInterfaces) {
1661 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
1662 // specification (titled "Inheritance and Overriding" under "Interfaces")
1663 // describes a much more complex scheme for finding the inherited member.
1664 // We need to follow that scheme. The code below should cover the 80% case.
1665 ClassElement targetClass = targetType.element;
1666 if (visitedInterfaces.contains(targetClass)) {
1667 return null;
1668 }
1669 visitedInterfaces.add(targetClass);
1670 if (includeTargetType) {
1671 ExecutableElement member = targetType.getMethod(memberName);
1672 if (member != null) {
1673 return member;
1674 }
1675 member = targetType.getGetter(memberName);
1676 if (member != null) {
1677 return member;
1678 }
1679 }
1680 for (InterfaceType interfaceType in targetType.interfaces) {
1681 ExecutableElement member = _lookUpGetterOrMethodInInterfaces(
1682 interfaceType, true, memberName, visitedInterfaces);
1683 if (member != null) {
1684 return member;
1685 }
1686 }
1687 for (InterfaceType mixinType in targetType.mixins.reversed) {
1688 ExecutableElement member = _lookUpGetterOrMethodInInterfaces(
1689 mixinType, true, memberName, visitedInterfaces);
1690 if (member != null) {
1691 return member;
1692 }
1693 }
1694 InterfaceType superclass = targetType.superclass;
1695 if (superclass == null) {
1696 return null;
1697 }
1698 return _lookUpGetterOrMethodInInterfaces(
1699 superclass, true, memberName, visitedInterfaces);
1700 }
1701
1702 /**
1703 * Look up the method with the given [methodName] in the given [type]. Return
1704 * the element representing the method that was found, or `null` if there is
1705 * no method with the given name. The [target] is the target of the
1706 * invocation, or `null` if there is no target.
1707 */
1708 MethodElement _lookUpMethod(
1709 Expression target, DartType type, String methodName) {
1710 type = _resolveTypeParameter(type);
1711 if (type is InterfaceType) {
1712 InterfaceType interfaceType = type;
1713 MethodElement method;
1714 if (target is SuperExpression) {
1715 method = interfaceType.lookUpMethodInSuperclass(
1716 methodName, _definingLibrary);
1717 } else {
1718 method = interfaceType.lookUpMethod(methodName, _definingLibrary);
1719 }
1720 if (method != null) {
1721 return method;
1722 }
1723 return _lookUpMethodInInterfaces(
1724 interfaceType, false, methodName, new HashSet<ClassElement>());
1725 }
1726 return null;
1727 }
1728
1729 /**
1730 * Look up the method with the given [methodName] in the interfaces
1731 * implemented by the given [targetType], either directly or indirectly.
1732 * Return the element representing the method that was found, or `null` if
1733 * there is no method with the given name. The flag [includeTargetType] should
1734 * be `true` if the search should include the target type. The
1735 * [visitedInterfaces] is a set containing all of the interfaces that have
1736 * been examined, used to prevent infinite recursion and to optimize the
1737 * search.
1738 */
1739 MethodElement _lookUpMethodInInterfaces(InterfaceType targetType,
1740 bool includeTargetType, String methodName,
1741 HashSet<ClassElement> visitedInterfaces) {
1742 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
1743 // specification (titled "Inheritance and Overriding" under "Interfaces")
1744 // describes a much more complex scheme for finding the inherited member.
1745 // We need to follow that scheme. The code below should cover the 80% case.
1746 ClassElement targetClass = targetType.element;
1747 if (visitedInterfaces.contains(targetClass)) {
1748 return null;
1749 }
1750 visitedInterfaces.add(targetClass);
1751 if (includeTargetType) {
1752 MethodElement method = targetType.getMethod(methodName);
1753 if (method != null && method.isAccessibleIn(_definingLibrary)) {
1754 return method;
1755 }
1756 }
1757 for (InterfaceType interfaceType in targetType.interfaces) {
1758 MethodElement method = _lookUpMethodInInterfaces(
1759 interfaceType, true, methodName, visitedInterfaces);
1760 if (method != null) {
1761 return method;
1762 }
1763 }
1764 for (InterfaceType mixinType in targetType.mixins.reversed) {
1765 MethodElement method = _lookUpMethodInInterfaces(
1766 mixinType, true, methodName, visitedInterfaces);
1767 if (method != null) {
1768 return method;
1769 }
1770 }
1771 InterfaceType superclass = targetType.superclass;
1772 if (superclass == null) {
1773 return null;
1774 }
1775 return _lookUpMethodInInterfaces(
1776 superclass, true, methodName, visitedInterfaces);
1777 }
1778
1779 /**
1780 * Look up the setter with the given [setterName] in the given [type]. Return
1781 * the element representing the setter that was found, or `null` if there is
1782 * no setter with the given name. The [target] is the target of the
1783 * invocation, or `null` if there is no target.
1784 */
1785 PropertyAccessorElement _lookUpSetter(
1786 Expression target, DartType type, String setterName) {
1787 type = _resolveTypeParameter(type);
1788 if (type is InterfaceType) {
1789 InterfaceType interfaceType = type;
1790 PropertyAccessorElement accessor;
1791 if (target is SuperExpression) {
1792 accessor = interfaceType.lookUpSetterInSuperclass(
1793 setterName, _definingLibrary);
1794 } else {
1795 accessor = interfaceType.lookUpSetter(setterName, _definingLibrary);
1796 }
1797 if (accessor != null) {
1798 return accessor;
1799 }
1800 return _lookUpSetterInInterfaces(
1801 interfaceType, false, setterName, new HashSet<ClassElement>());
1802 }
1803 return null;
1804 }
1805
1806 /**
1807 * Look up the setter with the given [setterName] in the interfaces
1808 * implemented by the given [targetType], either directly or indirectly.
1809 * Return the element representing the setter that was found, or `null` if
1810 * there is no setter with the given name. The [targetType] is the type in
1811 * which the setter might be defined. The flag [includeTargetType] should be
1812 * `true` if the search should include the target type. The
1813 * [visitedInterfaces] is a set containing all of the interfaces that have
1814 * been examined, used to prevent infinite recursion and to optimize the
1815 * search.
1816 */
1817 PropertyAccessorElement _lookUpSetterInInterfaces(InterfaceType targetType,
1818 bool includeTargetType, String setterName,
1819 HashSet<ClassElement> visitedInterfaces) {
1820 // TODO(brianwilkerson) This isn't correct. Section 8.1.1 of the
1821 // specification (titled "Inheritance and Overriding" under "Interfaces")
1822 // describes a much more complex scheme for finding the inherited member.
1823 // We need to follow that scheme. The code below should cover the 80% case.
1824 ClassElement targetClass = targetType.element;
1825 if (visitedInterfaces.contains(targetClass)) {
1826 return null;
1827 }
1828 visitedInterfaces.add(targetClass);
1829 if (includeTargetType) {
1830 PropertyAccessorElement setter = targetType.getSetter(setterName);
1831 if (setter != null && setter.isAccessibleIn(_definingLibrary)) {
1832 return setter;
1833 }
1834 }
1835 for (InterfaceType interfaceType in targetType.interfaces) {
1836 PropertyAccessorElement setter = _lookUpSetterInInterfaces(
1837 interfaceType, true, setterName, visitedInterfaces);
1838 if (setter != null) {
1839 return setter;
1840 }
1841 }
1842 for (InterfaceType mixinType in targetType.mixins.reversed) {
1843 PropertyAccessorElement setter = _lookUpSetterInInterfaces(
1844 mixinType, true, setterName, visitedInterfaces);
1845 if (setter != null) {
1846 return setter;
1847 }
1848 }
1849 InterfaceType superclass = targetType.superclass;
1850 if (superclass == null) {
1851 return null;
1852 }
1853 return _lookUpSetterInInterfaces(
1854 superclass, true, setterName, visitedInterfaces);
1855 }
1856
1857 /**
1858 * Given some class [element], this method uses [_subtypeManager] to find the
1859 * set of all subtypes; the subtypes are then searched for a member (method,
1860 * getter, or setter), that has the given [memberName]. The flag [asMethod]
1861 * should be `true` if the methods should be searched for in the subtypes. The
1862 * flag [asAccessor] should be `true` if the accessors (getters and setters)
1863 * should be searched for in the subtypes.
1864 */
1865 bool _memberFoundInSubclass(
1866 Element element, String memberName, bool asMethod, bool asAccessor) {
1867 if (element is ClassElement) {
1868 _subtypeManager.ensureLibraryVisited(_definingLibrary);
1869 HashSet<ClassElement> subtypeElements =
1870 _subtypeManager.computeAllSubtypes(element);
1871 for (ClassElement subtypeElement in subtypeElements) {
1872 if (asMethod && subtypeElement.getMethod(memberName) != null) {
1873 return true;
1874 } else if (asAccessor &&
1875 (subtypeElement.getGetter(memberName) != null ||
1876 subtypeElement.getSetter(memberName) != null)) {
1877 return true;
1878 }
1879 }
1880 }
1881 return false;
1882 }
1883
1884 /**
1885 * Return the binary operator that is invoked by the given compound assignment
1886 * [operator].
1887 */
1888 sc.TokenType _operatorFromCompoundAssignment(sc.TokenType operator) {
1889 while (true) {
1890 if (operator == sc.TokenType.AMPERSAND_EQ) {
1891 return sc.TokenType.AMPERSAND;
1892 } else if (operator == sc.TokenType.BAR_EQ) {
1893 return sc.TokenType.BAR;
1894 } else if (operator == sc.TokenType.CARET_EQ) {
1895 return sc.TokenType.CARET;
1896 } else if (operator == sc.TokenType.GT_GT_EQ) {
1897 return sc.TokenType.GT_GT;
1898 } else if (operator == sc.TokenType.LT_LT_EQ) {
1899 return sc.TokenType.LT_LT;
1900 } else if (operator == sc.TokenType.MINUS_EQ) {
1901 return sc.TokenType.MINUS;
1902 } else if (operator == sc.TokenType.PERCENT_EQ) {
1903 return sc.TokenType.PERCENT;
1904 } else if (operator == sc.TokenType.PLUS_EQ) {
1905 return sc.TokenType.PLUS;
1906 } else if (operator == sc.TokenType.SLASH_EQ) {
1907 return sc.TokenType.SLASH;
1908 } else if (operator == sc.TokenType.STAR_EQ) {
1909 return sc.TokenType.STAR;
1910 } else if (operator == sc.TokenType.TILDE_SLASH_EQ) {
1911 return sc.TokenType.TILDE_SLASH;
1912 } else {
1913 // Internal error: Unmapped assignment operator.
1914 AnalysisEngine.instance.logger.logError(
1915 "Failed to map ${operator.lexeme} to it's corresponding operator");
1916 return operator;
1917 }
1918 break;
1919 }
1920 }
1921
1922 /**
1923 * Record that the given [node] is undefined, causing an error to be reported
1924 * if appropriate. The [declaringElement] is the element inside which no
1925 * declaration was found. If this element is a proxy, no error will be
1926 * reported. If null, then an error will always be reported. The [errorCode]
1927 * is the error code to report. The [arguments] are the arguments to the error
1928 * message.
1929 */
1930 void _recordUndefinedNode(Element declaringElement, ErrorCode errorCode,
1931 AstNode node, List<Object> arguments) {
1932 if (_doesntHaveProxy(declaringElement)) {
1933 _resolver.reportErrorForNode(errorCode, node, arguments);
1934 }
1935 }
1936
1937 /**
1938 * Record that the given [offset]/[length] is undefined, causing an error to
1939 * be reported if appropriate. The [declaringElement] is the element inside
1940 * which no declaration was found. If this element is a proxy, no error will
1941 * be reported. If null, then an error will always be reported. The
1942 * [errorCode] is the error code to report. The [arguments] are arguments to
1943 * the error message.
1944 */
1945 void _recordUndefinedOffset(Element declaringElement, ErrorCode errorCode,
1946 int offset, int length, List<Object> arguments) {
1947 if (_doesntHaveProxy(declaringElement)) {
1948 _resolver.reportErrorForOffset(errorCode, offset, length, arguments);
1949 }
1950 }
1951
1952 /**
1953 * Record that the given [token] is undefined, causing an error to be reported
1954 * if appropriate. The [declaringElement] is the element inside which no
1955 * declaration was found. If this element is a proxy, no error will be
1956 * reported. If null, then an error will always be reported. The [errorCode]
1957 * is the error code to report. The [arguments] are arguments to the error
1958 * message.
1959 */
1960 void _recordUndefinedToken(Element declaringElement, ErrorCode errorCode,
1961 sc.Token token, List<Object> arguments) {
1962 if (_doesntHaveProxy(declaringElement)) {
1963 _resolver.reportErrorForToken(errorCode, token, arguments);
1964 }
1965 }
1966
1967 void _resolveAnnotationConstructorInvocationArguments(
1968 Annotation annotation, ConstructorElement constructor) {
1969 ArgumentList argumentList = annotation.arguments;
1970 // error will be reported in ConstantVerifier
1971 if (argumentList == null) {
1972 return;
1973 }
1974 // resolve arguments to parameters
1975 List<ParameterElement> parameters =
1976 _resolveArgumentsToFunction(true, argumentList, constructor);
1977 if (parameters != null) {
1978 argumentList.correspondingStaticParameters = parameters;
1979 }
1980 }
1981
1982 /**
1983 * Continues resolution of the given [annotation].
1984 */
1985 void _resolveAnnotationElement(Annotation annotation) {
1986 SimpleIdentifier nameNode1;
1987 SimpleIdentifier nameNode2;
1988 {
1989 Identifier annName = annotation.name;
1990 if (annName is PrefixedIdentifier) {
1991 PrefixedIdentifier prefixed = annName;
1992 nameNode1 = prefixed.prefix;
1993 nameNode2 = prefixed.identifier;
1994 } else {
1995 nameNode1 = annName as SimpleIdentifier;
1996 nameNode2 = null;
1997 }
1998 }
1999 SimpleIdentifier nameNode3 = annotation.constructorName;
2000 ConstructorElement constructor = null;
2001 //
2002 // CONST or Class(args)
2003 //
2004 if (nameNode1 != null && nameNode2 == null && nameNode3 == null) {
2005 Element element1 = nameNode1.staticElement;
2006 // CONST
2007 if (element1 is PropertyAccessorElement) {
2008 _resolveAnnotationElementGetter(annotation, element1);
2009 return;
2010 }
2011 // Class(args)
2012 if (element1 is ClassElement) {
2013 ClassElement classElement = element1;
2014 constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(
2015 null, _definingLibrary);
2016 }
2017 }
2018 //
2019 // prefix.CONST or prefix.Class() or Class.CONST or Class.constructor(args)
2020 //
2021 if (nameNode1 != null && nameNode2 != null && nameNode3 == null) {
2022 Element element1 = nameNode1.staticElement;
2023 Element element2 = nameNode2.staticElement;
2024 // Class.CONST - not resolved yet
2025 if (element1 is ClassElement) {
2026 ClassElement classElement = element1;
2027 element2 = classElement.lookUpGetter(nameNode2.name, _definingLibrary);
2028 }
2029 // prefix.CONST or Class.CONST
2030 if (element2 is PropertyAccessorElement) {
2031 nameNode2.staticElement = element2;
2032 annotation.element = element2;
2033 _resolveAnnotationElementGetter(annotation, element2);
2034 return;
2035 }
2036 // prefix.Class()
2037 if (element2 is ClassElement) {
2038 constructor = element2.unnamedConstructor;
2039 }
2040 // Class.constructor(args)
2041 if (element1 is ClassElement) {
2042 ClassElement classElement = element1;
2043 constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(
2044 nameNode2.name, _definingLibrary);
2045 nameNode2.staticElement = constructor;
2046 }
2047 }
2048 //
2049 // prefix.Class.CONST or prefix.Class.constructor(args)
2050 //
2051 if (nameNode1 != null && nameNode2 != null && nameNode3 != null) {
2052 Element element2 = nameNode2.staticElement;
2053 // element2 should be ClassElement
2054 if (element2 is ClassElement) {
2055 ClassElement classElement = element2;
2056 String name3 = nameNode3.name;
2057 // prefix.Class.CONST
2058 PropertyAccessorElement getter =
2059 classElement.lookUpGetter(name3, _definingLibrary);
2060 if (getter != null) {
2061 nameNode3.staticElement = getter;
2062 annotation.element = element2;
2063 _resolveAnnotationElementGetter(annotation, getter);
2064 return;
2065 }
2066 // prefix.Class.constructor(args)
2067 constructor = new InterfaceTypeImpl(classElement).lookUpConstructor(
2068 name3, _definingLibrary);
2069 nameNode3.staticElement = constructor;
2070 }
2071 }
2072 // we need constructor
2073 if (constructor == null) {
2074 _resolver.reportErrorForNode(
2075 CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
2076 return;
2077 }
2078 // record element
2079 annotation.element = constructor;
2080 // resolve arguments
2081 _resolveAnnotationConstructorInvocationArguments(annotation, constructor);
2082 }
2083
2084 void _resolveAnnotationElementGetter(
2085 Annotation annotation, PropertyAccessorElement accessorElement) {
2086 // accessor should be synthetic
2087 if (!accessorElement.isSynthetic) {
2088 _resolver.reportErrorForNode(
2089 CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
2090 return;
2091 }
2092 // variable should be constant
2093 VariableElement variableElement = accessorElement.variable;
2094 if (!variableElement.isConst) {
2095 _resolver.reportErrorForNode(
2096 CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
2097 }
2098 // OK
2099 return;
2100 }
2101
2102 /**
2103 * Given an [argumentList] and the [executableElement] that will be invoked
2104 * using those argument, compute the list of parameters that correspond to the
2105 * list of arguments. An error will be reported if any of the arguments cannot
2106 * be matched to a parameter. The flag [reportError] should be `true` if a
2107 * compile-time error should be reported; or `false` if a compile-time warning
2108 * should be reported. Return the parameters that correspond to the arguments,
2109 * or `null` if no correspondence could be computed.
2110 */
2111 List<ParameterElement> _resolveArgumentsToFunction(bool reportError,
2112 ArgumentList argumentList, ExecutableElement executableElement) {
2113 if (executableElement == null) {
2114 return null;
2115 }
2116 List<ParameterElement> parameters = executableElement.parameters;
2117 return _resolveArgumentsToParameters(reportError, argumentList, parameters);
2118 }
2119
2120 /**
2121 * Given an [argumentList] and the [parameters] related to the element that
2122 * will be invoked using those arguments, compute the list of parameters that
2123 * correspond to the list of arguments. An error will be reported if any of
2124 * the arguments cannot be matched to a parameter. The flag [reportError]
2125 * should be `true` if a compile-time error should be reported; or `false` if
2126 * a compile-time warning should be reported. Return the parameters that
2127 * correspond to the arguments.
2128 */
2129 List<ParameterElement> _resolveArgumentsToParameters(bool reportError,
2130 ArgumentList argumentList, List<ParameterElement> parameters) {
2131 List<ParameterElement> requiredParameters = new List<ParameterElement>();
2132 List<ParameterElement> positionalParameters = new List<ParameterElement>();
2133 HashMap<String, ParameterElement> namedParameters =
2134 new HashMap<String, ParameterElement>();
2135 for (ParameterElement parameter in parameters) {
2136 ParameterKind kind = parameter.parameterKind;
2137 if (kind == ParameterKind.REQUIRED) {
2138 requiredParameters.add(parameter);
2139 } else if (kind == ParameterKind.POSITIONAL) {
2140 positionalParameters.add(parameter);
2141 } else {
2142 namedParameters[parameter.name] = parameter;
2143 }
2144 }
2145 List<ParameterElement> unnamedParameters =
2146 new List<ParameterElement>.from(requiredParameters);
2147 unnamedParameters.addAll(positionalParameters);
2148 int unnamedParameterCount = unnamedParameters.length;
2149 int unnamedIndex = 0;
2150 NodeList<Expression> arguments = argumentList.arguments;
2151 int argumentCount = arguments.length;
2152 List<ParameterElement> resolvedParameters =
2153 new List<ParameterElement>(argumentCount);
2154 int positionalArgumentCount = 0;
2155 HashSet<String> usedNames = new HashSet<String>();
2156 bool noBlankArguments = true;
2157 for (int i = 0; i < argumentCount; i++) {
2158 Expression argument = arguments[i];
2159 if (argument is NamedExpression) {
2160 SimpleIdentifier nameNode = argument.name.label;
2161 String name = nameNode.name;
2162 ParameterElement element = namedParameters[name];
2163 if (element == null) {
2164 ErrorCode errorCode = (reportError
2165 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
2166 : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
2167 _resolver.reportErrorForNode(errorCode, nameNode, [name]);
2168 } else {
2169 resolvedParameters[i] = element;
2170 nameNode.staticElement = element;
2171 }
2172 if (!usedNames.add(name)) {
2173 _resolver.reportErrorForNode(
2174 CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
2175 }
2176 } else {
2177 if (argument is SimpleIdentifier && argument.name.isEmpty) {
2178 noBlankArguments = false;
2179 }
2180 positionalArgumentCount++;
2181 if (unnamedIndex < unnamedParameterCount) {
2182 resolvedParameters[i] = unnamedParameters[unnamedIndex++];
2183 }
2184 }
2185 }
2186 if (positionalArgumentCount < requiredParameters.length &&
2187 noBlankArguments) {
2188 ErrorCode errorCode = (reportError
2189 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
2190 : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
2191 _resolver.reportErrorForNode(errorCode, argumentList, [
2192 requiredParameters.length,
2193 positionalArgumentCount
2194 ]);
2195 } else if (positionalArgumentCount > unnamedParameterCount &&
2196 noBlankArguments) {
2197 ErrorCode errorCode = (reportError
2198 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
2199 : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
2200 _resolver.reportErrorForNode(errorCode, argumentList, [
2201 unnamedParameterCount,
2202 positionalArgumentCount
2203 ]);
2204 }
2205 return resolvedParameters;
2206 }
2207
2208 void _resolveBinaryExpression(BinaryExpression node, String methodName) {
2209 Expression leftOperand = node.leftOperand;
2210 if (leftOperand != null) {
2211 DartType staticType = _getStaticType(leftOperand);
2212 MethodElement staticMethod =
2213 _lookUpMethod(leftOperand, staticType, methodName);
2214 node.staticElement = staticMethod;
2215 DartType propagatedType = _getPropagatedType(leftOperand);
2216 MethodElement propagatedMethod =
2217 _lookUpMethod(leftOperand, propagatedType, methodName);
2218 node.propagatedElement = propagatedMethod;
2219 if (_shouldReportMissingMember(staticType, staticMethod)) {
2220 if (leftOperand is SuperExpression) {
2221 _recordUndefinedToken(staticType.element,
2222 StaticTypeWarningCode.UNDEFINED_SUPER_OPERATOR, node.operator, [
2223 methodName,
2224 staticType.displayName
2225 ]);
2226 } else {
2227 _recordUndefinedToken(staticType.element,
2228 StaticTypeWarningCode.UNDEFINED_OPERATOR, node.operator, [
2229 methodName,
2230 staticType.displayName
2231 ]);
2232 }
2233 } else if (_enableHints &&
2234 _shouldReportMissingMember(propagatedType, propagatedMethod) &&
2235 !_memberFoundInSubclass(
2236 propagatedType.element, methodName, true, false)) {
2237 _recordUndefinedToken(propagatedType.element,
2238 HintCode.UNDEFINED_OPERATOR, node.operator, [
2239 methodName,
2240 propagatedType.displayName
2241 ]);
2242 }
2243 }
2244 }
2245
2246 /**
2247 * Resolve the names in the given [combinators] in the scope of the given
2248 * [library].
2249 */
2250 void _resolveCombinators(
2251 LibraryElement library, NodeList<Combinator> combinators) {
2252 if (library == null) {
2253 //
2254 // The library will be null if the directive containing the combinators
2255 // has a URI that is not valid.
2256 //
2257 return;
2258 }
2259 Namespace namespace =
2260 new NamespaceBuilder().createExportNamespaceForLibrary(library);
2261 for (Combinator combinator in combinators) {
2262 NodeList<SimpleIdentifier> names;
2263 if (combinator is HideCombinator) {
2264 names = combinator.hiddenNames;
2265 } else {
2266 names = (combinator as ShowCombinator).shownNames;
2267 }
2268 for (SimpleIdentifier name in names) {
2269 String nameStr = name.name;
2270 Element element = namespace.get(nameStr);
2271 if (element == null) {
2272 element = namespace.get("$nameStr=");
2273 }
2274 if (element != null) {
2275 // Ensure that the name always resolves to a top-level variable
2276 // rather than a getter or setter
2277 if (element is PropertyAccessorElement) {
2278 element = (element as PropertyAccessorElement).variable;
2279 }
2280 name.staticElement = element;
2281 }
2282 }
2283 }
2284 }
2285
2286 /**
2287 * Given that we are accessing a property of the given [classElement] with the
2288 * given [propertyName], return the element that represents the property.
2289 */
2290 Element _resolveElement(
2291 ClassElementImpl classElement, SimpleIdentifier propertyName) {
2292 String name = propertyName.name;
2293 Element element = null;
2294 if (propertyName.inSetterContext()) {
2295 element = classElement.getSetter(name);
2296 }
2297 if (element == null) {
2298 element = classElement.getGetter(name);
2299 }
2300 if (element == null) {
2301 element = classElement.getMethod(name);
2302 }
2303 if (element != null && element.isAccessibleIn(_definingLibrary)) {
2304 return element;
2305 }
2306 return null;
2307 }
2308
2309 /**
2310 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the
2311 * element being invoked. If the returned element is a method, then the method
2312 * will be invoked. If the returned element is a getter, the getter will be
2313 * invoked without arguments and the result of that invocation will then be
2314 * invoked with the arguments. The [methodName] is the name of the method
2315 * being invoked ('m').
2316 */
2317 Element _resolveInvokedElement(SimpleIdentifier methodName) {
2318 //
2319 // Look first in the lexical scope.
2320 //
2321 Element element = _resolver.nameScope.lookup(methodName, _definingLibrary);
2322 if (element == null) {
2323 //
2324 // If it isn't defined in the lexical scope, and the invocation is within
2325 // a class, then look in the inheritance scope.
2326 //
2327 ClassElement enclosingClass = _resolver.enclosingClass;
2328 if (enclosingClass != null) {
2329 InterfaceType enclosingType = enclosingClass.type;
2330 element = _lookUpMethod(null, enclosingType, methodName.name);
2331 if (element == null) {
2332 //
2333 // If there's no method, then it's possible that 'm' is a getter that
2334 // returns a function.
2335 //
2336 element = _lookUpGetter(null, enclosingType, methodName.name);
2337 }
2338 }
2339 }
2340 // TODO(brianwilkerson) Report this error.
2341 return element;
2342 }
2343
2344 /**
2345 * Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the
2346 * element being invoked. If the returned element is a method, then the method
2347 * will be invoked. If the returned element is a getter, the getter will be
2348 * invoked without arguments and the result of that invocation will then be
2349 * invoked with the arguments. The [target] is the target of the invocation
2350 * ('e'). The [targetType] is the type of the target. The [methodName] is th
2351 * name of the method being invoked ('m'). [isConditional] indicates
2352 * whether the invocatoin uses a '?.' operator.
2353 */
2354 Element _resolveInvokedElementWithTarget(Expression target,
2355 DartType targetType, SimpleIdentifier methodName, bool isConditional) {
2356 if (targetType is InterfaceType) {
2357 Element element = _lookUpMethod(target, targetType, methodName.name);
2358 if (element == null) {
2359 //
2360 // If there's no method, then it's possible that 'm' is a getter that
2361 // returns a function.
2362 //
2363 // TODO (collinsn): need to add union type support here too, in the
2364 // style of [lookUpMethod].
2365 element = _lookUpGetter(target, targetType, methodName.name);
2366 }
2367 return element;
2368 } else if (target is SimpleIdentifier) {
2369 Element targetElement = target.staticElement;
2370 if (targetElement is PrefixElement) {
2371 if (isConditional) {
2372 _resolver.reportErrorForNode(
2373 CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
2374 target, [target.name]);
2375 }
2376 //
2377 // Look to see whether the name of the method is really part of a
2378 // prefixed identifier for an imported top-level function or top-level
2379 // getter that returns a function.
2380 //
2381 String name = "${target.name}.$methodName";
2382 Identifier functionName = new SyntheticIdentifier(name, methodName);
2383 Element element =
2384 _resolver.nameScope.lookup(functionName, _definingLibrary);
2385 if (element != null) {
2386 // TODO(brianwilkerson) This isn't a method invocation, it's a
2387 // function invocation where the function name is a prefixed
2388 // identifier. Consider re-writing the AST.
2389 return element;
2390 }
2391 }
2392 }
2393 // TODO(brianwilkerson) Report this error.
2394 return null;
2395 }
2396
2397 /**
2398 * Given that we are accessing a property of the given [targetType] with the
2399 * given [propertyName], return the element that represents the property. The
2400 * [target] is the target of the invocation ('e').
2401 */
2402 ExecutableElement _resolveProperty(
2403 Expression target, DartType targetType, SimpleIdentifier propertyName) {
2404 ExecutableElement memberElement = null;
2405 if (propertyName.inSetterContext()) {
2406 memberElement = _lookUpSetter(target, targetType, propertyName.name);
2407 }
2408 if (memberElement == null) {
2409 memberElement = _lookUpGetter(target, targetType, propertyName.name);
2410 }
2411 if (memberElement == null) {
2412 memberElement = _lookUpMethod(target, targetType, propertyName.name);
2413 }
2414 return memberElement;
2415 }
2416
2417 void _resolvePropertyAccess(
2418 Expression target, SimpleIdentifier propertyName) {
2419 DartType staticType = _getStaticType(target);
2420 DartType propagatedType = _getPropagatedType(target);
2421 Element staticElement = null;
2422 Element propagatedElement = null;
2423 //
2424 // If this property access is of the form 'C.m' where 'C' is a class,
2425 // then we don't call resolveProperty(...) which walks up the class
2426 // hierarchy, instead we just look for the member in the type only. This
2427 // does not apply to conditional property accesses (i.e. 'C?.m').
2428 //
2429 ClassElementImpl typeReference = getTypeReference(target);
2430 if (typeReference != null) {
2431 // TODO(brianwilkerson) Why are we setting the propagated element here?
2432 // It looks wrong.
2433 staticElement =
2434 propagatedElement = _resolveElement(typeReference, propertyName);
2435 } else {
2436 staticElement = _resolveProperty(target, staticType, propertyName);
2437 propagatedElement =
2438 _resolveProperty(target, propagatedType, propertyName);
2439 }
2440 // May be part of annotation, record property element only if exists.
2441 // Error was already reported in validateAnnotationElement().
2442 if (target.parent.parent is Annotation) {
2443 if (staticElement != null) {
2444 propertyName.staticElement = staticElement;
2445 }
2446 return;
2447 }
2448 propertyName.staticElement = staticElement;
2449 propertyName.propagatedElement = propagatedElement;
2450 bool shouldReportMissingMember_static =
2451 _shouldReportMissingMember(staticType, staticElement);
2452 bool shouldReportMissingMember_propagated =
2453 !shouldReportMissingMember_static &&
2454 _enableHints &&
2455 _shouldReportMissingMember(propagatedType, propagatedElement) &&
2456 !_memberFoundInSubclass(
2457 propagatedType.element, propertyName.name, false, true);
2458 if (shouldReportMissingMember_static ||
2459 shouldReportMissingMember_propagated) {
2460 DartType staticOrPropagatedType =
2461 shouldReportMissingMember_static ? staticType : propagatedType;
2462 Element staticOrPropagatedEnclosingElt = staticOrPropagatedType.element;
2463 bool isStaticProperty = _isStatic(staticOrPropagatedEnclosingElt);
2464 DartType displayType = staticOrPropagatedType != null
2465 ? staticOrPropagatedType
2466 : propagatedType != null ? propagatedType : staticType;
2467 // Special getter cases.
2468 if (propertyName.inGetterContext()) {
2469 if (!isStaticProperty &&
2470 staticOrPropagatedEnclosingElt is ClassElement) {
2471 ClassElement classElement = staticOrPropagatedEnclosingElt;
2472 InterfaceType targetType = classElement.type;
2473 if (!_enableStrictCallChecks &&
2474 targetType != null &&
2475 targetType.isDartCoreFunction &&
2476 propertyName.name == FunctionElement.CALL_METHOD_NAME) {
2477 // TODO(brianwilkerson) Can we ever resolve the function being
2478 // invoked?
2479 // resolveArgumentsToParameters(node.getArgumentList(), invokedFuncti on);
2480 return;
2481 } else if (classElement.isEnum && propertyName.name == "_name") {
2482 _resolver.reportErrorForNode(
2483 CompileTimeErrorCode.ACCESS_PRIVATE_ENUM_FIELD, propertyName,
2484 [propertyName.name]);
2485 return;
2486 }
2487 }
2488 }
2489 Element declaringElement =
2490 staticType.isVoid ? null : staticOrPropagatedEnclosingElt;
2491 if (propertyName.inSetterContext()) {
2492 ErrorCode errorCode;
2493 if (shouldReportMissingMember_static) {
2494 if (target is SuperExpression) {
2495 if (isStaticProperty && !staticType.isVoid) {
2496 errorCode = StaticWarningCode.UNDEFINED_SUPER_SETTER;
2497 } else {
2498 errorCode = StaticTypeWarningCode.UNDEFINED_SUPER_SETTER;
2499 }
2500 } else {
2501 if (isStaticProperty && !staticType.isVoid) {
2502 errorCode = StaticWarningCode.UNDEFINED_SETTER;
2503 } else {
2504 errorCode = StaticTypeWarningCode.UNDEFINED_SETTER;
2505 }
2506 }
2507 } else {
2508 errorCode = HintCode.UNDEFINED_SETTER;
2509 }
2510 _recordUndefinedNode(declaringElement, errorCode, propertyName, [
2511 propertyName.name,
2512 displayType.displayName
2513 ]);
2514 } else if (propertyName.inGetterContext()) {
2515 ErrorCode errorCode;
2516 if (shouldReportMissingMember_static) {
2517 if (target is SuperExpression) {
2518 if (isStaticProperty && !staticType.isVoid) {
2519 errorCode = StaticWarningCode.UNDEFINED_SUPER_GETTER;
2520 } else {
2521 errorCode = StaticTypeWarningCode.UNDEFINED_SUPER_GETTER;
2522 }
2523 } else {
2524 if (isStaticProperty && !staticType.isVoid) {
2525 errorCode = StaticWarningCode.UNDEFINED_GETTER;
2526 } else {
2527 errorCode = StaticTypeWarningCode.UNDEFINED_GETTER;
2528 }
2529 }
2530 } else {
2531 errorCode = HintCode.UNDEFINED_GETTER;
2532 }
2533 _recordUndefinedNode(declaringElement, errorCode, propertyName, [
2534 propertyName.name,
2535 displayType.displayName
2536 ]);
2537 } else {
2538 _recordUndefinedNode(declaringElement,
2539 StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName,
2540 [propertyName.name]);
2541 }
2542 }
2543 }
2544
2545 /**
2546 * Resolve the given simple [identifier] if possible. Return the element to
2547 * which it could be resolved, or `null` if it could not be resolved. This
2548 * does not record the results of the resolution.
2549 */
2550 Element _resolveSimpleIdentifier(SimpleIdentifier identifier) {
2551 Element element = _resolver.nameScope.lookup(identifier, _definingLibrary);
2552 if (element is PropertyAccessorElement && identifier.inSetterContext()) {
2553 PropertyInducingElement variable =
2554 (element as PropertyAccessorElement).variable;
2555 if (variable != null) {
2556 PropertyAccessorElement setter = variable.setter;
2557 if (setter == null) {
2558 //
2559 // Check to see whether there might be a locally defined getter and
2560 // an inherited setter.
2561 //
2562 ClassElement enclosingClass = _resolver.enclosingClass;
2563 if (enclosingClass != null) {
2564 setter = _lookUpSetter(null, enclosingClass.type, identifier.name);
2565 }
2566 }
2567 if (setter != null) {
2568 element = setter;
2569 }
2570 }
2571 } else if (element == null &&
2572 (identifier.inSetterContext() ||
2573 identifier.parent is CommentReference)) {
2574 element = _resolver.nameScope.lookup(
2575 new SyntheticIdentifier("${identifier.name}=", identifier),
2576 _definingLibrary);
2577 }
2578 ClassElement enclosingClass = _resolver.enclosingClass;
2579 if (element == null && enclosingClass != null) {
2580 InterfaceType enclosingType = enclosingClass.type;
2581 if (element == null &&
2582 (identifier.inSetterContext() ||
2583 identifier.parent is CommentReference)) {
2584 element = _lookUpSetter(null, enclosingType, identifier.name);
2585 }
2586 if (element == null && identifier.inGetterContext()) {
2587 element = _lookUpGetter(null, enclosingType, identifier.name);
2588 }
2589 if (element == null) {
2590 element = _lookUpMethod(null, enclosingType, identifier.name);
2591 }
2592 }
2593 return element;
2594 }
2595
2596 /**
2597 * If the given [type] is a type parameter, resolve it to the type that should
2598 * be used when looking up members. Otherwise, return the original type.
2599 */
2600 DartType _resolveTypeParameter(DartType type) {
2601 if (type is TypeParameterType) {
2602 DartType bound = type.element.bound;
2603 if (bound == null) {
2604 return _resolver.typeProvider.objectType;
2605 }
2606 return bound;
2607 }
2608 return type;
2609 }
2610
2611 /**
2612 * Given a [node] that can have annotations associated with it and the
2613 * [element] to which that node has been resolved, create the annotations in
2614 * the element model representing the annotations on the node.
2615 */
2616 void _setMetadataForParameter(Element element, NormalFormalParameter node) {
2617 if (element is! ElementImpl) {
2618 return;
2619 }
2620 List<ElementAnnotationImpl> annotationList =
2621 new List<ElementAnnotationImpl>();
2622 _addAnnotations(annotationList, node.metadata);
2623 if (!annotationList.isEmpty) {
2624 (element as ElementImpl).metadata = annotationList;
2625 }
2626 }
2627
2628 /**
2629 * Return `true` if we should report an error as a result of looking up a
2630 * [member] in the given [type] and not finding any member.
2631 */
2632 bool _shouldReportMissingMember(DartType type, Element member) {
2633 if (member != null || type == null || type.isDynamic || type.isBottom) {
2634 return false;
2635 }
2636 return true;
2637 }
2638
2639 /**
2640 * Checks whether the given [expression] is a reference to a class. If it is
2641 * then the element representing the class is returned, otherwise `null` is
2642 * returned.
2643 */
2644 static ClassElementImpl getTypeReference(Expression expression) {
2645 if (expression is Identifier) {
2646 Element staticElement = expression.staticElement;
2647 if (staticElement is ClassElementImpl) {
2648 return staticElement;
2649 }
2650 }
2651 return null;
2652 }
2653
2654 /**
2655 * Given a [node] that can have annotations associated with it and the
2656 * [element] to which that node has been resolved, create the annotations in
2657 * the element model representing the annotations on the node.
2658 */
2659 static void setMetadata(Element element, AnnotatedNode node) {
2660 if (element is! ElementImpl) {
2661 return;
2662 }
2663 List<ElementAnnotationImpl> annotationList = <ElementAnnotationImpl>[];
2664 _addAnnotations(annotationList, node.metadata);
2665 if (node is VariableDeclaration && node.parent is VariableDeclarationList) {
2666 VariableDeclarationList list = node.parent as VariableDeclarationList;
2667 _addAnnotations(annotationList, list.metadata);
2668 if (list.parent is FieldDeclaration) {
2669 FieldDeclaration fieldDeclaration = list.parent as FieldDeclaration;
2670 _addAnnotations(annotationList, fieldDeclaration.metadata);
2671 } else if (list.parent is TopLevelVariableDeclaration) {
2672 TopLevelVariableDeclaration variableDeclaration =
2673 list.parent as TopLevelVariableDeclaration;
2674 _addAnnotations(annotationList, variableDeclaration.metadata);
2675 }
2676 }
2677 if (!annotationList.isEmpty) {
2678 (element as ElementImpl).metadata = annotationList;
2679 }
2680 }
2681
2682 /**
2683 * Generate annotation elements for each of the annotations in the
2684 * [annotationList] and add them to the given list of [annotations].
2685 */
2686 static void _addAnnotations(List<ElementAnnotationImpl> annotationList,
2687 NodeList<Annotation> annotations) {
2688 int annotationCount = annotations.length;
2689 for (int i = 0; i < annotationCount; i++) {
2690 Annotation annotation = annotations[i];
2691 Element resolvedElement = annotation.element;
2692 if (resolvedElement != null) {
2693 ElementAnnotationImpl elementAnnotation =
2694 new ElementAnnotationImpl(resolvedElement);
2695 annotation.elementAnnotation = elementAnnotation;
2696 annotationList.add(elementAnnotation);
2697 }
2698 }
2699 }
2700
2701 /**
2702 * Return `true` if the given [identifier] is the return type of a constructor
2703 * declaration.
2704 */
2705 static bool _isConstructorReturnType(SimpleIdentifier identifier) {
2706 AstNode parent = identifier.parent;
2707 if (parent is ConstructorDeclaration) {
2708 return identical(parent.returnType, identifier);
2709 }
2710 return false;
2711 }
2712
2713 /**
2714 * Return `true` if the given [identifier] is the return type of a factory
2715 * constructor.
2716 */
2717 static bool _isFactoryConstructorReturnType(SimpleIdentifier identifier) {
2718 AstNode parent = identifier.parent;
2719 if (parent is ConstructorDeclaration) {
2720 ConstructorDeclaration constructor = parent;
2721 return identical(constructor.returnType, identifier) &&
2722 constructor.factoryKeyword != null;
2723 }
2724 return false;
2725 }
2726
2727 /**
2728 * Return `true` if the given 'super' [expression] is used in a valid context.
2729 */
2730 static bool _isSuperInValidContext(SuperExpression expression) {
2731 for (AstNode node = expression; node != null; node = node.parent) {
2732 if (node is CompilationUnit) {
2733 return false;
2734 }
2735 if (node is ConstructorDeclaration) {
2736 return node.factoryKeyword == null;
2737 }
2738 if (node is ConstructorFieldInitializer) {
2739 return false;
2740 }
2741 if (node is MethodDeclaration) {
2742 return !node.isStatic;
2743 }
2744 }
2745 return false;
2746 }
2747 }
2748
2749 /**
2750 * An identifier that can be used to look up names in the lexical scope when
2751 * there is no identifier in the AST structure. There is no identifier in the
2752 * AST when the parser could not distinguish between a method invocation and an
2753 * invocation of a top-level function imported with a prefix.
2754 */
2755 class SyntheticIdentifier extends Identifier {
2756 /**
2757 * The name of the synthetic identifier.
2758 */
2759 final String name;
2760
2761 /**
2762 * The identifier to be highlighted in case of an error
2763 */
2764 final Identifier targetIdentifier;
2765
2766 /**
2767 * Initialize a newly created synthetic identifier to have the given [name]
2768 * and [targetIdentifier].
2769 */
2770 SyntheticIdentifier(this.name, this.targetIdentifier);
2771
2772 @override
2773 sc.Token get beginToken => null;
2774
2775 @override
2776 Element get bestElement => null;
2777
2778 @override
2779 Iterable get childEntities {
2780 // Should never be called, since a SyntheticIdentifier never appears in the
2781 // AST--it is just used for lookup.
2782 assert(false);
2783 return new ChildEntities();
2784 }
2785
2786 @override
2787 sc.Token get endToken => null;
2788
2789 @override
2790 int get length => targetIdentifier.length;
2791
2792 @override
2793 int get offset => targetIdentifier.offset;
2794
2795 @override
2796 int get precedence => 16;
2797
2798 @override
2799 Element get propagatedElement => null;
2800
2801 @override
2802 Element get staticElement => null;
2803
2804 @override
2805 accept(AstVisitor visitor) => null;
2806
2807 @override
2808 void visitChildren(AstVisitor visitor) {}
2809 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698