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

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

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

Powered by Google App Engine
This is Rietveld 408576698