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

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

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « analyzer/lib/src/generated/parser.dart ('k') | analyzer/lib/src/generated/scanner.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;
6
7 import 'dart:collection';
8
9 import 'ast.dart';
10 import 'constant.dart';
11 import 'element.dart';
12 import 'element_resolver.dart';
13 import 'engine.dart';
14 import 'error.dart';
15 import 'error_verifier.dart';
16 import 'html.dart' as ht;
17 import 'java_core.dart';
18 import 'java_engine.dart';
19 import 'scanner.dart' as sc;
20 import 'sdk.dart' show DartSdk, SdkLibrary;
21 import 'source.dart';
22 import 'static_type_analyzer.dart';
23 import 'utilities_dart.dart';
24
25 /**
26 * Callback signature used by ImplicitConstructorBuilder to register
27 * computations to be performed, and their dependencies. A call to this
28 * callback indicates that [computation] may be used to compute implicit
29 * constructors for [classElement], but that the computation may not be invoked
30 * until after implicit constructors have been built for [superclassElement].
31 */
32 typedef void ImplicitConstructorBuilderCallback(ClassElement classElement,
33 ClassElement superclassElement, void computation());
34
35 typedef LibraryResolver LibraryResolverFactory(AnalysisContext context);
36
37 typedef ResolverVisitor ResolverVisitorFactory(
38 Library library, Source source, TypeProvider typeProvider);
39
40 typedef StaticTypeAnalyzer StaticTypeAnalyzerFactory(ResolverVisitor visitor);
41
42 typedef TypeResolverVisitor TypeResolverVisitorFactory(
43 Library library, Source source, TypeProvider typeProvider);
44
45 typedef void VoidFunction();
46
47 /**
48 * Instances of the class `BestPracticesVerifier` traverse an AST structure look ing for
49 * violations of Dart best practices.
50 */
51 class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
52 // static String _HASHCODE_GETTER_NAME = "hashCode";
53
54 static String _NULL_TYPE_NAME = "Null";
55
56 static String _TO_INT_METHOD_NAME = "toInt";
57
58 /**
59 * The class containing the AST nodes being visited, or `null` if we are not i n the scope of
60 * a class.
61 */
62 ClassElement _enclosingClass;
63
64 /**
65 * The error reporter by which errors will be reported.
66 */
67 final ErrorReporter _errorReporter;
68
69 /**
70 * The type Future<Null>, which is needed for determining whether it is safe
71 * to have a bare "return;" in an async method.
72 */
73 final InterfaceType _futureNullType;
74
75 /**
76 * Create a new instance of the [BestPracticesVerifier].
77 *
78 * @param errorReporter the error reporter
79 */
80 BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider)
81 : _futureNullType = typeProvider.futureNullType;
82
83 @override
84 Object visitArgumentList(ArgumentList node) {
85 _checkForArgumentTypesNotAssignableInList(node);
86 return super.visitArgumentList(node);
87 }
88
89 @override
90 Object visitAsExpression(AsExpression node) {
91 _checkForUnnecessaryCast(node);
92 return super.visitAsExpression(node);
93 }
94
95 @override
96 Object visitAssignmentExpression(AssignmentExpression node) {
97 sc.TokenType operatorType = node.operator.type;
98 if (operatorType == sc.TokenType.EQ) {
99 _checkForUseOfVoidResult(node.rightHandSide);
100 _checkForInvalidAssignment(node.leftHandSide, node.rightHandSide);
101 } else {
102 _checkForDeprecatedMemberUse(node.bestElement, node);
103 }
104 return super.visitAssignmentExpression(node);
105 }
106
107 @override
108 Object visitBinaryExpression(BinaryExpression node) {
109 _checkForDivisionOptimizationHint(node);
110 _checkForDeprecatedMemberUse(node.bestElement, node);
111 return super.visitBinaryExpression(node);
112 }
113
114 @override
115 Object visitClassDeclaration(ClassDeclaration node) {
116 ClassElement outerClass = _enclosingClass;
117 try {
118 _enclosingClass = node.element;
119 // Commented out until we decide that we want this hint in the analyzer
120 // checkForOverrideEqualsButNotHashCode(node);
121 return super.visitClassDeclaration(node);
122 } finally {
123 _enclosingClass = outerClass;
124 }
125 }
126
127 @override
128 Object visitExportDirective(ExportDirective node) {
129 _checkForDeprecatedMemberUse(node.uriElement, node);
130 return super.visitExportDirective(node);
131 }
132
133 @override
134 Object visitFunctionDeclaration(FunctionDeclaration node) {
135 _checkForMissingReturn(node.returnType, node.functionExpression.body);
136 return super.visitFunctionDeclaration(node);
137 }
138
139 @override
140 Object visitImportDirective(ImportDirective node) {
141 _checkForDeprecatedMemberUse(node.uriElement, node);
142 ImportElement importElement = node.element;
143 if (importElement != null) {
144 if (importElement.isDeferred) {
145 _checkForLoadLibraryFunction(node, importElement);
146 }
147 }
148 return super.visitImportDirective(node);
149 }
150
151 @override
152 Object visitIndexExpression(IndexExpression node) {
153 _checkForDeprecatedMemberUse(node.bestElement, node);
154 return super.visitIndexExpression(node);
155 }
156
157 @override
158 Object visitInstanceCreationExpression(InstanceCreationExpression node) {
159 _checkForDeprecatedMemberUse(node.staticElement, node);
160 return super.visitInstanceCreationExpression(node);
161 }
162
163 @override
164 Object visitIsExpression(IsExpression node) {
165 _checkAllTypeChecks(node);
166 return super.visitIsExpression(node);
167 }
168
169 @override
170 Object visitMethodDeclaration(MethodDeclaration node) {
171 // This was determined to not be a good hint, see: dartbug.com/16029
172 //checkForOverridingPrivateMember(node);
173 _checkForMissingReturn(node.returnType, node.body);
174 return super.visitMethodDeclaration(node);
175 }
176
177 @override
178 Object visitPostfixExpression(PostfixExpression node) {
179 _checkForDeprecatedMemberUse(node.bestElement, node);
180 return super.visitPostfixExpression(node);
181 }
182
183 @override
184 Object visitPrefixExpression(PrefixExpression node) {
185 _checkForDeprecatedMemberUse(node.bestElement, node);
186 return super.visitPrefixExpression(node);
187 }
188
189 @override
190 Object visitRedirectingConstructorInvocation(
191 RedirectingConstructorInvocation node) {
192 _checkForDeprecatedMemberUse(node.staticElement, node);
193 return super.visitRedirectingConstructorInvocation(node);
194 }
195
196 @override
197 Object visitSimpleIdentifier(SimpleIdentifier node) {
198 _checkForDeprecatedMemberUseAtIdentifier(node);
199 return super.visitSimpleIdentifier(node);
200 }
201
202 @override
203 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
204 _checkForDeprecatedMemberUse(node.staticElement, node);
205 return super.visitSuperConstructorInvocation(node);
206 }
207
208 @override
209 Object visitVariableDeclaration(VariableDeclaration node) {
210 _checkForUseOfVoidResult(node.initializer);
211 _checkForInvalidAssignment(node.name, node.initializer);
212 return super.visitVariableDeclaration(node);
213 }
214
215 /**
216 * Check for the passed is expression for the unnecessary type check hint code s as well as null
217 * checks expressed using an is expression.
218 *
219 * @param node the is expression to check
220 * @return `true` if and only if a hint code is generated on the passed node
221 * See [HintCode.TYPE_CHECK_IS_NOT_NULL], [HintCode.TYPE_CHECK_IS_NULL],
222 * [HintCode.UNNECESSARY_TYPE_CHECK_TRUE], and
223 * [HintCode.UNNECESSARY_TYPE_CHECK_FALSE].
224 */
225 bool _checkAllTypeChecks(IsExpression node) {
226 Expression expression = node.expression;
227 TypeName typeName = node.type;
228 DartType lhsType = expression.staticType;
229 DartType rhsType = typeName.type;
230 if (lhsType == null || rhsType == null) {
231 return false;
232 }
233 String rhsNameStr = typeName.name.name;
234 // if x is dynamic
235 if (rhsType.isDynamic && rhsNameStr == sc.Keyword.DYNAMIC.syntax) {
236 if (node.notOperator == null) {
237 // the is case
238 _errorReporter.reportErrorForNode(
239 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node);
240 } else {
241 // the is not case
242 _errorReporter.reportErrorForNode(
243 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node);
244 }
245 return true;
246 }
247 Element rhsElement = rhsType.element;
248 LibraryElement libraryElement =
249 rhsElement != null ? rhsElement.library : null;
250 if (libraryElement != null && libraryElement.isDartCore) {
251 // if x is Object or null is Null
252 if (rhsType.isObject ||
253 (expression is NullLiteral && rhsNameStr == _NULL_TYPE_NAME)) {
254 if (node.notOperator == null) {
255 // the is case
256 _errorReporter.reportErrorForNode(
257 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node);
258 } else {
259 // the is not case
260 _errorReporter.reportErrorForNode(
261 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node);
262 }
263 return true;
264 } else if (rhsNameStr == _NULL_TYPE_NAME) {
265 if (node.notOperator == null) {
266 // the is case
267 _errorReporter.reportErrorForNode(HintCode.TYPE_CHECK_IS_NULL, node);
268 } else {
269 // the is not case
270 _errorReporter.reportErrorForNode(
271 HintCode.TYPE_CHECK_IS_NOT_NULL, node);
272 }
273 return true;
274 }
275 }
276 return false;
277 }
278
279 /**
280 * This verifies that the passed expression can be assigned to its correspondi ng parameters.
281 *
282 * This method corresponds to ErrorVerifier.checkForArgumentTypeNotAssignable.
283 *
284 * TODO (jwren) In the ErrorVerifier there are other warnings that we could ha ve a corresponding
285 * hint for: see other callers of ErrorVerifier.checkForArgumentTypeNotAssigna ble(..).
286 *
287 * @param expression the expression to evaluate
288 * @param expectedStaticType the expected static type of the parameter
289 * @param actualStaticType the actual static type of the argument
290 * @param expectedPropagatedType the expected propagated type of the parameter , may be
291 * `null`
292 * @param actualPropagatedType the expected propagated type of the parameter, may be `null`
293 * @return `true` if and only if an hint code is generated on the passed node
294 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
295 */
296 bool _checkForArgumentTypeNotAssignable(Expression expression,
297 DartType expectedStaticType, DartType actualStaticType,
298 DartType expectedPropagatedType, DartType actualPropagatedType,
299 ErrorCode hintCode) {
300 //
301 // Warning case: test static type information
302 //
303 if (actualStaticType != null && expectedStaticType != null) {
304 if (!actualStaticType.isAssignableTo(expectedStaticType)) {
305 // A warning was created in the ErrorVerifier, return false, don't
306 // create a hint when a warning has already been created.
307 return false;
308 }
309 }
310 //
311 // Hint case: test propagated type information
312 //
313 // Compute the best types to use.
314 DartType expectedBestType = expectedPropagatedType != null
315 ? expectedPropagatedType
316 : expectedStaticType;
317 DartType actualBestType =
318 actualPropagatedType != null ? actualPropagatedType : actualStaticType;
319 if (actualBestType != null && expectedBestType != null) {
320 if (!actualBestType.isAssignableTo(expectedBestType)) {
321 _errorReporter.reportTypeErrorForNode(
322 hintCode, expression, [actualBestType, expectedBestType]);
323 return true;
324 }
325 }
326 return false;
327 }
328
329 /**
330 * This verifies that the passed argument can be assigned to its corresponding parameter.
331 *
332 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableForAr gument.
333 *
334 * @param argument the argument to evaluate
335 * @return `true` if and only if an hint code is generated on the passed node
336 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
337 */
338 bool _checkForArgumentTypeNotAssignableForArgument(Expression argument) {
339 if (argument == null) {
340 return false;
341 }
342 ParameterElement staticParameterElement = argument.staticParameterElement;
343 DartType staticParameterType =
344 staticParameterElement == null ? null : staticParameterElement.type;
345 ParameterElement propagatedParameterElement =
346 argument.propagatedParameterElement;
347 DartType propagatedParameterType = propagatedParameterElement == null
348 ? null
349 : propagatedParameterElement.type;
350 return _checkForArgumentTypeNotAssignableWithExpectedTypes(argument,
351 staticParameterType, propagatedParameterType,
352 HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE);
353 }
354
355 /**
356 * This verifies that the passed expression can be assigned to its correspondi ng parameters.
357 *
358 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableWithE xpectedTypes.
359 *
360 * @param expression the expression to evaluate
361 * @param expectedStaticType the expected static type
362 * @param expectedPropagatedType the expected propagated type, may be `null`
363 * @return `true` if and only if an hint code is generated on the passed node
364 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
365 */
366 bool _checkForArgumentTypeNotAssignableWithExpectedTypes(
367 Expression expression, DartType expectedStaticType,
368 DartType expectedPropagatedType, ErrorCode errorCode) =>
369 _checkForArgumentTypeNotAssignable(expression, expectedStaticType,
370 expression.staticType, expectedPropagatedType,
371 expression.propagatedType, errorCode);
372
373 /**
374 * This verifies that the passed arguments can be assigned to their correspond ing parameters.
375 *
376 * This method corresponds to ErrorCode.checkForArgumentTypesNotAssignableInLi st.
377 *
378 * @param node the arguments to evaluate
379 * @return `true` if and only if an hint code is generated on the passed node
380 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
381 */
382 bool _checkForArgumentTypesNotAssignableInList(ArgumentList argumentList) {
383 if (argumentList == null) {
384 return false;
385 }
386 bool problemReported = false;
387 for (Expression argument in argumentList.arguments) {
388 if (_checkForArgumentTypeNotAssignableForArgument(argument)) {
389 problemReported = true;
390 }
391 }
392 return problemReported;
393 }
394
395 /**
396 * Given some [Element], look at the associated metadata and report the use of the member if
397 * it is declared as deprecated.
398 *
399 * @param element some element to check for deprecated use of
400 * @param node the node use for the location of the error
401 * @return `true` if and only if a hint code is generated on the passed node
402 * See [HintCode.DEPRECATED_MEMBER_USE].
403 */
404 bool _checkForDeprecatedMemberUse(Element element, AstNode node) {
405 if (element != null && element.isDeprecated) {
406 String displayName = element.displayName;
407 if (element is ConstructorElement) {
408 // TODO(jwren) We should modify ConstructorElement.getDisplayName(),
409 // or have the logic centralized elsewhere, instead of doing this logic
410 // here.
411 ConstructorElement constructorElement = element;
412 displayName = constructorElement.enclosingElement.displayName;
413 if (!constructorElement.displayName.isEmpty) {
414 displayName = "$displayName.${constructorElement.displayName}";
415 }
416 }
417 _errorReporter.reportErrorForNode(
418 HintCode.DEPRECATED_MEMBER_USE, node, [displayName]);
419 return true;
420 }
421 return false;
422 }
423
424 /**
425 * For [SimpleIdentifier]s, only call [checkForDeprecatedMemberUse]
426 * if the node is not in a declaration context.
427 *
428 * Also, if the identifier is a constructor name in a constructor invocation, then calls to the
429 * deprecated constructor will be caught by
430 * [visitInstanceCreationExpression] and
431 * [visitSuperConstructorInvocation], and can be ignored by
432 * this visit method.
433 *
434 * @param identifier some simple identifier to check for deprecated use of
435 * @return `true` if and only if a hint code is generated on the passed node
436 * See [HintCode.DEPRECATED_MEMBER_USE].
437 */
438 bool _checkForDeprecatedMemberUseAtIdentifier(SimpleIdentifier identifier) {
439 if (identifier.inDeclarationContext()) {
440 return false;
441 }
442 AstNode parent = identifier.parent;
443 if ((parent is ConstructorName && identical(identifier, parent.name)) ||
444 (parent is SuperConstructorInvocation &&
445 identical(identifier, parent.constructorName)) ||
446 parent is HideCombinator) {
447 return false;
448 }
449 return _checkForDeprecatedMemberUse(identifier.bestElement, identifier);
450 }
451
452 /**
453 * Check for the passed binary expression for the [HintCode.DIVISION_OPTIMIZAT ION].
454 *
455 * @param node the binary expression to check
456 * @return `true` if and only if a hint code is generated on the passed node
457 * See [HintCode.DIVISION_OPTIMIZATION].
458 */
459 bool _checkForDivisionOptimizationHint(BinaryExpression node) {
460 // Return if the operator is not '/'
461 if (node.operator.type != sc.TokenType.SLASH) {
462 return false;
463 }
464 // Return if the '/' operator is not defined in core, or if we don't know
465 // its static or propagated type
466 MethodElement methodElement = node.bestElement;
467 if (methodElement == null) {
468 return false;
469 }
470 LibraryElement libraryElement = methodElement.library;
471 if (libraryElement != null && !libraryElement.isDartCore) {
472 return false;
473 }
474 // Report error if the (x/y) has toInt() invoked on it
475 if (node.parent is ParenthesizedExpression) {
476 ParenthesizedExpression parenthesizedExpression =
477 _wrapParenthesizedExpression(node.parent as ParenthesizedExpression);
478 if (parenthesizedExpression.parent is MethodInvocation) {
479 MethodInvocation methodInvocation =
480 parenthesizedExpression.parent as MethodInvocation;
481 if (_TO_INT_METHOD_NAME == methodInvocation.methodName.name &&
482 methodInvocation.argumentList.arguments.isEmpty) {
483 _errorReporter.reportErrorForNode(
484 HintCode.DIVISION_OPTIMIZATION, methodInvocation);
485 return true;
486 }
487 }
488 }
489 return false;
490 }
491
492 /**
493 * This verifies that the passed left hand side and right hand side represent a valid assignment.
494 *
495 * This method corresponds to ErrorVerifier.checkForInvalidAssignment.
496 *
497 * @param lhs the left hand side expression
498 * @param rhs the right hand side expression
499 * @return `true` if and only if an error code is generated on the passed node
500 * See [HintCode.INVALID_ASSIGNMENT].
501 */
502 bool _checkForInvalidAssignment(Expression lhs, Expression rhs) {
503 if (lhs == null || rhs == null) {
504 return false;
505 }
506 VariableElement leftVariableElement = ErrorVerifier.getVariableElement(lhs);
507 DartType leftType = (leftVariableElement == null)
508 ? ErrorVerifier.getStaticType(lhs)
509 : leftVariableElement.type;
510 DartType staticRightType = ErrorVerifier.getStaticType(rhs);
511 if (!staticRightType.isAssignableTo(leftType)) {
512 // The warning was generated on this rhs
513 return false;
514 }
515 // Test for, and then generate the hint
516 DartType bestRightType = rhs.bestType;
517 if (leftType != null && bestRightType != null) {
518 if (!bestRightType.isAssignableTo(leftType)) {
519 _errorReporter.reportTypeErrorForNode(
520 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]);
521 return true;
522 }
523 }
524 return false;
525 }
526
527 /**
528 * Check that the imported library does not define a loadLibrary function. The import has already
529 * been determined to be deferred when this is called.
530 *
531 * @param node the import directive to evaluate
532 * @param importElement the [ImportElement] retrieved from the node
533 * @return `true` if and only if an error code is generated on the passed node
534 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION].
535 */
536 bool _checkForLoadLibraryFunction(
537 ImportDirective node, ImportElement importElement) {
538 LibraryElement importedLibrary = importElement.importedLibrary;
539 if (importedLibrary == null) {
540 return false;
541 }
542 if (importedLibrary.hasLoadLibraryFunction) {
543 _errorReporter.reportErrorForNode(
544 HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION, node,
545 [importedLibrary.name]);
546 return true;
547 }
548 return false;
549 }
550
551 /**
552 * Generate a hint for functions or methods that have a return type, but do no t have a return
553 * statement on all branches. At the end of blocks with no return, Dart implic itly returns
554 * `null`, avoiding these implicit returns is considered a best practice.
555 *
556 * Note: for async functions/methods, this hint only applies when the
557 * function has a return type that Future<Null> is not assignable to.
558 *
559 * @param node the binary expression to check
560 * @param body the function body
561 * @return `true` if and only if a hint code is generated on the passed node
562 * See [HintCode.MISSING_RETURN].
563 */
564 bool _checkForMissingReturn(TypeName returnType, FunctionBody body) {
565 // Check that the method or function has a return type, and a function body
566 if (returnType == null || body == null) {
567 return false;
568 }
569 // Check that the body is a BlockFunctionBody
570 if (body is! BlockFunctionBody) {
571 return false;
572 }
573 // Generators are never required to have a return statement.
574 if (body.isGenerator) {
575 return false;
576 }
577 // Check that the type is resolvable, and is not "void"
578 DartType returnTypeType = returnType.type;
579 if (returnTypeType == null || returnTypeType.isVoid) {
580 return false;
581 }
582 // For async, give no hint if Future<Null> is assignable to the return
583 // type.
584 if (body.isAsynchronous && _futureNullType.isAssignableTo(returnTypeType)) {
585 return false;
586 }
587 // Check the block for a return statement, if not, create the hint
588 BlockFunctionBody blockFunctionBody = body as BlockFunctionBody;
589 if (!ExitDetector.exits(blockFunctionBody)) {
590 _errorReporter.reportErrorForNode(
591 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
592 return true;
593 }
594 return false;
595 }
596
597 /**
598 * Check for the passed class declaration for the
599 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
600 *
601 * @param node the class declaration to check
602 * @return `true` if and only if a hint code is generated on the passed node
603 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
604 */
605 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
606 // ClassElement classElement = node.element;
607 // if (classElement == null) {
608 // return false;
609 // }
610 // MethodElement equalsOperatorMethodElement =
611 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
612 // if (equalsOperatorMethodElement != null) {
613 // PropertyAccessorElement hashCodeElement =
614 // classElement.getGetter(_HASHCODE_GETTER_NAME);
615 // if (hashCodeElement == null) {
616 // _errorReporter.reportErrorForNode(
617 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
618 // node.name,
619 // [classElement.displayName]);
620 // return true;
621 // }
622 // }
623 // return false;
624 // }
625
626 /**
627 * Check for the passed as expression for the [HintCode.UNNECESSARY_CAST] hint code.
628 *
629 * @param node the as expression to check
630 * @return `true` if and only if a hint code is generated on the passed node
631 * See [HintCode.UNNECESSARY_CAST].
632 */
633 bool _checkForUnnecessaryCast(AsExpression node) {
634 // TODO(jwren) After dartbug.com/13732, revisit this, we should be able to
635 // remove the (x is! TypeParameterType) checks.
636 AstNode parent = node.parent;
637 if (parent is ConditionalExpression &&
638 (node == parent.thenExpression || node == parent.elseExpression)) {
639 Expression thenExpression = parent.thenExpression;
640 DartType thenType;
641 if (thenExpression is AsExpression) {
642 thenType = thenExpression.expression.staticType;
643 } else {
644 thenType = thenExpression.staticType;
645 }
646 Expression elseExpression = parent.elseExpression;
647 DartType elseType;
648 if (elseExpression is AsExpression) {
649 elseType = elseExpression.expression.staticType;
650 } else {
651 elseType = elseExpression.staticType;
652 }
653 if (thenType != null &&
654 elseType != null &&
655 !thenType.isDynamic &&
656 !elseType.isDynamic &&
657 !thenType.isMoreSpecificThan(elseType) &&
658 !elseType.isMoreSpecificThan(thenType)) {
659 return false;
660 }
661 }
662 DartType lhsType = node.expression.staticType;
663 DartType rhsType = node.type.type;
664 if (lhsType != null &&
665 rhsType != null &&
666 !lhsType.isDynamic &&
667 !rhsType.isDynamic &&
668 lhsType.isMoreSpecificThan(rhsType)) {
669 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node);
670 return true;
671 }
672 return false;
673 }
674
675 /**
676 * Check for situations where the result of a method or function is used, when it returns 'void'.
677 *
678 * TODO(jwren) Many other situations of use could be covered. We currently cov er the cases var x =
679 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m (), f(m()), return
680 * m().
681 *
682 * @param node expression on the RHS of some assignment
683 * @return `true` if and only if a hint code is generated on the passed node
684 * See [HintCode.USE_OF_VOID_RESULT].
685 */
686 bool _checkForUseOfVoidResult(Expression expression) {
687 if (expression == null || expression is! MethodInvocation) {
688 return false;
689 }
690 MethodInvocation methodInvocation = expression as MethodInvocation;
691 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) {
692 SimpleIdentifier methodName = methodInvocation.methodName;
693 _errorReporter.reportErrorForNode(
694 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
695 return true;
696 }
697 return false;
698 }
699
700 /**
701 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the
702 * expression that is a parenthesized expression, but whose parent is not a pa renthesized
703 * expression.
704 *
705 * For example given the code `(((e)))`: `(e) -> (((e)))`.
706 *
707 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression
708 * @return the first parent or grand-parent that is a parenthesized expression , that does not have
709 * a parenthesized expression parent
710 */
711 static ParenthesizedExpression _wrapParenthesizedExpression(
712 ParenthesizedExpression parenthesizedExpression) {
713 if (parenthesizedExpression.parent is ParenthesizedExpression) {
714 return _wrapParenthesizedExpression(
715 parenthesizedExpression.parent as ParenthesizedExpression);
716 }
717 return parenthesizedExpression;
718 }
719 }
720
721 /**
722 * Instances of the class `ClassScope` implement the scope defined by a class.
723 */
724 class ClassScope extends EnclosedScope {
725 /**
726 * Initialize a newly created scope enclosed within another scope.
727 *
728 * @param enclosingScope the scope in which this scope is lexically enclosed
729 * @param typeElement the element representing the type represented by this sc ope
730 */
731 ClassScope(Scope enclosingScope, ClassElement typeElement)
732 : super(enclosingScope) {
733 if (typeElement == null) {
734 throw new IllegalArgumentException("class element cannot be null");
735 }
736 _defineMembers(typeElement);
737 }
738
739 @override
740 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
741 if (existing is PropertyAccessorElement && duplicate is MethodElement) {
742 if (existing.nameOffset < duplicate.nameOffset) {
743 return new AnalysisError(duplicate.source, duplicate.nameOffset,
744 duplicate.displayName.length,
745 CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME,
746 [existing.displayName]);
747 } else {
748 return new AnalysisError(existing.source, existing.nameOffset,
749 existing.displayName.length,
750 CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
751 [existing.displayName]);
752 }
753 }
754 return super.getErrorForDuplicate(existing, duplicate);
755 }
756
757 /**
758 * Define the instance members defined by the class.
759 *
760 * @param typeElement the element representing the type represented by this sc ope
761 */
762 void _defineMembers(ClassElement typeElement) {
763 for (PropertyAccessorElement accessor in typeElement.accessors) {
764 define(accessor);
765 }
766 for (MethodElement method in typeElement.methods) {
767 define(method);
768 }
769 }
770 }
771
772 /**
773 * A `CompilationUnitBuilder` builds an element model for a single compilation
774 * unit.
775 */
776 class CompilationUnitBuilder {
777 /**
778 * Build the compilation unit element for the given [source] based on the
779 * compilation [unit] associated with the source. Throw an AnalysisException
780 * if the element could not be built. [librarySource] is the source for the
781 * containing library.
782 */
783 CompilationUnitElementImpl buildCompilationUnit(
784 Source source, CompilationUnit unit, Source librarySource) {
785 return PerformanceStatistics.resolve.makeCurrentWhile(() {
786 if (unit == null) {
787 return null;
788 }
789 ElementHolder holder = new ElementHolder();
790 ElementBuilder builder = new ElementBuilder(holder);
791 unit.accept(builder);
792 CompilationUnitElementImpl element =
793 new CompilationUnitElementImpl(source.shortName);
794 element.accessors = holder.accessors;
795 element.enums = holder.enums;
796 element.functions = holder.functions;
797 element.source = source;
798 element.librarySource = librarySource;
799 element.typeAliases = holder.typeAliases;
800 element.types = holder.types;
801 element.topLevelVariables = holder.topLevelVariables;
802 unit.element = element;
803 holder.validate();
804 return element;
805 });
806 }
807 }
808
809 /**
810 * Instances of the class `ConstantVerifier` traverse an AST structure looking f or additional
811 * errors and warnings not covered by the parser and resolver. In particular, it looks for errors
812 * and warnings related to constant expressions.
813 */
814 class ConstantVerifier extends RecursiveAstVisitor<Object> {
815 /**
816 * The error reporter by which errors will be reported.
817 */
818 final ErrorReporter _errorReporter;
819
820 /**
821 * The type provider used to access the known types.
822 */
823 final TypeProvider _typeProvider;
824
825 /**
826 * The set of variables declared using '-D' on the command line.
827 */
828 final DeclaredVariables declaredVariables;
829
830 /**
831 * The type representing the type 'bool'.
832 */
833 InterfaceType _boolType;
834
835 /**
836 * The type representing the type 'int'.
837 */
838 InterfaceType _intType;
839
840 /**
841 * The type representing the type 'num'.
842 */
843 InterfaceType _numType;
844
845 /**
846 * The type representing the type 'string'.
847 */
848 InterfaceType _stringType;
849
850 /**
851 * The current library that is being analyzed.
852 */
853 final LibraryElement _currentLibrary;
854
855 /**
856 * Initialize a newly created constant verifier.
857 *
858 * @param errorReporter the error reporter by which errors will be reported
859 */
860 ConstantVerifier(this._errorReporter, this._currentLibrary,
861 this._typeProvider, this.declaredVariables) {
862 this._boolType = _typeProvider.boolType;
863 this._intType = _typeProvider.intType;
864 this._numType = _typeProvider.numType;
865 this._stringType = _typeProvider.stringType;
866 }
867
868 @override
869 Object visitAnnotation(Annotation node) {
870 super.visitAnnotation(node);
871 // check annotation creation
872 Element element = node.element;
873 if (element is ConstructorElement) {
874 ConstructorElement constructorElement = element;
875 // should 'const' constructor
876 if (!constructorElement.isConst) {
877 _errorReporter.reportErrorForNode(
878 CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node);
879 return null;
880 }
881 // should have arguments
882 ArgumentList argumentList = node.arguments;
883 if (argumentList == null) {
884 _errorReporter.reportErrorForNode(
885 CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node);
886 return null;
887 }
888 // arguments should be constants
889 _validateConstantArguments(argumentList);
890 }
891 return null;
892 }
893
894 @override
895 Object visitConstructorDeclaration(ConstructorDeclaration node) {
896 if (node.constKeyword != null) {
897 _validateConstructorInitializers(node);
898 _validateFieldInitializers(node.parent as ClassDeclaration, node);
899 }
900 _validateDefaultValues(node.parameters);
901 return super.visitConstructorDeclaration(node);
902 }
903
904 @override
905 Object visitFunctionExpression(FunctionExpression node) {
906 super.visitFunctionExpression(node);
907 _validateDefaultValues(node.parameters);
908 return null;
909 }
910
911 @override
912 Object visitInstanceCreationExpression(InstanceCreationExpression node) {
913 if (node.isConst) {
914 // We need to evaluate the constant to see if any errors occur during its
915 // evaluation.
916 ConstructorElement constructor = node.staticElement;
917 if (constructor != null) {
918 ConstantEvaluationEngine evaluationEngine =
919 new ConstantEvaluationEngine(_typeProvider, declaredVariables);
920 ConstantVisitor constantVisitor =
921 new ConstantVisitor(evaluationEngine, _errorReporter);
922 evaluationEngine.evaluateConstructorCall(node,
923 node.argumentList.arguments, constructor, constantVisitor,
924 _errorReporter);
925 }
926 }
927 _validateInstanceCreationArguments(node);
928 return super.visitInstanceCreationExpression(node);
929 }
930
931 @override
932 Object visitListLiteral(ListLiteral node) {
933 super.visitListLiteral(node);
934 if (node.constKeyword != null) {
935 DartObjectImpl result;
936 for (Expression element in node.elements) {
937 result =
938 _validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT);
939 if (result != null) {
940 _reportErrorIfFromDeferredLibrary(element,
941 CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRA RY);
942 }
943 }
944 }
945 return null;
946 }
947
948 @override
949 Object visitMapLiteral(MapLiteral node) {
950 super.visitMapLiteral(node);
951 bool isConst = node.constKeyword != null;
952 bool reportEqualKeys = true;
953 HashSet<DartObject> keys = new HashSet<DartObject>();
954 List<Expression> invalidKeys = new List<Expression>();
955 for (MapLiteralEntry entry in node.entries) {
956 Expression key = entry.key;
957 if (isConst) {
958 DartObjectImpl keyResult =
959 _validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY);
960 Expression valueExpression = entry.value;
961 DartObjectImpl valueResult = _validate(
962 valueExpression, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE);
963 if (valueResult != null) {
964 _reportErrorIfFromDeferredLibrary(valueExpression,
965 CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY) ;
966 }
967 if (keyResult != null) {
968 _reportErrorIfFromDeferredLibrary(key,
969 CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY);
970 if (keys.contains(keyResult)) {
971 invalidKeys.add(key);
972 } else {
973 keys.add(keyResult);
974 }
975 DartType type = keyResult.type;
976 if (_implementsEqualsWhenNotAllowed(type)) {
977 _errorReporter.reportErrorForNode(
978 CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQ UALS,
979 key, [type.displayName]);
980 }
981 }
982 } else {
983 // Note: we throw the errors away because this isn't actually a const.
984 AnalysisErrorListener errorListener =
985 AnalysisErrorListener.NULL_LISTENER;
986 ErrorReporter subErrorReporter =
987 new ErrorReporter(errorListener, _errorReporter.source);
988 DartObjectImpl result = key.accept(new ConstantVisitor(
989 new ConstantEvaluationEngine(_typeProvider, declaredVariables),
990 subErrorReporter));
991 if (result != null) {
992 if (keys.contains(result)) {
993 invalidKeys.add(key);
994 } else {
995 keys.add(result);
996 }
997 } else {
998 reportEqualKeys = false;
999 }
1000 }
1001 }
1002 if (reportEqualKeys) {
1003 for (Expression key in invalidKeys) {
1004 _errorReporter.reportErrorForNode(
1005 StaticWarningCode.EQUAL_KEYS_IN_MAP, key);
1006 }
1007 }
1008 return null;
1009 }
1010
1011 @override
1012 Object visitMethodDeclaration(MethodDeclaration node) {
1013 super.visitMethodDeclaration(node);
1014 _validateDefaultValues(node.parameters);
1015 return null;
1016 }
1017
1018 @override
1019 Object visitSwitchStatement(SwitchStatement node) {
1020 // TODO(paulberry): to minimize error messages, it would be nice to
1021 // compare all types with the most popular type rather than the first
1022 // type.
1023 NodeList<SwitchMember> switchMembers = node.members;
1024 bool foundError = false;
1025 DartType firstType = null;
1026 for (SwitchMember switchMember in switchMembers) {
1027 if (switchMember is SwitchCase) {
1028 SwitchCase switchCase = switchMember;
1029 Expression expression = switchCase.expression;
1030 DartObjectImpl caseResult = _validate(
1031 expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION);
1032 if (caseResult != null) {
1033 _reportErrorIfFromDeferredLibrary(expression,
1034 CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LI BRARY);
1035 DartObject value = caseResult;
1036 if (firstType == null) {
1037 firstType = value.type;
1038 } else {
1039 DartType nType = value.type;
1040 if (firstType != nType) {
1041 _errorReporter.reportErrorForNode(
1042 CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES,
1043 expression, [expression.toSource(), firstType.displayName]);
1044 foundError = true;
1045 }
1046 }
1047 }
1048 }
1049 }
1050 if (!foundError) {
1051 _checkForCaseExpressionTypeImplementsEquals(node, firstType);
1052 }
1053 return super.visitSwitchStatement(node);
1054 }
1055
1056 @override
1057 Object visitVariableDeclaration(VariableDeclaration node) {
1058 super.visitVariableDeclaration(node);
1059 Expression initializer = node.initializer;
1060 if (initializer != null && (node.isConst || node.isFinal)) {
1061 VariableElementImpl element = node.element as VariableElementImpl;
1062 EvaluationResultImpl result = element.evaluationResult;
1063 if (result == null) {
1064 // Variables marked "const" should have had their values computed by
1065 // ConstantValueComputer. Other variables will only have had their
1066 // values computed if the value was needed (e.g. final variables in a
1067 // class containing const constructors).
1068 assert(!node.isConst);
1069 return null;
1070 }
1071 _reportErrors(result.errors,
1072 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
1073 _reportErrorIfFromDeferredLibrary(initializer,
1074 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DE FERRED_LIBRARY);
1075 }
1076 return null;
1077 }
1078
1079 /**
1080 * This verifies that the passed switch statement does not have a case express ion with the
1081 * operator '==' overridden.
1082 *
1083 * @param node the switch statement to evaluate
1084 * @param type the common type of all 'case' expressions
1085 * @return `true` if and only if an error code is generated on the passed node
1086 * See [CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS].
1087 */
1088 bool _checkForCaseExpressionTypeImplementsEquals(
1089 SwitchStatement node, DartType type) {
1090 if (!_implementsEqualsWhenNotAllowed(type)) {
1091 return false;
1092 }
1093 // report error
1094 _errorReporter.reportErrorForToken(
1095 CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
1096 node.switchKeyword, [type.displayName]);
1097 return true;
1098 }
1099
1100 /**
1101 * @return `true` if given [Type] implements operator <i>==</i>, and it is not
1102 * <i>int</i> or <i>String</i>.
1103 */
1104 bool _implementsEqualsWhenNotAllowed(DartType type) {
1105 // ignore int or String
1106 if (type == null || type == _intType || type == _typeProvider.stringType) {
1107 return false;
1108 } else if (type == _typeProvider.doubleType) {
1109 return true;
1110 }
1111 // prepare ClassElement
1112 Element element = type.element;
1113 if (element is! ClassElement) {
1114 return false;
1115 }
1116 ClassElement classElement = element as ClassElement;
1117 // lookup for ==
1118 MethodElement method =
1119 classElement.lookUpConcreteMethod("==", _currentLibrary);
1120 if (method == null || method.enclosingElement.type.isObject) {
1121 return false;
1122 }
1123 // there is == that we don't like
1124 return true;
1125 }
1126
1127 /**
1128 * Given some computed [Expression], this method generates the passed [ErrorCo de] on
1129 * the node if its' value consists of information from a deferred library.
1130 *
1131 * @param expression the expression to be tested for a deferred library refere nce
1132 * @param errorCode the error code to be used if the expression is or consists of a reference to a
1133 * deferred library
1134 */
1135 void _reportErrorIfFromDeferredLibrary(
1136 Expression expression, ErrorCode errorCode) {
1137 DeferredLibraryReferenceDetector referenceDetector =
1138 new DeferredLibraryReferenceDetector();
1139 expression.accept(referenceDetector);
1140 if (referenceDetector.result) {
1141 _errorReporter.reportErrorForNode(errorCode, expression);
1142 }
1143 }
1144
1145 /**
1146 * Report any errors in the given list. Except for special cases, use the give n error code rather
1147 * than the one reported in the error.
1148 *
1149 * @param errors the errors that need to be reported
1150 * @param errorCode the error code to be used
1151 */
1152 void _reportErrors(List<AnalysisError> errors, ErrorCode errorCode) {
1153 for (AnalysisError data in errors) {
1154 ErrorCode dataErrorCode = data.errorCode;
1155 if (identical(dataErrorCode,
1156 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) ||
1157 identical(
1158 dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) ||
1159 identical(dataErrorCode,
1160 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) ||
1161 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) ||
1162 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) ||
1163 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) ||
1164 identical(dataErrorCode,
1165 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) ||
1166 identical(dataErrorCode,
1167 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMA TCH) ||
1168 identical(dataErrorCode,
1169 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMA TCH) ||
1170 identical(dataErrorCode,
1171 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH)) {
1172 _errorReporter.reportError(data);
1173 } else if (errorCode != null) {
1174 _errorReporter.reportError(new AnalysisError(
1175 data.source, data.offset, data.length, errorCode));
1176 }
1177 }
1178 }
1179
1180 /**
1181 * Validate that the given expression is a compile time constant. Return the v alue of the compile
1182 * time constant, or `null` if the expression is not a compile time constant.
1183 *
1184 * @param expression the expression to be validated
1185 * @param errorCode the error code to be used if the expression is not a compi le time constant
1186 * @return the value of the compile time constant
1187 */
1188 DartObjectImpl _validate(Expression expression, ErrorCode errorCode) {
1189 RecordingErrorListener errorListener = new RecordingErrorListener();
1190 ErrorReporter subErrorReporter =
1191 new ErrorReporter(errorListener, _errorReporter.source);
1192 DartObjectImpl result = expression.accept(new ConstantVisitor(
1193 new ConstantEvaluationEngine(_typeProvider, declaredVariables),
1194 subErrorReporter));
1195 _reportErrors(errorListener.errors, errorCode);
1196 return result;
1197 }
1198
1199 /**
1200 * Validate that if the passed arguments are constant expressions.
1201 *
1202 * @param argumentList the argument list to evaluate
1203 */
1204 void _validateConstantArguments(ArgumentList argumentList) {
1205 for (Expression argument in argumentList.arguments) {
1206 if (argument is NamedExpression) {
1207 argument = (argument as NamedExpression).expression;
1208 }
1209 _validate(
1210 argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
1211 }
1212 }
1213
1214 /**
1215 * Validates that the expressions of the given initializers (of a constant con structor) are all
1216 * compile time constants.
1217 *
1218 * @param constructor the constant constructor declaration to validate
1219 */
1220 void _validateConstructorInitializers(ConstructorDeclaration constructor) {
1221 List<ParameterElement> parameterElements =
1222 constructor.parameters.parameterElements;
1223 NodeList<ConstructorInitializer> initializers = constructor.initializers;
1224 for (ConstructorInitializer initializer in initializers) {
1225 if (initializer is ConstructorFieldInitializer) {
1226 ConstructorFieldInitializer fieldInitializer = initializer;
1227 _validateInitializerExpression(
1228 parameterElements, fieldInitializer.expression);
1229 }
1230 if (initializer is RedirectingConstructorInvocation) {
1231 RedirectingConstructorInvocation invocation = initializer;
1232 _validateInitializerInvocationArguments(
1233 parameterElements, invocation.argumentList);
1234 }
1235 if (initializer is SuperConstructorInvocation) {
1236 SuperConstructorInvocation invocation = initializer;
1237 _validateInitializerInvocationArguments(
1238 parameterElements, invocation.argumentList);
1239 }
1240 }
1241 }
1242
1243 /**
1244 * Validate that the default value associated with each of the parameters in t he given list is a
1245 * compile time constant.
1246 *
1247 * @param parameters the list of parameters to be validated
1248 */
1249 void _validateDefaultValues(FormalParameterList parameters) {
1250 if (parameters == null) {
1251 return;
1252 }
1253 for (FormalParameter parameter in parameters.parameters) {
1254 if (parameter is DefaultFormalParameter) {
1255 DefaultFormalParameter defaultParameter = parameter;
1256 Expression defaultValue = defaultParameter.defaultValue;
1257 DartObjectImpl result;
1258 if (defaultValue == null) {
1259 result =
1260 new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE);
1261 } else {
1262 result = _validate(
1263 defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE);
1264 if (result != null) {
1265 _reportErrorIfFromDeferredLibrary(defaultValue,
1266 CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LI BRARY);
1267 }
1268 }
1269 VariableElementImpl element = parameter.element as VariableElementImpl;
1270 element.evaluationResult = new EvaluationResultImpl(result);
1271 }
1272 }
1273 }
1274
1275 /**
1276 * Validates that the expressions of any field initializers in the class decla ration are all
1277 * compile time constants. Since this is only required if the class has a cons tant constructor,
1278 * the error is reported at the constructor site.
1279 *
1280 * @param classDeclaration the class which should be validated
1281 * @param errorSite the site at which errors should be reported.
1282 */
1283 void _validateFieldInitializers(
1284 ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) {
1285 NodeList<ClassMember> members = classDeclaration.members;
1286 for (ClassMember member in members) {
1287 if (member is FieldDeclaration) {
1288 FieldDeclaration fieldDeclaration = member;
1289 if (!fieldDeclaration.isStatic) {
1290 for (VariableDeclaration variableDeclaration
1291 in fieldDeclaration.fields.variables) {
1292 Expression initializer = variableDeclaration.initializer;
1293 if (initializer != null) {
1294 // Ignore any errors produced during validation--if the constant
1295 // can't be eavluated we'll just report a single error.
1296 AnalysisErrorListener errorListener =
1297 AnalysisErrorListener.NULL_LISTENER;
1298 ErrorReporter subErrorReporter =
1299 new ErrorReporter(errorListener, _errorReporter.source);
1300 DartObjectImpl result = initializer.accept(new ConstantVisitor(
1301 new ConstantEvaluationEngine(
1302 _typeProvider, declaredVariables), subErrorReporter));
1303 if (result == null) {
1304 _errorReporter.reportErrorForNode(
1305 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZE D_BY_NON_CONST,
1306 errorSite, [variableDeclaration.name.name]);
1307 }
1308 }
1309 }
1310 }
1311 }
1312 }
1313 }
1314
1315 /**
1316 * Validates that the given expression is a compile time constant.
1317 *
1318 * @param parameterElements the elements of parameters of constant constructor , they are
1319 * considered as a valid potentially constant expressions
1320 * @param expression the expression to validate
1321 */
1322 void _validateInitializerExpression(
1323 List<ParameterElement> parameterElements, Expression expression) {
1324 RecordingErrorListener errorListener = new RecordingErrorListener();
1325 ErrorReporter subErrorReporter =
1326 new ErrorReporter(errorListener, _errorReporter.source);
1327 DartObjectImpl result = expression.accept(
1328 new _ConstantVerifier_validateInitializerExpression(_typeProvider,
1329 subErrorReporter, this, parameterElements, declaredVariables));
1330 _reportErrors(errorListener.errors,
1331 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
1332 if (result != null) {
1333 _reportErrorIfFromDeferredLibrary(expression,
1334 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_L IBRARY);
1335 }
1336 }
1337
1338 /**
1339 * Validates that all of the arguments of a constructor initializer are compil e time constants.
1340 *
1341 * @param parameterElements the elements of parameters of constant constructor , they are
1342 * considered as a valid potentially constant expressions
1343 * @param argumentList the argument list to validate
1344 */
1345 void _validateInitializerInvocationArguments(
1346 List<ParameterElement> parameterElements, ArgumentList argumentList) {
1347 if (argumentList == null) {
1348 return;
1349 }
1350 for (Expression argument in argumentList.arguments) {
1351 _validateInitializerExpression(parameterElements, argument);
1352 }
1353 }
1354
1355 /**
1356 * Validate that if the passed instance creation is 'const' then all its argum ents are constant
1357 * expressions.
1358 *
1359 * @param node the instance creation evaluate
1360 */
1361 void _validateInstanceCreationArguments(InstanceCreationExpression node) {
1362 if (!node.isConst) {
1363 return;
1364 }
1365 ArgumentList argumentList = node.argumentList;
1366 if (argumentList == null) {
1367 return;
1368 }
1369 _validateConstantArguments(argumentList);
1370 }
1371 }
1372
1373 /**
1374 * Instances of the class `Dart2JSVerifier` traverse an AST structure looking fo r hints for
1375 * code that will be compiled to JS, such as [HintCode.IS_DOUBLE].
1376 */
1377 class Dart2JSVerifier extends RecursiveAstVisitor<Object> {
1378 /**
1379 * The name of the `double` type.
1380 */
1381 static String _DOUBLE_TYPE_NAME = "double";
1382
1383 /**
1384 * The error reporter by which errors will be reported.
1385 */
1386 final ErrorReporter _errorReporter;
1387
1388 /**
1389 * Create a new instance of the [Dart2JSVerifier].
1390 *
1391 * @param errorReporter the error reporter
1392 */
1393 Dart2JSVerifier(this._errorReporter);
1394
1395 @override
1396 Object visitIsExpression(IsExpression node) {
1397 _checkForIsDoubleHints(node);
1398 return super.visitIsExpression(node);
1399 }
1400
1401 /**
1402 * Check for instances of `x is double`, `x is int`, `x is! double` and
1403 * `x is! int`.
1404 *
1405 * @param node the is expression to check
1406 * @return `true` if and only if a hint code is generated on the passed node
1407 * See [HintCode.IS_DOUBLE],
1408 * [HintCode.IS_INT],
1409 * [HintCode.IS_NOT_DOUBLE], and
1410 * [HintCode.IS_NOT_INT].
1411 */
1412 bool _checkForIsDoubleHints(IsExpression node) {
1413 TypeName typeName = node.type;
1414 DartType type = typeName.type;
1415 if (type != null && type.element != null) {
1416 Element element = type.element;
1417 String typeNameStr = element.name;
1418 LibraryElement libraryElement = element.library;
1419 // if (typeNameStr.equals(INT_TYPE_NAME) && libraryElement != null
1420 // && libraryElement.isDartCore()) {
1421 // if (node.getNotOperator() == null) {
1422 // errorReporter.reportError(HintCode.IS_INT, node);
1423 // } else {
1424 // errorReporter.reportError(HintCode.IS_NOT_INT, node);
1425 // }
1426 // return true;
1427 // } else
1428 if (typeNameStr == _DOUBLE_TYPE_NAME &&
1429 libraryElement != null &&
1430 libraryElement.isDartCore) {
1431 if (node.notOperator == null) {
1432 _errorReporter.reportErrorForNode(HintCode.IS_DOUBLE, node);
1433 } else {
1434 _errorReporter.reportErrorForNode(HintCode.IS_NOT_DOUBLE, node);
1435 }
1436 return true;
1437 }
1438 }
1439 return false;
1440 }
1441 }
1442
1443 /**
1444 * Instances of the class `DeadCodeVerifier` traverse an AST structure looking f or cases of
1445 * [HintCode.DEAD_CODE].
1446 */
1447 class DeadCodeVerifier extends RecursiveAstVisitor<Object> {
1448 /**
1449 * The error reporter by which errors will be reported.
1450 */
1451 final ErrorReporter _errorReporter;
1452
1453 /**
1454 * Create a new instance of the [DeadCodeVerifier].
1455 *
1456 * @param errorReporter the error reporter
1457 */
1458 DeadCodeVerifier(this._errorReporter);
1459
1460 @override
1461 Object visitBinaryExpression(BinaryExpression node) {
1462 sc.Token operator = node.operator;
1463 bool isAmpAmp = operator.type == sc.TokenType.AMPERSAND_AMPERSAND;
1464 bool isBarBar = operator.type == sc.TokenType.BAR_BAR;
1465 if (isAmpAmp || isBarBar) {
1466 Expression lhsCondition = node.leftOperand;
1467 if (!_isDebugConstant(lhsCondition)) {
1468 EvaluationResultImpl lhsResult = _getConstantBooleanValue(lhsCondition);
1469 if (lhsResult != null) {
1470 if (lhsResult.value.isTrue && isBarBar) {
1471 // report error on else block: true || !e!
1472 _errorReporter.reportErrorForNode(
1473 HintCode.DEAD_CODE, node.rightOperand);
1474 // only visit the LHS:
1475 _safelyVisit(lhsCondition);
1476 return null;
1477 } else if (lhsResult.value.isFalse && isAmpAmp) {
1478 // report error on if block: false && !e!
1479 _errorReporter.reportErrorForNode(
1480 HintCode.DEAD_CODE, node.rightOperand);
1481 // only visit the LHS:
1482 _safelyVisit(lhsCondition);
1483 return null;
1484 }
1485 }
1486 }
1487 // How do we want to handle the RHS? It isn't dead code, but "pointless"
1488 // or "obscure"...
1489 // Expression rhsCondition = node.getRightOperand();
1490 // ValidResult rhsResult = getConstantBooleanValue(rhsCondition);
1491 // if (rhsResult != null) {
1492 // if (rhsResult == ValidResult.RESULT_TRUE && isBarBar) {
1493 // // report error on else block: !e! || true
1494 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand());
1495 // // only visit the RHS:
1496 // safelyVisit(rhsCondition);
1497 // return null;
1498 // } else if (rhsResult == ValidResult.RESULT_FALSE && isAmpAmp) {
1499 // // report error on if block: !e! && false
1500 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand());
1501 // // only visit the RHS:
1502 // safelyVisit(rhsCondition);
1503 // return null;
1504 // }
1505 // }
1506 }
1507 return super.visitBinaryExpression(node);
1508 }
1509
1510 /**
1511 * For each [Block], this method reports and error on all statements between t he end of the
1512 * block and the first return statement (assuming there it is not at the end o f the block.)
1513 *
1514 * @param node the block to evaluate
1515 */
1516 @override
1517 Object visitBlock(Block node) {
1518 NodeList<Statement> statements = node.statements;
1519 _checkForDeadStatementsInNodeList(statements);
1520 return null;
1521 }
1522
1523 @override
1524 Object visitConditionalExpression(ConditionalExpression node) {
1525 Expression conditionExpression = node.condition;
1526 _safelyVisit(conditionExpression);
1527 if (!_isDebugConstant(conditionExpression)) {
1528 EvaluationResultImpl result =
1529 _getConstantBooleanValue(conditionExpression);
1530 if (result != null) {
1531 if (result.value.isTrue) {
1532 // report error on else block: true ? 1 : !2!
1533 _errorReporter.reportErrorForNode(
1534 HintCode.DEAD_CODE, node.elseExpression);
1535 _safelyVisit(node.thenExpression);
1536 return null;
1537 } else {
1538 // report error on if block: false ? !1! : 2
1539 _errorReporter.reportErrorForNode(
1540 HintCode.DEAD_CODE, node.thenExpression);
1541 _safelyVisit(node.elseExpression);
1542 return null;
1543 }
1544 }
1545 }
1546 return super.visitConditionalExpression(node);
1547 }
1548
1549 @override
1550 Object visitIfStatement(IfStatement node) {
1551 Expression conditionExpression = node.condition;
1552 _safelyVisit(conditionExpression);
1553 if (!_isDebugConstant(conditionExpression)) {
1554 EvaluationResultImpl result =
1555 _getConstantBooleanValue(conditionExpression);
1556 if (result != null) {
1557 if (result.value.isTrue) {
1558 // report error on else block: if(true) {} else {!}
1559 Statement elseStatement = node.elseStatement;
1560 if (elseStatement != null) {
1561 _errorReporter.reportErrorForNode(
1562 HintCode.DEAD_CODE, elseStatement);
1563 _safelyVisit(node.thenStatement);
1564 return null;
1565 }
1566 } else {
1567 // report error on if block: if (false) {!} else {}
1568 _errorReporter.reportErrorForNode(
1569 HintCode.DEAD_CODE, node.thenStatement);
1570 _safelyVisit(node.elseStatement);
1571 return null;
1572 }
1573 }
1574 }
1575 return super.visitIfStatement(node);
1576 }
1577
1578 @override
1579 Object visitSwitchCase(SwitchCase node) {
1580 _checkForDeadStatementsInNodeList(node.statements);
1581 return super.visitSwitchCase(node);
1582 }
1583
1584 @override
1585 Object visitSwitchDefault(SwitchDefault node) {
1586 _checkForDeadStatementsInNodeList(node.statements);
1587 return super.visitSwitchDefault(node);
1588 }
1589
1590 @override
1591 Object visitTryStatement(TryStatement node) {
1592 _safelyVisit(node.body);
1593 _safelyVisit(node.finallyBlock);
1594 NodeList<CatchClause> catchClauses = node.catchClauses;
1595 int numOfCatchClauses = catchClauses.length;
1596 List<DartType> visitedTypes = new List<DartType>();
1597 for (int i = 0; i < numOfCatchClauses; i++) {
1598 CatchClause catchClause = catchClauses[i];
1599 if (catchClause.onKeyword != null) {
1600 // on-catch clause found, verify that the exception type is not a
1601 // subtype of a previous on-catch exception type
1602 TypeName typeName = catchClause.exceptionType;
1603 if (typeName != null && typeName.type != null) {
1604 DartType currentType = typeName.type;
1605 if (currentType.isObject) {
1606 // Found catch clause clause that has Object as an exception type,
1607 // this is equivalent to having a catch clause that doesn't have an
1608 // exception type, visit the block, but generate an error on any
1609 // following catch clauses (and don't visit them).
1610 _safelyVisit(catchClause);
1611 if (i + 1 != numOfCatchClauses) {
1612 // this catch clause is not the last in the try statement
1613 CatchClause nextCatchClause = catchClauses[i + 1];
1614 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1615 int offset = nextCatchClause.offset;
1616 int length = lastCatchClause.end - offset;
1617 _errorReporter.reportErrorForOffset(
1618 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length);
1619 return null;
1620 }
1621 }
1622 for (DartType type in visitedTypes) {
1623 if (currentType.isSubtypeOf(type)) {
1624 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1625 int offset = catchClause.offset;
1626 int length = lastCatchClause.end - offset;
1627 _errorReporter.reportErrorForOffset(
1628 HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, offset, length, [
1629 currentType.displayName,
1630 type.displayName
1631 ]);
1632 return null;
1633 }
1634 }
1635 visitedTypes.add(currentType);
1636 }
1637 _safelyVisit(catchClause);
1638 } else {
1639 // Found catch clause clause that doesn't have an exception type,
1640 // visit the block, but generate an error on any following catch clauses
1641 // (and don't visit them).
1642 _safelyVisit(catchClause);
1643 if (i + 1 != numOfCatchClauses) {
1644 // this catch clause is not the last in the try statement
1645 CatchClause nextCatchClause = catchClauses[i + 1];
1646 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1647 int offset = nextCatchClause.offset;
1648 int length = lastCatchClause.end - offset;
1649 _errorReporter.reportErrorForOffset(
1650 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length);
1651 return null;
1652 }
1653 }
1654 }
1655 return null;
1656 }
1657
1658 @override
1659 Object visitWhileStatement(WhileStatement node) {
1660 Expression conditionExpression = node.condition;
1661 _safelyVisit(conditionExpression);
1662 if (!_isDebugConstant(conditionExpression)) {
1663 EvaluationResultImpl result =
1664 _getConstantBooleanValue(conditionExpression);
1665 if (result != null) {
1666 if (result.value.isFalse) {
1667 // report error on if block: while (false) {!}
1668 _errorReporter.reportErrorForNode(HintCode.DEAD_CODE, node.body);
1669 return null;
1670 }
1671 }
1672 }
1673 _safelyVisit(node.body);
1674 return null;
1675 }
1676
1677 /**
1678 * Given some [NodeList] of [Statement]s, from either a [Block] or
1679 * [SwitchMember], this loops through the list in reverse order searching for statements
1680 * after a return, unlabeled break or unlabeled continue statement to mark the m as dead code.
1681 *
1682 * @param statements some ordered list of statements in a [Block] or [SwitchMe mber]
1683 */
1684 void _checkForDeadStatementsInNodeList(NodeList<Statement> statements) {
1685 int size = statements.length;
1686 for (int i = 0; i < size; i++) {
1687 Statement currentStatement = statements[i];
1688 _safelyVisit(currentStatement);
1689 bool returnOrBreakingStatement = currentStatement is ReturnStatement ||
1690 (currentStatement is BreakStatement &&
1691 currentStatement.label == null) ||
1692 (currentStatement is ContinueStatement &&
1693 currentStatement.label == null);
1694 if (returnOrBreakingStatement && i != size - 1) {
1695 Statement nextStatement = statements[i + 1];
1696 Statement lastStatement = statements[size - 1];
1697 int offset = nextStatement.offset;
1698 int length = lastStatement.end - offset;
1699 _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length);
1700 return;
1701 }
1702 }
1703 }
1704
1705 /**
1706 * Given some [Expression], this method returns [ValidResult.RESULT_TRUE] if i t is
1707 * `true`, [ValidResult.RESULT_FALSE] if it is `false`, or `null` if the
1708 * expression is not a constant boolean value.
1709 *
1710 * @param expression the expression to evaluate
1711 * @return [ValidResult.RESULT_TRUE] if it is `true`, [ValidResult.RESULT_FALS E]
1712 * if it is `false`, or `null` if the expression is not a constant boo lean
1713 * value
1714 */
1715 EvaluationResultImpl _getConstantBooleanValue(Expression expression) {
1716 if (expression is BooleanLiteral) {
1717 if (expression.value) {
1718 return new EvaluationResultImpl(
1719 new DartObjectImpl(null, BoolState.from(true)));
1720 } else {
1721 return new EvaluationResultImpl(
1722 new DartObjectImpl(null, BoolState.from(false)));
1723 }
1724 }
1725 // Don't consider situations where we could evaluate to a constant boolean
1726 // expression with the ConstantVisitor
1727 // else {
1728 // EvaluationResultImpl result = expression.accept(new ConstantVisitor());
1729 // if (result == ValidResult.RESULT_TRUE) {
1730 // return ValidResult.RESULT_TRUE;
1731 // } else if (result == ValidResult.RESULT_FALSE) {
1732 // return ValidResult.RESULT_FALSE;
1733 // }
1734 // return null;
1735 // }
1736 return null;
1737 }
1738
1739 /**
1740 * Return `true` if and only if the passed expression is resolved to a constan t variable.
1741 *
1742 * @param expression some conditional expression
1743 * @return `true` if and only if the passed expression is resolved to a consta nt variable
1744 */
1745 bool _isDebugConstant(Expression expression) {
1746 Element element = null;
1747 if (expression is Identifier) {
1748 Identifier identifier = expression;
1749 element = identifier.staticElement;
1750 } else if (expression is PropertyAccess) {
1751 PropertyAccess propertyAccess = expression;
1752 element = propertyAccess.propertyName.staticElement;
1753 }
1754 if (element is PropertyAccessorElement) {
1755 PropertyInducingElement variable = element.variable;
1756 return variable != null && variable.isConst;
1757 }
1758 return false;
1759 }
1760
1761 /**
1762 * If the given node is not `null`, visit this instance of the dead code verif ier.
1763 *
1764 * @param node the node to be visited
1765 */
1766 void _safelyVisit(AstNode node) {
1767 if (node != null) {
1768 node.accept(this);
1769 }
1770 }
1771 }
1772
1773 /**
1774 * Instances of the class `DeclarationResolver` are used to resolve declarations in an AST
1775 * structure to already built elements.
1776 */
1777 class DeclarationResolver extends RecursiveAstVisitor<Object> {
1778 /**
1779 * The compilation unit containing the AST nodes being visited.
1780 */
1781 CompilationUnitElement _enclosingUnit;
1782
1783 /**
1784 * The function type alias containing the AST nodes being visited, or `null` i f we are not
1785 * in the scope of a function type alias.
1786 */
1787 FunctionTypeAliasElement _enclosingAlias;
1788
1789 /**
1790 * The class containing the AST nodes being visited, or `null` if we are not i n the scope of
1791 * a class.
1792 */
1793 ClassElement _enclosingClass;
1794
1795 /**
1796 * The method or function containing the AST nodes being visited, or `null` if we are not in
1797 * the scope of a method or function.
1798 */
1799 ExecutableElement _enclosingExecutable;
1800
1801 /**
1802 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the
1803 * scope of a parameter.
1804 */
1805 ParameterElement _enclosingParameter;
1806
1807 /**
1808 * Resolve the declarations within the given compilation unit to the elements rooted at the given
1809 * element.
1810 *
1811 * @param unit the compilation unit to be resolved
1812 * @param element the root of the element model used to resolve the AST nodes
1813 */
1814 void resolve(CompilationUnit unit, CompilationUnitElement element) {
1815 _enclosingUnit = element;
1816 unit.element = element;
1817 unit.accept(this);
1818 }
1819
1820 @override
1821 Object visitCatchClause(CatchClause node) {
1822 SimpleIdentifier exceptionParameter = node.exceptionParameter;
1823 if (exceptionParameter != null) {
1824 List<LocalVariableElement> localVariables =
1825 _enclosingExecutable.localVariables;
1826 _findIdentifier(localVariables, exceptionParameter);
1827 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
1828 if (stackTraceParameter != null) {
1829 _findIdentifier(localVariables, stackTraceParameter);
1830 }
1831 }
1832 return super.visitCatchClause(node);
1833 }
1834
1835 @override
1836 Object visitClassDeclaration(ClassDeclaration node) {
1837 ClassElement outerClass = _enclosingClass;
1838 try {
1839 SimpleIdentifier className = node.name;
1840 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
1841 return super.visitClassDeclaration(node);
1842 } finally {
1843 _enclosingClass = outerClass;
1844 }
1845 }
1846
1847 @override
1848 Object visitClassTypeAlias(ClassTypeAlias node) {
1849 ClassElement outerClass = _enclosingClass;
1850 try {
1851 SimpleIdentifier className = node.name;
1852 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
1853 return super.visitClassTypeAlias(node);
1854 } finally {
1855 _enclosingClass = outerClass;
1856 }
1857 }
1858
1859 @override
1860 Object visitConstructorDeclaration(ConstructorDeclaration node) {
1861 ExecutableElement outerExecutable = _enclosingExecutable;
1862 try {
1863 SimpleIdentifier constructorName = node.name;
1864 if (constructorName == null) {
1865 _enclosingExecutable = _enclosingClass.unnamedConstructor;
1866 } else {
1867 _enclosingExecutable =
1868 _enclosingClass.getNamedConstructor(constructorName.name);
1869 constructorName.staticElement = _enclosingExecutable;
1870 }
1871 node.element = _enclosingExecutable as ConstructorElement;
1872 return super.visitConstructorDeclaration(node);
1873 } finally {
1874 _enclosingExecutable = outerExecutable;
1875 }
1876 }
1877
1878 @override
1879 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
1880 SimpleIdentifier variableName = node.identifier;
1881 _findIdentifier(_enclosingExecutable.localVariables, variableName);
1882 return super.visitDeclaredIdentifier(node);
1883 }
1884
1885 @override
1886 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
1887 SimpleIdentifier parameterName = node.parameter.identifier;
1888 ParameterElement element = _getElementForParameter(node, parameterName);
1889 Expression defaultValue = node.defaultValue;
1890 if (defaultValue != null) {
1891 ExecutableElement outerExecutable = _enclosingExecutable;
1892 try {
1893 if (element == null) {
1894 // TODO(brianwilkerson) Report this internal error.
1895 } else {
1896 _enclosingExecutable = element.initializer;
1897 }
1898 defaultValue.accept(this);
1899 } finally {
1900 _enclosingExecutable = outerExecutable;
1901 }
1902 }
1903 ParameterElement outerParameter = _enclosingParameter;
1904 try {
1905 _enclosingParameter = element;
1906 return super.visitDefaultFormalParameter(node);
1907 } finally {
1908 _enclosingParameter = outerParameter;
1909 }
1910 }
1911
1912 @override
1913 Object visitEnumDeclaration(EnumDeclaration node) {
1914 ClassElement enclosingEnum =
1915 _findIdentifier(_enclosingUnit.enums, node.name);
1916 List<FieldElement> constants = enclosingEnum.fields;
1917 for (EnumConstantDeclaration constant in node.constants) {
1918 _findIdentifier(constants, constant.name);
1919 }
1920 return super.visitEnumDeclaration(node);
1921 }
1922
1923 @override
1924 Object visitExportDirective(ExportDirective node) {
1925 String uri = _getStringValue(node.uri);
1926 if (uri != null) {
1927 LibraryElement library = _enclosingUnit.library;
1928 ExportElement exportElement = _findExport(library.exports,
1929 _enclosingUnit.context.sourceFactory.resolveUri(
1930 _enclosingUnit.source, uri));
1931 node.element = exportElement;
1932 }
1933 return super.visitExportDirective(node);
1934 }
1935
1936 @override
1937 Object visitFieldFormalParameter(FieldFormalParameter node) {
1938 if (node.parent is! DefaultFormalParameter) {
1939 SimpleIdentifier parameterName = node.identifier;
1940 ParameterElement element = _getElementForParameter(node, parameterName);
1941 ParameterElement outerParameter = _enclosingParameter;
1942 try {
1943 _enclosingParameter = element;
1944 return super.visitFieldFormalParameter(node);
1945 } finally {
1946 _enclosingParameter = outerParameter;
1947 }
1948 } else {
1949 return super.visitFieldFormalParameter(node);
1950 }
1951 }
1952
1953 @override
1954 Object visitFunctionDeclaration(FunctionDeclaration node) {
1955 ExecutableElement outerExecutable = _enclosingExecutable;
1956 try {
1957 SimpleIdentifier functionName = node.name;
1958 sc.Token property = node.propertyKeyword;
1959 if (property == null) {
1960 if (_enclosingExecutable != null) {
1961 _enclosingExecutable =
1962 _findIdentifier(_enclosingExecutable.functions, functionName);
1963 } else {
1964 _enclosingExecutable =
1965 _findIdentifier(_enclosingUnit.functions, functionName);
1966 }
1967 } else {
1968 PropertyAccessorElement accessor =
1969 _findIdentifier(_enclosingUnit.accessors, functionName);
1970 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
1971 accessor = accessor.variable.setter;
1972 functionName.staticElement = accessor;
1973 }
1974 _enclosingExecutable = accessor;
1975 }
1976 node.functionExpression.element = _enclosingExecutable;
1977 return super.visitFunctionDeclaration(node);
1978 } finally {
1979 _enclosingExecutable = outerExecutable;
1980 }
1981 }
1982
1983 @override
1984 Object visitFunctionExpression(FunctionExpression node) {
1985 if (node.parent is! FunctionDeclaration) {
1986 FunctionElement element =
1987 _findAtOffset(_enclosingExecutable.functions, node.beginToken.offset);
1988 node.element = element;
1989 }
1990 ExecutableElement outerExecutable = _enclosingExecutable;
1991 try {
1992 _enclosingExecutable = node.element;
1993 return super.visitFunctionExpression(node);
1994 } finally {
1995 _enclosingExecutable = outerExecutable;
1996 }
1997 }
1998
1999 @override
2000 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
2001 FunctionTypeAliasElement outerAlias = _enclosingAlias;
2002 try {
2003 SimpleIdentifier aliasName = node.name;
2004 _enclosingAlias =
2005 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName);
2006 return super.visitFunctionTypeAlias(node);
2007 } finally {
2008 _enclosingAlias = outerAlias;
2009 }
2010 }
2011
2012 @override
2013 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
2014 if (node.parent is! DefaultFormalParameter) {
2015 SimpleIdentifier parameterName = node.identifier;
2016 ParameterElement element = _getElementForParameter(node, parameterName);
2017 ParameterElement outerParameter = _enclosingParameter;
2018 try {
2019 _enclosingParameter = element;
2020 return super.visitFunctionTypedFormalParameter(node);
2021 } finally {
2022 _enclosingParameter = outerParameter;
2023 }
2024 } else {
2025 return super.visitFunctionTypedFormalParameter(node);
2026 }
2027 }
2028
2029 @override
2030 Object visitImportDirective(ImportDirective node) {
2031 String uri = _getStringValue(node.uri);
2032 if (uri != null) {
2033 LibraryElement library = _enclosingUnit.library;
2034 ImportElement importElement = _findImport(library.imports,
2035 _enclosingUnit.context.sourceFactory.resolveUri(
2036 _enclosingUnit.source, uri), node.prefix);
2037 node.element = importElement;
2038 }
2039 return super.visitImportDirective(node);
2040 }
2041
2042 @override
2043 Object visitLabeledStatement(LabeledStatement node) {
2044 for (Label label in node.labels) {
2045 SimpleIdentifier labelName = label.label;
2046 _findIdentifier(_enclosingExecutable.labels, labelName);
2047 }
2048 return super.visitLabeledStatement(node);
2049 }
2050
2051 @override
2052 Object visitLibraryDirective(LibraryDirective node) {
2053 node.element = _enclosingUnit.library;
2054 return super.visitLibraryDirective(node);
2055 }
2056
2057 @override
2058 Object visitMethodDeclaration(MethodDeclaration node) {
2059 ExecutableElement outerExecutable = _enclosingExecutable;
2060 try {
2061 sc.Token property = node.propertyKeyword;
2062 SimpleIdentifier methodName = node.name;
2063 String nameOfMethod = methodName.name;
2064 if (property == null) {
2065 _enclosingExecutable = _findWithNameAndOffset(
2066 _enclosingClass.methods, nameOfMethod, methodName.offset);
2067 methodName.staticElement = _enclosingExecutable;
2068 } else {
2069 PropertyAccessorElement accessor =
2070 _findIdentifier(_enclosingClass.accessors, methodName);
2071 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
2072 accessor = accessor.variable.setter;
2073 methodName.staticElement = accessor;
2074 }
2075 _enclosingExecutable = accessor;
2076 }
2077 return super.visitMethodDeclaration(node);
2078 } finally {
2079 _enclosingExecutable = outerExecutable;
2080 }
2081 }
2082
2083 @override
2084 Object visitPartDirective(PartDirective node) {
2085 String uri = _getStringValue(node.uri);
2086 if (uri != null) {
2087 Source partSource = _enclosingUnit.context.sourceFactory.resolveUri(
2088 _enclosingUnit.source, uri);
2089 node.element = _findPart(_enclosingUnit.library.parts, partSource);
2090 }
2091 return super.visitPartDirective(node);
2092 }
2093
2094 @override
2095 Object visitPartOfDirective(PartOfDirective node) {
2096 node.element = _enclosingUnit.library;
2097 return super.visitPartOfDirective(node);
2098 }
2099
2100 @override
2101 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
2102 if (node.parent is! DefaultFormalParameter) {
2103 SimpleIdentifier parameterName = node.identifier;
2104 ParameterElement element = _getElementForParameter(node, parameterName);
2105 ParameterElement outerParameter = _enclosingParameter;
2106 try {
2107 _enclosingParameter = element;
2108 return super.visitSimpleFormalParameter(node);
2109 } finally {
2110 _enclosingParameter = outerParameter;
2111 }
2112 } else {}
2113 return super.visitSimpleFormalParameter(node);
2114 }
2115
2116 @override
2117 Object visitSwitchCase(SwitchCase node) {
2118 for (Label label in node.labels) {
2119 SimpleIdentifier labelName = label.label;
2120 _findIdentifier(_enclosingExecutable.labels, labelName);
2121 }
2122 return super.visitSwitchCase(node);
2123 }
2124
2125 @override
2126 Object visitSwitchDefault(SwitchDefault node) {
2127 for (Label label in node.labels) {
2128 SimpleIdentifier labelName = label.label;
2129 _findIdentifier(_enclosingExecutable.labels, labelName);
2130 }
2131 return super.visitSwitchDefault(node);
2132 }
2133
2134 @override
2135 Object visitTypeParameter(TypeParameter node) {
2136 SimpleIdentifier parameterName = node.name;
2137 if (_enclosingClass != null) {
2138 _findIdentifier(_enclosingClass.typeParameters, parameterName);
2139 } else if (_enclosingAlias != null) {
2140 _findIdentifier(_enclosingAlias.typeParameters, parameterName);
2141 }
2142 return super.visitTypeParameter(node);
2143 }
2144
2145 @override
2146 Object visitVariableDeclaration(VariableDeclaration node) {
2147 VariableElement element = null;
2148 SimpleIdentifier variableName = node.name;
2149 if (_enclosingExecutable != null) {
2150 element =
2151 _findIdentifier(_enclosingExecutable.localVariables, variableName);
2152 }
2153 if (element == null && _enclosingClass != null) {
2154 element = _findIdentifier(_enclosingClass.fields, variableName);
2155 }
2156 if (element == null && _enclosingUnit != null) {
2157 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName);
2158 }
2159 Expression initializer = node.initializer;
2160 if (initializer != null) {
2161 ExecutableElement outerExecutable = _enclosingExecutable;
2162 try {
2163 if (element == null) {
2164 // TODO(brianwilkerson) Report this internal error.
2165 } else {
2166 _enclosingExecutable = element.initializer;
2167 }
2168 return super.visitVariableDeclaration(node);
2169 } finally {
2170 _enclosingExecutable = outerExecutable;
2171 }
2172 }
2173 return super.visitVariableDeclaration(node);
2174 }
2175
2176 /**
2177 * Return the element in the given array of elements that was created for the declaration at the
2178 * given offset. This method should only be used when there is no name
2179 *
2180 * @param elements the elements of the appropriate kind that exist in the curr ent context
2181 * @param offset the offset of the name of the element to be returned
2182 * @return the element at the given offset
2183 */
2184 Element _findAtOffset(List<Element> elements, int offset) =>
2185 _findWithNameAndOffset(elements, "", offset);
2186
2187 /**
2188 * Return the export element from the given array whose library has the given source, or
2189 * `null` if there is no such export.
2190 *
2191 * @param exports the export elements being searched
2192 * @param source the source of the library associated with the export element to being searched
2193 * for
2194 * @return the export element whose library has the given source
2195 */
2196 ExportElement _findExport(List<ExportElement> exports, Source source) {
2197 for (ExportElement export in exports) {
2198 if (export.exportedLibrary.source == source) {
2199 return export;
2200 }
2201 }
2202 return null;
2203 }
2204
2205 /**
2206 * Return the element in the given array of elements that was created for the declaration with the
2207 * given name.
2208 *
2209 * @param elements the elements of the appropriate kind that exist in the curr ent context
2210 * @param identifier the name node in the declaration of the element to be ret urned
2211 * @return the element created for the declaration with the given name
2212 */
2213 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier) {
2214 Element element =
2215 _findWithNameAndOffset(elements, identifier.name, identifier.offset);
2216 identifier.staticElement = element;
2217 return element;
2218 }
2219
2220 /**
2221 * Return the import element from the given array whose library has the given source and that has
2222 * the given prefix, or `null` if there is no such import.
2223 *
2224 * @param imports the import elements being searched
2225 * @param source the source of the library associated with the import element to being searched
2226 * for
2227 * @param prefix the prefix with which the library was imported
2228 * @return the import element whose library has the given source and prefix
2229 */
2230 ImportElement _findImport(
2231 List<ImportElement> imports, Source source, SimpleIdentifier prefix) {
2232 for (ImportElement element in imports) {
2233 if (element.importedLibrary.source == source) {
2234 PrefixElement prefixElement = element.prefix;
2235 if (prefix == null) {
2236 if (prefixElement == null) {
2237 return element;
2238 }
2239 } else {
2240 if (prefixElement != null &&
2241 prefix.name == prefixElement.displayName) {
2242 return element;
2243 }
2244 }
2245 }
2246 }
2247 return null;
2248 }
2249
2250 /**
2251 * Return the element for the part with the given source, or `null` if there i s no element
2252 * for the given source.
2253 *
2254 * @param parts the elements for the parts
2255 * @param partSource the source for the part whose element is to be returned
2256 * @return the element for the part with the given source
2257 */
2258 CompilationUnitElement _findPart(
2259 List<CompilationUnitElement> parts, Source partSource) {
2260 for (CompilationUnitElement part in parts) {
2261 if (part.source == partSource) {
2262 return part;
2263 }
2264 }
2265 return null;
2266 }
2267
2268 /**
2269 * Return the element in the given array of elements that was created for the declaration with the
2270 * given name at the given offset.
2271 *
2272 * @param elements the elements of the appropriate kind that exist in the curr ent context
2273 * @param name the name of the element to be returned
2274 * @param offset the offset of the name of the element to be returned
2275 * @return the element with the given name and offset
2276 */
2277 Element _findWithNameAndOffset(
2278 List<Element> elements, String name, int offset) {
2279 for (Element element in elements) {
2280 if (element.nameOffset == offset && element.displayName == name) {
2281 return element;
2282 }
2283 }
2284 return null;
2285 }
2286
2287 /**
2288 * Search the most closely enclosing list of parameters for a parameter with t he given name.
2289 *
2290 * @param node the node defining the parameter with the given name
2291 * @param parameterName the name of the parameter being searched for
2292 * @return the element representing the parameter with that name
2293 */
2294 ParameterElement _getElementForParameter(
2295 FormalParameter node, SimpleIdentifier parameterName) {
2296 List<ParameterElement> parameters = null;
2297 if (_enclosingParameter != null) {
2298 parameters = _enclosingParameter.parameters;
2299 }
2300 if (parameters == null && _enclosingExecutable != null) {
2301 parameters = _enclosingExecutable.parameters;
2302 }
2303 if (parameters == null && _enclosingAlias != null) {
2304 parameters = _enclosingAlias.parameters;
2305 }
2306 ParameterElement element =
2307 parameters == null ? null : _findIdentifier(parameters, parameterName);
2308 if (element == null) {
2309 StringBuffer buffer = new StringBuffer();
2310 buffer.writeln("Invalid state found in the Analysis Engine:");
2311 buffer.writeln(
2312 "DeclarationResolver.getElementForParameter() is visiting a parameter that does not appear to be in a method or function.");
2313 buffer.writeln("Ancestors:");
2314 AstNode parent = node.parent;
2315 while (parent != null) {
2316 buffer.writeln(parent.runtimeType.toString());
2317 buffer.writeln("---------");
2318 parent = parent.parent;
2319 }
2320 AnalysisEngine.instance.logger.logError(buffer.toString(),
2321 new CaughtException(new AnalysisException(), null));
2322 }
2323 return element;
2324 }
2325
2326 /**
2327 * Return the value of the given string literal, or `null` if the string is no t a constant
2328 * string without any string interpolation.
2329 *
2330 * @param literal the string literal whose value is to be returned
2331 * @return the value of the given string literal
2332 */
2333 String _getStringValue(StringLiteral literal) {
2334 if (literal is StringInterpolation) {
2335 return null;
2336 }
2337 return literal.stringValue;
2338 }
2339 }
2340
2341 /**
2342 * Instances of the class `ElementBuilder` traverse an AST structure and build t he element
2343 * model representing the AST structure.
2344 */
2345 class ElementBuilder extends RecursiveAstVisitor<Object> {
2346 /**
2347 * The element holder associated with the element that is currently being buil t.
2348 */
2349 ElementHolder _currentHolder;
2350
2351 /**
2352 * A flag indicating whether a variable declaration is in the context of a fie ld declaration.
2353 */
2354 bool _inFieldContext = false;
2355
2356 /**
2357 * A flag indicating whether a variable declaration is within the body of a me thod or function.
2358 */
2359 bool _inFunction = false;
2360
2361 /**
2362 * A flag indicating whether the class currently being visited can be used as a mixin.
2363 */
2364 bool _isValidMixin = false;
2365
2366 /**
2367 * A collection holding the function types defined in a class that need to hav e their type
2368 * arguments set to the types of the type parameters for the class, or `null` if we are not
2369 * currently processing nodes within a class.
2370 */
2371 List<FunctionTypeImpl> _functionTypesToFix = null;
2372
2373 /**
2374 * A table mapping field names to field elements for the fields defined in the current class, or
2375 * `null` if we are not in the scope of a class.
2376 */
2377 HashMap<String, FieldElement> _fieldMap;
2378
2379 /**
2380 * Initialize a newly created element builder to build the elements for a comp ilation unit.
2381 *
2382 * @param initialHolder the element holder associated with the compilation uni t being built
2383 */
2384 ElementBuilder(ElementHolder initialHolder) {
2385 _currentHolder = initialHolder;
2386 }
2387
2388 @override
2389 Object visitBlock(Block node) {
2390 bool wasInField = _inFieldContext;
2391 _inFieldContext = false;
2392 try {
2393 node.visitChildren(this);
2394 } finally {
2395 _inFieldContext = wasInField;
2396 }
2397 return null;
2398 }
2399
2400 @override
2401 Object visitCatchClause(CatchClause node) {
2402 SimpleIdentifier exceptionParameter = node.exceptionParameter;
2403 if (exceptionParameter != null) {
2404 // exception
2405 LocalVariableElementImpl exception =
2406 new LocalVariableElementImpl.forNode(exceptionParameter);
2407 _currentHolder.addLocalVariable(exception);
2408 exceptionParameter.staticElement = exception;
2409 // stack trace
2410 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
2411 if (stackTraceParameter != null) {
2412 LocalVariableElementImpl stackTrace =
2413 new LocalVariableElementImpl.forNode(stackTraceParameter);
2414 _currentHolder.addLocalVariable(stackTrace);
2415 stackTraceParameter.staticElement = stackTrace;
2416 }
2417 }
2418 return super.visitCatchClause(node);
2419 }
2420
2421 @override
2422 Object visitClassDeclaration(ClassDeclaration node) {
2423 ElementHolder holder = new ElementHolder();
2424 _isValidMixin = true;
2425 _functionTypesToFix = new List<FunctionTypeImpl>();
2426 //
2427 // Process field declarations before constructors and methods so that field
2428 // formal parameters can be correctly resolved to their fields.
2429 //
2430 ElementHolder previousHolder = _currentHolder;
2431 _currentHolder = holder;
2432 try {
2433 List<ClassMember> nonFields = new List<ClassMember>();
2434 node.visitChildren(
2435 new _ElementBuilder_visitClassDeclaration(this, nonFields));
2436 _buildFieldMap(holder.fieldsWithoutFlushing);
2437 int count = nonFields.length;
2438 for (int i = 0; i < count; i++) {
2439 nonFields[i].accept(this);
2440 }
2441 } finally {
2442 _currentHolder = previousHolder;
2443 }
2444 SimpleIdentifier className = node.name;
2445 ClassElementImpl element = new ClassElementImpl.forNode(className);
2446 List<TypeParameterElement> typeParameters = holder.typeParameters;
2447 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
2448 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
2449 interfaceType.typeArguments = typeArguments;
2450 element.type = interfaceType;
2451 List<ConstructorElement> constructors = holder.constructors;
2452 if (constructors.length == 0) {
2453 //
2454 // Create the default constructor.
2455 //
2456 constructors = _createDefaultConstructors(interfaceType);
2457 }
2458 element.abstract = node.isAbstract;
2459 element.accessors = holder.accessors;
2460 element.constructors = constructors;
2461 element.fields = holder.fields;
2462 element.methods = holder.methods;
2463 element.typeParameters = typeParameters;
2464 element.validMixin = _isValidMixin;
2465 int functionTypeCount = _functionTypesToFix.length;
2466 for (int i = 0; i < functionTypeCount; i++) {
2467 _functionTypesToFix[i].typeArguments = typeArguments;
2468 }
2469 _functionTypesToFix = null;
2470 _currentHolder.addType(element);
2471 className.staticElement = element;
2472 _fieldMap = null;
2473 holder.validate();
2474 return null;
2475 }
2476
2477 /**
2478 * Implementation of this method should be synchronized with
2479 * [visitClassDeclaration].
2480 */
2481 void visitClassDeclarationIncrementally(ClassDeclaration node) {
2482 //
2483 // Process field declarations before constructors and methods so that field
2484 // formal parameters can be correctly resolved to their fields.
2485 //
2486 ClassElement classElement = node.element;
2487 _buildFieldMap(classElement.fields);
2488 }
2489
2490 @override
2491 Object visitClassTypeAlias(ClassTypeAlias node) {
2492 ElementHolder holder = new ElementHolder();
2493 _functionTypesToFix = new List<FunctionTypeImpl>();
2494 _visitChildren(holder, node);
2495 SimpleIdentifier className = node.name;
2496 ClassElementImpl element = new ClassElementImpl.forNode(className);
2497 element.abstract = node.abstractKeyword != null;
2498 element.mixinApplication = true;
2499 List<TypeParameterElement> typeParameters = holder.typeParameters;
2500 element.typeParameters = typeParameters;
2501 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
2502 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
2503 interfaceType.typeArguments = typeArguments;
2504 element.type = interfaceType;
2505 // set default constructor
2506 for (FunctionTypeImpl functionType in _functionTypesToFix) {
2507 functionType.typeArguments = typeArguments;
2508 }
2509 _functionTypesToFix = null;
2510 _currentHolder.addType(element);
2511 className.staticElement = element;
2512 holder.validate();
2513 return null;
2514 }
2515
2516 @override
2517 Object visitConstructorDeclaration(ConstructorDeclaration node) {
2518 _isValidMixin = false;
2519 ElementHolder holder = new ElementHolder();
2520 bool wasInFunction = _inFunction;
2521 _inFunction = true;
2522 try {
2523 _visitChildren(holder, node);
2524 } finally {
2525 _inFunction = wasInFunction;
2526 }
2527 FunctionBody body = node.body;
2528 SimpleIdentifier constructorName = node.name;
2529 ConstructorElementImpl element =
2530 new ConstructorElementImpl.forNode(constructorName);
2531 if (node.externalKeyword != null) {
2532 element.external = true;
2533 }
2534 if (node.factoryKeyword != null) {
2535 element.factory = true;
2536 }
2537 element.functions = holder.functions;
2538 element.labels = holder.labels;
2539 element.localVariables = holder.localVariables;
2540 element.parameters = holder.parameters;
2541 element.const2 = node.constKeyword != null;
2542 if (body.isAsynchronous) {
2543 element.asynchronous = true;
2544 }
2545 if (body.isGenerator) {
2546 element.generator = true;
2547 }
2548 _currentHolder.addConstructor(element);
2549 node.element = element;
2550 if (constructorName == null) {
2551 Identifier returnType = node.returnType;
2552 if (returnType != null) {
2553 element.nameOffset = returnType.offset;
2554 element.nameEnd = returnType.end;
2555 }
2556 } else {
2557 constructorName.staticElement = element;
2558 element.periodOffset = node.period.offset;
2559 element.nameEnd = constructorName.end;
2560 }
2561 holder.validate();
2562 return null;
2563 }
2564
2565 @override
2566 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
2567 SimpleIdentifier variableName = node.identifier;
2568 LocalVariableElementImpl element =
2569 new LocalVariableElementImpl.forNode(variableName);
2570 ForEachStatement statement = node.parent as ForEachStatement;
2571 int declarationEnd = node.offset + node.length;
2572 int statementEnd = statement.offset + statement.length;
2573 element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1);
2574 element.const3 = node.isConst;
2575 element.final2 = node.isFinal;
2576 _currentHolder.addLocalVariable(element);
2577 variableName.staticElement = element;
2578 return super.visitDeclaredIdentifier(node);
2579 }
2580
2581 @override
2582 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
2583 ElementHolder holder = new ElementHolder();
2584 NormalFormalParameter normalParameter = node.parameter;
2585 SimpleIdentifier parameterName = normalParameter.identifier;
2586 ParameterElementImpl parameter;
2587 if (normalParameter is FieldFormalParameter) {
2588 parameter = new DefaultFieldFormalParameterElementImpl(parameterName);
2589 FieldElement field =
2590 _fieldMap == null ? null : _fieldMap[parameterName.name];
2591 if (field != null) {
2592 (parameter as DefaultFieldFormalParameterElementImpl).field = field;
2593 }
2594 } else {
2595 parameter = new DefaultParameterElementImpl(parameterName);
2596 }
2597 parameter.const3 = node.isConst;
2598 parameter.final2 = node.isFinal;
2599 parameter.parameterKind = node.kind;
2600 // set initializer, default value range
2601 Expression defaultValue = node.defaultValue;
2602 if (defaultValue != null) {
2603 _visit(holder, defaultValue);
2604 FunctionElementImpl initializer =
2605 new FunctionElementImpl.forOffset(defaultValue.beginToken.offset);
2606 initializer.functions = holder.functions;
2607 initializer.labels = holder.labels;
2608 initializer.localVariables = holder.localVariables;
2609 initializer.parameters = holder.parameters;
2610 initializer.synthetic = true;
2611 parameter.initializer = initializer;
2612 parameter.defaultValueCode = defaultValue.toSource();
2613 }
2614 // visible range
2615 _setParameterVisibleRange(node, parameter);
2616 _currentHolder.addParameter(parameter);
2617 parameterName.staticElement = parameter;
2618 normalParameter.accept(this);
2619 holder.validate();
2620 return null;
2621 }
2622
2623 @override
2624 Object visitEnumDeclaration(EnumDeclaration node) {
2625 SimpleIdentifier enumName = node.name;
2626 ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
2627 enumElement.enum2 = true;
2628 InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
2629 enumElement.type = enumType;
2630 // The equivalent code for enums in the spec shows a single constructor,
2631 // but that constructor is not callable (since it is a compile-time error
2632 // to subclass, mix-in, implement, or explicitly instantiate an enum). So
2633 // we represent this as having no constructors.
2634 enumElement.constructors = ConstructorElement.EMPTY_LIST;
2635 _currentHolder.addEnum(enumElement);
2636 enumName.staticElement = enumElement;
2637 return super.visitEnumDeclaration(node);
2638 }
2639
2640 @override
2641 Object visitFieldDeclaration(FieldDeclaration node) {
2642 bool wasInField = _inFieldContext;
2643 _inFieldContext = true;
2644 try {
2645 node.visitChildren(this);
2646 } finally {
2647 _inFieldContext = wasInField;
2648 }
2649 return null;
2650 }
2651
2652 @override
2653 Object visitFieldFormalParameter(FieldFormalParameter node) {
2654 if (node.parent is! DefaultFormalParameter) {
2655 SimpleIdentifier parameterName = node.identifier;
2656 FieldElement field =
2657 _fieldMap == null ? null : _fieldMap[parameterName.name];
2658 FieldFormalParameterElementImpl parameter =
2659 new FieldFormalParameterElementImpl(parameterName);
2660 parameter.const3 = node.isConst;
2661 parameter.final2 = node.isFinal;
2662 parameter.parameterKind = node.kind;
2663 if (field != null) {
2664 parameter.field = field;
2665 }
2666 _currentHolder.addParameter(parameter);
2667 parameterName.staticElement = parameter;
2668 }
2669 //
2670 // The children of this parameter include any parameters defined on the type
2671 // of this parameter.
2672 //
2673 ElementHolder holder = new ElementHolder();
2674 _visitChildren(holder, node);
2675 ParameterElementImpl element = node.element;
2676 element.parameters = holder.parameters;
2677 element.typeParameters = holder.typeParameters;
2678 holder.validate();
2679 return null;
2680 }
2681
2682 @override
2683 Object visitFunctionDeclaration(FunctionDeclaration node) {
2684 FunctionExpression expression = node.functionExpression;
2685 if (expression != null) {
2686 ElementHolder holder = new ElementHolder();
2687 bool wasInFunction = _inFunction;
2688 _inFunction = true;
2689 try {
2690 _visitChildren(holder, node);
2691 } finally {
2692 _inFunction = wasInFunction;
2693 }
2694 FunctionBody body = expression.body;
2695 sc.Token property = node.propertyKeyword;
2696 if (property == null || _inFunction) {
2697 SimpleIdentifier functionName = node.name;
2698 FunctionElementImpl element =
2699 new FunctionElementImpl.forNode(functionName);
2700 if (node.externalKeyword != null) {
2701 element.external = true;
2702 }
2703 element.functions = holder.functions;
2704 element.labels = holder.labels;
2705 element.localVariables = holder.localVariables;
2706 element.parameters = holder.parameters;
2707 element.typeParameters = holder.typeParameters;
2708 if (body.isAsynchronous) {
2709 element.asynchronous = true;
2710 }
2711 if (body.isGenerator) {
2712 element.generator = true;
2713 }
2714 if (_inFunction) {
2715 Block enclosingBlock = node.getAncestor((node) => node is Block);
2716 if (enclosingBlock != null) {
2717 int functionEnd = node.offset + node.length;
2718 int blockEnd = enclosingBlock.offset + enclosingBlock.length;
2719 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
2720 }
2721 }
2722 _currentHolder.addFunction(element);
2723 expression.element = element;
2724 functionName.staticElement = element;
2725 } else {
2726 SimpleIdentifier propertyNameNode = node.name;
2727 if (propertyNameNode == null) {
2728 // TODO(brianwilkerson) Report this internal error.
2729 return null;
2730 }
2731 String propertyName = propertyNameNode.name;
2732 TopLevelVariableElementImpl variable = _currentHolder
2733 .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl;
2734 if (variable == null) {
2735 variable = new TopLevelVariableElementImpl(node.name.name, -1);
2736 variable.final2 = true;
2737 variable.synthetic = true;
2738 _currentHolder.addTopLevelVariable(variable);
2739 }
2740 if (node.isGetter) {
2741 PropertyAccessorElementImpl getter =
2742 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2743 if (node.externalKeyword != null) {
2744 getter.external = true;
2745 }
2746 getter.functions = holder.functions;
2747 getter.labels = holder.labels;
2748 getter.localVariables = holder.localVariables;
2749 if (body.isAsynchronous) {
2750 getter.asynchronous = true;
2751 }
2752 if (body.isGenerator) {
2753 getter.generator = true;
2754 }
2755 getter.variable = variable;
2756 getter.getter = true;
2757 getter.static = true;
2758 variable.getter = getter;
2759 _currentHolder.addAccessor(getter);
2760 expression.element = getter;
2761 propertyNameNode.staticElement = getter;
2762 } else {
2763 PropertyAccessorElementImpl setter =
2764 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2765 if (node.externalKeyword != null) {
2766 setter.external = true;
2767 }
2768 setter.functions = holder.functions;
2769 setter.labels = holder.labels;
2770 setter.localVariables = holder.localVariables;
2771 setter.parameters = holder.parameters;
2772 if (body.isAsynchronous) {
2773 setter.asynchronous = true;
2774 }
2775 if (body.isGenerator) {
2776 setter.generator = true;
2777 }
2778 setter.variable = variable;
2779 setter.setter = true;
2780 setter.static = true;
2781 variable.setter = setter;
2782 variable.final2 = false;
2783 _currentHolder.addAccessor(setter);
2784 expression.element = setter;
2785 propertyNameNode.staticElement = setter;
2786 }
2787 }
2788 holder.validate();
2789 }
2790 return null;
2791 }
2792
2793 @override
2794 Object visitFunctionExpression(FunctionExpression node) {
2795 if (node.parent is FunctionDeclaration) {
2796 // visitFunctionDeclaration has already created the element for the
2797 // declaration. We just need to visit children.
2798 return super.visitFunctionExpression(node);
2799 }
2800 ElementHolder holder = new ElementHolder();
2801 bool wasInFunction = _inFunction;
2802 _inFunction = true;
2803 try {
2804 _visitChildren(holder, node);
2805 } finally {
2806 _inFunction = wasInFunction;
2807 }
2808 FunctionBody body = node.body;
2809 FunctionElementImpl element =
2810 new FunctionElementImpl.forOffset(node.beginToken.offset);
2811 element.functions = holder.functions;
2812 element.labels = holder.labels;
2813 element.localVariables = holder.localVariables;
2814 element.parameters = holder.parameters;
2815 element.typeParameters = holder.typeParameters;
2816 if (body.isAsynchronous) {
2817 element.asynchronous = true;
2818 }
2819 if (body.isGenerator) {
2820 element.generator = true;
2821 }
2822 if (_inFunction) {
2823 Block enclosingBlock = node.getAncestor((node) => node is Block);
2824 if (enclosingBlock != null) {
2825 int functionEnd = node.offset + node.length;
2826 int blockEnd = enclosingBlock.offset + enclosingBlock.length;
2827 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
2828 }
2829 }
2830 FunctionTypeImpl type = new FunctionTypeImpl(element);
2831 if (_functionTypesToFix != null) {
2832 _functionTypesToFix.add(type);
2833 }
2834 element.type = type;
2835 _currentHolder.addFunction(element);
2836 node.element = element;
2837 holder.validate();
2838 return null;
2839 }
2840
2841 @override
2842 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
2843 ElementHolder holder = new ElementHolder();
2844 _visitChildren(holder, node);
2845 SimpleIdentifier aliasName = node.name;
2846 List<ParameterElement> parameters = holder.parameters;
2847 List<TypeParameterElement> typeParameters = holder.typeParameters;
2848 FunctionTypeAliasElementImpl element =
2849 new FunctionTypeAliasElementImpl.forNode(aliasName);
2850 element.parameters = parameters;
2851 element.typeParameters = typeParameters;
2852 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element);
2853 type.typeArguments = _createTypeParameterTypes(typeParameters);
2854 element.type = type;
2855 _currentHolder.addTypeAlias(element);
2856 aliasName.staticElement = element;
2857 holder.validate();
2858 return null;
2859 }
2860
2861 @override
2862 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
2863 if (node.parent is! DefaultFormalParameter) {
2864 SimpleIdentifier parameterName = node.identifier;
2865 ParameterElementImpl parameter =
2866 new ParameterElementImpl.forNode(parameterName);
2867 parameter.parameterKind = node.kind;
2868 _setParameterVisibleRange(node, parameter);
2869 _currentHolder.addParameter(parameter);
2870 parameterName.staticElement = parameter;
2871 }
2872 //
2873 // The children of this parameter include any parameters defined on the type
2874 //of this parameter.
2875 //
2876 ElementHolder holder = new ElementHolder();
2877 _visitChildren(holder, node);
2878 ParameterElementImpl element = node.element;
2879 element.parameters = holder.parameters;
2880 element.typeParameters = holder.typeParameters;
2881 holder.validate();
2882 return null;
2883 }
2884
2885 @override
2886 Object visitLabeledStatement(LabeledStatement node) {
2887 bool onSwitchStatement = node.statement is SwitchStatement;
2888 for (Label label in node.labels) {
2889 SimpleIdentifier labelName = label.label;
2890 LabelElementImpl element =
2891 new LabelElementImpl(labelName, onSwitchStatement, false);
2892 _currentHolder.addLabel(element);
2893 labelName.staticElement = element;
2894 }
2895 return super.visitLabeledStatement(node);
2896 }
2897
2898 @override
2899 Object visitMethodDeclaration(MethodDeclaration node) {
2900 try {
2901 ElementHolder holder = new ElementHolder();
2902 bool wasInFunction = _inFunction;
2903 _inFunction = true;
2904 try {
2905 _visitChildren(holder, node);
2906 } finally {
2907 _inFunction = wasInFunction;
2908 }
2909 bool isStatic = node.isStatic;
2910 sc.Token property = node.propertyKeyword;
2911 FunctionBody body = node.body;
2912 if (property == null) {
2913 SimpleIdentifier methodName = node.name;
2914 String nameOfMethod = methodName.name;
2915 if (nameOfMethod == sc.TokenType.MINUS.lexeme &&
2916 node.parameters.parameters.length == 0) {
2917 nameOfMethod = "unary-";
2918 }
2919 MethodElementImpl element =
2920 new MethodElementImpl(nameOfMethod, methodName.offset);
2921 element.abstract = node.isAbstract;
2922 if (node.externalKeyword != null) {
2923 element.external = true;
2924 }
2925 element.functions = holder.functions;
2926 element.labels = holder.labels;
2927 element.localVariables = holder.localVariables;
2928 element.parameters = holder.parameters;
2929 element.static = isStatic;
2930 element.typeParameters = holder.typeParameters;
2931 if (body.isAsynchronous) {
2932 element.asynchronous = true;
2933 }
2934 if (body.isGenerator) {
2935 element.generator = true;
2936 }
2937 _currentHolder.addMethod(element);
2938 methodName.staticElement = element;
2939 } else {
2940 SimpleIdentifier propertyNameNode = node.name;
2941 String propertyName = propertyNameNode.name;
2942 FieldElementImpl field =
2943 _currentHolder.getField(propertyName) as FieldElementImpl;
2944 if (field == null) {
2945 field = new FieldElementImpl(node.name.name, -1);
2946 field.final2 = true;
2947 field.static = isStatic;
2948 field.synthetic = true;
2949 _currentHolder.addField(field);
2950 }
2951 if (node.isGetter) {
2952 PropertyAccessorElementImpl getter =
2953 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2954 if (node.externalKeyword != null) {
2955 getter.external = true;
2956 }
2957 getter.functions = holder.functions;
2958 getter.labels = holder.labels;
2959 getter.localVariables = holder.localVariables;
2960 if (body.isAsynchronous) {
2961 getter.asynchronous = true;
2962 }
2963 if (body.isGenerator) {
2964 getter.generator = true;
2965 }
2966 getter.variable = field;
2967 getter.abstract = node.isAbstract;
2968 getter.getter = true;
2969 getter.static = isStatic;
2970 field.getter = getter;
2971 _currentHolder.addAccessor(getter);
2972 propertyNameNode.staticElement = getter;
2973 } else {
2974 PropertyAccessorElementImpl setter =
2975 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2976 if (node.externalKeyword != null) {
2977 setter.external = true;
2978 }
2979 setter.functions = holder.functions;
2980 setter.labels = holder.labels;
2981 setter.localVariables = holder.localVariables;
2982 setter.parameters = holder.parameters;
2983 if (body.isAsynchronous) {
2984 setter.asynchronous = true;
2985 }
2986 if (body.isGenerator) {
2987 setter.generator = true;
2988 }
2989 setter.variable = field;
2990 setter.abstract = node.isAbstract;
2991 setter.setter = true;
2992 setter.static = isStatic;
2993 field.setter = setter;
2994 field.final2 = false;
2995 _currentHolder.addAccessor(setter);
2996 propertyNameNode.staticElement = setter;
2997 }
2998 }
2999 holder.validate();
3000 } catch (exception, stackTrace) {
3001 if (node.name.staticElement == null) {
3002 ClassDeclaration classNode =
3003 node.getAncestor((node) => node is ClassDeclaration);
3004 StringBuffer buffer = new StringBuffer();
3005 buffer.write("The element for the method ");
3006 buffer.write(node.name);
3007 buffer.write(" in ");
3008 buffer.write(classNode.name);
3009 buffer.write(" was not set while trying to build the element model.");
3010 AnalysisEngine.instance.logger.logError(
3011 buffer.toString(), new CaughtException(exception, stackTrace));
3012 } else {
3013 String message =
3014 "Exception caught in ElementBuilder.visitMethodDeclaration()";
3015 AnalysisEngine.instance.logger.logError(
3016 message, new CaughtException(exception, stackTrace));
3017 }
3018 } finally {
3019 if (node.name.staticElement == null) {
3020 ClassDeclaration classNode =
3021 node.getAncestor((node) => node is ClassDeclaration);
3022 StringBuffer buffer = new StringBuffer();
3023 buffer.write("The element for the method ");
3024 buffer.write(node.name);
3025 buffer.write(" in ");
3026 buffer.write(classNode.name);
3027 buffer.write(" was not set while trying to resolve types.");
3028 AnalysisEngine.instance.logger.logError(buffer.toString(),
3029 new CaughtException(
3030 new AnalysisException(buffer.toString()), null));
3031 }
3032 }
3033 return null;
3034 }
3035
3036 @override
3037 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
3038 if (node.parent is! DefaultFormalParameter) {
3039 SimpleIdentifier parameterName = node.identifier;
3040 ParameterElementImpl parameter =
3041 new ParameterElementImpl.forNode(parameterName);
3042 parameter.const3 = node.isConst;
3043 parameter.final2 = node.isFinal;
3044 parameter.parameterKind = node.kind;
3045 _setParameterVisibleRange(node, parameter);
3046 _currentHolder.addParameter(parameter);
3047 parameterName.staticElement = parameter;
3048 }
3049 return super.visitSimpleFormalParameter(node);
3050 }
3051
3052 @override
3053 Object visitSuperExpression(SuperExpression node) {
3054 _isValidMixin = false;
3055 return super.visitSuperExpression(node);
3056 }
3057
3058 @override
3059 Object visitSwitchCase(SwitchCase node) {
3060 for (Label label in node.labels) {
3061 SimpleIdentifier labelName = label.label;
3062 LabelElementImpl element = new LabelElementImpl(labelName, false, true);
3063 _currentHolder.addLabel(element);
3064 labelName.staticElement = element;
3065 }
3066 return super.visitSwitchCase(node);
3067 }
3068
3069 @override
3070 Object visitSwitchDefault(SwitchDefault node) {
3071 for (Label label in node.labels) {
3072 SimpleIdentifier labelName = label.label;
3073 LabelElementImpl element = new LabelElementImpl(labelName, false, true);
3074 _currentHolder.addLabel(element);
3075 labelName.staticElement = element;
3076 }
3077 return super.visitSwitchDefault(node);
3078 }
3079
3080 @override
3081 Object visitTypeParameter(TypeParameter node) {
3082 SimpleIdentifier parameterName = node.name;
3083 TypeParameterElementImpl typeParameter =
3084 new TypeParameterElementImpl.forNode(parameterName);
3085 TypeParameterTypeImpl typeParameterType =
3086 new TypeParameterTypeImpl(typeParameter);
3087 typeParameter.type = typeParameterType;
3088 _currentHolder.addTypeParameter(typeParameter);
3089 parameterName.staticElement = typeParameter;
3090 return super.visitTypeParameter(node);
3091 }
3092
3093 @override
3094 Object visitVariableDeclaration(VariableDeclaration node) {
3095 bool isConst = node.isConst;
3096 bool isFinal = node.isFinal;
3097 bool hasInitializer = node.initializer != null;
3098 VariableElementImpl element;
3099 if (_inFieldContext) {
3100 SimpleIdentifier fieldName = node.name;
3101 FieldElementImpl field;
3102 if ((isConst || isFinal) && hasInitializer) {
3103 field = new ConstFieldElementImpl.forNode(fieldName);
3104 } else {
3105 field = new FieldElementImpl.forNode(fieldName);
3106 }
3107 element = field;
3108 _currentHolder.addField(field);
3109 fieldName.staticElement = field;
3110 } else if (_inFunction) {
3111 SimpleIdentifier variableName = node.name;
3112 LocalVariableElementImpl variable;
3113 if (isConst && hasInitializer) {
3114 variable = new ConstLocalVariableElementImpl.forNode(variableName);
3115 } else {
3116 variable = new LocalVariableElementImpl.forNode(variableName);
3117 }
3118 element = variable;
3119 Block enclosingBlock = node.getAncestor((node) => node is Block);
3120 // TODO(brianwilkerson) This isn't right for variables declared in a for
3121 // loop.
3122 variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
3123 _currentHolder.addLocalVariable(variable);
3124 variableName.staticElement = element;
3125 } else {
3126 SimpleIdentifier variableName = node.name;
3127 TopLevelVariableElementImpl variable;
3128 if (isConst && hasInitializer) {
3129 variable = new ConstTopLevelVariableElementImpl(variableName);
3130 } else {
3131 variable = new TopLevelVariableElementImpl.forNode(variableName);
3132 }
3133 element = variable;
3134 _currentHolder.addTopLevelVariable(variable);
3135 variableName.staticElement = element;
3136 }
3137 element.const3 = isConst;
3138 element.final2 = isFinal;
3139 if (hasInitializer) {
3140 ElementHolder holder = new ElementHolder();
3141 bool wasInFieldContext = _inFieldContext;
3142 _inFieldContext = false;
3143 try {
3144 _visit(holder, node.initializer);
3145 } finally {
3146 _inFieldContext = wasInFieldContext;
3147 }
3148 FunctionElementImpl initializer =
3149 new FunctionElementImpl.forOffset(node.initializer.beginToken.offset);
3150 initializer.functions = holder.functions;
3151 initializer.labels = holder.labels;
3152 initializer.localVariables = holder.localVariables;
3153 initializer.synthetic = true;
3154 element.initializer = initializer;
3155 holder.validate();
3156 }
3157 if (element is PropertyInducingElementImpl) {
3158 if (_inFieldContext) {
3159 (element as FieldElementImpl).static =
3160 (node.parent.parent as FieldDeclaration).isStatic;
3161 }
3162 PropertyAccessorElementImpl getter =
3163 new PropertyAccessorElementImpl.forVariable(element);
3164 getter.getter = true;
3165 _currentHolder.addAccessor(getter);
3166 element.getter = getter;
3167 if (!isConst && !isFinal) {
3168 PropertyAccessorElementImpl setter =
3169 new PropertyAccessorElementImpl.forVariable(element);
3170 setter.setter = true;
3171 ParameterElementImpl parameter =
3172 new ParameterElementImpl("_${element.name}", element.nameOffset);
3173 parameter.synthetic = true;
3174 parameter.parameterKind = ParameterKind.REQUIRED;
3175 setter.parameters = <ParameterElement>[parameter];
3176 _currentHolder.addAccessor(setter);
3177 element.setter = setter;
3178 }
3179 }
3180 return null;
3181 }
3182
3183 /**
3184 * Build the table mapping field names to field elements for the fields define d in the current
3185 * class.
3186 *
3187 * @param fields the field elements defined in the current class
3188 */
3189 void _buildFieldMap(List<FieldElement> fields) {
3190 _fieldMap = new HashMap<String, FieldElement>();
3191 int count = fields.length;
3192 for (int i = 0; i < count; i++) {
3193 FieldElement field = fields[i];
3194 _fieldMap[field.name] = field;
3195 }
3196 }
3197
3198 /**
3199 * Creates the [ConstructorElement]s array with the single default constructor element.
3200 *
3201 * @param interfaceType the interface type for which to create a default const ructor
3202 * @return the [ConstructorElement]s array with the single default constructor element
3203 */
3204 List<ConstructorElement> _createDefaultConstructors(
3205 InterfaceTypeImpl interfaceType) {
3206 ConstructorElementImpl constructor =
3207 new ConstructorElementImpl.forNode(null);
3208 constructor.synthetic = true;
3209 constructor.returnType = interfaceType;
3210 FunctionTypeImpl type = new FunctionTypeImpl(constructor);
3211 _functionTypesToFix.add(type);
3212 constructor.type = type;
3213 return <ConstructorElement>[constructor];
3214 }
3215
3216 /**
3217 * Create the types associated with the given type parameters, setting the typ e of each type
3218 * parameter, and return an array of types corresponding to the given paramete rs.
3219 *
3220 * @param typeParameters the type parameters for which types are to be created
3221 * @return an array of types corresponding to the given parameters
3222 */
3223 List<DartType> _createTypeParameterTypes(
3224 List<TypeParameterElement> typeParameters) {
3225 int typeParameterCount = typeParameters.length;
3226 List<DartType> typeArguments = new List<DartType>(typeParameterCount);
3227 for (int i = 0; i < typeParameterCount; i++) {
3228 TypeParameterElementImpl typeParameter =
3229 typeParameters[i] as TypeParameterElementImpl;
3230 TypeParameterTypeImpl typeParameterType =
3231 new TypeParameterTypeImpl(typeParameter);
3232 typeParameter.type = typeParameterType;
3233 typeArguments[i] = typeParameterType;
3234 }
3235 return typeArguments;
3236 }
3237
3238 /**
3239 * Return the body of the function that contains the given parameter, or `null ` if no
3240 * function body could be found.
3241 *
3242 * @param node the parameter contained in the function whose body is to be ret urned
3243 * @return the body of the function that contains the given parameter
3244 */
3245 FunctionBody _getFunctionBody(FormalParameter node) {
3246 AstNode parent = node.parent;
3247 while (parent != null) {
3248 if (parent is ConstructorDeclaration) {
3249 return parent.body;
3250 } else if (parent is FunctionExpression) {
3251 return parent.body;
3252 } else if (parent is MethodDeclaration) {
3253 return parent.body;
3254 }
3255 parent = parent.parent;
3256 }
3257 return null;
3258 }
3259
3260 /**
3261 * Sets the visible source range for formal parameter.
3262 */
3263 void _setParameterVisibleRange(
3264 FormalParameter node, ParameterElementImpl element) {
3265 FunctionBody body = _getFunctionBody(node);
3266 if (body != null) {
3267 element.setVisibleRange(body.offset, body.length);
3268 }
3269 }
3270
3271 /**
3272 * Make the given holder be the current holder while visiting the given node.
3273 *
3274 * @param holder the holder that will gather elements that are built while vis iting the children
3275 * @param node the node to be visited
3276 */
3277 void _visit(ElementHolder holder, AstNode node) {
3278 if (node != null) {
3279 ElementHolder previousHolder = _currentHolder;
3280 _currentHolder = holder;
3281 try {
3282 node.accept(this);
3283 } finally {
3284 _currentHolder = previousHolder;
3285 }
3286 }
3287 }
3288
3289 /**
3290 * Make the given holder be the current holder while visiting the children of the given node.
3291 *
3292 * @param holder the holder that will gather elements that are built while vis iting the children
3293 * @param node the node whose children are to be visited
3294 */
3295 void _visitChildren(ElementHolder holder, AstNode node) {
3296 if (node != null) {
3297 ElementHolder previousHolder = _currentHolder;
3298 _currentHolder = holder;
3299 try {
3300 node.visitChildren(this);
3301 } finally {
3302 _currentHolder = previousHolder;
3303 }
3304 }
3305 }
3306 }
3307
3308 /**
3309 * Instances of the class `ElementHolder` hold on to elements created while trav ersing an AST
3310 * structure so that they can be accessed when creating their enclosing element.
3311 */
3312 class ElementHolder {
3313 List<PropertyAccessorElement> _accessors;
3314
3315 List<ConstructorElement> _constructors;
3316
3317 List<ClassElement> _enums;
3318
3319 List<FieldElement> _fields;
3320
3321 List<FunctionElement> _functions;
3322
3323 List<LabelElement> _labels;
3324
3325 List<LocalVariableElement> _localVariables;
3326
3327 List<MethodElement> _methods;
3328
3329 List<ParameterElement> _parameters;
3330
3331 List<TopLevelVariableElement> _topLevelVariables;
3332
3333 List<ClassElement> _types;
3334
3335 List<FunctionTypeAliasElement> _typeAliases;
3336
3337 List<TypeParameterElement> _typeParameters;
3338
3339 List<PropertyAccessorElement> get accessors {
3340 if (_accessors == null) {
3341 return PropertyAccessorElement.EMPTY_LIST;
3342 }
3343 List<PropertyAccessorElement> result = _accessors;
3344 _accessors = null;
3345 return result;
3346 }
3347
3348 List<ConstructorElement> get constructors {
3349 if (_constructors == null) {
3350 return ConstructorElement.EMPTY_LIST;
3351 }
3352 List<ConstructorElement> result = _constructors;
3353 _constructors = null;
3354 return result;
3355 }
3356
3357 List<ClassElement> get enums {
3358 if (_enums == null) {
3359 return ClassElement.EMPTY_LIST;
3360 }
3361 List<ClassElement> result = _enums;
3362 _enums = null;
3363 return result;
3364 }
3365
3366 List<FieldElement> get fields {
3367 if (_fields == null) {
3368 return FieldElement.EMPTY_LIST;
3369 }
3370 List<FieldElement> result = _fields;
3371 _fields = null;
3372 return result;
3373 }
3374
3375 List<FieldElement> get fieldsWithoutFlushing {
3376 if (_fields == null) {
3377 return FieldElement.EMPTY_LIST;
3378 }
3379 List<FieldElement> result = _fields;
3380 return result;
3381 }
3382
3383 List<FunctionElement> get functions {
3384 if (_functions == null) {
3385 return FunctionElement.EMPTY_LIST;
3386 }
3387 List<FunctionElement> result = _functions;
3388 _functions = null;
3389 return result;
3390 }
3391
3392 List<LabelElement> get labels {
3393 if (_labels == null) {
3394 return LabelElement.EMPTY_LIST;
3395 }
3396 List<LabelElement> result = _labels;
3397 _labels = null;
3398 return result;
3399 }
3400
3401 List<LocalVariableElement> get localVariables {
3402 if (_localVariables == null) {
3403 return LocalVariableElement.EMPTY_LIST;
3404 }
3405 List<LocalVariableElement> result = _localVariables;
3406 _localVariables = null;
3407 return result;
3408 }
3409
3410 List<MethodElement> get methods {
3411 if (_methods == null) {
3412 return MethodElement.EMPTY_LIST;
3413 }
3414 List<MethodElement> result = _methods;
3415 _methods = null;
3416 return result;
3417 }
3418
3419 List<ParameterElement> get parameters {
3420 if (_parameters == null) {
3421 return ParameterElement.EMPTY_LIST;
3422 }
3423 List<ParameterElement> result = _parameters;
3424 _parameters = null;
3425 return result;
3426 }
3427
3428 List<TopLevelVariableElement> get topLevelVariables {
3429 if (_topLevelVariables == null) {
3430 return TopLevelVariableElement.EMPTY_LIST;
3431 }
3432 List<TopLevelVariableElement> result = _topLevelVariables;
3433 _topLevelVariables = null;
3434 return result;
3435 }
3436
3437 List<FunctionTypeAliasElement> get typeAliases {
3438 if (_typeAliases == null) {
3439 return FunctionTypeAliasElement.EMPTY_LIST;
3440 }
3441 List<FunctionTypeAliasElement> result = _typeAliases;
3442 _typeAliases = null;
3443 return result;
3444 }
3445
3446 List<TypeParameterElement> get typeParameters {
3447 if (_typeParameters == null) {
3448 return TypeParameterElement.EMPTY_LIST;
3449 }
3450 List<TypeParameterElement> result = _typeParameters;
3451 _typeParameters = null;
3452 return result;
3453 }
3454
3455 List<ClassElement> get types {
3456 if (_types == null) {
3457 return ClassElement.EMPTY_LIST;
3458 }
3459 List<ClassElement> result = _types;
3460 _types = null;
3461 return result;
3462 }
3463
3464 void addAccessor(PropertyAccessorElement element) {
3465 if (_accessors == null) {
3466 _accessors = new List<PropertyAccessorElement>();
3467 }
3468 _accessors.add(element);
3469 }
3470
3471 void addConstructor(ConstructorElement element) {
3472 if (_constructors == null) {
3473 _constructors = new List<ConstructorElement>();
3474 }
3475 _constructors.add(element);
3476 }
3477
3478 void addEnum(ClassElement element) {
3479 if (_enums == null) {
3480 _enums = new List<ClassElement>();
3481 }
3482 _enums.add(element);
3483 }
3484
3485 void addField(FieldElement element) {
3486 if (_fields == null) {
3487 _fields = new List<FieldElement>();
3488 }
3489 _fields.add(element);
3490 }
3491
3492 void addFunction(FunctionElement element) {
3493 if (_functions == null) {
3494 _functions = new List<FunctionElement>();
3495 }
3496 _functions.add(element);
3497 }
3498
3499 void addLabel(LabelElement element) {
3500 if (_labels == null) {
3501 _labels = new List<LabelElement>();
3502 }
3503 _labels.add(element);
3504 }
3505
3506 void addLocalVariable(LocalVariableElement element) {
3507 if (_localVariables == null) {
3508 _localVariables = new List<LocalVariableElement>();
3509 }
3510 _localVariables.add(element);
3511 }
3512
3513 void addMethod(MethodElement element) {
3514 if (_methods == null) {
3515 _methods = new List<MethodElement>();
3516 }
3517 _methods.add(element);
3518 }
3519
3520 void addParameter(ParameterElement element) {
3521 if (_parameters == null) {
3522 _parameters = new List<ParameterElement>();
3523 }
3524 _parameters.add(element);
3525 }
3526
3527 void addTopLevelVariable(TopLevelVariableElement element) {
3528 if (_topLevelVariables == null) {
3529 _topLevelVariables = new List<TopLevelVariableElement>();
3530 }
3531 _topLevelVariables.add(element);
3532 }
3533
3534 void addType(ClassElement element) {
3535 if (_types == null) {
3536 _types = new List<ClassElement>();
3537 }
3538 _types.add(element);
3539 }
3540
3541 void addTypeAlias(FunctionTypeAliasElement element) {
3542 if (_typeAliases == null) {
3543 _typeAliases = new List<FunctionTypeAliasElement>();
3544 }
3545 _typeAliases.add(element);
3546 }
3547
3548 void addTypeParameter(TypeParameterElement element) {
3549 if (_typeParameters == null) {
3550 _typeParameters = new List<TypeParameterElement>();
3551 }
3552 _typeParameters.add(element);
3553 }
3554
3555 FieldElement getField(String fieldName) {
3556 if (_fields == null) {
3557 return null;
3558 }
3559 for (FieldElement field in _fields) {
3560 if (field.name == fieldName) {
3561 return field;
3562 }
3563 }
3564 return null;
3565 }
3566
3567 TopLevelVariableElement getTopLevelVariable(String variableName) {
3568 if (_topLevelVariables == null) {
3569 return null;
3570 }
3571 for (TopLevelVariableElement variable in _topLevelVariables) {
3572 if (variable.name == variableName) {
3573 return variable;
3574 }
3575 }
3576 return null;
3577 }
3578
3579 void validate() {
3580 StringBuffer buffer = new StringBuffer();
3581 if (_accessors != null) {
3582 buffer.write(_accessors.length);
3583 buffer.write(" accessors");
3584 }
3585 if (_constructors != null) {
3586 if (buffer.length > 0) {
3587 buffer.write("; ");
3588 }
3589 buffer.write(_constructors.length);
3590 buffer.write(" constructors");
3591 }
3592 if (_fields != null) {
3593 if (buffer.length > 0) {
3594 buffer.write("; ");
3595 }
3596 buffer.write(_fields.length);
3597 buffer.write(" fields");
3598 }
3599 if (_functions != null) {
3600 if (buffer.length > 0) {
3601 buffer.write("; ");
3602 }
3603 buffer.write(_functions.length);
3604 buffer.write(" functions");
3605 }
3606 if (_labels != null) {
3607 if (buffer.length > 0) {
3608 buffer.write("; ");
3609 }
3610 buffer.write(_labels.length);
3611 buffer.write(" labels");
3612 }
3613 if (_localVariables != null) {
3614 if (buffer.length > 0) {
3615 buffer.write("; ");
3616 }
3617 buffer.write(_localVariables.length);
3618 buffer.write(" local variables");
3619 }
3620 if (_methods != null) {
3621 if (buffer.length > 0) {
3622 buffer.write("; ");
3623 }
3624 buffer.write(_methods.length);
3625 buffer.write(" methods");
3626 }
3627 if (_parameters != null) {
3628 if (buffer.length > 0) {
3629 buffer.write("; ");
3630 }
3631 buffer.write(_parameters.length);
3632 buffer.write(" parameters");
3633 }
3634 if (_topLevelVariables != null) {
3635 if (buffer.length > 0) {
3636 buffer.write("; ");
3637 }
3638 buffer.write(_topLevelVariables.length);
3639 buffer.write(" top-level variables");
3640 }
3641 if (_types != null) {
3642 if (buffer.length > 0) {
3643 buffer.write("; ");
3644 }
3645 buffer.write(_types.length);
3646 buffer.write(" types");
3647 }
3648 if (_typeAliases != null) {
3649 if (buffer.length > 0) {
3650 buffer.write("; ");
3651 }
3652 buffer.write(_typeAliases.length);
3653 buffer.write(" type aliases");
3654 }
3655 if (_typeParameters != null) {
3656 if (buffer.length > 0) {
3657 buffer.write("; ");
3658 }
3659 buffer.write(_typeParameters.length);
3660 buffer.write(" type parameters");
3661 }
3662 if (buffer.length > 0) {
3663 AnalysisEngine.instance.logger
3664 .logError("Failed to capture elements: $buffer");
3665 }
3666 }
3667 }
3668
3669 /**
3670 * Instances of the class `EnclosedScope` implement a scope that is lexically en closed in
3671 * another scope.
3672 */
3673 class EnclosedScope extends Scope {
3674 /**
3675 * The scope in which this scope is lexically enclosed.
3676 */
3677 final Scope enclosingScope;
3678
3679 /**
3680 * A table mapping names that will be defined in this scope, but right now are not initialized.
3681 * According to the scoping rules these names are hidden, even if they were de fined in an outer
3682 * scope.
3683 */
3684 HashMap<String, Element> _hiddenElements = new HashMap<String, Element>();
3685
3686 /**
3687 * A flag indicating whether there are any names defined in this scope.
3688 */
3689 bool _hasHiddenName = false;
3690
3691 /**
3692 * Initialize a newly created scope enclosed within another scope.
3693 *
3694 * @param enclosingScope the scope in which this scope is lexically enclosed
3695 */
3696 EnclosedScope(this.enclosingScope);
3697
3698 @override
3699 AnalysisErrorListener get errorListener => enclosingScope.errorListener;
3700
3701 /**
3702 * Record that given element is declared in this scope, but hasn't been initia lized yet, so it is
3703 * error to use. If there is already an element with the given name defined in an outer scope,
3704 * then it will become unavailable.
3705 *
3706 * @param element the element declared, but not initialized in this scope
3707 */
3708 void hide(Element element) {
3709 if (element != null) {
3710 String name = element.name;
3711 if (name != null && !name.isEmpty) {
3712 _hiddenElements[name] = element;
3713 _hasHiddenName = true;
3714 }
3715 }
3716 }
3717
3718 @override
3719 Element internalLookup(
3720 Identifier identifier, String name, LibraryElement referencingLibrary) {
3721 Element element = localLookup(name, referencingLibrary);
3722 if (element != null) {
3723 return element;
3724 }
3725 // May be there is a hidden Element.
3726 if (_hasHiddenName) {
3727 Element hiddenElement = _hiddenElements[name];
3728 if (hiddenElement != null) {
3729 errorListener.onError(new AnalysisError(getSource(identifier),
3730 identifier.offset, identifier.length,
3731 CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, []));
3732 return hiddenElement;
3733 }
3734 }
3735 // Check enclosing scope.
3736 return enclosingScope.internalLookup(identifier, name, referencingLibrary);
3737 }
3738 }
3739
3740 /**
3741 * Instances of the class `EnumMemberBuilder` build the members in enum declarat ions.
3742 */
3743 class EnumMemberBuilder extends RecursiveAstVisitor<Object> {
3744 /**
3745 * The type provider used to access the types needed to build an element model for enum
3746 * declarations.
3747 */
3748 final TypeProvider _typeProvider;
3749
3750 /**
3751 * Initialize a newly created enum member builder.
3752 *
3753 * @param typeProvider the type provider used to access the types needed to bu ild an element model
3754 * for enum declarations
3755 */
3756 EnumMemberBuilder(this._typeProvider);
3757
3758 @override
3759 Object visitEnumDeclaration(EnumDeclaration node) {
3760 //
3761 // Finish building the enum.
3762 //
3763 ClassElementImpl enumElement = node.name.staticElement as ClassElementImpl;
3764 InterfaceType enumType = enumElement.type;
3765 enumElement.supertype = _typeProvider.objectType;
3766 //
3767 // Populate the fields.
3768 //
3769 List<FieldElement> fields = new List<FieldElement>();
3770 List<PropertyAccessorElement> getters = new List<PropertyAccessorElement>();
3771 InterfaceType intType = _typeProvider.intType;
3772 String indexFieldName = "index";
3773 FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1);
3774 indexField.final2 = true;
3775 indexField.synthetic = true;
3776 indexField.type = intType;
3777 fields.add(indexField);
3778 getters.add(_createGetter(indexField));
3779 ConstFieldElementImpl valuesField = new ConstFieldElementImpl("values", -1);
3780 valuesField.static = true;
3781 valuesField.const3 = true;
3782 valuesField.synthetic = true;
3783 valuesField.type = _typeProvider.listType.substitute4(<DartType>[enumType]);
3784 fields.add(valuesField);
3785 getters.add(_createGetter(valuesField));
3786 //
3787 // Build the enum constants.
3788 //
3789 NodeList<EnumConstantDeclaration> constants = node.constants;
3790 List<DartObjectImpl> constantValues = new List<DartObjectImpl>();
3791 int constantCount = constants.length;
3792 for (int i = 0; i < constantCount; i++) {
3793 SimpleIdentifier constantName = constants[i].name;
3794 FieldElementImpl constantField =
3795 new ConstFieldElementImpl.forNode(constantName);
3796 constantField.static = true;
3797 constantField.const3 = true;
3798 constantField.type = enumType;
3799 //
3800 // Create a value for the constant.
3801 //
3802 HashMap<String, DartObjectImpl> fieldMap =
3803 new HashMap<String, DartObjectImpl>();
3804 fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i));
3805 DartObjectImpl value =
3806 new DartObjectImpl(enumType, new GenericState(fieldMap));
3807 constantValues.add(value);
3808 constantField.evaluationResult = new EvaluationResultImpl(value);
3809 fields.add(constantField);
3810 getters.add(_createGetter(constantField));
3811 constantName.staticElement = constantField;
3812 }
3813 //
3814 // Build the value of the 'values' field.
3815 //
3816 valuesField.evaluationResult = new EvaluationResultImpl(
3817 new DartObjectImpl(valuesField.type, new ListState(constantValues)));
3818 //
3819 // Finish building the enum.
3820 //
3821 enumElement.fields = fields;
3822 enumElement.accessors = getters;
3823 // Client code isn't allowed to invoke the constructor, so we do not model
3824 // it.
3825 return super.visitEnumDeclaration(node);
3826 }
3827
3828 /**
3829 * Create a getter that corresponds to the given field.
3830 *
3831 * @param field the field for which a getter is to be created
3832 * @return the getter that was created
3833 */
3834 PropertyAccessorElement _createGetter(FieldElementImpl field) {
3835 PropertyAccessorElementImpl getter =
3836 new PropertyAccessorElementImpl.forVariable(field);
3837 getter.getter = true;
3838 getter.returnType = field.type;
3839 getter.type = new FunctionTypeImpl(getter);
3840 field.getter = getter;
3841 return getter;
3842 }
3843 }
3844
3845 /**
3846 * Instances of the class `ExitDetector` determine whether the visited AST node is guaranteed
3847 * to terminate by executing a `return` statement, `throw` expression, `rethrow`
3848 * expression, or simple infinite loop such as `while(true)`.
3849 */
3850 class ExitDetector extends GeneralizingAstVisitor<bool> {
3851 /**
3852 * Set to `true` when a `break` is encountered, and reset to `false` when a
3853 * `do`, `while`, `for` or `switch` block is entered.
3854 */
3855 bool _enclosingBlockContainsBreak = false;
3856
3857 @override
3858 bool visitArgumentList(ArgumentList node) =>
3859 _visitExpressions(node.arguments);
3860
3861 @override
3862 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression);
3863
3864 @override
3865 bool visitAssertStatement(AssertStatement node) => _nodeExits(node.condition);
3866
3867 @override
3868 bool visitAssignmentExpression(AssignmentExpression node) =>
3869 _nodeExits(node.leftHandSide) || _nodeExits(node.rightHandSide);
3870
3871 @override
3872 bool visitAwaitExpression(AwaitExpression node) =>
3873 _nodeExits(node.expression);
3874
3875 @override
3876 bool visitBinaryExpression(BinaryExpression node) {
3877 Expression lhsExpression = node.leftOperand;
3878 sc.TokenType operatorType = node.operator.type;
3879 // If the operator is || and the left hand side is false literal, don't
3880 // consider the RHS of the binary expression.
3881 // TODO(jwren) Do we want to take constant expressions into account,
3882 // evaluate if(false) {} differently than if(<condition>), when <condition>
3883 // evaluates to a constant false value?
3884 if (operatorType == sc.TokenType.BAR_BAR) {
3885 if (lhsExpression is BooleanLiteral) {
3886 BooleanLiteral booleanLiteral = lhsExpression;
3887 if (!booleanLiteral.value) {
3888 return false;
3889 }
3890 }
3891 }
3892 // If the operator is && and the left hand side is true literal, don't
3893 // consider the RHS of the binary expression.
3894 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) {
3895 if (lhsExpression is BooleanLiteral) {
3896 BooleanLiteral booleanLiteral = lhsExpression;
3897 if (booleanLiteral.value) {
3898 return false;
3899 }
3900 }
3901 }
3902 Expression rhsExpression = node.rightOperand;
3903 return _nodeExits(lhsExpression) || _nodeExits(rhsExpression);
3904 }
3905
3906 @override
3907 bool visitBlock(Block node) => _visitStatements(node.statements);
3908
3909 @override
3910 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block);
3911
3912 @override
3913 bool visitBreakStatement(BreakStatement node) {
3914 _enclosingBlockContainsBreak = true;
3915 return false;
3916 }
3917
3918 @override
3919 bool visitCascadeExpression(CascadeExpression node) =>
3920 _nodeExits(node.target) || _visitExpressions(node.cascadeSections);
3921
3922 @override
3923 bool visitConditionalExpression(ConditionalExpression node) {
3924 Expression conditionExpression = node.condition;
3925 Expression thenStatement = node.thenExpression;
3926 Expression elseStatement = node.elseExpression;
3927 // TODO(jwren) Do we want to take constant expressions into account,
3928 // evaluate if(false) {} differently than if(<condition>), when <condition>
3929 // evaluates to a constant false value?
3930 if (_nodeExits(conditionExpression)) {
3931 return true;
3932 }
3933 if (thenStatement == null || elseStatement == null) {
3934 return false;
3935 }
3936 return thenStatement.accept(this) && elseStatement.accept(this);
3937 }
3938
3939 @override
3940 bool visitContinueStatement(ContinueStatement node) => false;
3941
3942 @override
3943 bool visitDoStatement(DoStatement node) {
3944 bool outerBreakValue = _enclosingBlockContainsBreak;
3945 _enclosingBlockContainsBreak = false;
3946 try {
3947 Expression conditionExpression = node.condition;
3948 if (_nodeExits(conditionExpression)) {
3949 return true;
3950 }
3951 // TODO(jwren) Do we want to take all constant expressions into account?
3952 if (conditionExpression is BooleanLiteral) {
3953 BooleanLiteral booleanLiteral = conditionExpression;
3954 // If do {} while (true), and the body doesn't return or the body
3955 // doesn't have a break, then return true.
3956 bool blockReturns = _nodeExits(node.body);
3957 if (booleanLiteral.value &&
3958 (blockReturns || !_enclosingBlockContainsBreak)) {
3959 return true;
3960 }
3961 }
3962 return false;
3963 } finally {
3964 _enclosingBlockContainsBreak = outerBreakValue;
3965 }
3966 }
3967
3968 @override
3969 bool visitEmptyStatement(EmptyStatement node) => false;
3970
3971 @override
3972 bool visitExpressionStatement(ExpressionStatement node) =>
3973 _nodeExits(node.expression);
3974
3975 @override
3976 bool visitForEachStatement(ForEachStatement node) {
3977 bool outerBreakValue = _enclosingBlockContainsBreak;
3978 _enclosingBlockContainsBreak = false;
3979 try {
3980 return _nodeExits(node.iterable);
3981 } finally {
3982 _enclosingBlockContainsBreak = outerBreakValue;
3983 }
3984 }
3985
3986 @override
3987 bool visitForStatement(ForStatement node) {
3988 bool outerBreakValue = _enclosingBlockContainsBreak;
3989 _enclosingBlockContainsBreak = false;
3990 try {
3991 if (node.variables != null &&
3992 _visitVariableDeclarations(node.variables.variables)) {
3993 return true;
3994 }
3995 if (node.initialization != null && _nodeExits(node.initialization)) {
3996 return true;
3997 }
3998 Expression conditionExpression = node.condition;
3999 if (conditionExpression != null && _nodeExits(conditionExpression)) {
4000 return true;
4001 }
4002 if (_visitExpressions(node.updaters)) {
4003 return true;
4004 }
4005 // TODO(jwren) Do we want to take all constant expressions into account?
4006 // If for(; true; ) (or for(;;)), and the body doesn't return or the body
4007 // doesn't have a break, then return true.
4008 bool implicitOrExplictTrue = conditionExpression == null ||
4009 (conditionExpression is BooleanLiteral && conditionExpression.value);
4010 if (implicitOrExplictTrue) {
4011 bool blockReturns = _nodeExits(node.body);
4012 if (blockReturns || !_enclosingBlockContainsBreak) {
4013 return true;
4014 }
4015 }
4016 return false;
4017 } finally {
4018 _enclosingBlockContainsBreak = outerBreakValue;
4019 }
4020 }
4021
4022 @override
4023 bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) =>
4024 false;
4025
4026 @override
4027 bool visitFunctionExpression(FunctionExpression node) => false;
4028
4029 @override
4030 bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
4031 if (_nodeExits(node.function)) {
4032 return true;
4033 }
4034 return node.argumentList.accept(this);
4035 }
4036
4037 @override
4038 bool visitIdentifier(Identifier node) => false;
4039
4040 @override
4041 bool visitIfStatement(IfStatement node) {
4042 Expression conditionExpression = node.condition;
4043 Statement thenStatement = node.thenStatement;
4044 Statement elseStatement = node.elseStatement;
4045 if (_nodeExits(conditionExpression)) {
4046 return true;
4047 }
4048 // TODO(jwren) Do we want to take all constant expressions into account?
4049 if (conditionExpression is BooleanLiteral) {
4050 BooleanLiteral booleanLiteral = conditionExpression;
4051 if (booleanLiteral.value) {
4052 // if(true) ...
4053 return _nodeExits(thenStatement);
4054 } else if (elseStatement != null) {
4055 // if (false) ...
4056 return _nodeExits(elseStatement);
4057 }
4058 }
4059 if (thenStatement == null || elseStatement == null) {
4060 return false;
4061 }
4062 return _nodeExits(thenStatement) && _nodeExits(elseStatement);
4063 }
4064
4065 @override
4066 bool visitIndexExpression(IndexExpression node) {
4067 Expression target = node.realTarget;
4068 if (_nodeExits(target)) {
4069 return true;
4070 }
4071 if (_nodeExits(node.index)) {
4072 return true;
4073 }
4074 return false;
4075 }
4076
4077 @override
4078 bool visitInstanceCreationExpression(InstanceCreationExpression node) =>
4079 _nodeExits(node.argumentList);
4080
4081 @override
4082 bool visitIsExpression(IsExpression node) => node.expression.accept(this);
4083
4084 @override
4085 bool visitLabel(Label node) => false;
4086
4087 @override
4088 bool visitLabeledStatement(LabeledStatement node) =>
4089 node.statement.accept(this);
4090
4091 @override
4092 bool visitLiteral(Literal node) => false;
4093
4094 @override
4095 bool visitMethodInvocation(MethodInvocation node) {
4096 Expression target = node.realTarget;
4097 if (target != null && target.accept(this)) {
4098 return true;
4099 }
4100 return _nodeExits(node.argumentList);
4101 }
4102
4103 @override
4104 bool visitNamedExpression(NamedExpression node) =>
4105 node.expression.accept(this);
4106
4107 @override
4108 bool visitParenthesizedExpression(ParenthesizedExpression node) =>
4109 node.expression.accept(this);
4110
4111 @override
4112 bool visitPostfixExpression(PostfixExpression node) => false;
4113
4114 @override
4115 bool visitPrefixExpression(PrefixExpression node) => false;
4116
4117 @override
4118 bool visitPropertyAccess(PropertyAccess node) {
4119 Expression target = node.realTarget;
4120 if (target != null && target.accept(this)) {
4121 return true;
4122 }
4123 return false;
4124 }
4125
4126 @override
4127 bool visitRethrowExpression(RethrowExpression node) => true;
4128
4129 @override
4130 bool visitReturnStatement(ReturnStatement node) => true;
4131
4132 @override
4133 bool visitSuperExpression(SuperExpression node) => false;
4134
4135 @override
4136 bool visitSwitchCase(SwitchCase node) => _visitStatements(node.statements);
4137
4138 @override
4139 bool visitSwitchDefault(SwitchDefault node) =>
4140 _visitStatements(node.statements);
4141
4142 @override
4143 bool visitSwitchStatement(SwitchStatement node) {
4144 bool outerBreakValue = _enclosingBlockContainsBreak;
4145 _enclosingBlockContainsBreak = false;
4146 try {
4147 bool hasDefault = false;
4148 List<SwitchMember> members = node.members;
4149 for (int i = 0; i < members.length; i++) {
4150 SwitchMember switchMember = members[i];
4151 if (switchMember is SwitchDefault) {
4152 hasDefault = true;
4153 // If this is the last member and there are no statements, return
4154 // false
4155 if (switchMember.statements.isEmpty && i + 1 == members.length) {
4156 return false;
4157 }
4158 }
4159 // For switch members with no statements, don't visit the children,
4160 // otherwise, return false if no return is found in the children
4161 // statements.
4162 if (!switchMember.statements.isEmpty && !switchMember.accept(this)) {
4163 return false;
4164 }
4165 }
4166 // All of the members exit, determine whether there are possible cases
4167 // that are not caught by the members.
4168 DartType type = node.expression == null ? null : node.expression.bestType;
4169 if (type is InterfaceType) {
4170 ClassElement element = type.element;
4171 if (element != null && element.isEnum) {
4172 // If some of the enum values are not covered, then a warning will
4173 // have already been generated, so there's no point in generating a
4174 // hint.
4175 return true;
4176 }
4177 }
4178 return hasDefault;
4179 } finally {
4180 _enclosingBlockContainsBreak = outerBreakValue;
4181 }
4182 }
4183
4184 @override
4185 bool visitThisExpression(ThisExpression node) => false;
4186
4187 @override
4188 bool visitThrowExpression(ThrowExpression node) => true;
4189
4190 @override
4191 bool visitTryStatement(TryStatement node) {
4192 if (_nodeExits(node.body)) {
4193 return true;
4194 }
4195 Block finallyBlock = node.finallyBlock;
4196 if (_nodeExits(finallyBlock)) {
4197 return true;
4198 }
4199 return false;
4200 }
4201
4202 @override
4203 bool visitTypeName(TypeName node) => false;
4204
4205 @override
4206 bool visitVariableDeclaration(VariableDeclaration node) {
4207 Expression initializer = node.initializer;
4208 if (initializer != null) {
4209 return initializer.accept(this);
4210 }
4211 return false;
4212 }
4213
4214 @override
4215 bool visitVariableDeclarationList(VariableDeclarationList node) =>
4216 _visitVariableDeclarations(node.variables);
4217
4218 @override
4219 bool visitVariableDeclarationStatement(VariableDeclarationStatement node) {
4220 NodeList<VariableDeclaration> variables = node.variables.variables;
4221 for (int i = 0; i < variables.length; i++) {
4222 if (variables[i].accept(this)) {
4223 return true;
4224 }
4225 }
4226 return false;
4227 }
4228
4229 @override
4230 bool visitWhileStatement(WhileStatement node) {
4231 bool outerBreakValue = _enclosingBlockContainsBreak;
4232 _enclosingBlockContainsBreak = false;
4233 try {
4234 Expression conditionExpression = node.condition;
4235 if (conditionExpression.accept(this)) {
4236 return true;
4237 }
4238 // TODO(jwren) Do we want to take all constant expressions into account?
4239 if (conditionExpression is BooleanLiteral) {
4240 BooleanLiteral booleanLiteral = conditionExpression;
4241 // If while(true), and the body doesn't return or the body doesn't have
4242 // a break, then return true.
4243 bool blockReturns = node.body.accept(this);
4244 if (booleanLiteral.value &&
4245 (blockReturns || !_enclosingBlockContainsBreak)) {
4246 return true;
4247 }
4248 }
4249 return false;
4250 } finally {
4251 _enclosingBlockContainsBreak = outerBreakValue;
4252 }
4253 }
4254
4255 /**
4256 * Return `true` if the given node exits.
4257 *
4258 * @param node the node being tested
4259 * @return `true` if the given node exits
4260 */
4261 bool _nodeExits(AstNode node) {
4262 if (node == null) {
4263 return false;
4264 }
4265 return node.accept(this);
4266 }
4267
4268 bool _visitExpressions(NodeList<Expression> expressions) {
4269 for (int i = expressions.length - 1; i >= 0; i--) {
4270 if (expressions[i].accept(this)) {
4271 return true;
4272 }
4273 }
4274 return false;
4275 }
4276
4277 bool _visitStatements(NodeList<Statement> statements) {
4278 for (int i = statements.length - 1; i >= 0; i--) {
4279 if (statements[i].accept(this)) {
4280 return true;
4281 }
4282 }
4283 return false;
4284 }
4285
4286 bool _visitVariableDeclarations(
4287 NodeList<VariableDeclaration> variableDeclarations) {
4288 for (int i = variableDeclarations.length - 1; i >= 0; i--) {
4289 if (variableDeclarations[i].accept(this)) {
4290 return true;
4291 }
4292 }
4293 return false;
4294 }
4295
4296 /**
4297 * Return `true` if the given [node] exits.
4298 */
4299 static bool exits(AstNode node) {
4300 return new ExitDetector()._nodeExits(node);
4301 }
4302 }
4303
4304 /**
4305 * The scope defined by a function.
4306 */
4307 class FunctionScope extends EnclosedScope {
4308 /**
4309 * The element representing the function that defines this scope.
4310 */
4311 final ExecutableElement _functionElement;
4312
4313 /**
4314 * A flag indicating whether the parameters have already been defined, used to
4315 * prevent the parameters from being defined multiple times.
4316 */
4317 bool _parametersDefined = false;
4318
4319 /**
4320 * Initialize a newly created scope enclosed within the [enclosingScope] that
4321 * represents the given [_functionElement].
4322 */
4323 FunctionScope(Scope enclosingScope, this._functionElement)
4324 : super(new EnclosedScope(new EnclosedScope(enclosingScope))) {
4325 if (_functionElement == null) {
4326 throw new IllegalArgumentException("function element cannot be null");
4327 }
4328 _defineTypeParameters();
4329 }
4330
4331 /**
4332 * Define the parameters for the given function in the scope that encloses
4333 * this function.
4334 */
4335 void defineParameters() {
4336 if (_parametersDefined) {
4337 return;
4338 }
4339 _parametersDefined = true;
4340 Scope parameterScope = enclosingScope;
4341 for (ParameterElement parameter in _functionElement.parameters) {
4342 if (!parameter.isInitializingFormal) {
4343 parameterScope.define(parameter);
4344 }
4345 }
4346 }
4347
4348 /**
4349 * Define the type parameters for the function.
4350 */
4351 void _defineTypeParameters() {
4352 Scope typeParameterScope = enclosingScope.enclosingScope;
4353 for (TypeParameterElement typeParameter
4354 in _functionElement.typeParameters) {
4355 typeParameterScope.define(typeParameter);
4356 }
4357 }
4358 }
4359
4360 /**
4361 * The scope defined by a function type alias.
4362 */
4363 class FunctionTypeScope extends EnclosedScope {
4364 final FunctionTypeAliasElement _typeElement;
4365
4366 bool _parametersDefined = false;
4367
4368 /**
4369 * Initialize a newly created scope enclosed within the [enclosingScope] that
4370 * represents the given [_typeElement].
4371 */
4372 FunctionTypeScope(Scope enclosingScope, this._typeElement)
4373 : super(new EnclosedScope(enclosingScope)) {
4374 _defineTypeParameters();
4375 }
4376
4377 /**
4378 * Define the parameters for the function type alias.
4379 */
4380 void defineParameters() {
4381 if (_parametersDefined) {
4382 return;
4383 }
4384 _parametersDefined = true;
4385 for (ParameterElement parameter in _typeElement.parameters) {
4386 define(parameter);
4387 }
4388 }
4389
4390 /**
4391 * Define the type parameters for the function type alias.
4392 */
4393 void _defineTypeParameters() {
4394 Scope typeParameterScope = enclosingScope;
4395 for (TypeParameterElement typeParameter in _typeElement.typeParameters) {
4396 typeParameterScope.define(typeParameter);
4397 }
4398 }
4399 }
4400
4401 /**
4402 * A visitor that visits ASTs and fills [UsedImportedElements].
4403 */
4404 class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
4405 final LibraryElement library;
4406 final UsedImportedElements usedElements = new UsedImportedElements();
4407
4408 GatherUsedImportedElementsVisitor(this.library);
4409
4410 @override
4411 void visitExportDirective(ExportDirective node) {
4412 _visitMetadata(node.metadata);
4413 }
4414
4415 @override
4416 void visitImportDirective(ImportDirective node) {
4417 _visitMetadata(node.metadata);
4418 }
4419
4420 @override
4421 void visitLibraryDirective(LibraryDirective node) {
4422 _visitMetadata(node.metadata);
4423 }
4424
4425 @override
4426 void visitPrefixedIdentifier(PrefixedIdentifier node) {
4427 // If the prefixed identifier references some A.B, where A is a library
4428 // prefix, then we can lookup the associated ImportDirective in
4429 // prefixElementMap and remove it from the unusedImports list.
4430 SimpleIdentifier prefixIdentifier = node.prefix;
4431 Element element = prefixIdentifier.staticElement;
4432 if (element is PrefixElement) {
4433 usedElements.prefixes.add(element);
4434 return;
4435 }
4436 // Otherwise, pass the prefixed identifier element and name onto
4437 // visitIdentifier.
4438 _visitIdentifier(element, prefixIdentifier.name);
4439 }
4440
4441 @override
4442 void visitSimpleIdentifier(SimpleIdentifier node) {
4443 _visitIdentifier(node.staticElement, node.name);
4444 }
4445
4446 void _visitIdentifier(Element element, String name) {
4447 if (element == null) {
4448 return;
4449 }
4450 // If the element is multiply defined then call this method recursively for
4451 // each of the conflicting elements.
4452 if (element is MultiplyDefinedElement) {
4453 MultiplyDefinedElement multiplyDefinedElement = element;
4454 for (Element elt in multiplyDefinedElement.conflictingElements) {
4455 _visitIdentifier(elt, name);
4456 }
4457 return;
4458 } else if (element is PrefixElement) {
4459 usedElements.prefixes.add(element);
4460 return;
4461 } else if (element.enclosingElement is! CompilationUnitElement) {
4462 // Identifiers that aren't a prefix element and whose enclosing element
4463 // isn't a CompilationUnit are ignored- this covers the case the
4464 // identifier is a relative-reference, a reference to an identifier not
4465 // imported by this library.
4466 return;
4467 }
4468 // Ignore if an unknown library.
4469 LibraryElement containingLibrary = element.library;
4470 if (containingLibrary == null) {
4471 return;
4472 }
4473 // Ignore if a local element.
4474 if (library == containingLibrary) {
4475 return;
4476 }
4477 // Remember the element.
4478 usedElements.elements.add(element);
4479 }
4480
4481 /**
4482 * Given some [NodeList] of [Annotation]s, ensure that the identifiers are vis ited by
4483 * this visitor. Specifically, this covers the cases where AST nodes don't hav e their identifiers
4484 * visited by this visitor, but still need their annotations visited.
4485 *
4486 * @param annotations the list of annotations to visit
4487 */
4488 void _visitMetadata(NodeList<Annotation> annotations) {
4489 int count = annotations.length;
4490 for (int i = 0; i < count; i++) {
4491 annotations[i].accept(this);
4492 }
4493 }
4494 }
4495
4496 /**
4497 * An [AstVisitor] that fills [UsedLocalElements].
4498 */
4499 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor {
4500 final UsedLocalElements usedElements = new UsedLocalElements();
4501
4502 final LibraryElement _enclosingLibrary;
4503 ClassElement _enclosingClass;
4504 ExecutableElement _enclosingExec;
4505
4506 GatherUsedLocalElementsVisitor(this._enclosingLibrary);
4507
4508 @override
4509 visitCatchClause(CatchClause node) {
4510 SimpleIdentifier exceptionParameter = node.exceptionParameter;
4511 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
4512 if (exceptionParameter != null) {
4513 Element element = exceptionParameter.staticElement;
4514 usedElements.addCatchException(element);
4515 if (stackTraceParameter != null || node.onKeyword == null) {
4516 usedElements.addElement(element);
4517 }
4518 }
4519 if (stackTraceParameter != null) {
4520 Element element = stackTraceParameter.staticElement;
4521 usedElements.addCatchStackTrace(element);
4522 }
4523 super.visitCatchClause(node);
4524 }
4525
4526 @override
4527 visitClassDeclaration(ClassDeclaration node) {
4528 ClassElement enclosingClassOld = _enclosingClass;
4529 try {
4530 _enclosingClass = node.element;
4531 super.visitClassDeclaration(node);
4532 } finally {
4533 _enclosingClass = enclosingClassOld;
4534 }
4535 }
4536
4537 @override
4538 visitFunctionDeclaration(FunctionDeclaration node) {
4539 ExecutableElement enclosingExecOld = _enclosingExec;
4540 try {
4541 _enclosingExec = node.element;
4542 super.visitFunctionDeclaration(node);
4543 } finally {
4544 _enclosingExec = enclosingExecOld;
4545 }
4546 }
4547
4548 @override
4549 visitFunctionExpression(FunctionExpression node) {
4550 if (node.parent is! FunctionDeclaration) {
4551 usedElements.addElement(node.element);
4552 }
4553 super.visitFunctionExpression(node);
4554 }
4555
4556 @override
4557 visitMethodDeclaration(MethodDeclaration node) {
4558 ExecutableElement enclosingExecOld = _enclosingExec;
4559 try {
4560 _enclosingExec = node.element;
4561 super.visitMethodDeclaration(node);
4562 } finally {
4563 _enclosingExec = enclosingExecOld;
4564 }
4565 }
4566
4567 @override
4568 visitSimpleIdentifier(SimpleIdentifier node) {
4569 if (node.inDeclarationContext()) {
4570 return;
4571 }
4572 Element element = node.staticElement;
4573 bool isIdentifierRead = _isReadIdentifier(node);
4574 if (element is LocalVariableElement) {
4575 if (isIdentifierRead) {
4576 usedElements.addElement(element);
4577 }
4578 } else {
4579 _useIdentifierElement(node);
4580 if (element == null ||
4581 element.enclosingElement is ClassElement &&
4582 !identical(element, _enclosingExec)) {
4583 usedElements.members.add(node.name);
4584 if (isIdentifierRead) {
4585 usedElements.readMembers.add(node.name);
4586 }
4587 }
4588 }
4589 }
4590
4591 /**
4592 * Marks an [Element] of [node] as used in the library.
4593 */
4594 void _useIdentifierElement(Identifier node) {
4595 Element element = node.staticElement;
4596 if (element == null) {
4597 return;
4598 }
4599 // check if a local element
4600 if (!identical(element.library, _enclosingLibrary)) {
4601 return;
4602 }
4603 // ignore references to an element from itself
4604 if (identical(element, _enclosingClass)) {
4605 return;
4606 }
4607 if (identical(element, _enclosingExec)) {
4608 return;
4609 }
4610 // ignore places where the element is not actually used
4611 if (node.parent is TypeName) {
4612 if (element is ClassElement) {
4613 AstNode parent2 = node.parent.parent;
4614 if (parent2 is IsExpression) {
4615 return;
4616 }
4617 if (parent2 is VariableDeclarationList) {
4618 return;
4619 }
4620 }
4621 }
4622 // OK
4623 usedElements.addElement(element);
4624 }
4625
4626 static bool _isReadIdentifier(SimpleIdentifier node) {
4627 // not reading at all
4628 if (!node.inGetterContext()) {
4629 return false;
4630 }
4631 // check if useless reading
4632 AstNode parent = node.parent;
4633 if (parent.parent is ExpressionStatement &&
4634 (parent is PrefixExpression ||
4635 parent is PostfixExpression ||
4636 parent is AssignmentExpression && parent.leftHandSide == node)) {
4637 // v++;
4638 // ++v;
4639 // v += 2;
4640 return false;
4641 }
4642 // OK
4643 return true;
4644 }
4645 }
4646
4647 /**
4648 * Instances of the class `HintGenerator` traverse a library's worth of dart cod e at a time to
4649 * generate hints over the set of sources.
4650 *
4651 * See [HintCode].
4652 */
4653 class HintGenerator {
4654 final List<CompilationUnit> _compilationUnits;
4655
4656 final InternalAnalysisContext _context;
4657
4658 final AnalysisErrorListener _errorListener;
4659
4660 LibraryElement _library;
4661
4662 GatherUsedImportedElementsVisitor _usedImportedElementsVisitor;
4663
4664 bool _enableDart2JSHints = false;
4665
4666 /**
4667 * The inheritance manager used to find overridden methods.
4668 */
4669 InheritanceManager _manager;
4670
4671 GatherUsedLocalElementsVisitor _usedLocalElementsVisitor;
4672
4673 HintGenerator(this._compilationUnits, this._context, this._errorListener) {
4674 _library = _compilationUnits[0].element.library;
4675 _usedImportedElementsVisitor =
4676 new GatherUsedImportedElementsVisitor(_library);
4677 _enableDart2JSHints = _context.analysisOptions.dart2jsHint;
4678 _manager = new InheritanceManager(_compilationUnits[0].element.library);
4679 _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library);
4680 }
4681
4682 void generateForLibrary() {
4683 PerformanceStatistics.hints.makeCurrentWhile(() {
4684 for (CompilationUnit unit in _compilationUnits) {
4685 CompilationUnitElement element = unit.element;
4686 if (element != null) {
4687 _generateForCompilationUnit(unit, element.source);
4688 }
4689 }
4690 CompilationUnit definingUnit = _compilationUnits[0];
4691 ErrorReporter definingUnitErrorReporter =
4692 new ErrorReporter(_errorListener, definingUnit.element.source);
4693 {
4694 ImportsVerifier importsVerifier = new ImportsVerifier();
4695 importsVerifier.addImports(definingUnit);
4696 importsVerifier
4697 .removeUsedElements(_usedImportedElementsVisitor.usedElements);
4698 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter);
4699 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter);
4700 }
4701 _library.accept(new UnusedLocalElementsVerifier(
4702 _errorListener, _usedLocalElementsVisitor.usedElements));
4703 });
4704 }
4705
4706 void _generateForCompilationUnit(CompilationUnit unit, Source source) {
4707 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source);
4708 unit.accept(_usedImportedElementsVisitor);
4709 // dead code analysis
4710 unit.accept(new DeadCodeVerifier(errorReporter));
4711 unit.accept(_usedLocalElementsVisitor);
4712 // dart2js analysis
4713 if (_enableDart2JSHints) {
4714 unit.accept(new Dart2JSVerifier(errorReporter));
4715 }
4716 // Dart best practices
4717 unit.accept(
4718 new BestPracticesVerifier(errorReporter, _context.typeProvider));
4719 unit.accept(new OverrideVerifier(errorReporter, _manager));
4720 // Find to-do comments
4721 new ToDoFinder(errorReporter).findIn(unit);
4722 // pub analysis
4723 // TODO(danrubel/jwren) Commented out until bugs in the pub verifier are
4724 // fixed
4725 // unit.accept(new PubVerifier(context, errorReporter));
4726 }
4727 }
4728
4729 /**
4730 * Instances of the class {@code HtmlTagInfo} record information about the tags used in an HTML
4731 * file.
4732 */
4733 class HtmlTagInfo {
4734 /**
4735 * An array containing all of the tags used in the HTML file.
4736 */
4737 List<String> allTags;
4738
4739 /**
4740 * A table mapping the id's defined in the HTML file to an array containing th e names of tags with
4741 * that identifier.
4742 */
4743 HashMap<String, String> idToTagMap;
4744
4745 /**
4746 * A table mapping the classes defined in the HTML file to an array containing the names of tags
4747 * with that class.
4748 */
4749 HashMap<String, List<String>> classToTagsMap;
4750
4751 /**
4752 * Initialize a newly created information holder to hold the given information about the tags in
4753 * an HTML file.
4754 *
4755 * @param allTags an array containing all of the tags used in the HTML file
4756 * @param idToTagMap a table mapping the id's defined in the HTML file to an a rray containing the
4757 * names of tags with that identifier
4758 * @param classToTagsMap a table mapping the classes defined in the HTML file to an array
4759 * containing the names of tags with that class
4760 */
4761 HtmlTagInfo(List<String> allTags, HashMap<String, String> idToTagMap,
4762 HashMap<String, List<String>> classToTagsMap) {
4763 this.allTags = allTags;
4764 this.idToTagMap = idToTagMap;
4765 this.classToTagsMap = classToTagsMap;
4766 }
4767
4768 /**
4769 * Return an array containing the tags that have the given class, or {@code nu ll} if there are no
4770 * such tags.
4771 *
4772 * @return an array containing the tags that have the given class
4773 */
4774 List<String> getTagsWithClass(String identifier) {
4775 return classToTagsMap[identifier];
4776 }
4777
4778 /**
4779 * Return the tag that has the given identifier, or {@code null} if there is n o such tag (the
4780 * identifier is not defined).
4781 *
4782 * @return the tag that has the given identifier
4783 */
4784 String getTagWithId(String identifier) {
4785 return idToTagMap[identifier];
4786 }
4787 }
4788
4789 /**
4790 * Instances of the class {@code HtmlTagInfoBuilder} gather information about th e tags used in one
4791 * or more HTML structures.
4792 */
4793 class HtmlTagInfoBuilder implements ht.XmlVisitor {
4794 /**
4795 * The name of the 'id' attribute.
4796 */
4797 static final String ID_ATTRIBUTE = "id";
4798
4799 /**
4800 * The name of the 'class' attribute.
4801 */
4802 static final String ID_CLASS = "class";
4803
4804 /**
4805 * A set containing all of the tag names used in the HTML.
4806 */
4807 HashSet<String> tagSet = new HashSet<String>();
4808
4809 /**
4810 * A table mapping the id's that are defined to the tag name with that id.
4811 */
4812 HashMap<String, String> idMap = new HashMap<String, String>();
4813
4814 /**
4815 * A table mapping the classes that are defined to a set of the tag names with that class.
4816 */
4817 HashMap<String, HashSet<String>> classMap =
4818 new HashMap<String, HashSet<String>>();
4819
4820 /**
4821 * Initialize a newly created HTML tag info builder.
4822 */
4823 HtmlTagInfoBuilder();
4824
4825 /**
4826 * Create a tag information holder holding all of the information gathered abo ut the tags in the
4827 * HTML structures that were visited.
4828 *
4829 * @return the information gathered about the tags in the visited HTML structu res
4830 */
4831 HtmlTagInfo getTagInfo() {
4832 List<String> allTags = tagSet.toList();
4833 HashMap<String, List<String>> classToTagsMap =
4834 new HashMap<String, List<String>>();
4835 classMap.forEach((String key, Set<String> tags) {
4836 classToTagsMap[key] = tags.toList();
4837 });
4838 return new HtmlTagInfo(allTags, idMap, classToTagsMap);
4839 }
4840
4841 @override
4842 visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
4843 visitXmlTagNode(node);
4844 }
4845
4846 @override
4847 visitHtmlUnit(ht.HtmlUnit node) {
4848 node.visitChildren(this);
4849 }
4850
4851 @override
4852 visitXmlAttributeNode(ht.XmlAttributeNode node) {}
4853
4854 @override
4855 visitXmlTagNode(ht.XmlTagNode node) {
4856 node.visitChildren(this);
4857 String tagName = node.tag;
4858 tagSet.add(tagName);
4859 for (ht.XmlAttributeNode attribute in node.attributes) {
4860 String attributeName = attribute.name;
4861 if (attributeName == ID_ATTRIBUTE) {
4862 String attributeValue = attribute.text;
4863 if (attributeValue != null) {
4864 String tag = idMap[attributeValue];
4865 if (tag == null) {
4866 idMap[attributeValue] = tagName;
4867 } else {
4868 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken);
4869 }
4870 }
4871 } else if (attributeName == ID_CLASS) {
4872 String attributeValue = attribute.text;
4873 if (attributeValue != null) {
4874 HashSet<String> tagList = classMap[attributeValue];
4875 if (tagList == null) {
4876 tagList = new HashSet<String>();
4877 classMap[attributeValue] = tagList;
4878 } else {
4879 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken);
4880 }
4881 tagList.add(tagName);
4882 }
4883 }
4884 }
4885 }
4886
4887 // /**
4888 // * Report an error with the given error code at the given location. Use the given arguments to
4889 // * compose the error message.
4890 // *
4891 // * @param errorCode the error code of the error to be reported
4892 // * @param offset the offset of the first character to be highlighted
4893 // * @param length the number of characters to be highlighted
4894 // * @param arguments the arguments used to compose the error message
4895 // */
4896 // private void reportError(ErrorCode errorCode, Token token, Object... argumen ts) {
4897 // errorListener.onError(new AnalysisError(
4898 // htmlElement.getSource(),
4899 // token.getOffset(),
4900 // token.getLength(),
4901 // errorCode,
4902 // arguments));
4903 // }
4904 //
4905 // /**
4906 // * Report an error with the given error code at the given location. Use the given arguments to
4907 // * compose the error message.
4908 // *
4909 // * @param errorCode the error code of the error to be reported
4910 // * @param offset the offset of the first character to be highlighted
4911 // * @param length the number of characters to be highlighted
4912 // * @param arguments the arguments used to compose the error message
4913 // */
4914 // private void reportError(ErrorCode errorCode, int offset, int length, Object ... arguments) {
4915 // errorListener.onError(new AnalysisError(
4916 // htmlElement.getSource(),
4917 // offset,
4918 // length,
4919 // errorCode,
4920 // arguments));
4921 // }
4922 }
4923
4924 /**
4925 * Instances of the class `HtmlUnitBuilder` build an element model for a single HTML unit.
4926 */
4927 class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
4928 static String _SRC = "src";
4929
4930 /**
4931 * The analysis context in which the element model will be built.
4932 */
4933 final InternalAnalysisContext _context;
4934
4935 /**
4936 * The error listener to which errors will be reported.
4937 */
4938 RecordingErrorListener _errorListener;
4939
4940 /**
4941 * The HTML element being built.
4942 */
4943 HtmlElementImpl _htmlElement;
4944
4945 /**
4946 * The elements in the path from the HTML unit to the current tag node.
4947 */
4948 List<ht.XmlTagNode> _parentNodes;
4949
4950 /**
4951 * The script elements being built.
4952 */
4953 List<HtmlScriptElement> _scripts;
4954
4955 /**
4956 * A set of the libraries that were resolved while resolving the HTML unit.
4957 */
4958 Set<Library> _resolvedLibraries = new HashSet<Library>();
4959
4960 /**
4961 * Initialize a newly created HTML unit builder.
4962 *
4963 * @param context the analysis context in which the element model will be buil t
4964 */
4965 HtmlUnitBuilder(this._context) {
4966 this._errorListener = new RecordingErrorListener();
4967 }
4968
4969 /**
4970 * Return the listener to which analysis errors will be reported.
4971 *
4972 * @return the listener to which analysis errors will be reported
4973 */
4974 RecordingErrorListener get errorListener => _errorListener;
4975
4976 /**
4977 * Return an array containing information about all of the libraries that were resolved.
4978 *
4979 * @return an array containing the libraries that were resolved
4980 */
4981 Set<Library> get resolvedLibraries => _resolvedLibraries;
4982
4983 /**
4984 * Build the HTML element for the given source.
4985 *
4986 * @param source the source describing the compilation unit
4987 * @param unit the AST structure representing the HTML
4988 * @throws AnalysisException if the analysis could not be performed
4989 */
4990 HtmlElementImpl buildHtmlElement(Source source, ht.HtmlUnit unit) {
4991 HtmlElementImpl result = new HtmlElementImpl(_context, source.shortName);
4992 result.source = source;
4993 _htmlElement = result;
4994 unit.accept(this);
4995 _htmlElement = null;
4996 unit.element = result;
4997 return result;
4998 }
4999
5000 @override
5001 Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
5002 if (_parentNodes.contains(node)) {
5003 return _reportCircularity(node);
5004 }
5005 _parentNodes.add(node);
5006 try {
5007 Source htmlSource = _htmlElement.source;
5008 ht.XmlAttributeNode scriptAttribute = _getScriptSourcePath(node);
5009 String scriptSourcePath =
5010 scriptAttribute == null ? null : scriptAttribute.text;
5011 if (node.attributeEnd.type == ht.TokenType.GT &&
5012 scriptSourcePath == null) {
5013 EmbeddedHtmlScriptElementImpl script =
5014 new EmbeddedHtmlScriptElementImpl(node);
5015 try {
5016 LibraryResolver resolver = new LibraryResolver(_context);
5017 LibraryElementImpl library =
5018 resolver.resolveEmbeddedLibrary(htmlSource, node.script, true);
5019 script.scriptLibrary = library;
5020 _resolvedLibraries.addAll(resolver.resolvedLibraries);
5021 _errorListener.addAll(resolver.errorListener);
5022 } on AnalysisException catch (exception, stackTrace) {
5023 //TODO (danrubel): Handle or forward the exception
5024 AnalysisEngine.instance.logger.logError(
5025 "Could not resolve script tag",
5026 new CaughtException(exception, stackTrace));
5027 }
5028 node.scriptElement = script;
5029 _scripts.add(script);
5030 } else {
5031 ExternalHtmlScriptElementImpl script =
5032 new ExternalHtmlScriptElementImpl(node);
5033 if (scriptSourcePath != null) {
5034 try {
5035 scriptSourcePath = Uri.encodeFull(scriptSourcePath);
5036 // Force an exception to be thrown if the URI is invalid so that we
5037 // can report the problem.
5038 parseUriWithException(scriptSourcePath);
5039 Source scriptSource =
5040 _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
5041 script.scriptSource = scriptSource;
5042 if (!_context.exists(scriptSource)) {
5043 _reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST,
5044 scriptAttribute, [scriptSourcePath]);
5045 }
5046 } on URISyntaxException {
5047 _reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute,
5048 [scriptSourcePath]);
5049 }
5050 }
5051 node.scriptElement = script;
5052 _scripts.add(script);
5053 }
5054 } finally {
5055 _parentNodes.remove(node);
5056 }
5057 return null;
5058 }
5059
5060 @override
5061 Object visitHtmlUnit(ht.HtmlUnit node) {
5062 _parentNodes = new List<ht.XmlTagNode>();
5063 _scripts = new List<HtmlScriptElement>();
5064 try {
5065 node.visitChildren(this);
5066 _htmlElement.scripts = new List.from(_scripts);
5067 } finally {
5068 _scripts = null;
5069 _parentNodes = null;
5070 }
5071 return null;
5072 }
5073
5074 @override
5075 Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
5076
5077 @override
5078 Object visitXmlTagNode(ht.XmlTagNode node) {
5079 if (_parentNodes.contains(node)) {
5080 return _reportCircularity(node);
5081 }
5082 _parentNodes.add(node);
5083 try {
5084 node.visitChildren(this);
5085 } finally {
5086 _parentNodes.remove(node);
5087 }
5088 return null;
5089 }
5090
5091 /**
5092 * Return the first source attribute for the given tag node, or `null` if it d oes not exist.
5093 *
5094 * @param node the node containing attributes
5095 * @return the source attribute contained in the given tag
5096 */
5097 ht.XmlAttributeNode _getScriptSourcePath(ht.XmlTagNode node) {
5098 for (ht.XmlAttributeNode attribute in node.attributes) {
5099 if (attribute.name == _SRC) {
5100 return attribute;
5101 }
5102 }
5103 return null;
5104 }
5105
5106 Object _reportCircularity(ht.XmlTagNode node) {
5107 //
5108 // This should not be possible, but we have an error report that suggests
5109 // that it happened at least once. This code will guard against infinite
5110 // recursion and might help us identify the cause of the issue.
5111 //
5112 StringBuffer buffer = new StringBuffer();
5113 buffer.write("Found circularity in XML nodes: ");
5114 bool first = true;
5115 for (ht.XmlTagNode pathNode in _parentNodes) {
5116 if (first) {
5117 first = false;
5118 } else {
5119 buffer.write(", ");
5120 }
5121 String tagName = pathNode.tag;
5122 if (identical(pathNode, node)) {
5123 buffer.write("*");
5124 buffer.write(tagName);
5125 buffer.write("*");
5126 } else {
5127 buffer.write(tagName);
5128 }
5129 }
5130 AnalysisEngine.instance.logger.logError(buffer.toString());
5131 return null;
5132 }
5133
5134 /**
5135 * Report an error with the given error code at the given location. Use the gi ven arguments to
5136 * compose the error message.
5137 *
5138 * @param errorCode the error code of the error to be reported
5139 * @param offset the offset of the first character to be highlighted
5140 * @param length the number of characters to be highlighted
5141 * @param arguments the arguments used to compose the error message
5142 */
5143 void _reportErrorForOffset(
5144 ErrorCode errorCode, int offset, int length, List<Object> arguments) {
5145 _errorListener.onError(new AnalysisError(
5146 _htmlElement.source, offset, length, errorCode, arguments));
5147 }
5148
5149 /**
5150 * Report an error with the given error code at the location of the value of t he given attribute.
5151 * Use the given arguments to compose the error message.
5152 *
5153 * @param errorCode the error code of the error to be reported
5154 * @param offset the offset of the first character to be highlighted
5155 * @param length the number of characters to be highlighted
5156 * @param arguments the arguments used to compose the error message
5157 */
5158 void _reportValueError(ErrorCode errorCode, ht.XmlAttributeNode attribute,
5159 List<Object> arguments) {
5160 int offset = attribute.valueToken.offset + 1;
5161 int length = attribute.valueToken.length - 2;
5162 _reportErrorForOffset(errorCode, offset, length, arguments);
5163 }
5164 }
5165
5166 /**
5167 * Instances of the class `ImplicitLabelScope` represent the scope statements
5168 * that can be the target of unlabeled break and continue statements.
5169 */
5170 class ImplicitLabelScope {
5171 /**
5172 * The implicit label scope associated with the top level of a function.
5173 */
5174 static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null);
5175
5176 /**
5177 * The implicit label scope enclosing this implicit label scope.
5178 */
5179 final ImplicitLabelScope outerScope;
5180
5181 /**
5182 * The statement that acts as a target for break and/or continue statements
5183 * at this scoping level.
5184 */
5185 final Statement statement;
5186
5187 /**
5188 * Private constructor.
5189 */
5190 const ImplicitLabelScope._(this.outerScope, this.statement);
5191
5192 /**
5193 * Get the statement which should be the target of an unlabeled `break` or
5194 * `continue` statement, or `null` if there is no appropriate target.
5195 */
5196 Statement getTarget(bool isContinue) {
5197 if (outerScope == null) {
5198 // This scope represents the toplevel of a function body, so it doesn't
5199 // match either break or continue.
5200 return null;
5201 }
5202 if (isContinue && statement is SwitchStatement) {
5203 return outerScope.getTarget(isContinue);
5204 }
5205 return statement;
5206 }
5207
5208 /**
5209 * Initialize a newly created scope to represent a switch statement or loop
5210 * nested within the current scope. [statement] is the statement associated
5211 * with the newly created scope.
5212 */
5213 ImplicitLabelScope nest(Statement statement) =>
5214 new ImplicitLabelScope._(this, statement);
5215 }
5216
5217 /**
5218 * Instances of the class `ImportsVerifier` visit all of the referenced librarie s in the
5219 * source code verifying that all of the imports are used, otherwise a
5220 * [HintCode.UNUSED_IMPORT] is generated with
5221 * [generateUnusedImportHints].
5222 *
5223 * While this class does not yet have support for an "Organize Imports" action, this logic built up
5224 * in this class could be used for such an action in the future.
5225 */
5226 class ImportsVerifier /*extends RecursiveAstVisitor<Object>*/ {
5227 /**
5228 * A list of [ImportDirective]s that the current library imports, as identifie rs are visited
5229 * by this visitor and an import has been identified as being used by the libr ary, the
5230 * [ImportDirective] is removed from this list. After all the sources in the l ibrary have
5231 * been evaluated, this list represents the set of unused imports.
5232 *
5233 * See [ImportsVerifier.generateUnusedImportErrors].
5234 */
5235 final List<ImportDirective> _unusedImports = <ImportDirective>[];
5236
5237 /**
5238 * After the list of [unusedImports] has been computed, this list is a proper subset of the
5239 * unused imports that are listed more than once.
5240 */
5241 final List<ImportDirective> _duplicateImports = <ImportDirective>[];
5242
5243 /**
5244 * This is a map between the set of [LibraryElement]s that the current library imports, and
5245 * a list of [ImportDirective]s that imports the library. In cases where the c urrent library
5246 * imports a library with a single directive (such as `import lib1.dart;`), th e library
5247 * element will map to a list of one [ImportDirective], which will then be rem oved from the
5248 * [unusedImports] list. In cases where the current library imports a library with multiple
5249 * directives (such as `import lib1.dart; import lib1.dart show C;`), the
5250 * [LibraryElement] will be mapped to a list of the import directives, and the namespace
5251 * will need to be used to compute the correct [ImportDirective] being used, s ee
5252 * [namespaceMap].
5253 */
5254 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap =
5255 new HashMap<LibraryElement, List<ImportDirective>>();
5256
5257 /**
5258 * In cases where there is more than one import directive per library element, this mapping is
5259 * used to determine which of the multiple import directives are used by gener ating a
5260 * [Namespace] for each of the imports to do lookups in the same way that they are done from
5261 * the [ElementResolver].
5262 */
5263 final HashMap<ImportDirective, Namespace> _namespaceMap =
5264 new HashMap<ImportDirective, Namespace>();
5265
5266 /**
5267 * This is a map between prefix elements and the import directives from which they are derived. In
5268 * cases where a type is referenced via a prefix element, the import directive can be marked as
5269 * used (removed from the unusedImports) by looking at the resolved `lib` in ` lib.X`,
5270 * instead of looking at which library the `lib.X` resolves.
5271 *
5272 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl ement],
5273 * it is possible to have an unreported unused import in situations where two imports use the same
5274 * prefix and at least one import directive is used.
5275 */
5276 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap =
5277 new HashMap<PrefixElement, List<ImportDirective>>();
5278
5279 void addImports(CompilationUnit node) {
5280 for (Directive directive in node.directives) {
5281 if (directive is ImportDirective) {
5282 ImportDirective importDirective = directive;
5283 LibraryElement libraryElement = importDirective.uriElement;
5284 if (libraryElement != null) {
5285 _unusedImports.add(importDirective);
5286 //
5287 // Initialize prefixElementMap
5288 //
5289 if (importDirective.asKeyword != null) {
5290 SimpleIdentifier prefixIdentifier = importDirective.prefix;
5291 if (prefixIdentifier != null) {
5292 Element element = prefixIdentifier.staticElement;
5293 if (element is PrefixElement) {
5294 PrefixElement prefixElementKey = element;
5295 List<ImportDirective> list =
5296 _prefixElementMap[prefixElementKey];
5297 if (list == null) {
5298 list = new List<ImportDirective>();
5299 _prefixElementMap[prefixElementKey] = list;
5300 }
5301 list.add(importDirective);
5302 }
5303 // TODO (jwren) Can the element ever not be a PrefixElement?
5304 }
5305 }
5306 //
5307 // Initialize libraryMap: libraryElement -> importDirective
5308 //
5309 _putIntoLibraryMap(libraryElement, importDirective);
5310 //
5311 // For this new addition to the libraryMap, also recursively add any
5312 // exports from the libraryElement.
5313 //
5314 _addAdditionalLibrariesForExports(
5315 libraryElement, importDirective, new List<LibraryElement>());
5316 }
5317 }
5318 }
5319 if (_unusedImports.length > 1) {
5320 // order the list of unusedImports to find duplicates in faster than
5321 // O(n^2) time
5322 List<ImportDirective> importDirectiveArray =
5323 new List<ImportDirective>.from(_unusedImports);
5324 importDirectiveArray.sort(ImportDirective.COMPARATOR);
5325 ImportDirective currentDirective = importDirectiveArray[0];
5326 for (int i = 1; i < importDirectiveArray.length; i++) {
5327 ImportDirective nextDirective = importDirectiveArray[i];
5328 if (ImportDirective.COMPARATOR(currentDirective, nextDirective) == 0) {
5329 // Add either the currentDirective or nextDirective depending on which
5330 // comes second, this guarantees that the first of the duplicates
5331 // won't be highlighted.
5332 if (currentDirective.offset < nextDirective.offset) {
5333 _duplicateImports.add(nextDirective);
5334 } else {
5335 _duplicateImports.add(currentDirective);
5336 }
5337 }
5338 currentDirective = nextDirective;
5339 }
5340 }
5341 }
5342
5343 /**
5344 * Any time after the defining compilation unit has been visited by this visit or, this method can
5345 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp ort directives
5346 * in the [duplicateImports] list.
5347 *
5348 * @param errorReporter the error reporter to report the set of [HintCode.DUPL ICATE_IMPORT]
5349 * hints to
5350 */
5351 void generateDuplicateImportHints(ErrorReporter errorReporter) {
5352 for (ImportDirective duplicateImport in _duplicateImports) {
5353 errorReporter.reportErrorForNode(
5354 HintCode.DUPLICATE_IMPORT, duplicateImport.uri);
5355 }
5356 }
5357
5358 /**
5359 * After all of the compilation units have been visited by this visitor, this method can be called
5360 * to report an [HintCode.UNUSED_IMPORT] hint for each of the import directive s in the
5361 * [unusedImports] list.
5362 *
5363 * @param errorReporter the error reporter to report the set of [HintCode.UNUS ED_IMPORT]
5364 * hints to
5365 */
5366 void generateUnusedImportHints(ErrorReporter errorReporter) {
5367 for (ImportDirective unusedImport in _unusedImports) {
5368 // Check that the import isn't dart:core
5369 ImportElement importElement = unusedImport.element;
5370 if (importElement != null) {
5371 LibraryElement libraryElement = importElement.importedLibrary;
5372 if (libraryElement != null && libraryElement.isDartCore) {
5373 continue;
5374 }
5375 }
5376 errorReporter.reportErrorForNode(
5377 HintCode.UNUSED_IMPORT, unusedImport.uri);
5378 }
5379 }
5380
5381 /**
5382 * Remove elements from [_unusedImports] using the given [usedElements].
5383 */
5384 void removeUsedElements(UsedImportedElements usedElements) {
5385 // Stop if all the imports are known to be used.
5386 if (_unusedImports.isEmpty) {
5387 return;
5388 }
5389 // Process import prefixes.
5390 for (PrefixElement prefix in usedElements.prefixes) {
5391 List<ImportDirective> importDirectives = _prefixElementMap[prefix];
5392 if (importDirectives != null) {
5393 for (ImportDirective importDirective in importDirectives) {
5394 _unusedImports.remove(importDirective);
5395 }
5396 }
5397 }
5398 // Process top-level elements.
5399 for (Element element in usedElements.elements) {
5400 // Stop if all the imports are known to be used.
5401 if (_unusedImports.isEmpty) {
5402 return;
5403 }
5404 // Prepare import directives for this library.
5405 LibraryElement library = element.library;
5406 List<ImportDirective> importsLibrary = _libraryMap[library];
5407 if (importsLibrary == null) {
5408 continue;
5409 }
5410 // If there is only one import directive for this library, then it must be
5411 // the directive that this element is imported with, remove it from the
5412 // unusedImports list.
5413 if (importsLibrary.length == 1) {
5414 ImportDirective usedImportDirective = importsLibrary[0];
5415 _unusedImports.remove(usedImportDirective);
5416 continue;
5417 }
5418 // Otherwise, find import directives using namespaces.
5419 String name = element.displayName;
5420 for (ImportDirective importDirective in importsLibrary) {
5421 Namespace namespace = _computeNamespace(importDirective);
5422 if (namespace != null && namespace.get(name) != null) {
5423 _unusedImports.remove(importDirective);
5424 }
5425 }
5426 }
5427 }
5428
5429 /**
5430 * Recursively add any exported library elements into the [libraryMap].
5431 */
5432 void _addAdditionalLibrariesForExports(LibraryElement library,
5433 ImportDirective importDirective, List<LibraryElement> exportPath) {
5434 if (exportPath.contains(library)) {
5435 return;
5436 }
5437 exportPath.add(library);
5438 for (LibraryElement exportedLibraryElt in library.exportedLibraries) {
5439 _putIntoLibraryMap(exportedLibraryElt, importDirective);
5440 _addAdditionalLibrariesForExports(
5441 exportedLibraryElt, importDirective, exportPath);
5442 }
5443 }
5444
5445 /**
5446 * Lookup and return the [Namespace] from the [namespaceMap], if the map does not
5447 * have the computed namespace, compute it and cache it in the map. If the imp ort directive is not
5448 * resolved or is not resolvable, `null` is returned.
5449 *
5450 * @param importDirective the import directive used to compute the returned na mespace
5451 * @return the computed or looked up [Namespace]
5452 */
5453 Namespace _computeNamespace(ImportDirective importDirective) {
5454 Namespace namespace = _namespaceMap[importDirective];
5455 if (namespace == null) {
5456 // If the namespace isn't in the namespaceMap, then compute and put it in
5457 // the map.
5458 ImportElement importElement = importDirective.element;
5459 if (importElement != null) {
5460 NamespaceBuilder builder = new NamespaceBuilder();
5461 namespace = builder.createImportNamespaceForDirective(importElement);
5462 _namespaceMap[importDirective] = namespace;
5463 }
5464 }
5465 return namespace;
5466 }
5467
5468 /**
5469 * The [libraryMap] is a mapping between a library elements and a list of impo rt
5470 * directives, but when adding these mappings into the [libraryMap], this meth od can be
5471 * used to simply add the mapping between the library element an an import dir ective without
5472 * needing to check to see if a list needs to be created.
5473 */
5474 void _putIntoLibraryMap(
5475 LibraryElement libraryElement, ImportDirective importDirective) {
5476 List<ImportDirective> importList = _libraryMap[libraryElement];
5477 if (importList == null) {
5478 importList = new List<ImportDirective>();
5479 _libraryMap[libraryElement] = importList;
5480 }
5481 importList.add(importDirective);
5482 }
5483 }
5484
5485 /**
5486 * Instances of the class `InheritanceManager` manage the knowledge of where cla ss members
5487 * (methods, getters & setters) are inherited from.
5488 */
5489 class InheritanceManager {
5490 /**
5491 * The [LibraryElement] that is managed by this manager.
5492 */
5493 LibraryElement _library;
5494
5495 /**
5496 * This is a mapping between each [ClassElement] and a map between the [String ] member
5497 * names and the associated [ExecutableElement] in the mixin and superclass ch ain.
5498 */
5499 HashMap<ClassElement, MemberMap> _classLookup;
5500
5501 /**
5502 * This is a mapping between each [ClassElement] and a map between the [String ] member
5503 * names and the associated [ExecutableElement] in the interface set.
5504 */
5505 HashMap<ClassElement, MemberMap> _interfaceLookup;
5506
5507 /**
5508 * A map between each visited [ClassElement] and the set of [AnalysisError]s f ound on
5509 * the class element.
5510 */
5511 HashMap<ClassElement, HashSet<AnalysisError>> _errorsInClassElement =
5512 new HashMap<ClassElement, HashSet<AnalysisError>>();
5513
5514 /**
5515 * Initialize a newly created inheritance manager.
5516 *
5517 * @param library the library element context that the inheritance mappings ar e being generated
5518 */
5519 InheritanceManager(LibraryElement library) {
5520 this._library = library;
5521 _classLookup = new HashMap<ClassElement, MemberMap>();
5522 _interfaceLookup = new HashMap<ClassElement, MemberMap>();
5523 }
5524
5525 /**
5526 * Set the new library element context.
5527 *
5528 * @param library the new library element
5529 */
5530 void set libraryElement(LibraryElement library) {
5531 this._library = library;
5532 }
5533
5534 /**
5535 * Return the set of [AnalysisError]s found on the passed [ClassElement], or
5536 * `null` if there are none.
5537 *
5538 * @param classElt the class element to query
5539 * @return the set of [AnalysisError]s found on the passed [ClassElement], or
5540 * `null` if there are none
5541 */
5542 HashSet<AnalysisError> getErrors(ClassElement classElt) =>
5543 _errorsInClassElement[classElt];
5544
5545 /**
5546 * Get and return a mapping between the set of all string names of the members inherited from the
5547 * passed [ClassElement] superclass hierarchy, and the associated [ExecutableE lement].
5548 *
5549 * @param classElt the class element to query
5550 * @return a mapping between the set of all members inherited from the passed [ClassElement]
5551 * superclass hierarchy, and the associated [ExecutableElement]
5552 */
5553 MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) =>
5554 _computeClassChainLookupMap(classElt, new HashSet<ClassElement>());
5555
5556 /**
5557 * Get and return a mapping between the set of all string names of the members inherited from the
5558 * passed [ClassElement] interface hierarchy, and the associated [ExecutableEl ement].
5559 *
5560 * @param classElt the class element to query
5561 * @return a mapping between the set of all string names of the members inheri ted from the passed
5562 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement].
5563 */
5564 MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) =>
5565 _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>());
5566
5567 /**
5568 * Given some [ClassElement] and some member name, this returns the
5569 * [ExecutableElement] that the class inherits from the mixins,
5570 * superclasses or interfaces, that has the member name, if no member is inher ited `null` is
5571 * returned.
5572 *
5573 * @param classElt the class element to query
5574 * @param memberName the name of the executable element to find and return
5575 * @return the inherited executable element with the member name, or `null` if no such
5576 * member exists
5577 */
5578 ExecutableElement lookupInheritance(
5579 ClassElement classElt, String memberName) {
5580 if (memberName == null || memberName.isEmpty) {
5581 return null;
5582 }
5583 ExecutableElement executable = _computeClassChainLookupMap(
5584 classElt, new HashSet<ClassElement>()).get(memberName);
5585 if (executable == null) {
5586 return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>())
5587 .get(memberName);
5588 }
5589 return executable;
5590 }
5591
5592 /**
5593 * Given some [ClassElement] and some member name, this returns the
5594 * [ExecutableElement] that the class either declares itself, or
5595 * inherits, that has the member name, if no member is inherited `null` is ret urned.
5596 *
5597 * @param classElt the class element to query
5598 * @param memberName the name of the executable element to find and return
5599 * @return the inherited executable element with the member name, or `null` if no such
5600 * member exists
5601 */
5602 ExecutableElement lookupMember(ClassElement classElt, String memberName) {
5603 ExecutableElement element = _lookupMemberInClass(classElt, memberName);
5604 if (element != null) {
5605 return element;
5606 }
5607 return lookupInheritance(classElt, memberName);
5608 }
5609
5610 /**
5611 * Given some [InterfaceType] and some member name, this returns the
5612 * [FunctionType] of the [ExecutableElement] that the
5613 * class either declares itself, or inherits, that has the member name, if no member is inherited
5614 * `null` is returned. The returned [FunctionType] has all type
5615 * parameters substituted with corresponding type arguments from the given [In terfaceType].
5616 *
5617 * @param interfaceType the interface type to query
5618 * @param memberName the name of the executable element to find and return
5619 * @return the member's function type, or `null` if no such member exists
5620 */
5621 FunctionType lookupMemberType(
5622 InterfaceType interfaceType, String memberName) {
5623 ExecutableElement iteratorMember =
5624 lookupMember(interfaceType.element, memberName);
5625 if (iteratorMember == null) {
5626 return null;
5627 }
5628 return substituteTypeArgumentsInMemberFromInheritance(
5629 iteratorMember.type, memberName, interfaceType);
5630 }
5631
5632 /**
5633 * Determine the set of methods which is overridden by the given class member. If no member is
5634 * inherited, an empty list is returned. If one of the inherited members is a
5635 * [MultiplyInheritedExecutableElement], then it is expanded into its constitu ent inherited
5636 * elements.
5637 *
5638 * @param classElt the class to query
5639 * @param memberName the name of the class member to query
5640 * @return a list of overridden methods
5641 */
5642 List<ExecutableElement> lookupOverrides(
5643 ClassElement classElt, String memberName) {
5644 List<ExecutableElement> result = new List<ExecutableElement>();
5645 if (memberName == null || memberName.isEmpty) {
5646 return result;
5647 }
5648 List<MemberMap> interfaceMaps =
5649 _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>());
5650 if (interfaceMaps != null) {
5651 for (MemberMap interfaceMap in interfaceMaps) {
5652 ExecutableElement overriddenElement = interfaceMap.get(memberName);
5653 if (overriddenElement != null) {
5654 if (overriddenElement is MultiplyInheritedExecutableElement) {
5655 MultiplyInheritedExecutableElement multiplyInheritedElement =
5656 overriddenElement;
5657 for (ExecutableElement element
5658 in multiplyInheritedElement.inheritedElements) {
5659 result.add(element);
5660 }
5661 } else {
5662 result.add(overriddenElement);
5663 }
5664 }
5665 }
5666 }
5667 return result;
5668 }
5669
5670 /**
5671 * This method takes some inherited [FunctionType], and resolves all the param eterized types
5672 * in the function type, dependent on the class in which it is being overridde n.
5673 *
5674 * @param baseFunctionType the function type that is being overridden
5675 * @param memberName the name of the member, this is used to lookup the inheri tance path of the
5676 * override
5677 * @param definingType the type that is overriding the member
5678 * @return the passed function type with any parameterized types substituted
5679 */
5680 FunctionType substituteTypeArgumentsInMemberFromInheritance(
5681 FunctionType baseFunctionType, String memberName,
5682 InterfaceType definingType) {
5683 // if the baseFunctionType is null, or does not have any parameters,
5684 // return it.
5685 if (baseFunctionType == null ||
5686 baseFunctionType.typeArguments.length == 0) {
5687 return baseFunctionType;
5688 }
5689 // First, generate the path from the defining type to the overridden member
5690 Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
5691 _computeInheritancePath(inheritancePath, definingType, memberName);
5692 if (inheritancePath == null || inheritancePath.isEmpty) {
5693 // TODO(jwren) log analysis engine error
5694 return baseFunctionType;
5695 }
5696 FunctionType functionTypeToReturn = baseFunctionType;
5697 // loop backward through the list substituting as we go:
5698 while (!inheritancePath.isEmpty) {
5699 InterfaceType lastType = inheritancePath.removeLast();
5700 List<DartType> parameterTypes = lastType.element.type.typeArguments;
5701 List<DartType> argumentTypes = lastType.typeArguments;
5702 functionTypeToReturn =
5703 functionTypeToReturn.substitute2(argumentTypes, parameterTypes);
5704 }
5705 return functionTypeToReturn;
5706 }
5707
5708 /**
5709 * Compute and return a mapping between the set of all string names of the mem bers inherited from
5710 * the passed [ClassElement] superclass hierarchy, and the associated
5711 * [ExecutableElement].
5712 *
5713 * @param classElt the class element to query
5714 * @param visitedClasses a set of visited classes passed back into this method when it calls
5715 * itself recursively
5716 * @return a mapping between the set of all string names of the members inheri ted from the passed
5717 * [ClassElement] superclass hierarchy, and the associated [Executable Element]
5718 */
5719 MemberMap _computeClassChainLookupMap(
5720 ClassElement classElt, HashSet<ClassElement> visitedClasses) {
5721 MemberMap resultMap = _classLookup[classElt];
5722 if (resultMap != null) {
5723 return resultMap;
5724 } else {
5725 resultMap = new MemberMap();
5726 }
5727 ClassElement superclassElt = null;
5728 InterfaceType supertype = classElt.supertype;
5729 if (supertype != null) {
5730 superclassElt = supertype.element;
5731 } else {
5732 // classElt is Object
5733 _classLookup[classElt] = resultMap;
5734 return resultMap;
5735 }
5736 if (superclassElt != null) {
5737 if (!visitedClasses.contains(superclassElt)) {
5738 visitedClasses.add(superclassElt);
5739 try {
5740 resultMap = new MemberMap.from(
5741 _computeClassChainLookupMap(superclassElt, visitedClasses));
5742 //
5743 // Substitute the super types down the hierarchy.
5744 //
5745 _substituteTypeParametersDownHierarchy(supertype, resultMap);
5746 //
5747 // Include the members from the superclass in the resultMap.
5748 //
5749 _recordMapWithClassMembers(resultMap, supertype, false);
5750 } finally {
5751 visitedClasses.remove(superclassElt);
5752 }
5753 } else {
5754 // This case happens only when the superclass was previously visited and
5755 // not in the lookup, meaning this is meant to shorten the compute for
5756 // recursive cases.
5757 _classLookup[superclassElt] = resultMap;
5758 return resultMap;
5759 }
5760 }
5761 //
5762 // Include the members from the mixins in the resultMap. If there are
5763 // multiple mixins, visit them in the order listed so that methods in later
5764 // mixins will overwrite identically-named methods in earlier mixins.
5765 //
5766 List<InterfaceType> mixins = classElt.mixins;
5767 for (InterfaceType mixin in mixins) {
5768 ClassElement mixinElement = mixin.element;
5769 if (mixinElement != null) {
5770 if (!visitedClasses.contains(mixinElement)) {
5771 visitedClasses.add(mixinElement);
5772 try {
5773 MemberMap map = new MemberMap.from(
5774 _computeClassChainLookupMap(mixinElement, visitedClasses));
5775 //
5776 // Substitute the super types down the hierarchy.
5777 //
5778 _substituteTypeParametersDownHierarchy(mixin, map);
5779 //
5780 // Include the members from the superclass in the resultMap.
5781 //
5782 _recordMapWithClassMembers(map, mixin, false);
5783 //
5784 // Add the members from map into result map.
5785 //
5786 for (int j = 0; j < map.size; j++) {
5787 String key = map.getKey(j);
5788 ExecutableElement value = map.getValue(j);
5789 if (key != null) {
5790 ClassElement definingClass = value
5791 .getAncestor((Element element) => element is ClassElement);
5792 if (!definingClass.type.isObject) {
5793 ExecutableElement existingValue = resultMap.get(key);
5794 if (existingValue == null ||
5795 (existingValue != null && !_isAbstract(value))) {
5796 resultMap.put(key, value);
5797 }
5798 }
5799 }
5800 }
5801 } finally {
5802 visitedClasses.remove(mixinElement);
5803 }
5804 } else {
5805 // This case happens only when the superclass was previously visited
5806 // and not in the lookup, meaning this is meant to shorten the compute
5807 // for recursive cases.
5808 _classLookup[mixinElement] = resultMap;
5809 return resultMap;
5810 }
5811 }
5812 }
5813 _classLookup[classElt] = resultMap;
5814 return resultMap;
5815 }
5816
5817 /**
5818 * Compute and return the inheritance path given the context of a type and a m ember that is
5819 * overridden in the inheritance path (for which the type is in the path).
5820 *
5821 * @param chain the inheritance path that is built up as this method calls its elf recursively,
5822 * when this method is called an empty [LinkedList] should be provide d
5823 * @param currentType the current type in the inheritance path
5824 * @param memberName the name of the member that is being looked up the inheri tance path
5825 */
5826 void _computeInheritancePath(Queue<InterfaceType> chain,
5827 InterfaceType currentType, String memberName) {
5828 // TODO (jwren) create a public version of this method which doesn't require
5829 // the initial chain to be provided, then provided tests for this
5830 // functionality in InheritanceManagerTest
5831 chain.add(currentType);
5832 ClassElement classElt = currentType.element;
5833 InterfaceType supertype = classElt.supertype;
5834 // Base case- reached Object
5835 if (supertype == null) {
5836 // Looked up the chain all the way to Object, return null.
5837 // This should never happen.
5838 return;
5839 }
5840 // If we are done, return the chain
5841 // We are not done if this is the first recursive call on this method.
5842 if (chain.length != 1) {
5843 // We are done however if the member is in this classElt
5844 if (_lookupMemberInClass(classElt, memberName) != null) {
5845 return;
5846 }
5847 }
5848 // Mixins- note that mixins call lookupMemberInClass, not lookupMember
5849 List<InterfaceType> mixins = classElt.mixins;
5850 for (int i = mixins.length - 1; i >= 0; i--) {
5851 ClassElement mixinElement = mixins[i].element;
5852 if (mixinElement != null) {
5853 ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName);
5854 if (elt != null) {
5855 // this is equivalent (but faster than) calling this method
5856 // recursively
5857 // (return computeInheritancePath(chain, mixins[i], memberName);)
5858 chain.add(mixins[i]);
5859 return;
5860 }
5861 }
5862 }
5863 // Superclass
5864 ClassElement superclassElt = supertype.element;
5865 if (lookupMember(superclassElt, memberName) != null) {
5866 _computeInheritancePath(chain, supertype, memberName);
5867 return;
5868 }
5869 // Interfaces
5870 List<InterfaceType> interfaces = classElt.interfaces;
5871 for (InterfaceType interfaceType in interfaces) {
5872 ClassElement interfaceElement = interfaceType.element;
5873 if (interfaceElement != null &&
5874 lookupMember(interfaceElement, memberName) != null) {
5875 _computeInheritancePath(chain, interfaceType, memberName);
5876 return;
5877 }
5878 }
5879 }
5880
5881 /**
5882 * Compute and return a mapping between the set of all string names of the mem bers inherited from
5883 * the passed [ClassElement] interface hierarchy, and the associated
5884 * [ExecutableElement].
5885 *
5886 * @param classElt the class element to query
5887 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
5888 * itself recursively
5889 * @return a mapping between the set of all string names of the members inheri ted from the passed
5890 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement]
5891 */
5892 MemberMap _computeInterfaceLookupMap(
5893 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
5894 MemberMap resultMap = _interfaceLookup[classElt];
5895 if (resultMap != null) {
5896 return resultMap;
5897 }
5898 List<MemberMap> lookupMaps =
5899 _gatherInterfaceLookupMaps(classElt, visitedInterfaces);
5900 if (lookupMaps == null) {
5901 resultMap = new MemberMap();
5902 } else {
5903 HashMap<String, List<ExecutableElement>> unionMap =
5904 _unionInterfaceLookupMaps(lookupMaps);
5905 resultMap = _resolveInheritanceLookup(classElt, unionMap);
5906 }
5907 _interfaceLookup[classElt] = resultMap;
5908 return resultMap;
5909 }
5910
5911 /**
5912 * Collect a list of interface lookup maps whose elements correspond to all of the classes
5913 * directly above [classElt] in the class hierarchy (the direct superclass if any, all
5914 * mixins, and all direct superinterfaces). Each item in the list is the inter face lookup map
5915 * returned by [computeInterfaceLookupMap] for the corresponding super, except with type
5916 * parameters appropriately substituted.
5917 *
5918 * @param classElt the class element to query
5919 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
5920 * itself recursively
5921 * @return `null` if there was a problem (such as a loop in the class hierarch y) or if there
5922 * are no classes above this one in the class hierarchy. Otherwise, a list of interface
5923 * lookup maps.
5924 */
5925 List<MemberMap> _gatherInterfaceLookupMaps(
5926 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
5927 InterfaceType supertype = classElt.supertype;
5928 ClassElement superclassElement =
5929 supertype != null ? supertype.element : null;
5930 List<InterfaceType> mixins = classElt.mixins;
5931 List<InterfaceType> interfaces = classElt.interfaces;
5932 // Recursively collect the list of mappings from all of the interface types
5933 List<MemberMap> lookupMaps = new List<MemberMap>();
5934 //
5935 // Superclass element
5936 //
5937 if (superclassElement != null) {
5938 if (!visitedInterfaces.contains(superclassElement)) {
5939 try {
5940 visitedInterfaces.add(superclassElement);
5941 //
5942 // Recursively compute the map for the super type.
5943 //
5944 MemberMap map =
5945 _computeInterfaceLookupMap(superclassElement, visitedInterfaces);
5946 map = new MemberMap.from(map);
5947 //
5948 // Substitute the super type down the hierarchy.
5949 //
5950 _substituteTypeParametersDownHierarchy(supertype, map);
5951 //
5952 // Add any members from the super type into the map as well.
5953 //
5954 _recordMapWithClassMembers(map, supertype, true);
5955 lookupMaps.add(map);
5956 } finally {
5957 visitedInterfaces.remove(superclassElement);
5958 }
5959 } else {
5960 return null;
5961 }
5962 }
5963 //
5964 // Mixin elements
5965 //
5966 for (int i = mixins.length - 1; i >= 0; i--) {
5967 InterfaceType mixinType = mixins[i];
5968 ClassElement mixinElement = mixinType.element;
5969 if (mixinElement != null) {
5970 if (!visitedInterfaces.contains(mixinElement)) {
5971 try {
5972 visitedInterfaces.add(mixinElement);
5973 //
5974 // Recursively compute the map for the mixin.
5975 //
5976 MemberMap map =
5977 _computeInterfaceLookupMap(mixinElement, visitedInterfaces);
5978 map = new MemberMap.from(map);
5979 //
5980 // Substitute the mixin type down the hierarchy.
5981 //
5982 _substituteTypeParametersDownHierarchy(mixinType, map);
5983 //
5984 // Add any members from the mixin type into the map as well.
5985 //
5986 _recordMapWithClassMembers(map, mixinType, true);
5987 lookupMaps.add(map);
5988 } finally {
5989 visitedInterfaces.remove(mixinElement);
5990 }
5991 } else {
5992 return null;
5993 }
5994 }
5995 }
5996 //
5997 // Interface elements
5998 //
5999 for (InterfaceType interfaceType in interfaces) {
6000 ClassElement interfaceElement = interfaceType.element;
6001 if (interfaceElement != null) {
6002 if (!visitedInterfaces.contains(interfaceElement)) {
6003 try {
6004 visitedInterfaces.add(interfaceElement);
6005 //
6006 // Recursively compute the map for the interfaces.
6007 //
6008 MemberMap map =
6009 _computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
6010 map = new MemberMap.from(map);
6011 //
6012 // Substitute the supertypes down the hierarchy
6013 //
6014 _substituteTypeParametersDownHierarchy(interfaceType, map);
6015 //
6016 // And add any members from the interface into the map as well.
6017 //
6018 _recordMapWithClassMembers(map, interfaceType, true);
6019 lookupMaps.add(map);
6020 } finally {
6021 visitedInterfaces.remove(interfaceElement);
6022 }
6023 } else {
6024 return null;
6025 }
6026 }
6027 }
6028 if (lookupMaps.length == 0) {
6029 return null;
6030 }
6031 return lookupMaps;
6032 }
6033
6034 /**
6035 * Given some [ClassElement], this method finds and returns the [ExecutableEle ment] of
6036 * the passed name in the class element. Static members, members in super type s and members not
6037 * accessible from the current library are not considered.
6038 *
6039 * @param classElt the class element to query
6040 * @param memberName the name of the member to lookup in the class
6041 * @return the found [ExecutableElement], or `null` if no such member was foun d
6042 */
6043 ExecutableElement _lookupMemberInClass(
6044 ClassElement classElt, String memberName) {
6045 List<MethodElement> methods = classElt.methods;
6046 for (MethodElement method in methods) {
6047 if (memberName == method.name &&
6048 method.isAccessibleIn(_library) &&
6049 !method.isStatic) {
6050 return method;
6051 }
6052 }
6053 List<PropertyAccessorElement> accessors = classElt.accessors;
6054 for (PropertyAccessorElement accessor in accessors) {
6055 if (memberName == accessor.name &&
6056 accessor.isAccessibleIn(_library) &&
6057 !accessor.isStatic) {
6058 return accessor;
6059 }
6060 }
6061 return null;
6062 }
6063
6064 /**
6065 * Record the passed map with the set of all members (methods, getters and set ters) in the type
6066 * into the passed map.
6067 *
6068 * @param map some non-`null` map to put the methods and accessors from the pa ssed
6069 * [ClassElement] into
6070 * @param type the type that will be recorded into the passed map
6071 * @param doIncludeAbstract `true` if abstract members will be put into the ma p
6072 */
6073 void _recordMapWithClassMembers(
6074 MemberMap map, InterfaceType type, bool doIncludeAbstract) {
6075 List<MethodElement> methods = type.methods;
6076 for (MethodElement method in methods) {
6077 if (method.isAccessibleIn(_library) &&
6078 !method.isStatic &&
6079 (doIncludeAbstract || !method.isAbstract)) {
6080 map.put(method.name, method);
6081 }
6082 }
6083 List<PropertyAccessorElement> accessors = type.accessors;
6084 for (PropertyAccessorElement accessor in accessors) {
6085 if (accessor.isAccessibleIn(_library) &&
6086 !accessor.isStatic &&
6087 (doIncludeAbstract || !accessor.isAbstract)) {
6088 map.put(accessor.name, accessor);
6089 }
6090 }
6091 }
6092
6093 /**
6094 * This method is used to report errors on when they are found computing inher itance information.
6095 * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where thes e generated
6096 * error codes are reported back into the analysis engine.
6097 *
6098 * @param classElt the location of the source for which the exception occurred
6099 * @param offset the offset of the location of the error
6100 * @param length the length of the location of the error
6101 * @param errorCode the error code to be associated with this error
6102 * @param arguments the arguments used to build the error message
6103 */
6104 void _reportError(ClassElement classElt, int offset, int length,
6105 ErrorCode errorCode, List<Object> arguments) {
6106 HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt];
6107 if (errorSet == null) {
6108 errorSet = new HashSet<AnalysisError>();
6109 _errorsInClassElement[classElt] = errorSet;
6110 }
6111 errorSet.add(new AnalysisError(
6112 classElt.source, offset, length, errorCode, arguments));
6113 }
6114
6115 /**
6116 * Given the set of methods defined by classes above [classElt] in the class h ierarchy,
6117 * apply the appropriate inheritance rules to determine those methods inherite d by or overridden
6118 * by [classElt]. Also report static warnings
6119 * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and
6120 * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if ap propriate.
6121 *
6122 * @param classElt the class element to query.
6123 * @param unionMap a mapping from method name to the set of unique (in terms o f signature) methods
6124 * defined in superclasses of [classElt].
6125 * @return the inheritance lookup map for [classElt].
6126 */
6127 MemberMap _resolveInheritanceLookup(ClassElement classElt,
6128 HashMap<String, List<ExecutableElement>> unionMap) {
6129 MemberMap resultMap = new MemberMap();
6130 unionMap.forEach((String key, List<ExecutableElement> list) {
6131 int numOfEltsWithMatchingNames = list.length;
6132 if (numOfEltsWithMatchingNames == 1) {
6133 //
6134 // Example: class A inherits only 1 method named 'm'.
6135 // Since it is the only such method, it is inherited.
6136 // Another example: class A inherits 2 methods named 'm' from 2
6137 // different interfaces, but they both have the same signature, so it is
6138 // the method inherited.
6139 //
6140 resultMap.put(key, list[0]);
6141 } else {
6142 //
6143 // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
6144 //
6145 bool allMethods = true;
6146 bool allSetters = true;
6147 bool allGetters = true;
6148 for (ExecutableElement executableElement in list) {
6149 if (executableElement is PropertyAccessorElement) {
6150 allMethods = false;
6151 if (executableElement.isSetter) {
6152 allGetters = false;
6153 } else {
6154 allSetters = false;
6155 }
6156 } else {
6157 allGetters = false;
6158 allSetters = false;
6159 }
6160 }
6161 //
6162 // If there isn't a mixture of methods with getters, then continue,
6163 // otherwise create a warning.
6164 //
6165 if (allMethods || allGetters || allSetters) {
6166 //
6167 // Compute the element whose type is the subtype of all of the other
6168 // types.
6169 //
6170 List<ExecutableElement> elements = new List.from(list);
6171 List<FunctionType> executableElementTypes =
6172 new List<FunctionType>(numOfEltsWithMatchingNames);
6173 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
6174 executableElementTypes[i] = elements[i].type;
6175 }
6176 List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
6177 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
6178 FunctionType subtype = executableElementTypes[i];
6179 if (subtype == null) {
6180 continue;
6181 }
6182 bool subtypeOfAllTypes = true;
6183 for (int j = 0;
6184 j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
6185 j++) {
6186 if (i != j) {
6187 if (!subtype.isSubtypeOf(executableElementTypes[j])) {
6188 subtypeOfAllTypes = false;
6189 break;
6190 }
6191 }
6192 }
6193 if (subtypeOfAllTypes) {
6194 subtypesOfAllOtherTypesIndexes.add(i);
6195 }
6196 }
6197 //
6198 // The following is split into three cases determined by the number of
6199 // elements in subtypesOfAllOtherTypes
6200 //
6201 if (subtypesOfAllOtherTypesIndexes.length == 1) {
6202 //
6203 // Example: class A inherited only 2 method named 'm'.
6204 // One has the function type '() -> dynamic' and one has the
6205 // function type '([int]) -> dynamic'. Since the second method is a
6206 // subtype of all the others, it is the inherited method.
6207 // Tests: InheritanceManagerTest.
6208 // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
6209 //
6210 resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]);
6211 } else {
6212 if (subtypesOfAllOtherTypesIndexes.isEmpty) {
6213 //
6214 // Determine if the current class has a method or accessor with
6215 // the member name, if it does then then this class does not
6216 // "inherit" from any of the supertypes. See issue 16134.
6217 //
6218 bool classHasMember = false;
6219 if (allMethods) {
6220 classHasMember = classElt.getMethod(key) != null;
6221 } else {
6222 List<PropertyAccessorElement> accessors = classElt.accessors;
6223 for (int i = 0; i < accessors.length; i++) {
6224 if (accessors[i].name == key) {
6225 classHasMember = true;
6226 }
6227 }
6228 }
6229 //
6230 // Example: class A inherited only 2 method named 'm'.
6231 // One has the function type '() -> int' and one has the function
6232 // type '() -> String'. Since neither is a subtype of the other,
6233 // we create a warning, and have this class inherit nothing.
6234 //
6235 if (!classHasMember) {
6236 String firstTwoFuntionTypesStr =
6237 "${executableElementTypes[0]}, ${executableElementTypes[1]}" ;
6238 _reportError(classElt, classElt.nameOffset,
6239 classElt.displayName.length,
6240 StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, [
6241 key,
6242 firstTwoFuntionTypesStr
6243 ]);
6244 }
6245 } else {
6246 //
6247 // Example: class A inherits 2 methods named 'm'.
6248 // One has the function type '(int) -> dynamic' and one has the
6249 // function type '(num) -> dynamic'. Since they are both a subtype
6250 // of the other, a synthetic function '(dynamic) -> dynamic' is
6251 // inherited.
6252 // Tests: test_getMapOfMembersInheritedFromInterfaces_
6253 // union_multipleSubtypes_*
6254 //
6255 List<ExecutableElement> elementArrayToMerge =
6256 new List<ExecutableElement>(
6257 subtypesOfAllOtherTypesIndexes.length);
6258 for (int i = 0; i < elementArrayToMerge.length; i++) {
6259 elementArrayToMerge[i] =
6260 elements[subtypesOfAllOtherTypesIndexes[i]];
6261 }
6262 ExecutableElement mergedExecutableElement =
6263 _computeMergedExecutableElement(elementArrayToMerge);
6264 resultMap.put(key, mergedExecutableElement);
6265 }
6266 }
6267 } else {
6268 _reportError(classElt, classElt.nameOffset,
6269 classElt.displayName.length,
6270 StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHO D,
6271 [key]);
6272 }
6273 }
6274 });
6275 return resultMap;
6276 }
6277
6278 /**
6279 * Loop through all of the members in some [MemberMap], performing type parame ter
6280 * substitutions using a passed supertype.
6281 *
6282 * @param superType the supertype to substitute into the members of the [Membe rMap]
6283 * @param map the MemberMap to perform the substitutions on
6284 */
6285 void _substituteTypeParametersDownHierarchy(
6286 InterfaceType superType, MemberMap map) {
6287 for (int i = 0; i < map.size; i++) {
6288 ExecutableElement executableElement = map.getValue(i);
6289 if (executableElement is MethodMember) {
6290 executableElement =
6291 MethodMember.from(executableElement as MethodMember, superType);
6292 map.setValue(i, executableElement);
6293 } else if (executableElement is PropertyAccessorMember) {
6294 executableElement = PropertyAccessorMember.from(
6295 executableElement as PropertyAccessorMember, superType);
6296 map.setValue(i, executableElement);
6297 }
6298 }
6299 }
6300
6301 /**
6302 * Union all of the [lookupMaps] together into a single map, grouping the Exec utableElements
6303 * into a list where none of the elements are equal where equality is determin ed by having equal
6304 * function types. (We also take note too of the kind of the element: ()->int and () -> int may
6305 * not be equal if one is a getter and the other is a method.)
6306 *
6307 * @param lookupMaps the maps to be unioned together.
6308 * @return the resulting union map.
6309 */
6310 HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps(
6311 List<MemberMap> lookupMaps) {
6312 HashMap<String, List<ExecutableElement>> unionMap =
6313 new HashMap<String, List<ExecutableElement>>();
6314 for (MemberMap lookupMap in lookupMaps) {
6315 int lookupMapSize = lookupMap.size;
6316 for (int i = 0; i < lookupMapSize; i++) {
6317 // Get the string key, if null, break.
6318 String key = lookupMap.getKey(i);
6319 if (key == null) {
6320 break;
6321 }
6322 // Get the list value out of the unionMap
6323 List<ExecutableElement> list = unionMap[key];
6324 // If we haven't created such a map for this key yet, do create it and
6325 // put the list entry into the unionMap.
6326 if (list == null) {
6327 list = new List<ExecutableElement>();
6328 unionMap[key] = list;
6329 }
6330 // Fetch the entry out of this lookupMap
6331 ExecutableElement newExecutableElementEntry = lookupMap.getValue(i);
6332 if (list.isEmpty) {
6333 // If the list is empty, just the new value
6334 list.add(newExecutableElementEntry);
6335 } else {
6336 // Otherwise, only add the newExecutableElementEntry if it isn't
6337 // already in the list, this covers situation where a class inherits
6338 // two methods (or two getters) that are identical.
6339 bool alreadyInList = false;
6340 bool isMethod1 = newExecutableElementEntry is MethodElement;
6341 for (ExecutableElement executableElementInList in list) {
6342 bool isMethod2 = executableElementInList is MethodElement;
6343 if (isMethod1 == isMethod2 &&
6344 executableElementInList.type ==
6345 newExecutableElementEntry.type) {
6346 alreadyInList = true;
6347 break;
6348 }
6349 }
6350 if (!alreadyInList) {
6351 list.add(newExecutableElementEntry);
6352 }
6353 }
6354 }
6355 }
6356 return unionMap;
6357 }
6358
6359 /**
6360 * Given some array of [ExecutableElement]s, this method creates a synthetic e lement as
6361 * described in 8.1.1:
6362 *
6363 * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional pa rameters of a
6364 * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote t he number of
6365 * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denot e the set of all
6366 * named parameters of the <i>m<sub>1</sub>, &hellip;, m<sub>k</sub></i>. Then let
6367 * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i>
6368 * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <= i <= k.</i>
6369 * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameter s of type
6370 * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, name d parameters
6371 * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
6372 *
6373 */
6374 static ExecutableElement _computeMergedExecutableElement(
6375 List<ExecutableElement> elementArrayToMerge) {
6376 int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
6377 int r = _getNumOfRequiredParameters(elementArrayToMerge[0]);
6378 Set<String> namedParametersList = new HashSet<String>();
6379 for (int i = 1; i < elementArrayToMerge.length; i++) {
6380 ExecutableElement element = elementArrayToMerge[i];
6381 int numOfPositionalParams = _getNumOfPositionalParameters(element);
6382 if (h < numOfPositionalParams) {
6383 h = numOfPositionalParams;
6384 }
6385 int numOfRequiredParams = _getNumOfRequiredParameters(element);
6386 if (r > numOfRequiredParams) {
6387 r = numOfRequiredParams;
6388 }
6389 namedParametersList.addAll(_getNamedParameterNames(element));
6390 }
6391 return _createSyntheticExecutableElement(elementArrayToMerge,
6392 elementArrayToMerge[0].displayName, r, h - r,
6393 new List.from(namedParametersList));
6394 }
6395
6396 /**
6397 * Used by [computeMergedExecutableElement] to actually create the
6398 * synthetic element.
6399 *
6400 * @param elementArrayToMerge the array used to create the synthetic element
6401 * @param name the name of the method, getter or setter
6402 * @param numOfRequiredParameters the number of required parameters
6403 * @param numOfPositionalParameters the number of positional parameters
6404 * @param namedParameters the list of [String]s that are the named parameters
6405 * @return the created synthetic element
6406 */
6407 static ExecutableElement _createSyntheticExecutableElement(
6408 List<ExecutableElement> elementArrayToMerge, String name,
6409 int numOfRequiredParameters, int numOfPositionalParameters,
6410 List<String> namedParameters) {
6411 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
6412 SimpleIdentifier nameIdentifier = new SimpleIdentifier(
6413 new sc.StringToken(sc.TokenType.IDENTIFIER, name, 0));
6414 ExecutableElementImpl executable;
6415 if (elementArrayToMerge[0] is MethodElement) {
6416 MultiplyInheritedMethodElementImpl unionedMethod =
6417 new MultiplyInheritedMethodElementImpl(nameIdentifier);
6418 unionedMethod.inheritedElements = elementArrayToMerge;
6419 executable = unionedMethod;
6420 } else {
6421 MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor =
6422 new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
6423 unionedPropertyAccessor.getter =
6424 (elementArrayToMerge[0] as PropertyAccessorElement).isGetter;
6425 unionedPropertyAccessor.setter =
6426 (elementArrayToMerge[0] as PropertyAccessorElement).isSetter;
6427 unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
6428 executable = unionedPropertyAccessor;
6429 }
6430 int numOfParameters = numOfRequiredParameters +
6431 numOfPositionalParameters +
6432 namedParameters.length;
6433 List<ParameterElement> parameters =
6434 new List<ParameterElement>(numOfParameters);
6435 int i = 0;
6436 for (int j = 0; j < numOfRequiredParameters; j++, i++) {
6437 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
6438 parameter.type = dynamicType;
6439 parameter.parameterKind = ParameterKind.REQUIRED;
6440 parameters[i] = parameter;
6441 }
6442 for (int k = 0; k < numOfPositionalParameters; k++, i++) {
6443 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
6444 parameter.type = dynamicType;
6445 parameter.parameterKind = ParameterKind.POSITIONAL;
6446 parameters[i] = parameter;
6447 }
6448 for (int m = 0; m < namedParameters.length; m++, i++) {
6449 ParameterElementImpl parameter =
6450 new ParameterElementImpl(namedParameters[m], 0);
6451 parameter.type = dynamicType;
6452 parameter.parameterKind = ParameterKind.NAMED;
6453 parameters[i] = parameter;
6454 }
6455 executable.returnType = dynamicType;
6456 executable.parameters = parameters;
6457 FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
6458 executable.type = methodType;
6459 return executable;
6460 }
6461
6462 /**
6463 * Given some [ExecutableElement], return the list of named parameters.
6464 */
6465 static List<String> _getNamedParameterNames(
6466 ExecutableElement executableElement) {
6467 List<String> namedParameterNames = new List<String>();
6468 List<ParameterElement> parameters = executableElement.parameters;
6469 for (int i = 0; i < parameters.length; i++) {
6470 ParameterElement parameterElement = parameters[i];
6471 if (parameterElement.parameterKind == ParameterKind.NAMED) {
6472 namedParameterNames.add(parameterElement.name);
6473 }
6474 }
6475 return namedParameterNames;
6476 }
6477
6478 /**
6479 * Given some [ExecutableElement] return the number of parameters of the speci fied kind.
6480 */
6481 static int _getNumOfParameters(
6482 ExecutableElement executableElement, ParameterKind parameterKind) {
6483 int parameterCount = 0;
6484 List<ParameterElement> parameters = executableElement.parameters;
6485 for (int i = 0; i < parameters.length; i++) {
6486 ParameterElement parameterElement = parameters[i];
6487 if (parameterElement.parameterKind == parameterKind) {
6488 parameterCount++;
6489 }
6490 }
6491 return parameterCount;
6492 }
6493
6494 /**
6495 * Given some [ExecutableElement] return the number of positional parameters.
6496 *
6497 * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSI TIONAL].
6498 */
6499 static int _getNumOfPositionalParameters(
6500 ExecutableElement executableElement) =>
6501 _getNumOfParameters(executableElement, ParameterKind.REQUIRED) +
6502 _getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
6503
6504 /**
6505 * Given some [ExecutableElement] return the number of required parameters.
6506 */
6507 static int _getNumOfRequiredParameters(ExecutableElement executableElement) =>
6508 _getNumOfParameters(executableElement, ParameterKind.REQUIRED);
6509
6510 /**
6511 * Given some [ExecutableElement] returns `true` if it is an abstract member o f a
6512 * class.
6513 *
6514 * @param executableElement some [ExecutableElement] to evaluate
6515 * @return `true` if the given element is an abstract member of a class
6516 */
6517 static bool _isAbstract(ExecutableElement executableElement) {
6518 if (executableElement is MethodElement) {
6519 return executableElement.isAbstract;
6520 } else if (executableElement is PropertyAccessorElement) {
6521 return executableElement.isAbstract;
6522 }
6523 return false;
6524 }
6525 }
6526
6527 /**
6528 * This enum holds one of four states of a field initialization state through a constructor
6529 * signature, not initialized, initialized in the field declaration, initialized in the field
6530 * formal, and finally, initialized in the initializers list.
6531 */
6532 class INIT_STATE extends Enum<INIT_STATE> {
6533 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0);
6534
6535 static const INIT_STATE INIT_IN_DECLARATION =
6536 const INIT_STATE('INIT_IN_DECLARATION', 1);
6537
6538 static const INIT_STATE INIT_IN_FIELD_FORMAL =
6539 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2);
6540
6541 static const INIT_STATE INIT_IN_INITIALIZERS =
6542 const INIT_STATE('INIT_IN_INITIALIZERS', 3);
6543
6544 static const List<INIT_STATE> values = const [
6545 NOT_INIT,
6546 INIT_IN_DECLARATION,
6547 INIT_IN_FIELD_FORMAL,
6548 INIT_IN_INITIALIZERS
6549 ];
6550
6551 const INIT_STATE(String name, int ordinal) : super(name, ordinal);
6552 }
6553
6554 /**
6555 * Instances of the class `LabelScope` represent a scope in which a single label is defined.
6556 */
6557 class LabelScope {
6558 /**
6559 * The label scope enclosing this label scope.
6560 */
6561 final LabelScope _outerScope;
6562
6563 /**
6564 * The label defined in this scope.
6565 */
6566 final String _label;
6567
6568 /**
6569 * The element to which the label resolves.
6570 */
6571 final LabelElement element;
6572
6573 /**
6574 * The AST node to which the label resolves.
6575 */
6576 final AstNode node;
6577
6578 /**
6579 * Initialize a newly created scope to represent the label [_label].
6580 * [_outerScope] is the scope enclosing the new label scope. [node] is the
6581 * AST node the label resolves to. [element] is the element the label
6582 * resolves to.
6583 */
6584 LabelScope(this._outerScope, this._label, this.node, this.element);
6585
6586 /**
6587 * Return the LabelScope which defines [targetLabel], or `null` if it is not
6588 * defined in this scope.
6589 */
6590 LabelScope lookup(String targetLabel) {
6591 if (_label == targetLabel) {
6592 return this;
6593 } else if (_outerScope != null) {
6594 return _outerScope.lookup(targetLabel);
6595 } else {
6596 return null;
6597 }
6598 }
6599 }
6600
6601 /**
6602 * Instances of the class `Library` represent the data about a single library du ring the
6603 * resolution of some (possibly different) library. They are not intended to be used except during
6604 * the resolution process.
6605 */
6606 class Library {
6607 /**
6608 * An empty list that can be used to initialize lists of libraries.
6609 */
6610 static const List<Library> _EMPTY_ARRAY = const <Library>[];
6611
6612 /**
6613 * The prefix of a URI using the dart-ext scheme to reference a native code li brary.
6614 */
6615 static String _DART_EXT_SCHEME = "dart-ext:";
6616
6617 /**
6618 * The analysis context in which this library is being analyzed.
6619 */
6620 final InternalAnalysisContext _analysisContext;
6621
6622 /**
6623 * The inheritance manager which is used for this member lookups in this libra ry.
6624 */
6625 InheritanceManager _inheritanceManager;
6626
6627 /**
6628 * The listener to which analysis errors will be reported.
6629 */
6630 final AnalysisErrorListener errorListener;
6631
6632 /**
6633 * The source specifying the defining compilation unit of this library.
6634 */
6635 final Source librarySource;
6636
6637 /**
6638 * The library element representing this library.
6639 */
6640 LibraryElementImpl _libraryElement;
6641
6642 /**
6643 * A list containing all of the libraries that are imported into this library.
6644 */
6645 List<Library> _importedLibraries = _EMPTY_ARRAY;
6646
6647 /**
6648 * A table mapping URI-based directive to the actual URI value.
6649 */
6650 HashMap<UriBasedDirective, String> _directiveUris =
6651 new HashMap<UriBasedDirective, String>();
6652
6653 /**
6654 * A flag indicating whether this library explicitly imports core.
6655 */
6656 bool explicitlyImportsCore = false;
6657
6658 /**
6659 * A list containing all of the libraries that are exported from this library.
6660 */
6661 List<Library> _exportedLibraries = _EMPTY_ARRAY;
6662
6663 /**
6664 * A table mapping the sources for the compilation units in this library to th eir corresponding
6665 * AST structures.
6666 */
6667 HashMap<Source, CompilationUnit> _astMap =
6668 new HashMap<Source, CompilationUnit>();
6669
6670 /**
6671 * The library scope used when resolving elements within this library's compil ation units.
6672 */
6673 LibraryScope _libraryScope;
6674
6675 /**
6676 * Initialize a newly created data holder that can maintain the data associate d with a library.
6677 *
6678 * @param analysisContext the analysis context in which this library is being analyzed
6679 * @param errorListener the listener to which analysis errors will be reported
6680 * @param librarySource the source specifying the defining compilation unit of this library
6681 */
6682 Library(this._analysisContext, this.errorListener, this.librarySource) {
6683 this._libraryElement =
6684 _analysisContext.getLibraryElement(librarySource) as LibraryElementImpl;
6685 }
6686
6687 /**
6688 * Return an array of the [CompilationUnit]s that make up the library. The fir st unit is
6689 * always the defining unit.
6690 *
6691 * @return an array of the [CompilationUnit]s that make up the library. The fi rst unit is
6692 * always the defining unit
6693 */
6694 List<CompilationUnit> get compilationUnits {
6695 List<CompilationUnit> unitArrayList = new List<CompilationUnit>();
6696 unitArrayList.add(definingCompilationUnit);
6697 for (Source source in _astMap.keys.toSet()) {
6698 if (librarySource != source) {
6699 unitArrayList.add(getAST(source));
6700 }
6701 }
6702 return unitArrayList;
6703 }
6704
6705 /**
6706 * Return a collection containing the sources for the compilation units in thi s library, including
6707 * the defining compilation unit.
6708 *
6709 * @return the sources for the compilation units in this library
6710 */
6711 Set<Source> get compilationUnitSources => _astMap.keys.toSet();
6712
6713 /**
6714 * Return the AST structure associated with the defining compilation unit for this library.
6715 *
6716 * @return the AST structure associated with the defining compilation unit for this library
6717 * @throws AnalysisException if an AST structure could not be created for the defining compilation
6718 * unit
6719 */
6720 CompilationUnit get definingCompilationUnit => getAST(librarySource);
6721
6722 /**
6723 * Set the libraries that are exported by this library to be those in the give n array.
6724 *
6725 * @param exportedLibraries the libraries that are exported by this library
6726 */
6727 void set exportedLibraries(List<Library> exportedLibraries) {
6728 this._exportedLibraries = exportedLibraries;
6729 }
6730
6731 /**
6732 * Return an array containing the libraries that are exported from this librar y.
6733 *
6734 * @return an array containing the libraries that are exported from this libra ry
6735 */
6736 List<Library> get exports => _exportedLibraries;
6737
6738 /**
6739 * Set the libraries that are imported into this library to be those in the gi ven array.
6740 *
6741 * @param importedLibraries the libraries that are imported into this library
6742 */
6743 void set importedLibraries(List<Library> importedLibraries) {
6744 this._importedLibraries = importedLibraries;
6745 }
6746
6747 /**
6748 * Return an array containing the libraries that are imported into this librar y.
6749 *
6750 * @return an array containing the libraries that are imported into this libra ry
6751 */
6752 List<Library> get imports => _importedLibraries;
6753
6754 /**
6755 * Return an array containing the libraries that are either imported or export ed from this
6756 * library.
6757 *
6758 * @return the libraries that are either imported or exported from this librar y
6759 */
6760 List<Library> get importsAndExports {
6761 HashSet<Library> libraries = new HashSet<Library>();
6762 for (Library library in _importedLibraries) {
6763 libraries.add(library);
6764 }
6765 for (Library library in _exportedLibraries) {
6766 libraries.add(library);
6767 }
6768 return new List.from(libraries);
6769 }
6770
6771 /**
6772 * Return the inheritance manager for this library.
6773 *
6774 * @return the inheritance manager for this library
6775 */
6776 InheritanceManager get inheritanceManager {
6777 if (_inheritanceManager == null) {
6778 return _inheritanceManager = new InheritanceManager(_libraryElement);
6779 }
6780 return _inheritanceManager;
6781 }
6782
6783 /**
6784 * Return the library element representing this library, creating it if necess ary.
6785 *
6786 * @return the library element representing this library
6787 */
6788 LibraryElementImpl get libraryElement {
6789 if (_libraryElement == null) {
6790 try {
6791 _libraryElement = _analysisContext
6792 .computeLibraryElement(librarySource) as LibraryElementImpl;
6793 } on AnalysisException catch (exception, stackTrace) {
6794 AnalysisEngine.instance.logger.logError(
6795 "Could not compute library element for ${librarySource.fullName}",
6796 new CaughtException(exception, stackTrace));
6797 }
6798 }
6799 return _libraryElement;
6800 }
6801
6802 /**
6803 * Set the library element representing this library to the given library elem ent.
6804 *
6805 * @param libraryElement the library element representing this library
6806 */
6807 void set libraryElement(LibraryElementImpl libraryElement) {
6808 this._libraryElement = libraryElement;
6809 if (_inheritanceManager != null) {
6810 _inheritanceManager.libraryElement = libraryElement;
6811 }
6812 }
6813
6814 /**
6815 * Return the library scope used when resolving elements within this library's compilation units.
6816 *
6817 * @return the library scope used when resolving elements within this library' s compilation units
6818 */
6819 LibraryScope get libraryScope {
6820 if (_libraryScope == null) {
6821 _libraryScope = new LibraryScope(_libraryElement, errorListener);
6822 }
6823 return _libraryScope;
6824 }
6825
6826 /**
6827 * Return the AST structure associated with the given source.
6828 *
6829 * @param source the source representing the compilation unit whose AST is to be returned
6830 * @return the AST structure associated with the given source
6831 * @throws AnalysisException if an AST structure could not be created for the compilation unit
6832 */
6833 CompilationUnit getAST(Source source) {
6834 CompilationUnit unit = _astMap[source];
6835 if (unit == null) {
6836 unit = _analysisContext.computeResolvableCompilationUnit(source);
6837 _astMap[source] = unit;
6838 }
6839 return unit;
6840 }
6841
6842 /**
6843 * Return the result of resolving the URI of the given URI-based directive aga inst the URI of the
6844 * library, or `null` if the URI is not valid. If the URI is not valid, report the error.
6845 *
6846 * @param directive the directive which URI should be resolved
6847 * @return the result of resolving the URI against the URI of the library
6848 */
6849 Source getSource(UriBasedDirective directive) {
6850 StringLiteral uriLiteral = directive.uri;
6851 if (uriLiteral is StringInterpolation) {
6852 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
6853 uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION));
6854 return null;
6855 }
6856 String uriContent = uriLiteral.stringValue.trim();
6857 _directiveUris[directive] = uriContent;
6858 uriContent = Uri.encodeFull(uriContent);
6859 if (directive is ImportDirective &&
6860 uriContent.startsWith(_DART_EXT_SCHEME)) {
6861 _libraryElement.hasExtUri = true;
6862 return null;
6863 }
6864 try {
6865 parseUriWithException(uriContent);
6866 Source source =
6867 _analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
6868 if (!_analysisContext.exists(source)) {
6869 errorListener.onError(new AnalysisError(librarySource,
6870 uriLiteral.offset, uriLiteral.length,
6871 CompileTimeErrorCode.URI_DOES_NOT_EXIST, [uriContent]));
6872 }
6873 return source;
6874 } on URISyntaxException {
6875 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
6876 uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent]));
6877 }
6878 return null;
6879 }
6880
6881 /**
6882 * Returns the URI value of the given directive.
6883 */
6884 String getUri(UriBasedDirective directive) => _directiveUris[directive];
6885
6886 /**
6887 * Set the AST structure associated with the defining compilation unit for thi s library to the
6888 * given AST structure.
6889 *
6890 * @param unit the AST structure associated with the defining compilation unit for this library
6891 */
6892 void setDefiningCompilationUnit(CompilationUnit unit) {
6893 _astMap[librarySource] = unit;
6894 }
6895
6896 @override
6897 String toString() => librarySource.shortName;
6898 }
6899
6900 /**
6901 * Instances of the class `LibraryElementBuilder` build an element model for a s ingle library.
6902 */
6903 class LibraryElementBuilder {
6904 /**
6905 * The analysis context in which the element model will be built.
6906 */
6907 final InternalAnalysisContext _analysisContext;
6908
6909 /**
6910 * The listener to which errors will be reported.
6911 */
6912 final AnalysisErrorListener _errorListener;
6913
6914 /**
6915 * Initialize a newly created library element builder.
6916 *
6917 * @param analysisContext the analysis context in which the element model will be built
6918 * @param errorListener the listener to which errors will be reported
6919 */
6920 LibraryElementBuilder(this._analysisContext, this._errorListener);
6921
6922 /**
6923 * Build the library element for the given library.
6924 *
6925 * @param library the library for which an element model is to be built
6926 * @return the library element that was built
6927 * @throws AnalysisException if the analysis could not be performed
6928 */
6929 LibraryElementImpl buildLibrary(Library library) {
6930 CompilationUnitBuilder builder = new CompilationUnitBuilder();
6931 Source librarySource = library.librarySource;
6932 CompilationUnit definingCompilationUnit = library.definingCompilationUnit;
6933 CompilationUnitElementImpl definingCompilationUnitElement = builder
6934 .buildCompilationUnit(
6935 librarySource, definingCompilationUnit, librarySource);
6936 NodeList<Directive> directives = definingCompilationUnit.directives;
6937 LibraryIdentifier libraryNameNode = null;
6938 bool hasPartDirective = false;
6939 FunctionElement entryPoint =
6940 _findEntryPoint(definingCompilationUnitElement);
6941 List<Directive> directivesToResolve = new List<Directive>();
6942 List<CompilationUnitElementImpl> sourcedCompilationUnits =
6943 new List<CompilationUnitElementImpl>();
6944 for (Directive directive in directives) {
6945 //
6946 // We do not build the elements representing the import and export
6947 // directives at this point. That is not done until we get to
6948 // LibraryResolver.buildDirectiveModels() because we need the
6949 // LibraryElements for the referenced libraries, which might not exist at
6950 // this point (due to the possibility of circular references).
6951 //
6952 if (directive is LibraryDirective) {
6953 if (libraryNameNode == null) {
6954 libraryNameNode = directive.name;
6955 directivesToResolve.add(directive);
6956 }
6957 } else if (directive is PartDirective) {
6958 PartDirective partDirective = directive;
6959 StringLiteral partUri = partDirective.uri;
6960 Source partSource = partDirective.source;
6961 if (_analysisContext.exists(partSource)) {
6962 hasPartDirective = true;
6963 CompilationUnit partUnit = library.getAST(partSource);
6964 CompilationUnitElementImpl part =
6965 builder.buildCompilationUnit(partSource, partUnit, librarySource);
6966 part.uriOffset = partUri.offset;
6967 part.uriEnd = partUri.end;
6968 part.uri = partDirective.uriContent;
6969 //
6970 // Validate that the part contains a part-of directive with the same
6971 // name as the library.
6972 //
6973 String partLibraryName =
6974 _getPartLibraryName(partSource, partUnit, directivesToResolve);
6975 if (partLibraryName == null) {
6976 _errorListener.onError(new AnalysisError(librarySource,
6977 partUri.offset, partUri.length,
6978 CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()]));
6979 } else if (libraryNameNode == null) {
6980 // TODO(brianwilkerson) Collect the names declared by the part.
6981 // If they are all the same then we can use that name as the
6982 // inferred name of the library and present it in a quick-fix.
6983 // partLibraryNames.add(partLibraryName);
6984 } else if (libraryNameNode.name != partLibraryName) {
6985 _errorListener.onError(new AnalysisError(librarySource,
6986 partUri.offset, partUri.length,
6987 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [
6988 libraryNameNode.name,
6989 partLibraryName
6990 ]));
6991 }
6992 if (entryPoint == null) {
6993 entryPoint = _findEntryPoint(part);
6994 }
6995 directive.element = part;
6996 sourcedCompilationUnits.add(part);
6997 }
6998 }
6999 }
7000 if (hasPartDirective && libraryNameNode == null) {
7001 _errorListener.onError(new AnalysisError(librarySource, 0, 0,
7002 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
7003 }
7004 //
7005 // Create and populate the library element.
7006 //
7007 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
7008 _analysisContext.getContextFor(librarySource), libraryNameNode);
7009 libraryElement.definingCompilationUnit = definingCompilationUnitElement;
7010 if (entryPoint != null) {
7011 libraryElement.entryPoint = entryPoint;
7012 }
7013 int sourcedUnitCount = sourcedCompilationUnits.length;
7014 libraryElement.parts = sourcedCompilationUnits;
7015 for (Directive directive in directivesToResolve) {
7016 directive.element = libraryElement;
7017 }
7018 library.libraryElement = libraryElement;
7019 if (sourcedUnitCount > 0) {
7020 _patchTopLevelAccessors(libraryElement);
7021 }
7022 return libraryElement;
7023 }
7024
7025 /**
7026 * Build the library element for the given library. The resulting element is
7027 * stored in the [ResolvableLibrary] structure.
7028 *
7029 * @param library the library for which an element model is to be built
7030 * @throws AnalysisException if the analysis could not be performed
7031 */
7032 void buildLibrary2(ResolvableLibrary library) {
7033 CompilationUnitBuilder builder = new CompilationUnitBuilder();
7034 Source librarySource = library.librarySource;
7035 CompilationUnit definingCompilationUnit = library.definingCompilationUnit;
7036 CompilationUnitElementImpl definingCompilationUnitElement = builder
7037 .buildCompilationUnit(
7038 librarySource, definingCompilationUnit, librarySource);
7039 NodeList<Directive> directives = definingCompilationUnit.directives;
7040 LibraryIdentifier libraryNameNode = null;
7041 bool hasPartDirective = false;
7042 FunctionElement entryPoint =
7043 _findEntryPoint(definingCompilationUnitElement);
7044 List<Directive> directivesToResolve = new List<Directive>();
7045 List<CompilationUnitElementImpl> sourcedCompilationUnits =
7046 new List<CompilationUnitElementImpl>();
7047 for (Directive directive in directives) {
7048 //
7049 // We do not build the elements representing the import and export
7050 // directives at this point. That is not done until we get to
7051 // LibraryResolver.buildDirectiveModels() because we need the
7052 // LibraryElements for the referenced libraries, which might not exist at
7053 // this point (due to the possibility of circular references).
7054 //
7055 if (directive is LibraryDirective) {
7056 if (libraryNameNode == null) {
7057 libraryNameNode = directive.name;
7058 directivesToResolve.add(directive);
7059 }
7060 } else if (directive is PartDirective) {
7061 PartDirective partDirective = directive;
7062 StringLiteral partUri = partDirective.uri;
7063 Source partSource = partDirective.source;
7064 if (_analysisContext.exists(partSource)) {
7065 hasPartDirective = true;
7066 CompilationUnit partUnit = library.getAST(partSource);
7067 if (partUnit != null) {
7068 CompilationUnitElementImpl part = builder.buildCompilationUnit(
7069 partSource, partUnit, librarySource);
7070 part.uriOffset = partUri.offset;
7071 part.uriEnd = partUri.end;
7072 part.uri = partDirective.uriContent;
7073 //
7074 // Validate that the part contains a part-of directive with the same
7075 // name as the library.
7076 //
7077 String partLibraryName =
7078 _getPartLibraryName(partSource, partUnit, directivesToResolve);
7079 if (partLibraryName == null) {
7080 _errorListener.onError(new AnalysisError(librarySource,
7081 partUri.offset, partUri.length,
7082 CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSource()]));
7083 } else if (libraryNameNode == null) {
7084 // TODO(brianwilkerson) Collect the names declared by the part.
7085 // If they are all the same then we can use that name as the
7086 // inferred name of the library and present it in a quick-fix.
7087 // partLibraryNames.add(partLibraryName);
7088 } else if (libraryNameNode.name != partLibraryName) {
7089 _errorListener.onError(new AnalysisError(librarySource,
7090 partUri.offset, partUri.length,
7091 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [
7092 libraryNameNode.name,
7093 partLibraryName
7094 ]));
7095 }
7096 if (entryPoint == null) {
7097 entryPoint = _findEntryPoint(part);
7098 }
7099 directive.element = part;
7100 sourcedCompilationUnits.add(part);
7101 }
7102 }
7103 }
7104 }
7105 if (hasPartDirective && libraryNameNode == null) {
7106 _errorListener.onError(new AnalysisError(librarySource, 0, 0,
7107 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
7108 }
7109 //
7110 // Create and populate the library element.
7111 //
7112 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
7113 _analysisContext.getContextFor(librarySource), libraryNameNode);
7114 libraryElement.definingCompilationUnit = definingCompilationUnitElement;
7115 if (entryPoint != null) {
7116 libraryElement.entryPoint = entryPoint;
7117 }
7118 int sourcedUnitCount = sourcedCompilationUnits.length;
7119 libraryElement.parts = sourcedCompilationUnits;
7120 for (Directive directive in directivesToResolve) {
7121 directive.element = libraryElement;
7122 }
7123 library.libraryElement = libraryElement;
7124 if (sourcedUnitCount > 0) {
7125 _patchTopLevelAccessors(libraryElement);
7126 }
7127 }
7128
7129 /**
7130 * Add all of the non-synthetic getters and setters defined in the given compi lation unit that
7131 * have no corresponding accessor to one of the given collections.
7132 *
7133 * @param getters the map to which getters are to be added
7134 * @param setters the list to which setters are to be added
7135 * @param unit the compilation unit defining the accessors that are potentiall y being added
7136 */
7137 void _collectAccessors(HashMap<String, PropertyAccessorElement> getters,
7138 List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
7139 for (PropertyAccessorElement accessor in unit.accessors) {
7140 if (accessor.isGetter) {
7141 if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
7142 getters[accessor.displayName] = accessor;
7143 }
7144 } else {
7145 if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
7146 setters.add(accessor);
7147 }
7148 }
7149 }
7150 }
7151
7152 /**
7153 * Search the top-level functions defined in the given compilation unit for th e entry point.
7154 *
7155 * @param element the compilation unit to be searched
7156 * @return the entry point that was found, or `null` if the compilation unit d oes not define
7157 * an entry point
7158 */
7159 FunctionElement _findEntryPoint(CompilationUnitElementImpl element) {
7160 for (FunctionElement function in element.functions) {
7161 if (function.isEntryPoint) {
7162 return function;
7163 }
7164 }
7165 return null;
7166 }
7167
7168 /**
7169 * Return the name of the library that the given part is declared to be a part of, or `null`
7170 * if the part does not contain a part-of directive.
7171 *
7172 * @param partSource the source representing the part
7173 * @param partUnit the AST structure of the part
7174 * @param directivesToResolve a list of directives that should be resolved to the library being
7175 * built
7176 * @return the name of the library that the given part is declared to be a par t of
7177 */
7178 String _getPartLibraryName(Source partSource, CompilationUnit partUnit,
7179 List<Directive> directivesToResolve) {
7180 for (Directive directive in partUnit.directives) {
7181 if (directive is PartOfDirective) {
7182 directivesToResolve.add(directive);
7183 LibraryIdentifier libraryName = directive.libraryName;
7184 if (libraryName != null) {
7185 return libraryName.name;
7186 }
7187 }
7188 }
7189 return null;
7190 }
7191
7192 /**
7193 * Look through all of the compilation units defined for the given library, lo oking for getters
7194 * and setters that are defined in different compilation units but that have t he same names. If
7195 * any are found, make sure that they have the same variable element.
7196 *
7197 * @param libraryElement the library defining the compilation units to be proc essed
7198 */
7199 void _patchTopLevelAccessors(LibraryElementImpl libraryElement) {
7200 HashMap<String, PropertyAccessorElement> getters =
7201 new HashMap<String, PropertyAccessorElement>();
7202 List<PropertyAccessorElement> setters = new List<PropertyAccessorElement>();
7203 _collectAccessors(getters, setters, libraryElement.definingCompilationUnit);
7204 for (CompilationUnitElement unit in libraryElement.parts) {
7205 _collectAccessors(getters, setters, unit);
7206 }
7207 for (PropertyAccessorElement setter in setters) {
7208 PropertyAccessorElement getter = getters[setter.displayName];
7209 if (getter != null) {
7210 PropertyInducingElementImpl variable =
7211 getter.variable as PropertyInducingElementImpl;
7212 variable.setter = setter;
7213 (setter as PropertyAccessorElementImpl).variable = variable;
7214 }
7215 }
7216 }
7217 }
7218
7219 /**
7220 * Instances of the class `LibraryImportScope` represent the scope containing al l of the names
7221 * available from imported libraries.
7222 */
7223 class LibraryImportScope extends Scope {
7224 /**
7225 * The element representing the library in which this scope is enclosed.
7226 */
7227 final LibraryElement _definingLibrary;
7228
7229 /**
7230 * The listener that is to be informed when an error is encountered.
7231 */
7232 final AnalysisErrorListener errorListener;
7233
7234 /**
7235 * A list of the namespaces representing the names that are available in this scope from imported
7236 * libraries.
7237 */
7238 List<Namespace> _importedNamespaces;
7239
7240 /**
7241 * Initialize a newly created scope representing the names imported into the g iven library.
7242 *
7243 * @param definingLibrary the element representing the library that imports th e names defined in
7244 * this scope
7245 * @param errorListener the listener that is to be informed when an error is e ncountered
7246 */
7247 LibraryImportScope(this._definingLibrary, this.errorListener) {
7248 _createImportedNamespaces();
7249 }
7250
7251 @override
7252 void define(Element element) {
7253 if (!Scope.isPrivateName(element.displayName)) {
7254 super.define(element);
7255 }
7256 }
7257
7258 @override
7259 Source getSource(AstNode node) {
7260 Source source = super.getSource(node);
7261 if (source == null) {
7262 source = _definingLibrary.definingCompilationUnit.source;
7263 }
7264 return source;
7265 }
7266
7267 @override
7268 Element internalLookup(
7269 Identifier identifier, String name, LibraryElement referencingLibrary) {
7270 Element foundElement = localLookup(name, referencingLibrary);
7271 if (foundElement != null) {
7272 return foundElement;
7273 }
7274 for (int i = 0; i < _importedNamespaces.length; i++) {
7275 Namespace nameSpace = _importedNamespaces[i];
7276 Element element = nameSpace.get(name);
7277 if (element != null) {
7278 if (foundElement == null) {
7279 foundElement = element;
7280 } else if (!identical(foundElement, element)) {
7281 foundElement = MultiplyDefinedElementImpl.fromElements(
7282 _definingLibrary.context, foundElement, element);
7283 }
7284 }
7285 }
7286 if (foundElement is MultiplyDefinedElementImpl) {
7287 foundElement = _removeSdkElements(
7288 identifier, name, foundElement as MultiplyDefinedElementImpl);
7289 }
7290 if (foundElement is MultiplyDefinedElementImpl) {
7291 String foundEltName = foundElement.displayName;
7292 List<Element> conflictingMembers = foundElement.conflictingElements;
7293 int count = conflictingMembers.length;
7294 List<String> libraryNames = new List<String>(count);
7295 for (int i = 0; i < count; i++) {
7296 libraryNames[i] = _getLibraryName(conflictingMembers[i]);
7297 }
7298 libraryNames.sort();
7299 errorListener.onError(new AnalysisError(getSource(identifier),
7300 identifier.offset, identifier.length,
7301 StaticWarningCode.AMBIGUOUS_IMPORT, [
7302 foundEltName,
7303 StringUtilities.printListOfQuotedNames(libraryNames)
7304 ]));
7305 return foundElement;
7306 }
7307 if (foundElement != null) {
7308 defineNameWithoutChecking(name, foundElement);
7309 }
7310 return foundElement;
7311 }
7312
7313 /**
7314 * Create all of the namespaces associated with the libraries imported into th is library. The
7315 * names are not added to this scope, but are stored for later reference.
7316 *
7317 * @param definingLibrary the element representing the library that imports th e libraries for
7318 * which namespaces will be created
7319 */
7320 void _createImportedNamespaces() {
7321 NamespaceBuilder builder = new NamespaceBuilder();
7322 List<ImportElement> imports = _definingLibrary.imports;
7323 int count = imports.length;
7324 _importedNamespaces = new List<Namespace>(count);
7325 for (int i = 0; i < count; i++) {
7326 _importedNamespaces[i] =
7327 builder.createImportNamespaceForDirective(imports[i]);
7328 }
7329 }
7330
7331 /**
7332 * Returns the name of the library that defines given element.
7333 *
7334 * @param element the element to get library name
7335 * @return the name of the library that defines given element
7336 */
7337 String _getLibraryName(Element element) {
7338 if (element == null) {
7339 return StringUtilities.EMPTY;
7340 }
7341 LibraryElement library = element.library;
7342 if (library == null) {
7343 return StringUtilities.EMPTY;
7344 }
7345 List<ImportElement> imports = _definingLibrary.imports;
7346 int count = imports.length;
7347 for (int i = 0; i < count; i++) {
7348 if (identical(imports[i].importedLibrary, library)) {
7349 return library.definingCompilationUnit.displayName;
7350 }
7351 }
7352 List<String> indirectSources = new List<String>();
7353 for (int i = 0; i < count; i++) {
7354 LibraryElement importedLibrary = imports[i].importedLibrary;
7355 if (importedLibrary != null) {
7356 for (LibraryElement exportedLibrary
7357 in importedLibrary.exportedLibraries) {
7358 if (identical(exportedLibrary, library)) {
7359 indirectSources
7360 .add(importedLibrary.definingCompilationUnit.displayName);
7361 }
7362 }
7363 }
7364 }
7365 int indirectCount = indirectSources.length;
7366 StringBuffer buffer = new StringBuffer();
7367 buffer.write(library.definingCompilationUnit.displayName);
7368 if (indirectCount > 0) {
7369 buffer.write(" (via ");
7370 if (indirectCount > 1) {
7371 indirectSources.sort();
7372 buffer.write(StringUtilities.printListOfQuotedNames(indirectSources));
7373 } else {
7374 buffer.write(indirectSources[0]);
7375 }
7376 buffer.write(")");
7377 }
7378 return buffer.toString();
7379 }
7380
7381 /**
7382 * Given a collection of elements (captured by the [foundElement]) that the
7383 * [identifier] (with the given [name]) resolved to, remove from the list all
7384 * of the names defined in the SDK and return the element(s) that remain.
7385 */
7386 Element _removeSdkElements(Identifier identifier, String name,
7387 MultiplyDefinedElementImpl foundElement) {
7388 List<Element> conflictingElements = foundElement.conflictingElements;
7389 List<Element> nonSdkElements = new List<Element>();
7390 Element sdkElement = null;
7391 for (Element member in conflictingElements) {
7392 if (member.library.isInSdk) {
7393 sdkElement = member;
7394 } else {
7395 nonSdkElements.add(member);
7396 }
7397 }
7398 if (sdkElement != null && nonSdkElements.length > 0) {
7399 String sdkLibName = _getLibraryName(sdkElement);
7400 String otherLibName = _getLibraryName(nonSdkElements[0]);
7401 errorListener.onError(new AnalysisError(getSource(identifier),
7402 identifier.offset, identifier.length,
7403 StaticWarningCode.CONFLICTING_DART_IMPORT, [
7404 name,
7405 sdkLibName,
7406 otherLibName
7407 ]));
7408 }
7409 if (nonSdkElements.length == conflictingElements.length) {
7410 // None of the members were removed
7411 return foundElement;
7412 } else if (nonSdkElements.length == 1) {
7413 // All but one member was removed
7414 return nonSdkElements[0];
7415 } else if (nonSdkElements.length == 0) {
7416 // All members were removed
7417 AnalysisEngine.instance.logger
7418 .logInformation("Multiply defined SDK element: $foundElement");
7419 return foundElement;
7420 }
7421 return new MultiplyDefinedElementImpl(
7422 _definingLibrary.context, nonSdkElements);
7423 }
7424 }
7425
7426 /**
7427 * Instances of the class `LibraryResolver` are used to resolve one or more mutu ally dependent
7428 * libraries within a single context.
7429 */
7430 class LibraryResolver {
7431 /**
7432 * The analysis context in which the libraries are being analyzed.
7433 */
7434 final InternalAnalysisContext analysisContext;
7435
7436 /**
7437 * The listener to which analysis errors will be reported, this error listener is either
7438 * references [recordingErrorListener], or it unions the passed
7439 * [AnalysisErrorListener] with the [recordingErrorListener].
7440 */
7441 RecordingErrorListener _errorListener;
7442
7443 /**
7444 * A source object representing the core library (dart:core).
7445 */
7446 Source _coreLibrarySource;
7447
7448 /**
7449 * A Source object representing the async library (dart:async).
7450 */
7451 Source _asyncLibrarySource;
7452
7453 /**
7454 * The object representing the core library.
7455 */
7456 Library _coreLibrary;
7457
7458 /**
7459 * The object representing the async library.
7460 */
7461 Library _asyncLibrary;
7462
7463 /**
7464 * The object used to access the types from the core library.
7465 */
7466 TypeProvider _typeProvider;
7467
7468 /**
7469 * A table mapping library sources to the information being maintained for tho se libraries.
7470 */
7471 HashMap<Source, Library> _libraryMap = new HashMap<Source, Library>();
7472
7473 /**
7474 * A collection containing the libraries that are being resolved together.
7475 */
7476 Set<Library> _librariesInCycles;
7477
7478 /**
7479 * Initialize a newly created library resolver to resolve libraries within the given context.
7480 *
7481 * @param analysisContext the analysis context in which the library is being a nalyzed
7482 */
7483 LibraryResolver(this.analysisContext) {
7484 this._errorListener = new RecordingErrorListener();
7485 _coreLibrarySource =
7486 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE);
7487 _asyncLibrarySource =
7488 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC);
7489 }
7490
7491 /**
7492 * Return the listener to which analysis errors will be reported.
7493 *
7494 * @return the listener to which analysis errors will be reported
7495 */
7496 RecordingErrorListener get errorListener => _errorListener;
7497
7498 /**
7499 * Return an array containing information about all of the libraries that were resolved.
7500 *
7501 * @return an array containing the libraries that were resolved
7502 */
7503 Set<Library> get resolvedLibraries => _librariesInCycles;
7504
7505 /**
7506 * The object used to access the types from the core library.
7507 */
7508 TypeProvider get typeProvider => _typeProvider;
7509
7510 /**
7511 * Create an object to represent the information about the library defined by the compilation unit
7512 * with the given source.
7513 *
7514 * @param librarySource the source of the library's defining compilation unit
7515 * @return the library object that was created
7516 * @throws AnalysisException if the library source is not valid
7517 */
7518 Library createLibrary(Source librarySource) {
7519 Library library =
7520 new Library(analysisContext, _errorListener, librarySource);
7521 _libraryMap[librarySource] = library;
7522 return library;
7523 }
7524
7525 /**
7526 * Resolve the library specified by the given source in the given context. The library is assumed
7527 * to be embedded in the given source.
7528 *
7529 * @param librarySource the source specifying the defining compilation unit of the library to be
7530 * resolved
7531 * @param unit the compilation unit representing the embedded library
7532 * @param fullAnalysis `true` if a full analysis should be performed
7533 * @return the element representing the resolved library
7534 * @throws AnalysisException if the library could not be resolved for some rea son
7535 */
7536 LibraryElement resolveEmbeddedLibrary(
7537 Source librarySource, CompilationUnit unit, bool fullAnalysis) {
7538 //
7539 // Create the objects representing the library being resolved and the core
7540 // library.
7541 //
7542 Library targetLibrary = _createLibraryWithUnit(librarySource, unit);
7543 _coreLibrary = _libraryMap[_coreLibrarySource];
7544 if (_coreLibrary == null) {
7545 // This will only happen if the library being analyzed is the core
7546 // library.
7547 _coreLibrary = createLibrary(_coreLibrarySource);
7548 if (_coreLibrary == null) {
7549 LibraryResolver2.missingCoreLibrary(
7550 analysisContext, _coreLibrarySource);
7551 }
7552 }
7553 _asyncLibrary = _libraryMap[_asyncLibrarySource];
7554 if (_asyncLibrary == null) {
7555 // This will only happen if the library being analyzed is the async
7556 // library.
7557 _asyncLibrary = createLibrary(_asyncLibrarySource);
7558 if (_asyncLibrary == null) {
7559 LibraryResolver2.missingAsyncLibrary(
7560 analysisContext, _asyncLibrarySource);
7561 }
7562 }
7563 //
7564 // Compute the set of libraries that need to be resolved together.
7565 //
7566 _computeEmbeddedLibraryDependencies(targetLibrary, unit);
7567 _librariesInCycles = _computeLibrariesInCycles(targetLibrary);
7568 //
7569 // Build the element models representing the libraries being resolved.
7570 // This is done in three steps:
7571 //
7572 // 1. Build the basic element models without making any connections
7573 // between elements other than the basic parent/child relationships.
7574 // This includes building the elements representing the libraries.
7575 // 2. Build the elements for the import and export directives. This
7576 // requires that we have the elements built for the referenced
7577 // libraries, but because of the possibility of circular references
7578 // needs to happen after all of the library elements have been created.
7579 // 3. Build the rest of the type model by connecting superclasses, mixins,
7580 // and interfaces. This requires that we be able to compute the names
7581 // visible in the libraries being resolved, which in turn requires that
7582 // we have resolved the import directives.
7583 //
7584 _buildElementModels();
7585 LibraryElement coreElement = _coreLibrary.libraryElement;
7586 if (coreElement == null) {
7587 throw new AnalysisException("Could not resolve dart:core");
7588 }
7589 LibraryElement asyncElement = _asyncLibrary.libraryElement;
7590 if (asyncElement == null) {
7591 throw new AnalysisException("Could not resolve dart:async");
7592 }
7593 _buildDirectiveModels();
7594 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
7595 _buildTypeHierarchies();
7596 //
7597 // Perform resolution and type analysis.
7598 //
7599 // TODO(brianwilkerson) Decide whether we want to resolve all of the
7600 // libraries or whether we want to only resolve the target library.
7601 // The advantage to resolving everything is that we have already done part
7602 // of the work so we'll avoid duplicated effort. The disadvantage of
7603 // resolving everything is that we might do extra work that we don't
7604 // really care about. Another possibility is to add a parameter to this
7605 // method and punt the decision to the clients.
7606 //
7607 //if (analyzeAll) {
7608 resolveReferencesAndTypes();
7609 //} else {
7610 // resolveReferencesAndTypes(targetLibrary);
7611 //}
7612 _performConstantEvaluation();
7613 return targetLibrary.libraryElement;
7614 }
7615
7616 /**
7617 * Resolve the library specified by the given source in the given context.
7618 *
7619 * Note that because Dart allows circular imports between libraries, it is pos sible that more than
7620 * one library will need to be resolved. In such cases the error listener can receive errors from
7621 * multiple libraries.
7622 *
7623 * @param librarySource the source specifying the defining compilation unit of the library to be
7624 * resolved
7625 * @param fullAnalysis `true` if a full analysis should be performed
7626 * @return the element representing the resolved library
7627 * @throws AnalysisException if the library could not be resolved for some rea son
7628 */
7629 LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) {
7630 //
7631 // Create the object representing the library being resolved and compute
7632 // the dependency relationship. Note that all libraries depend implicitly
7633 // on core, and we inject an ersatz dependency on async, so once this is
7634 // done the core and async library elements will have been created.
7635 //
7636 Library targetLibrary = createLibrary(librarySource);
7637 _computeLibraryDependencies(targetLibrary);
7638 _coreLibrary = _libraryMap[_coreLibrarySource];
7639 _asyncLibrary = _libraryMap[_asyncLibrarySource];
7640 //
7641 // Compute the set of libraries that need to be resolved together.
7642 //
7643 _librariesInCycles = _computeLibrariesInCycles(targetLibrary);
7644 //
7645 // Build the element models representing the libraries being resolved.
7646 // This is done in three steps:
7647 //
7648 // 1. Build the basic element models without making any connections
7649 // between elements other than the basic parent/child relationships.
7650 // This includes building the elements representing the libraries, but
7651 // excludes members defined in enums.
7652 // 2. Build the elements for the import and export directives. This
7653 // requires that we have the elements built for the referenced
7654 // libraries, but because of the possibility of circular references
7655 // needs to happen after all of the library elements have been created.
7656 // 3. Build the members in enum declarations.
7657 // 4. Build the rest of the type model by connecting superclasses, mixins,
7658 // and interfaces. This requires that we be able to compute the names
7659 // visible in the libraries being resolved, which in turn requires that
7660 // we have resolved the import directives.
7661 //
7662 _buildElementModels();
7663 LibraryElement coreElement = _coreLibrary.libraryElement;
7664 if (coreElement == null) {
7665 throw new AnalysisException("Could not resolve dart:core");
7666 }
7667 LibraryElement asyncElement = _asyncLibrary.libraryElement;
7668 if (asyncElement == null) {
7669 throw new AnalysisException("Could not resolve dart:async");
7670 }
7671 _buildDirectiveModels();
7672 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
7673 _buildEnumMembers();
7674 _buildTypeHierarchies();
7675 //
7676 // Perform resolution and type analysis.
7677 //
7678 // TODO(brianwilkerson) Decide whether we want to resolve all of the
7679 // libraries or whether we want to only resolve the target library. The
7680 // advantage to resolving everything is that we have already done part of
7681 // the work so we'll avoid duplicated effort. The disadvantage of
7682 // resolving everything is that we might do extra work that we don't
7683 // really care about. Another possibility is to add a parameter to this
7684 // method and punt the decision to the clients.
7685 //
7686 //if (analyzeAll) {
7687 resolveReferencesAndTypes();
7688 //} else {
7689 // resolveReferencesAndTypes(targetLibrary);
7690 //}
7691 _performConstantEvaluation();
7692 return targetLibrary.libraryElement;
7693 }
7694
7695 /**
7696 * Resolve the identifiers and perform type analysis in the libraries in the c urrent cycle.
7697 *
7698 * @throws AnalysisException if any of the identifiers could not be resolved o r if any of the
7699 * libraries could not have their types analyzed
7700 */
7701 void resolveReferencesAndTypes() {
7702 for (Library library in _librariesInCycles) {
7703 _resolveReferencesAndTypesInLibrary(library);
7704 }
7705 }
7706
7707 /**
7708 * Add a dependency to the given map from the referencing library to the refer enced library.
7709 *
7710 * @param dependencyMap the map to which the dependency is to be added
7711 * @param referencingLibrary the library that references the referenced librar y
7712 * @param referencedLibrary the library referenced by the referencing library
7713 */
7714 void _addDependencyToMap(HashMap<Library, List<Library>> dependencyMap,
7715 Library referencingLibrary, Library referencedLibrary) {
7716 List<Library> dependentLibraries = dependencyMap[referencedLibrary];
7717 if (dependentLibraries == null) {
7718 dependentLibraries = new List<Library>();
7719 dependencyMap[referencedLibrary] = dependentLibraries;
7720 }
7721 dependentLibraries.add(referencingLibrary);
7722 }
7723
7724 /**
7725 * Given a library that is part of a cycle that includes the root library, add to the given set of
7726 * libraries all of the libraries reachable from the root library that are als o included in the
7727 * cycle.
7728 *
7729 * @param library the library to be added to the collection of libraries in cy cles
7730 * @param librariesInCycle a collection of the libraries that are in the cycle
7731 * @param dependencyMap a table mapping libraries to the collection of librari es from which those
7732 * libraries are referenced
7733 */
7734 void _addLibrariesInCycle(Library library, Set<Library> librariesInCycle,
7735 HashMap<Library, List<Library>> dependencyMap) {
7736 if (librariesInCycle.add(library)) {
7737 List<Library> dependentLibraries = dependencyMap[library];
7738 if (dependentLibraries != null) {
7739 for (Library dependentLibrary in dependentLibraries) {
7740 _addLibrariesInCycle(
7741 dependentLibrary, librariesInCycle, dependencyMap);
7742 }
7743 }
7744 }
7745 }
7746
7747 /**
7748 * Add the given library, and all libraries reachable from it that have not al ready been visited,
7749 * to the given dependency map.
7750 *
7751 * @param library the library currently being added to the dependency map
7752 * @param dependencyMap the dependency map being computed
7753 * @param visitedLibraries the libraries that have already been visited, used to prevent infinite
7754 * recursion
7755 */
7756 void _addToDependencyMap(Library library,
7757 HashMap<Library, List<Library>> dependencyMap,
7758 Set<Library> visitedLibraries) {
7759 if (visitedLibraries.add(library)) {
7760 bool asyncFound = false;
7761 for (Library referencedLibrary in library.importsAndExports) {
7762 _addDependencyToMap(dependencyMap, library, referencedLibrary);
7763 _addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries);
7764 if (identical(referencedLibrary, _asyncLibrary)) {
7765 asyncFound = true;
7766 }
7767 }
7768 if (!library.explicitlyImportsCore && !identical(library, _coreLibrary)) {
7769 _addDependencyToMap(dependencyMap, library, _coreLibrary);
7770 }
7771 if (!asyncFound && !identical(library, _asyncLibrary)) {
7772 _addDependencyToMap(dependencyMap, library, _asyncLibrary);
7773 _addToDependencyMap(_asyncLibrary, dependencyMap, visitedLibraries);
7774 }
7775 }
7776 }
7777
7778 /**
7779 * Build the element model representing the combinators declared by the given directive.
7780 *
7781 * @param directive the directive that declares the combinators
7782 * @return an array containing the import combinators that were built
7783 */
7784 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) {
7785 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>();
7786 for (Combinator combinator in directive.combinators) {
7787 if (combinator is HideCombinator) {
7788 HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
7789 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames);
7790 combinators.add(hide);
7791 } else {
7792 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
7793 show.offset = combinator.offset;
7794 show.end = combinator.end;
7795 show.shownNames =
7796 _getIdentifiers((combinator as ShowCombinator).shownNames);
7797 combinators.add(show);
7798 }
7799 }
7800 return combinators;
7801 }
7802
7803 /**
7804 * Every library now has a corresponding [LibraryElement], so it is now possib le to resolve
7805 * the import and export directives.
7806 *
7807 * @throws AnalysisException if the defining compilation unit for any of the l ibraries could not
7808 * be accessed
7809 */
7810 void _buildDirectiveModels() {
7811 for (Library library in _librariesInCycles) {
7812 HashMap<String, PrefixElementImpl> nameToPrefixMap =
7813 new HashMap<String, PrefixElementImpl>();
7814 List<ImportElement> imports = new List<ImportElement>();
7815 List<ExportElement> exports = new List<ExportElement>();
7816 for (Directive directive in library.definingCompilationUnit.directives) {
7817 if (directive is ImportDirective) {
7818 ImportDirective importDirective = directive;
7819 String uriContent = importDirective.uriContent;
7820 if (DartUriResolver.isDartExtUri(uriContent)) {
7821 library.libraryElement.hasExtUri = true;
7822 }
7823 Source importedSource = importDirective.source;
7824 if (importedSource != null) {
7825 // The imported source will be null if the URI in the import
7826 // directive was invalid.
7827 Library importedLibrary = _libraryMap[importedSource];
7828 if (importedLibrary != null) {
7829 ImportElementImpl importElement =
7830 new ImportElementImpl(directive.offset);
7831 StringLiteral uriLiteral = importDirective.uri;
7832 importElement.uriOffset = uriLiteral.offset;
7833 importElement.uriEnd = uriLiteral.end;
7834 importElement.uri = uriContent;
7835 importElement.deferred = importDirective.deferredKeyword != null;
7836 importElement.combinators = _buildCombinators(importDirective);
7837 LibraryElement importedLibraryElement =
7838 importedLibrary.libraryElement;
7839 if (importedLibraryElement != null) {
7840 importElement.importedLibrary = importedLibraryElement;
7841 }
7842 SimpleIdentifier prefixNode = directive.prefix;
7843 if (prefixNode != null) {
7844 importElement.prefixOffset = prefixNode.offset;
7845 String prefixName = prefixNode.name;
7846 PrefixElementImpl prefix = nameToPrefixMap[prefixName];
7847 if (prefix == null) {
7848 prefix = new PrefixElementImpl.forNode(prefixNode);
7849 nameToPrefixMap[prefixName] = prefix;
7850 }
7851 importElement.prefix = prefix;
7852 prefixNode.staticElement = prefix;
7853 }
7854 directive.element = importElement;
7855 imports.add(importElement);
7856 if (analysisContext.computeKindOf(importedSource) !=
7857 SourceKind.LIBRARY) {
7858 ErrorCode errorCode = (importElement.isDeferred
7859 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
7860 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
7861 _errorListener.onError(new AnalysisError(library.librarySource,
7862 uriLiteral.offset, uriLiteral.length, errorCode,
7863 [uriLiteral.toSource()]));
7864 }
7865 }
7866 }
7867 } else if (directive is ExportDirective) {
7868 ExportDirective exportDirective = directive;
7869 Source exportedSource = exportDirective.source;
7870 if (exportedSource != null) {
7871 // The exported source will be null if the URI in the export
7872 // directive was invalid.
7873 Library exportedLibrary = _libraryMap[exportedSource];
7874 if (exportedLibrary != null) {
7875 ExportElementImpl exportElement =
7876 new ExportElementImpl(directive.offset);
7877 StringLiteral uriLiteral = exportDirective.uri;
7878 exportElement.uriOffset = uriLiteral.offset;
7879 exportElement.uriEnd = uriLiteral.end;
7880 exportElement.uri = exportDirective.uriContent;
7881 exportElement.combinators = _buildCombinators(exportDirective);
7882 LibraryElement exportedLibraryElement =
7883 exportedLibrary.libraryElement;
7884 if (exportedLibraryElement != null) {
7885 exportElement.exportedLibrary = exportedLibraryElement;
7886 }
7887 directive.element = exportElement;
7888 exports.add(exportElement);
7889 if (analysisContext.computeKindOf(exportedSource) !=
7890 SourceKind.LIBRARY) {
7891 _errorListener.onError(new AnalysisError(library.librarySource,
7892 uriLiteral.offset, uriLiteral.length,
7893 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
7894 [uriLiteral.toSource()]));
7895 }
7896 }
7897 }
7898 }
7899 }
7900 Source librarySource = library.librarySource;
7901 if (!library.explicitlyImportsCore &&
7902 _coreLibrarySource != librarySource) {
7903 ImportElementImpl importElement = new ImportElementImpl(-1);
7904 importElement.importedLibrary = _coreLibrary.libraryElement;
7905 importElement.synthetic = true;
7906 imports.add(importElement);
7907 }
7908 LibraryElementImpl libraryElement = library.libraryElement;
7909 libraryElement.imports = imports;
7910 libraryElement.exports = exports;
7911 if (libraryElement.entryPoint == null) {
7912 Namespace namespace = new NamespaceBuilder()
7913 .createExportNamespaceForLibrary(libraryElement);
7914 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME);
7915 if (element is FunctionElement) {
7916 libraryElement.entryPoint = element;
7917 }
7918 }
7919 }
7920 }
7921
7922 /**
7923 * Build element models for all of the libraries in the current cycle.
7924 *
7925 * @throws AnalysisException if any of the element models cannot be built
7926 */
7927 void _buildElementModels() {
7928 for (Library library in _librariesInCycles) {
7929 LibraryElementBuilder builder =
7930 new LibraryElementBuilder(analysisContext, errorListener);
7931 LibraryElementImpl libraryElement = builder.buildLibrary(library);
7932 library.libraryElement = libraryElement;
7933 }
7934 }
7935
7936 /**
7937 * Build the members in enum declarations. This cannot be done while building the rest of the
7938 * element model because it depends on being able to access core types, which cannot happen until
7939 * the rest of the element model has been built (when resolving the core libra ry).
7940 *
7941 * @throws AnalysisException if any of the enum members could not be built
7942 */
7943 void _buildEnumMembers() {
7944 PerformanceStatistics.resolve.makeCurrentWhile(() {
7945 for (Library library in _librariesInCycles) {
7946 for (Source source in library.compilationUnitSources) {
7947 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider);
7948 library.getAST(source).accept(builder);
7949 }
7950 }
7951 });
7952 }
7953
7954 /**
7955 * Resolve the type hierarchy across all of the types declared in the librarie s in the current
7956 * cycle.
7957 *
7958 * @throws AnalysisException if any of the type hierarchies could not be resol ved
7959 */
7960 void _buildTypeHierarchies() {
7961 PerformanceStatistics.resolve.makeCurrentWhile(() {
7962 for (Library library in _librariesInCycles) {
7963 for (Source source in library.compilationUnitSources) {
7964 TypeResolverVisitorFactory typeResolverVisitorFactory =
7965 analysisContext.typeResolverVisitorFactory;
7966 TypeResolverVisitor visitor = (typeResolverVisitorFactory == null)
7967 ? new TypeResolverVisitor(library.libraryElement, source,
7968 _typeProvider, library.errorListener,
7969 nameScope: library.libraryScope)
7970 : typeResolverVisitorFactory(library, source, _typeProvider);
7971 library.getAST(source).accept(visitor);
7972 }
7973 }
7974 });
7975 }
7976
7977 /**
7978 * Compute a dependency map of libraries reachable from the given library. A d ependency map is a
7979 * table that maps individual libraries to a list of the libraries that either import or export
7980 * those libraries.
7981 *
7982 * This map is used to compute all of the libraries involved in a cycle that i nclude the root
7983 * library. Given that we only add libraries that are reachable from the root library, when we
7984 * work backward we are guaranteed to only get libraries in the cycle.
7985 *
7986 * @param library the library currently being added to the dependency map
7987 */
7988 HashMap<Library, List<Library>> _computeDependencyMap(Library library) {
7989 HashMap<Library, List<Library>> dependencyMap =
7990 new HashMap<Library, List<Library>>();
7991 _addToDependencyMap(library, dependencyMap, new HashSet<Library>());
7992 return dependencyMap;
7993 }
7994
7995 /**
7996 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
7997 * class [Library] to represent them, and record the references in the library objects.
7998 *
7999 * @param library the library to be processed to find libraries that have not yet been traversed
8000 * @throws AnalysisException if some portion of the library graph could not be traversed
8001 */
8002 void _computeEmbeddedLibraryDependencies(
8003 Library library, CompilationUnit unit) {
8004 Source librarySource = library.librarySource;
8005 HashSet<Source> exportedSources = new HashSet<Source>();
8006 HashSet<Source> importedSources = new HashSet<Source>();
8007 for (Directive directive in unit.directives) {
8008 if (directive is ExportDirective) {
8009 Source exportSource = _resolveSource(librarySource, directive);
8010 if (exportSource != null) {
8011 exportedSources.add(exportSource);
8012 }
8013 } else if (directive is ImportDirective) {
8014 Source importSource = _resolveSource(librarySource, directive);
8015 if (importSource != null) {
8016 importedSources.add(importSource);
8017 }
8018 }
8019 }
8020 _computeLibraryDependenciesFromDirectives(library,
8021 new List.from(importedSources), new List.from(exportedSources));
8022 }
8023
8024 /**
8025 * Return a collection containing all of the libraries reachable from the give n library that are
8026 * contained in a cycle that includes the given library.
8027 *
8028 * @param library the library that must be included in any cycles whose member s are to be returned
8029 * @return all of the libraries referenced by the given library that have a ci rcular reference
8030 * back to the given library
8031 */
8032 Set<Library> _computeLibrariesInCycles(Library library) {
8033 HashMap<Library, List<Library>> dependencyMap =
8034 _computeDependencyMap(library);
8035 Set<Library> librariesInCycle = new HashSet<Library>();
8036 _addLibrariesInCycle(library, librariesInCycle, dependencyMap);
8037 return librariesInCycle;
8038 }
8039
8040 /**
8041 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8042 * class [Library] to represent them, and record the references in the library objects.
8043 *
8044 * @param library the library to be processed to find libraries that have not yet been traversed
8045 * @throws AnalysisException if some portion of the library graph could not be traversed
8046 */
8047 void _computeLibraryDependencies(Library library) {
8048 Source librarySource = library.librarySource;
8049 _computeLibraryDependenciesFromDirectives(library,
8050 analysisContext.computeImportedLibraries(librarySource),
8051 analysisContext.computeExportedLibraries(librarySource));
8052 }
8053
8054 /**
8055 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8056 * class [Library] to represent them, and record the references in the library objects.
8057 *
8058 * @param library the library to be processed to find libraries that have not yet been traversed
8059 * @param importedSources an array containing the sources that are imported in to the given library
8060 * @param exportedSources an array containing the sources that are exported fr om the given library
8061 * @throws AnalysisException if some portion of the library graph could not be traversed
8062 */
8063 void _computeLibraryDependenciesFromDirectives(Library library,
8064 List<Source> importedSources, List<Source> exportedSources) {
8065 List<Library> importedLibraries = new List<Library>();
8066 bool explicitlyImportsCore = false;
8067 bool importsAsync = false;
8068 for (Source importedSource in importedSources) {
8069 if (importedSource == _coreLibrarySource) {
8070 explicitlyImportsCore = true;
8071 }
8072 if (importedSource == _asyncLibrarySource) {
8073 importsAsync = true;
8074 }
8075 Library importedLibrary = _libraryMap[importedSource];
8076 if (importedLibrary == null) {
8077 importedLibrary = _createLibraryOrNull(importedSource);
8078 if (importedLibrary != null) {
8079 _computeLibraryDependencies(importedLibrary);
8080 }
8081 }
8082 if (importedLibrary != null) {
8083 importedLibraries.add(importedLibrary);
8084 }
8085 }
8086 library.importedLibraries = importedLibraries;
8087 List<Library> exportedLibraries = new List<Library>();
8088 for (Source exportedSource in exportedSources) {
8089 Library exportedLibrary = _libraryMap[exportedSource];
8090 if (exportedLibrary == null) {
8091 exportedLibrary = _createLibraryOrNull(exportedSource);
8092 if (exportedLibrary != null) {
8093 _computeLibraryDependencies(exportedLibrary);
8094 }
8095 }
8096 if (exportedLibrary != null) {
8097 exportedLibraries.add(exportedLibrary);
8098 }
8099 }
8100 library.exportedLibraries = exportedLibraries;
8101 library.explicitlyImportsCore = explicitlyImportsCore;
8102 if (!explicitlyImportsCore && _coreLibrarySource != library.librarySource) {
8103 Library importedLibrary = _libraryMap[_coreLibrarySource];
8104 if (importedLibrary == null) {
8105 importedLibrary = _createLibraryOrNull(_coreLibrarySource);
8106 if (importedLibrary != null) {
8107 _computeLibraryDependencies(importedLibrary);
8108 }
8109 }
8110 }
8111 if (!importsAsync && _asyncLibrarySource != library.librarySource) {
8112 Library importedLibrary = _libraryMap[_asyncLibrarySource];
8113 if (importedLibrary == null) {
8114 importedLibrary = _createLibraryOrNull(_asyncLibrarySource);
8115 if (importedLibrary != null) {
8116 _computeLibraryDependencies(importedLibrary);
8117 }
8118 }
8119 }
8120 }
8121
8122 /**
8123 * Create an object to represent the information about the library defined by the compilation unit
8124 * with the given source. Return the library object that was created, or `null ` if the
8125 * source is not valid.
8126 *
8127 * @param librarySource the source of the library's defining compilation unit
8128 * @return the library object that was created
8129 */
8130 Library _createLibraryOrNull(Source librarySource) {
8131 if (!analysisContext.exists(librarySource)) {
8132 return null;
8133 }
8134 Library library =
8135 new Library(analysisContext, _errorListener, librarySource);
8136 _libraryMap[librarySource] = library;
8137 return library;
8138 }
8139
8140 /**
8141 * Create an object to represent the information about the library defined by the compilation unit
8142 * with the given source.
8143 *
8144 * @param librarySource the source of the library's defining compilation unit
8145 * @param unit the compilation unit that defines the library
8146 * @return the library object that was created
8147 * @throws AnalysisException if the library source is not valid
8148 */
8149 Library _createLibraryWithUnit(Source librarySource, CompilationUnit unit) {
8150 Library library =
8151 new Library(analysisContext, _errorListener, librarySource);
8152 library.setDefiningCompilationUnit(unit);
8153 _libraryMap[librarySource] = library;
8154 return library;
8155 }
8156
8157 /**
8158 * Return an array containing the lexical identifiers associated with the node s in the given list.
8159 *
8160 * @param names the AST nodes representing the identifiers
8161 * @return the lexical identifiers associated with the nodes in the list
8162 */
8163 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) {
8164 int count = names.length;
8165 List<String> identifiers = new List<String>(count);
8166 for (int i = 0; i < count; i++) {
8167 identifiers[i] = names[i].name;
8168 }
8169 return identifiers;
8170 }
8171
8172 /**
8173 * Compute a value for all of the constants in the libraries being analyzed.
8174 */
8175 void _performConstantEvaluation() {
8176 PerformanceStatistics.resolve.makeCurrentWhile(() {
8177 ConstantValueComputer computer = new ConstantValueComputer(
8178 analysisContext, _typeProvider, analysisContext.declaredVariables);
8179 for (Library library in _librariesInCycles) {
8180 for (Source source in library.compilationUnitSources) {
8181 try {
8182 CompilationUnit unit = library.getAST(source);
8183 if (unit != null) {
8184 computer.add(unit, source, library.librarySource);
8185 }
8186 } on AnalysisException catch (exception, stackTrace) {
8187 AnalysisEngine.instance.logger.logError(
8188 "Internal Error: Could not access AST for ${source.fullName} dur ing constant evaluation",
8189 new CaughtException(exception, stackTrace));
8190 }
8191 }
8192 }
8193 computer.computeValues();
8194 // As a temporary workaround for issue 21572, run ConstantVerifier now.
8195 // TODO(paulberry): remove this workaround once issue 21572 is fixed.
8196 for (Library library in _librariesInCycles) {
8197 for (Source source in library.compilationUnitSources) {
8198 try {
8199 CompilationUnit unit = library.getAST(source);
8200 ErrorReporter errorReporter =
8201 new ErrorReporter(_errorListener, source);
8202 ConstantVerifier constantVerifier = new ConstantVerifier(
8203 errorReporter, library.libraryElement, _typeProvider,
8204 analysisContext.declaredVariables);
8205 unit.accept(constantVerifier);
8206 } on AnalysisException catch (exception, stackTrace) {
8207 AnalysisEngine.instance.logger.logError(
8208 "Internal Error: Could not access AST for ${source.fullName} "
8209 "during constant verification",
8210 new CaughtException(exception, stackTrace));
8211 }
8212 }
8213 }
8214 });
8215 }
8216
8217 /**
8218 * Resolve the identifiers and perform type analysis in the given library.
8219 *
8220 * @param library the library to be resolved
8221 * @throws AnalysisException if any of the identifiers could not be resolved o r if the types in
8222 * the library cannot be analyzed
8223 */
8224 void _resolveReferencesAndTypesInLibrary(Library library) {
8225 PerformanceStatistics.resolve.makeCurrentWhile(() {
8226 for (Source source in library.compilationUnitSources) {
8227 CompilationUnit ast = library.getAST(source);
8228 ast.accept(new VariableResolverVisitor(library.libraryElement, source,
8229 _typeProvider, library.errorListener,
8230 nameScope: library.libraryScope));
8231 ResolverVisitorFactory visitorFactory =
8232 analysisContext.resolverVisitorFactory;
8233 ResolverVisitor visitor = visitorFactory != null
8234 ? visitorFactory(library, source, _typeProvider)
8235 : new ResolverVisitor(library.libraryElement, source, _typeProvider,
8236 library.errorListener,
8237 nameScope: library.libraryScope,
8238 inheritanceManager: library.inheritanceManager);
8239 ast.accept(visitor);
8240 }
8241 });
8242 }
8243
8244 /**
8245 * Return the result of resolving the URI of the given URI-based directive aga inst the URI of the
8246 * given library, or `null` if the URI is not valid.
8247 *
8248 * @param librarySource the source representing the library containing the dir ective
8249 * @param directive the directive which URI should be resolved
8250 * @return the result of resolving the URI against the URI of the library
8251 */
8252 Source _resolveSource(Source librarySource, UriBasedDirective directive) {
8253 StringLiteral uriLiteral = directive.uri;
8254 if (uriLiteral is StringInterpolation) {
8255 return null;
8256 }
8257 String uriContent = uriLiteral.stringValue.trim();
8258 if (uriContent == null || uriContent.isEmpty) {
8259 return null;
8260 }
8261 uriContent = Uri.encodeFull(uriContent);
8262 return analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
8263 }
8264 }
8265
8266 /**
8267 * Instances of the class `LibraryResolver` are used to resolve one or more mutu ally dependent
8268 * libraries within a single context.
8269 */
8270 class LibraryResolver2 {
8271 /**
8272 * The analysis context in which the libraries are being analyzed.
8273 */
8274 final InternalAnalysisContext analysisContext;
8275
8276 /**
8277 * The listener to which analysis errors will be reported, this error listener is either
8278 * references [recordingErrorListener], or it unions the passed
8279 * [AnalysisErrorListener] with the [recordingErrorListener].
8280 */
8281 RecordingErrorListener _errorListener;
8282
8283 /**
8284 * A source object representing the core library (dart:core).
8285 */
8286 Source _coreLibrarySource;
8287
8288 /**
8289 * A source object representing the async library (dart:async).
8290 */
8291 Source _asyncLibrarySource;
8292
8293 /**
8294 * The object representing the core library.
8295 */
8296 ResolvableLibrary _coreLibrary;
8297
8298 /**
8299 * The object representing the async library.
8300 */
8301 ResolvableLibrary _asyncLibrary;
8302
8303 /**
8304 * The object used to access the types from the core library.
8305 */
8306 TypeProvider _typeProvider;
8307
8308 /**
8309 * A table mapping library sources to the information being maintained for tho se libraries.
8310 */
8311 HashMap<Source, ResolvableLibrary> _libraryMap =
8312 new HashMap<Source, ResolvableLibrary>();
8313
8314 /**
8315 * A collection containing the libraries that are being resolved together.
8316 */
8317 List<ResolvableLibrary> _librariesInCycle;
8318
8319 /**
8320 * Initialize a newly created library resolver to resolve libraries within the given context.
8321 *
8322 * @param analysisContext the analysis context in which the library is being a nalyzed
8323 */
8324 LibraryResolver2(this.analysisContext) {
8325 this._errorListener = new RecordingErrorListener();
8326 _coreLibrarySource =
8327 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE);
8328 _asyncLibrarySource =
8329 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC);
8330 }
8331
8332 /**
8333 * Return the listener to which analysis errors will be reported.
8334 *
8335 * @return the listener to which analysis errors will be reported
8336 */
8337 RecordingErrorListener get errorListener => _errorListener;
8338
8339 /**
8340 * Return an array containing information about all of the libraries that were resolved.
8341 *
8342 * @return an array containing the libraries that were resolved
8343 */
8344 List<ResolvableLibrary> get resolvedLibraries => _librariesInCycle;
8345
8346 /**
8347 * Resolve the library specified by the given source in the given context.
8348 *
8349 * Note that because Dart allows circular imports between libraries, it is pos sible that more than
8350 * one library will need to be resolved. In such cases the error listener can receive errors from
8351 * multiple libraries.
8352 *
8353 * @param librarySource the source specifying the defining compilation unit of the library to be
8354 * resolved
8355 * @param fullAnalysis `true` if a full analysis should be performed
8356 * @return the element representing the resolved library
8357 * @throws AnalysisException if the library could not be resolved for some rea son
8358 */
8359 LibraryElement resolveLibrary(
8360 Source librarySource, List<ResolvableLibrary> librariesInCycle) {
8361 //
8362 // Build the map of libraries that are known.
8363 //
8364 this._librariesInCycle = librariesInCycle;
8365 _libraryMap = _buildLibraryMap();
8366 ResolvableLibrary targetLibrary = _libraryMap[librarySource];
8367 _coreLibrary = _libraryMap[_coreLibrarySource];
8368 _asyncLibrary = _libraryMap[_asyncLibrarySource];
8369 //
8370 // Build the element models representing the libraries being resolved.
8371 // This is done in three steps:
8372 //
8373 // 1. Build the basic element models without making any connections
8374 // between elements other than the basic parent/child relationships.
8375 // This includes building the elements representing the libraries, but
8376 // excludes members defined in enums.
8377 // 2. Build the elements for the import and export directives. This
8378 // requires that we have the elements built for the referenced
8379 // libraries, but because of the possibility of circular references
8380 // needs to happen after all of the library elements have been created.
8381 // 3. Build the members in enum declarations.
8382 // 4. Build the rest of the type model by connecting superclasses, mixins,
8383 // and interfaces. This requires that we be able to compute the names
8384 // visible in the libraries being resolved, which in turn requires that
8385 // we have resolved the import directives.
8386 //
8387 _buildElementModels();
8388 LibraryElement coreElement = _coreLibrary.libraryElement;
8389 if (coreElement == null) {
8390 missingCoreLibrary(analysisContext, _coreLibrarySource);
8391 }
8392 LibraryElement asyncElement = _asyncLibrary.libraryElement;
8393 if (asyncElement == null) {
8394 missingAsyncLibrary(analysisContext, _asyncLibrarySource);
8395 }
8396 _buildDirectiveModels();
8397 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
8398 _buildEnumMembers();
8399 _buildTypeHierarchies();
8400 //
8401 // Perform resolution and type analysis.
8402 //
8403 // TODO(brianwilkerson) Decide whether we want to resolve all of the
8404 // libraries or whether we want to only resolve the target library. The
8405 // advantage to resolving everything is that we have already done part of
8406 // the work so we'll avoid duplicated effort. The disadvantage of
8407 // resolving everything is that we might do extra work that we don't
8408 // really care about. Another possibility is to add a parameter to this
8409 // method and punt the decision to the clients.
8410 //
8411 //if (analyzeAll) {
8412 _resolveReferencesAndTypes();
8413 //} else {
8414 // resolveReferencesAndTypes(targetLibrary);
8415 //}
8416 _performConstantEvaluation();
8417 return targetLibrary.libraryElement;
8418 }
8419
8420 /**
8421 * Build the element model representing the combinators declared by the given directive.
8422 *
8423 * @param directive the directive that declares the combinators
8424 * @return an array containing the import combinators that were built
8425 */
8426 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) {
8427 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>();
8428 for (Combinator combinator in directive.combinators) {
8429 if (combinator is HideCombinator) {
8430 HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
8431 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames);
8432 combinators.add(hide);
8433 } else {
8434 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
8435 show.offset = combinator.offset;
8436 show.end = combinator.end;
8437 show.shownNames =
8438 _getIdentifiers((combinator as ShowCombinator).shownNames);
8439 combinators.add(show);
8440 }
8441 }
8442 return combinators;
8443 }
8444
8445 /**
8446 * Every library now has a corresponding [LibraryElement], so it is now possib le to resolve
8447 * the import and export directives.
8448 *
8449 * @throws AnalysisException if the defining compilation unit for any of the l ibraries could not
8450 * be accessed
8451 */
8452 void _buildDirectiveModels() {
8453 for (ResolvableLibrary library in _librariesInCycle) {
8454 HashMap<String, PrefixElementImpl> nameToPrefixMap =
8455 new HashMap<String, PrefixElementImpl>();
8456 List<ImportElement> imports = new List<ImportElement>();
8457 List<ExportElement> exports = new List<ExportElement>();
8458 for (Directive directive in library.definingCompilationUnit.directives) {
8459 if (directive is ImportDirective) {
8460 ImportDirective importDirective = directive;
8461 String uriContent = importDirective.uriContent;
8462 if (DartUriResolver.isDartExtUri(uriContent)) {
8463 library.libraryElement.hasExtUri = true;
8464 }
8465 Source importedSource = importDirective.source;
8466 if (importedSource != null &&
8467 analysisContext.exists(importedSource)) {
8468 // The imported source will be null if the URI in the import
8469 // directive was invalid.
8470 ResolvableLibrary importedLibrary = _libraryMap[importedSource];
8471 if (importedLibrary != null) {
8472 ImportElementImpl importElement =
8473 new ImportElementImpl(directive.offset);
8474 StringLiteral uriLiteral = importDirective.uri;
8475 if (uriLiteral != null) {
8476 importElement.uriOffset = uriLiteral.offset;
8477 importElement.uriEnd = uriLiteral.end;
8478 }
8479 importElement.uri = uriContent;
8480 importElement.deferred = importDirective.deferredKeyword != null;
8481 importElement.combinators = _buildCombinators(importDirective);
8482 LibraryElement importedLibraryElement =
8483 importedLibrary.libraryElement;
8484 if (importedLibraryElement != null) {
8485 importElement.importedLibrary = importedLibraryElement;
8486 }
8487 SimpleIdentifier prefixNode = directive.prefix;
8488 if (prefixNode != null) {
8489 importElement.prefixOffset = prefixNode.offset;
8490 String prefixName = prefixNode.name;
8491 PrefixElementImpl prefix = nameToPrefixMap[prefixName];
8492 if (prefix == null) {
8493 prefix = new PrefixElementImpl.forNode(prefixNode);
8494 nameToPrefixMap[prefixName] = prefix;
8495 }
8496 importElement.prefix = prefix;
8497 prefixNode.staticElement = prefix;
8498 }
8499 directive.element = importElement;
8500 imports.add(importElement);
8501 if (analysisContext.computeKindOf(importedSource) !=
8502 SourceKind.LIBRARY) {
8503 ErrorCode errorCode = (importElement.isDeferred
8504 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
8505 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
8506 _errorListener.onError(new AnalysisError(library.librarySource,
8507 uriLiteral.offset, uriLiteral.length, errorCode,
8508 [uriLiteral.toSource()]));
8509 }
8510 }
8511 }
8512 } else if (directive is ExportDirective) {
8513 ExportDirective exportDirective = directive;
8514 Source exportedSource = exportDirective.source;
8515 if (exportedSource != null &&
8516 analysisContext.exists(exportedSource)) {
8517 // The exported source will be null if the URI in the export
8518 // directive was invalid.
8519 ResolvableLibrary exportedLibrary = _libraryMap[exportedSource];
8520 if (exportedLibrary != null) {
8521 ExportElementImpl exportElement =
8522 new ExportElementImpl(directive.offset);
8523 StringLiteral uriLiteral = exportDirective.uri;
8524 if (uriLiteral != null) {
8525 exportElement.uriOffset = uriLiteral.offset;
8526 exportElement.uriEnd = uriLiteral.end;
8527 }
8528 exportElement.uri = exportDirective.uriContent;
8529 exportElement.combinators = _buildCombinators(exportDirective);
8530 LibraryElement exportedLibraryElement =
8531 exportedLibrary.libraryElement;
8532 if (exportedLibraryElement != null) {
8533 exportElement.exportedLibrary = exportedLibraryElement;
8534 }
8535 directive.element = exportElement;
8536 exports.add(exportElement);
8537 if (analysisContext.computeKindOf(exportedSource) !=
8538 SourceKind.LIBRARY) {
8539 _errorListener.onError(new AnalysisError(library.librarySource,
8540 uriLiteral.offset, uriLiteral.length,
8541 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
8542 [uriLiteral.toSource()]));
8543 }
8544 }
8545 }
8546 }
8547 }
8548 Source librarySource = library.librarySource;
8549 if (!library.explicitlyImportsCore &&
8550 _coreLibrarySource != librarySource) {
8551 ImportElementImpl importElement = new ImportElementImpl(-1);
8552 importElement.importedLibrary = _coreLibrary.libraryElement;
8553 importElement.synthetic = true;
8554 imports.add(importElement);
8555 }
8556 LibraryElementImpl libraryElement = library.libraryElement;
8557 libraryElement.imports = imports;
8558 libraryElement.exports = exports;
8559 if (libraryElement.entryPoint == null) {
8560 Namespace namespace = new NamespaceBuilder()
8561 .createExportNamespaceForLibrary(libraryElement);
8562 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME);
8563 if (element is FunctionElement) {
8564 libraryElement.entryPoint = element;
8565 }
8566 }
8567 }
8568 }
8569
8570 /**
8571 * Build element models for all of the libraries in the current cycle.
8572 *
8573 * @throws AnalysisException if any of the element models cannot be built
8574 */
8575 void _buildElementModels() {
8576 for (ResolvableLibrary library in _librariesInCycle) {
8577 LibraryElementBuilder builder =
8578 new LibraryElementBuilder(analysisContext, errorListener);
8579 builder.buildLibrary2(library);
8580 }
8581 }
8582
8583 /**
8584 * Build the members in enum declarations. This cannot be done while building the rest of the
8585 * element model because it depends on being able to access core types, which cannot happen until
8586 * the rest of the element model has been built (when resolving the core libra ry).
8587 *
8588 * @throws AnalysisException if any of the enum members could not be built
8589 */
8590 void _buildEnumMembers() {
8591 PerformanceStatistics.resolve.makeCurrentWhile(() {
8592 for (ResolvableLibrary library in _librariesInCycle) {
8593 for (Source source in library.compilationUnitSources) {
8594 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider);
8595 library.getAST(source).accept(builder);
8596 }
8597 }
8598 });
8599 }
8600
8601 HashMap<Source, ResolvableLibrary> _buildLibraryMap() {
8602 HashMap<Source, ResolvableLibrary> libraryMap =
8603 new HashMap<Source, ResolvableLibrary>();
8604 int libraryCount = _librariesInCycle.length;
8605 for (int i = 0; i < libraryCount; i++) {
8606 ResolvableLibrary library = _librariesInCycle[i];
8607 library.errorListener = _errorListener;
8608 libraryMap[library.librarySource] = library;
8609 List<ResolvableLibrary> dependencies = library.importsAndExports;
8610 int dependencyCount = dependencies.length;
8611 for (int j = 0; j < dependencyCount; j++) {
8612 ResolvableLibrary dependency = dependencies[j];
8613 //dependency.setErrorListener(errorListener);
8614 libraryMap[dependency.librarySource] = dependency;
8615 }
8616 }
8617 return libraryMap;
8618 }
8619
8620 /**
8621 * Resolve the type hierarchy across all of the types declared in the librarie s in the current
8622 * cycle.
8623 *
8624 * @throws AnalysisException if any of the type hierarchies could not be resol ved
8625 */
8626 void _buildTypeHierarchies() {
8627 PerformanceStatistics.resolve.makeCurrentWhile(() {
8628 for (ResolvableLibrary library in _librariesInCycle) {
8629 for (ResolvableCompilationUnit unit
8630 in library.resolvableCompilationUnits) {
8631 Source source = unit.source;
8632 CompilationUnit ast = unit.compilationUnit;
8633 TypeResolverVisitor visitor = new TypeResolverVisitor(
8634 library.libraryElement, source, _typeProvider,
8635 library.libraryScope.errorListener,
8636 nameScope: library.libraryScope);
8637 ast.accept(visitor);
8638 }
8639 }
8640 });
8641 }
8642
8643 /**
8644 * Return an array containing the lexical identifiers associated with the node s in the given list.
8645 *
8646 * @param names the AST nodes representing the identifiers
8647 * @return the lexical identifiers associated with the nodes in the list
8648 */
8649 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) {
8650 int count = names.length;
8651 List<String> identifiers = new List<String>(count);
8652 for (int i = 0; i < count; i++) {
8653 identifiers[i] = names[i].name;
8654 }
8655 return identifiers;
8656 }
8657
8658 /**
8659 * Compute a value for all of the constants in the libraries being analyzed.
8660 */
8661 void _performConstantEvaluation() {
8662 PerformanceStatistics.resolve.makeCurrentWhile(() {
8663 ConstantValueComputer computer = new ConstantValueComputer(
8664 analysisContext, _typeProvider, analysisContext.declaredVariables);
8665 for (ResolvableLibrary library in _librariesInCycle) {
8666 for (ResolvableCompilationUnit unit
8667 in library.resolvableCompilationUnits) {
8668 CompilationUnit ast = unit.compilationUnit;
8669 if (ast != null) {
8670 computer.add(ast, unit.source, library.librarySource);
8671 }
8672 }
8673 }
8674 computer.computeValues();
8675 // As a temporary workaround for issue 21572, run ConstantVerifier now.
8676 // TODO(paulberry): remove this workaround once issue 21572 is fixed.
8677 for (ResolvableLibrary library in _librariesInCycle) {
8678 for (ResolvableCompilationUnit unit
8679 in library.resolvableCompilationUnits) {
8680 CompilationUnit ast = unit.compilationUnit;
8681 ErrorReporter errorReporter =
8682 new ErrorReporter(_errorListener, unit.source);
8683 ConstantVerifier constantVerifier = new ConstantVerifier(
8684 errorReporter, library.libraryElement, _typeProvider,
8685 analysisContext.declaredVariables);
8686 ast.accept(constantVerifier);
8687 }
8688 }
8689 });
8690 }
8691
8692 /**
8693 * Resolve the identifiers and perform type analysis in the libraries in the c urrent cycle.
8694 *
8695 * @throws AnalysisException if any of the identifiers could not be resolved o r if any of the
8696 * libraries could not have their types analyzed
8697 */
8698 void _resolveReferencesAndTypes() {
8699 for (ResolvableLibrary library in _librariesInCycle) {
8700 _resolveReferencesAndTypesInLibrary(library);
8701 }
8702 }
8703
8704 /**
8705 * Resolve the identifiers and perform type analysis in the given library.
8706 *
8707 * @param library the library to be resolved
8708 * @throws AnalysisException if any of the identifiers could not be resolved o r if the types in
8709 * the library cannot be analyzed
8710 */
8711 void _resolveReferencesAndTypesInLibrary(ResolvableLibrary library) {
8712 PerformanceStatistics.resolve.makeCurrentWhile(() {
8713 for (ResolvableCompilationUnit unit
8714 in library.resolvableCompilationUnits) {
8715 Source source = unit.source;
8716 CompilationUnit ast = unit.compilationUnit;
8717 ast.accept(new VariableResolverVisitor(library.libraryElement, source,
8718 _typeProvider, library.libraryScope.errorListener,
8719 nameScope: library.libraryScope));
8720 ResolverVisitor visitor = new ResolverVisitor(library.libraryElement,
8721 source, _typeProvider, library._libraryScope.errorListener,
8722 nameScope: library._libraryScope,
8723 inheritanceManager: library.inheritanceManager);
8724 ast.accept(visitor);
8725 }
8726 });
8727 }
8728
8729 /**
8730 * Report that the async library could not be resolved in the given
8731 * [analysisContext] and throw an exception. [asyncLibrarySource] is the sour ce
8732 * representing the async library.
8733 */
8734 static void missingAsyncLibrary(
8735 AnalysisContext analysisContext, Source asyncLibrarySource) {
8736 throw new AnalysisException("Could not resolve dart:async");
8737 }
8738
8739 /**
8740 * Report that the core library could not be resolved in the given analysis co ntext and throw an
8741 * exception.
8742 *
8743 * @param analysisContext the analysis context in which the failure occurred
8744 * @param coreLibrarySource the source representing the core library
8745 * @throws AnalysisException always
8746 */
8747 static void missingCoreLibrary(
8748 AnalysisContext analysisContext, Source coreLibrarySource) {
8749 throw new AnalysisException("Could not resolve dart:core");
8750 }
8751 }
8752
8753 /**
8754 * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
8755 */
8756 class LibraryResolver2_TypeAliasInfo {
8757 final ResolvableLibrary _library;
8758
8759 final Source _source;
8760
8761 final FunctionTypeAlias _typeAlias;
8762
8763 /**
8764 * Initialize a newly created information holder with the given information.
8765 *
8766 * @param library the library containing the type alias
8767 * @param source the source of the file containing the type alias
8768 * @param typeAlias the type alias being remembered
8769 */
8770 LibraryResolver2_TypeAliasInfo(this._library, this._source, this._typeAlias);
8771 }
8772
8773 /**
8774 * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
8775 */
8776 class LibraryResolver_TypeAliasInfo {
8777 final Library _library;
8778
8779 final Source _source;
8780
8781 final FunctionTypeAlias _typeAlias;
8782
8783 /**
8784 * Initialize a newly created information holder with the given information.
8785 *
8786 * @param library the library containing the type alias
8787 * @param source the source of the file containing the type alias
8788 * @param typeAlias the type alias being remembered
8789 */
8790 LibraryResolver_TypeAliasInfo(this._library, this._source, this._typeAlias);
8791 }
8792
8793 /**
8794 * Instances of the class `LibraryScope` implement a scope containing all of the names defined
8795 * in a given library.
8796 */
8797 class LibraryScope extends EnclosedScope {
8798 /**
8799 * Initialize a newly created scope representing the names defined in the give n library.
8800 *
8801 * @param definingLibrary the element representing the library represented by this scope
8802 * @param errorListener the listener that is to be informed when an error is e ncountered
8803 */
8804 LibraryScope(
8805 LibraryElement definingLibrary, AnalysisErrorListener errorListener)
8806 : super(new LibraryImportScope(definingLibrary, errorListener)) {
8807 _defineTopLevelNames(definingLibrary);
8808 }
8809
8810 @override
8811 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
8812 if (existing is PrefixElement) {
8813 // TODO(scheglov) consider providing actual 'nameOffset' from the
8814 // synthetic accessor
8815 int offset = duplicate.nameOffset;
8816 if (duplicate is PropertyAccessorElement) {
8817 PropertyAccessorElement accessor = duplicate;
8818 if (accessor.isSynthetic) {
8819 offset = accessor.variable.nameOffset;
8820 }
8821 }
8822 return new AnalysisError(duplicate.source, offset,
8823 duplicate.displayName.length,
8824 CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
8825 [existing.displayName]);
8826 }
8827 return super.getErrorForDuplicate(existing, duplicate);
8828 }
8829
8830 /**
8831 * Add to this scope all of the public top-level names that are defined in the given compilation
8832 * unit.
8833 *
8834 * @param compilationUnit the compilation unit defining the top-level names to be added to this
8835 * scope
8836 */
8837 void _defineLocalNames(CompilationUnitElement compilationUnit) {
8838 for (PropertyAccessorElement element in compilationUnit.accessors) {
8839 define(element);
8840 }
8841 for (ClassElement element in compilationUnit.enums) {
8842 define(element);
8843 }
8844 for (FunctionElement element in compilationUnit.functions) {
8845 define(element);
8846 }
8847 for (FunctionTypeAliasElement element
8848 in compilationUnit.functionTypeAliases) {
8849 define(element);
8850 }
8851 for (ClassElement element in compilationUnit.types) {
8852 define(element);
8853 }
8854 }
8855
8856 /**
8857 * Add to this scope all of the names that are explicitly defined in the given library.
8858 *
8859 * @param definingLibrary the element representing the library that defines th e names in this
8860 * scope
8861 */
8862 void _defineTopLevelNames(LibraryElement definingLibrary) {
8863 for (PrefixElement prefix in definingLibrary.prefixes) {
8864 define(prefix);
8865 }
8866 _defineLocalNames(definingLibrary.definingCompilationUnit);
8867 for (CompilationUnitElement compilationUnit in definingLibrary.parts) {
8868 _defineLocalNames(compilationUnit);
8869 }
8870 }
8871 }
8872
8873 /**
8874 * This class is used to replace uses of `HashMap<String, ExecutableElement>`
8875 * which are not as performant as this class.
8876 */
8877 class MemberMap {
8878 /**
8879 * The current size of this map.
8880 */
8881 int _size = 0;
8882
8883 /**
8884 * The array of keys.
8885 */
8886 List<String> _keys;
8887
8888 /**
8889 * The array of ExecutableElement values.
8890 */
8891 List<ExecutableElement> _values;
8892
8893 /**
8894 * Initialize a newly created member map to have the given [initialCapacity].
8895 * The map will grow if needed.
8896 */
8897 MemberMap([int initialCapacity = 10]) {
8898 _initArrays(initialCapacity);
8899 }
8900
8901 /**
8902 * This constructor takes an initial capacity of the map.
8903 *
8904 * @param initialCapacity the initial capacity
8905 */
8906 @deprecated // Use new MemberMap(initialCapacity)
8907 MemberMap.con1(int initialCapacity) {
8908 _initArrays(initialCapacity);
8909 }
8910
8911 /**
8912 * Copy constructor.
8913 */
8914 @deprecated // Use new MemberMap.from(memberMap)
8915 MemberMap.con2(MemberMap memberMap) {
8916 _initArrays(memberMap._size + 5);
8917 for (int i = 0; i < memberMap._size; i++) {
8918 _keys[i] = memberMap._keys[i];
8919 _values[i] = memberMap._values[i];
8920 }
8921 _size = memberMap._size;
8922 }
8923
8924 /**
8925 * Initialize a newly created member map to contain the same members as the
8926 * given [memberMap].
8927 */
8928 MemberMap.from(MemberMap memberMap) {
8929 _initArrays(memberMap._size + 5);
8930 for (int i = 0; i < memberMap._size; i++) {
8931 _keys[i] = memberMap._keys[i];
8932 _values[i] = memberMap._values[i];
8933 }
8934 _size = memberMap._size;
8935 }
8936
8937 /**
8938 * The size of the map.
8939 *
8940 * @return the size of the map.
8941 */
8942 int get size => _size;
8943
8944 /**
8945 * Given some key, return the ExecutableElement value from the map, if the key does not exist in
8946 * the map, `null` is returned.
8947 *
8948 * @param key some key to look up in the map
8949 * @return the associated ExecutableElement value from the map, if the key doe s not exist in the
8950 * map, `null` is returned
8951 */
8952 ExecutableElement get(String key) {
8953 for (int i = 0; i < _size; i++) {
8954 if (_keys[i] != null && _keys[i] == key) {
8955 return _values[i];
8956 }
8957 }
8958 return null;
8959 }
8960
8961 /**
8962 * Get and return the key at the specified location. If the key/value pair has been removed from
8963 * the set, then `null` is returned.
8964 *
8965 * @param i some non-zero value less than size
8966 * @return the key at the passed index
8967 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
8968 * zero or greater than or equal to the capacity of the arrays
8969 */
8970 String getKey(int i) => _keys[i];
8971
8972 /**
8973 * Get and return the ExecutableElement at the specified location. If the key/ value pair has been
8974 * removed from the set, then then `null` is returned.
8975 *
8976 * @param i some non-zero value less than size
8977 * @return the key at the passed index
8978 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
8979 * zero or greater than or equal to the capacity of the arrays
8980 */
8981 ExecutableElement getValue(int i) => _values[i];
8982
8983 /**
8984 * Given some key/value pair, store the pair in the map. If the key exists alr eady, then the new
8985 * value overrides the old value.
8986 *
8987 * @param key the key to store in the map
8988 * @param value the ExecutableElement value to store in the map
8989 */
8990 void put(String key, ExecutableElement value) {
8991 // If we already have a value with this key, override the value
8992 for (int i = 0; i < _size; i++) {
8993 if (_keys[i] != null && _keys[i] == key) {
8994 _values[i] = value;
8995 return;
8996 }
8997 }
8998 // If needed, double the size of our arrays and copy values over in both
8999 // arrays
9000 if (_size == _keys.length) {
9001 int newArrayLength = _size * 2;
9002 List<String> keys_new_array = new List<String>(newArrayLength);
9003 List<ExecutableElement> values_new_array =
9004 new List<ExecutableElement>(newArrayLength);
9005 for (int i = 0; i < _size; i++) {
9006 keys_new_array[i] = _keys[i];
9007 }
9008 for (int i = 0; i < _size; i++) {
9009 values_new_array[i] = _values[i];
9010 }
9011 _keys = keys_new_array;
9012 _values = values_new_array;
9013 }
9014 // Put new value at end of array
9015 _keys[_size] = key;
9016 _values[_size] = value;
9017 _size++;
9018 }
9019
9020 /**
9021 * Given some [String] key, this method replaces the associated key and value pair with
9022 * `null`. The size is not decremented with this call, instead it is expected that the users
9023 * check for `null`.
9024 *
9025 * @param key the key of the key/value pair to remove from the map
9026 */
9027 void remove(String key) {
9028 for (int i = 0; i < _size; i++) {
9029 if (_keys[i] == key) {
9030 _keys[i] = null;
9031 _values[i] = null;
9032 return;
9033 }
9034 }
9035 }
9036
9037 /**
9038 * Sets the ExecutableElement at the specified location.
9039 *
9040 * @param i some non-zero value less than size
9041 * @param value the ExecutableElement value to store in the map
9042 */
9043 void setValue(int i, ExecutableElement value) {
9044 _values[i] = value;
9045 }
9046
9047 /**
9048 * Initializes [keys] and [values].
9049 */
9050 void _initArrays(int initialCapacity) {
9051 _keys = new List<String>(initialCapacity);
9052 _values = new List<ExecutableElement>(initialCapacity);
9053 }
9054 }
9055
9056 /**
9057 * Instances of the class `Namespace` implement a mapping of identifiers to the elements
9058 * represented by those identifiers. Namespaces are the building blocks for scop es.
9059 */
9060 class Namespace {
9061 /**
9062 * An empty namespace.
9063 */
9064 static Namespace EMPTY = new Namespace(new HashMap<String, Element>());
9065
9066 /**
9067 * A table mapping names that are defined in this namespace to the element rep resenting the thing
9068 * declared with that name.
9069 */
9070 final HashMap<String, Element> _definedNames;
9071
9072 /**
9073 * Initialize a newly created namespace to have the given defined names.
9074 *
9075 * @param definedNames the mapping from names that are defined in this namespa ce to the
9076 * corresponding elements
9077 */
9078 Namespace(this._definedNames);
9079
9080 /**
9081 * Return a table containing the same mappings as those defined by this namesp ace.
9082 *
9083 * @return a table containing the same mappings as those defined by this names pace
9084 */
9085 Map<String, Element> get definedNames =>
9086 new HashMap<String, Element>.from(_definedNames);
9087
9088 /**
9089 * Return the element in this namespace that is available to the containing sc ope using the given
9090 * name.
9091 *
9092 * @param name the name used to reference the
9093 * @return the element represented by the given identifier
9094 */
9095 Element get(String name) => _definedNames[name];
9096 }
9097
9098 /**
9099 * Instances of the class `NamespaceBuilder` are used to build a `Namespace`. Na mespace
9100 * builders are thread-safe and re-usable.
9101 */
9102 class NamespaceBuilder {
9103 /**
9104 * Create a namespace representing the export namespace of the given [ExportEl ement].
9105 *
9106 * @param element the export element whose export namespace is to be created
9107 * @return the export namespace that was created
9108 */
9109 Namespace createExportNamespaceForDirective(ExportElement element) {
9110 LibraryElement exportedLibrary = element.exportedLibrary;
9111 if (exportedLibrary == null) {
9112 //
9113 // The exported library will be null if the URI does not reference a valid
9114 // library.
9115 //
9116 return Namespace.EMPTY;
9117 }
9118 HashMap<String, Element> definedNames =
9119 _createExportMapping(exportedLibrary, new HashSet<LibraryElement>());
9120 definedNames = _applyCombinators(definedNames, element.combinators);
9121 return new Namespace(definedNames);
9122 }
9123
9124 /**
9125 * Create a namespace representing the export namespace of the given library.
9126 *
9127 * @param library the library whose export namespace is to be created
9128 * @return the export namespace that was created
9129 */
9130 Namespace createExportNamespaceForLibrary(LibraryElement library) =>
9131 new Namespace(
9132 _createExportMapping(library, new HashSet<LibraryElement>()));
9133
9134 /**
9135 * Create a namespace representing the import namespace of the given library.
9136 *
9137 * @param library the library whose import namespace is to be created
9138 * @return the import namespace that was created
9139 */
9140 Namespace createImportNamespaceForDirective(ImportElement element) {
9141 LibraryElement importedLibrary = element.importedLibrary;
9142 if (importedLibrary == null) {
9143 //
9144 // The imported library will be null if the URI does not reference a valid
9145 // library.
9146 //
9147 return Namespace.EMPTY;
9148 }
9149 HashMap<String, Element> definedNames =
9150 _createExportMapping(importedLibrary, new HashSet<LibraryElement>());
9151 definedNames = _applyCombinators(definedNames, element.combinators);
9152 definedNames = _applyPrefix(definedNames, element.prefix);
9153 return new Namespace(definedNames);
9154 }
9155
9156 /**
9157 * Create a namespace representing the public namespace of the given library.
9158 *
9159 * @param library the library whose public namespace is to be created
9160 * @return the public namespace that was created
9161 */
9162 Namespace createPublicNamespaceForLibrary(LibraryElement library) {
9163 HashMap<String, Element> definedNames = new HashMap<String, Element>();
9164 _addPublicNames(definedNames, library.definingCompilationUnit);
9165 for (CompilationUnitElement compilationUnit in library.parts) {
9166 _addPublicNames(definedNames, compilationUnit);
9167 }
9168 return new Namespace(definedNames);
9169 }
9170
9171 /**
9172 * Add all of the names in the given namespace to the given mapping table.
9173 *
9174 * @param definedNames the mapping table to which the names in the given names pace are to be added
9175 * @param namespace the namespace containing the names to be added to this nam espace
9176 */
9177 void _addAllFromNamespace(
9178 Map<String, Element> definedNames, Namespace namespace) {
9179 if (namespace != null) {
9180 definedNames.addAll(namespace.definedNames);
9181 }
9182 }
9183
9184 /**
9185 * Add the given element to the given mapping table if it has a publicly visib le name.
9186 *
9187 * @param definedNames the mapping table to which the public name is to be add ed
9188 * @param element the element to be added
9189 */
9190 void _addIfPublic(Map<String, Element> definedNames, Element element) {
9191 String name = element.name;
9192 if (name != null && !Scope.isPrivateName(name)) {
9193 definedNames[name] = element;
9194 }
9195 }
9196
9197 /**
9198 * Add to the given mapping table all of the public top-level names that are d efined in the given
9199 * compilation unit.
9200 *
9201 * @param definedNames the mapping table to which the public names are to be a dded
9202 * @param compilationUnit the compilation unit defining the top-level names to be added to this
9203 * namespace
9204 */
9205 void _addPublicNames(Map<String, Element> definedNames,
9206 CompilationUnitElement compilationUnit) {
9207 for (PropertyAccessorElement element in compilationUnit.accessors) {
9208 _addIfPublic(definedNames, element);
9209 }
9210 for (ClassElement element in compilationUnit.enums) {
9211 _addIfPublic(definedNames, element);
9212 }
9213 for (FunctionElement element in compilationUnit.functions) {
9214 _addIfPublic(definedNames, element);
9215 }
9216 for (FunctionTypeAliasElement element
9217 in compilationUnit.functionTypeAliases) {
9218 _addIfPublic(definedNames, element);
9219 }
9220 for (ClassElement element in compilationUnit.types) {
9221 _addIfPublic(definedNames, element);
9222 }
9223 }
9224
9225 /**
9226 * Apply the given combinators to all of the names in the given mapping table.
9227 *
9228 * @param definedNames the mapping table to which the namespace operations are to be applied
9229 * @param combinators the combinators to be applied
9230 */
9231 HashMap<String, Element> _applyCombinators(
9232 HashMap<String, Element> definedNames,
9233 List<NamespaceCombinator> combinators) {
9234 for (NamespaceCombinator combinator in combinators) {
9235 if (combinator is HideElementCombinator) {
9236 _hide(definedNames, combinator.hiddenNames);
9237 } else if (combinator is ShowElementCombinator) {
9238 definedNames = _show(definedNames, combinator.shownNames);
9239 } else {
9240 // Internal error.
9241 AnalysisEngine.instance.logger
9242 .logError("Unknown type of combinator: ${combinator.runtimeType}");
9243 }
9244 }
9245 return definedNames;
9246 }
9247
9248 /**
9249 * Apply the given prefix to all of the names in the table of defined names.
9250 *
9251 * @param definedNames the names that were defined before this operation
9252 * @param prefixElement the element defining the prefix to be added to the nam es
9253 */
9254 HashMap<String, Element> _applyPrefix(
9255 HashMap<String, Element> definedNames, PrefixElement prefixElement) {
9256 if (prefixElement != null) {
9257 String prefix = prefixElement.name;
9258 HashMap<String, Element> newNames = new HashMap<String, Element>();
9259 definedNames.forEach((String name, Element element) {
9260 newNames["$prefix.$name"] = element;
9261 });
9262 return newNames;
9263 } else {
9264 return definedNames;
9265 }
9266 }
9267
9268 /**
9269 * Create a mapping table representing the export namespace of the given libra ry.
9270 *
9271 * @param library the library whose public namespace is to be created
9272 * @param visitedElements a set of libraries that do not need to be visited wh en processing the
9273 * export directives of the given library because all of the names de fined by them will
9274 * be added by another library
9275 * @return the mapping table that was created
9276 */
9277 HashMap<String, Element> _createExportMapping(
9278 LibraryElement library, HashSet<LibraryElement> visitedElements) {
9279 // Check if the export namespace has been already computed.
9280 {
9281 Namespace exportNamespace = library.exportNamespace;
9282 if (exportNamespace != null) {
9283 return exportNamespace.definedNames;
9284 }
9285 }
9286 // TODO(scheglov) Remove this after switching to the new task model.
9287 visitedElements.add(library);
9288 try {
9289 HashMap<String, Element> definedNames = new HashMap<String, Element>();
9290 for (ExportElement element in library.exports) {
9291 LibraryElement exportedLibrary = element.exportedLibrary;
9292 if (exportedLibrary != null &&
9293 !visitedElements.contains(exportedLibrary)) {
9294 //
9295 // The exported library will be null if the URI does not reference a
9296 // valid library.
9297 //
9298 HashMap<String, Element> exportedNames =
9299 _createExportMapping(exportedLibrary, visitedElements);
9300 exportedNames = _applyCombinators(exportedNames, element.combinators);
9301 definedNames.addAll(exportedNames);
9302 }
9303 }
9304 _addAllFromNamespace(definedNames,
9305 (library.context as InternalAnalysisContext)
9306 .getPublicNamespace(library));
9307 return definedNames;
9308 } finally {
9309 visitedElements.remove(library);
9310 }
9311 }
9312
9313 /**
9314 * Hide all of the given names by removing them from the given collection of d efined names.
9315 *
9316 * @param definedNames the names that were defined before this operation
9317 * @param hiddenNames the names to be hidden
9318 */
9319 void _hide(HashMap<String, Element> definedNames, List<String> hiddenNames) {
9320 for (String name in hiddenNames) {
9321 definedNames.remove(name);
9322 definedNames.remove("$name=");
9323 }
9324 }
9325
9326 /**
9327 * Show only the given names by removing all other names from the given collec tion of defined
9328 * names.
9329 *
9330 * @param definedNames the names that were defined before this operation
9331 * @param shownNames the names to be shown
9332 */
9333 HashMap<String, Element> _show(
9334 HashMap<String, Element> definedNames, List<String> shownNames) {
9335 HashMap<String, Element> newNames = new HashMap<String, Element>();
9336 for (String name in shownNames) {
9337 Element element = definedNames[name];
9338 if (element != null) {
9339 newNames[name] = element;
9340 }
9341 String setterName = "$name=";
9342 element = definedNames[setterName];
9343 if (element != null) {
9344 newNames[setterName] = element;
9345 }
9346 }
9347 return newNames;
9348 }
9349 }
9350
9351 /**
9352 * Instances of the class `OverrideVerifier` visit all of the declarations in a compilation
9353 * unit to verify that if they have an override annotation it is being used corr ectly.
9354 */
9355 class OverrideVerifier extends RecursiveAstVisitor<Object> {
9356 /**
9357 * The error reporter used to report errors.
9358 */
9359 final ErrorReporter _errorReporter;
9360
9361 /**
9362 * The inheritance manager used to find overridden methods.
9363 */
9364 final InheritanceManager _manager;
9365
9366 /**
9367 * Initialize a newly created verifier to look for inappropriate uses of the o verride annotation.
9368 *
9369 * @param errorReporter the error reporter used to report errors
9370 * @param manager the inheritance manager used to find overridden methods
9371 */
9372 OverrideVerifier(this._errorReporter, this._manager);
9373
9374 @override
9375 Object visitMethodDeclaration(MethodDeclaration node) {
9376 ExecutableElement element = node.element;
9377 if (_isOverride(element)) {
9378 if (_getOverriddenMember(element) == null) {
9379 if (element is MethodElement) {
9380 _errorReporter.reportErrorForNode(
9381 HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name);
9382 } else if (element is PropertyAccessorElement) {
9383 if (element.isGetter) {
9384 _errorReporter.reportErrorForNode(
9385 HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER, node.name);
9386 } else {
9387 _errorReporter.reportErrorForNode(
9388 HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER, node.name);
9389 }
9390 }
9391 }
9392 }
9393 return super.visitMethodDeclaration(node);
9394 }
9395
9396 /**
9397 * Return the member that overrides the given member.
9398 *
9399 * @param member the member that overrides the returned member
9400 * @return the member that overrides the given member
9401 */
9402 ExecutableElement _getOverriddenMember(ExecutableElement member) {
9403 LibraryElement library = member.library;
9404 if (library == null) {
9405 return null;
9406 }
9407 ClassElement classElement =
9408 member.getAncestor((element) => element is ClassElement);
9409 if (classElement == null) {
9410 return null;
9411 }
9412 return _manager.lookupInheritance(classElement, member.name);
9413 }
9414
9415 /**
9416 * Return `true` if the given element has an override annotation associated wi th it.
9417 *
9418 * @param element the element being tested
9419 * @return `true` if the element has an override annotation associated with it
9420 */
9421 bool _isOverride(Element element) => element != null && element.isOverride;
9422 }
9423
9424 /**
9425 * Instances of the class `PubVerifier` traverse an AST structure looking for de viations from
9426 * pub best practices.
9427 */
9428 class PubVerifier extends RecursiveAstVisitor<Object> {
9429 // static String _PUBSPEC_YAML = "pubspec.yaml";
9430
9431 /**
9432 * The analysis context containing the sources to be analyzed
9433 */
9434 final AnalysisContext _context;
9435
9436 /**
9437 * The error reporter by which errors will be reported.
9438 */
9439 final ErrorReporter _errorReporter;
9440
9441 PubVerifier(this._context, this._errorReporter);
9442
9443 @override
9444 Object visitImportDirective(ImportDirective directive) {
9445 return null;
9446 }
9447
9448 // /**
9449 // * This verifies that the passed file import directive is not contained in a source inside a
9450 // * package "lib" directory hierarchy referencing a source outside that packa ge "lib" directory
9451 // * hierarchy.
9452 // *
9453 // * @param uriLiteral the import URL (not `null`)
9454 // * @param path the file path being verified (not `null`)
9455 // * @return `true` if and only if an error code is generated on the passed no de
9456 // * See [PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE].
9457 // */
9458 // bool
9459 // _checkForFileImportInsideLibReferencesFileOutside(StringLiteral uriLiter al,
9460 // String path) {
9461 // Source source = _getSource(uriLiteral);
9462 // String fullName = _getSourceFullName(source);
9463 // if (fullName != null) {
9464 // int pathIndex = 0;
9465 // int fullNameIndex = fullName.length;
9466 // while (pathIndex < path.length &&
9467 // StringUtilities.startsWith3(path, pathIndex, 0x2E, 0x2E, 0x2F)) {
9468 // fullNameIndex = JavaString.lastIndexOf(fullName, '/', fullNameIndex);
9469 // if (fullNameIndex < 4) {
9470 // return false;
9471 // }
9472 // // Check for "/lib" at a specified place in the fullName
9473 // if (StringUtilities.startsWith4(
9474 // fullName,
9475 // fullNameIndex - 4,
9476 // 0x2F,
9477 // 0x6C,
9478 // 0x69,
9479 // 0x62)) {
9480 // String relativePubspecPath =
9481 // path.substring(0, pathIndex + 3) +
9482 // _PUBSPEC_YAML;
9483 // Source pubspecSource =
9484 // _context.sourceFactory.resolveUri(source, relativePubspecPath);
9485 // if (_context.exists(pubspecSource)) {
9486 // // Files inside the lib directory hierarchy should not reference
9487 // // files outside
9488 // _errorReporter.reportErrorForNode(
9489 // HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE,
9490 // uriLiteral);
9491 // }
9492 // return true;
9493 // }
9494 // pathIndex += 3;
9495 // }
9496 // }
9497 // return false;
9498 // }
9499
9500 // /**
9501 // * This verifies that the passed file import directive is not contained in a source outside a
9502 // * package "lib" directory hierarchy referencing a source inside that packag e "lib" directory
9503 // * hierarchy.
9504 // *
9505 // * @param uriLiteral the import URL (not `null`)
9506 // * @param path the file path being verified (not `null`)
9507 // * @return `true` if and only if an error code is generated on the passed no de
9508 // * See [PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE].
9509 // */
9510 // bool
9511 // _checkForFileImportOutsideLibReferencesFileInside(StringLiteral uriLiter al,
9512 // String path) {
9513 // if (StringUtilities.startsWith4(path, 0, 0x6C, 0x69, 0x62, 0x2F)) {
9514 // if (_checkForFileImportOutsideLibReferencesFileInsideAtIndex(
9515 // uriLiteral,
9516 // path,
9517 // 0)) {
9518 // return true;
9519 // }
9520 // }
9521 // int pathIndex =
9522 // StringUtilities.indexOf5(path, 0, 0x2F, 0x6C, 0x69, 0x62, 0x2F);
9523 // while (pathIndex != -1) {
9524 // if (_checkForFileImportOutsideLibReferencesFileInsideAtIndex(
9525 // uriLiteral,
9526 // path,
9527 // pathIndex + 1)) {
9528 // return true;
9529 // }
9530 // pathIndex =
9531 // StringUtilities.indexOf5(path, pathIndex + 4, 0x2F, 0x6C, 0x69, 0x62 , 0x2F);
9532 // }
9533 // return false;
9534 // }
9535
9536 // bool
9537 // _checkForFileImportOutsideLibReferencesFileInsideAtIndex(StringLiteral u riLiteral,
9538 // String path, int pathIndex) {
9539 // Source source = _getSource(uriLiteral);
9540 // String relativePubspecPath = path.substring(0, pathIndex) + _PUBSPEC_YAML;
9541 // Source pubspecSource =
9542 // _context.sourceFactory.resolveUri(source, relativePubspecPath);
9543 // if (!_context.exists(pubspecSource)) {
9544 // return false;
9545 // }
9546 // String fullName = _getSourceFullName(source);
9547 // if (fullName != null) {
9548 // if (StringUtilities.indexOf5(fullName, 0, 0x2F, 0x6C, 0x69, 0x62, 0x2F) <
9549 // 0) {
9550 // // Files outside the lib directory hierarchy should not reference file s
9551 // // inside ... use package: url instead
9552 // _errorReporter.reportErrorForNode(
9553 // HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE,
9554 // uriLiteral);
9555 // return true;
9556 // }
9557 // }
9558 // return false;
9559 // }
9560
9561 // /**
9562 // * This verifies that the passed package import directive does not contain " .."
9563 // *
9564 // * @param uriLiteral the import URL (not `null`)
9565 // * @param path the path to be validated (not `null`)
9566 // * @return `true` if and only if an error code is generated on the passed no de
9567 // * See [PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT].
9568 // */
9569 // bool _checkForPackageImportContainsDotDot(StringLiteral uriLiteral,
9570 // String path) {
9571 // if (StringUtilities.startsWith3(path, 0, 0x2E, 0x2E, 0x2F) ||
9572 // StringUtilities.indexOf4(path, 0, 0x2F, 0x2E, 0x2E, 0x2F) >= 0) {
9573 // // Package import should not to contain ".."
9574 // _errorReporter.reportErrorForNode(
9575 // HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
9576 // uriLiteral);
9577 // return true;
9578 // }
9579 // return false;
9580 // }
9581
9582 // /**
9583 // * Answer the source associated with the compilation unit containing the giv en AST node.
9584 // *
9585 // * @param node the node (not `null`)
9586 // * @return the source or `null` if it could not be determined
9587 // */
9588 // Source _getSource(AstNode node) {
9589 // Source source = null;
9590 // CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit) ;
9591 // if (unit != null) {
9592 // CompilationUnitElement element = unit.element;
9593 // if (element != null) {
9594 // source = element.source;
9595 // }
9596 // }
9597 // return source;
9598 // }
9599
9600 // /**
9601 // * Answer the full name of the given source. The returned value will have al l
9602 // * [File.separatorChar] replace by '/'.
9603 // *
9604 // * @param source the source
9605 // * @return the full name or `null` if it could not be determined
9606 // */
9607 // String _getSourceFullName(Source source) {
9608 // if (source != null) {
9609 // String fullName = source.fullName;
9610 // if (fullName != null) {
9611 // return fullName.replaceAll(r'\', '/');
9612 // }
9613 // }
9614 // return null;
9615 // }
9616 }
9617
9618 /**
9619 * Kind of the redirecting constructor.
9620 */
9621 class RedirectingConstructorKind extends Enum<RedirectingConstructorKind> {
9622 static const RedirectingConstructorKind CONST =
9623 const RedirectingConstructorKind('CONST', 0);
9624
9625 static const RedirectingConstructorKind NORMAL =
9626 const RedirectingConstructorKind('NORMAL', 1);
9627
9628 static const List<RedirectingConstructorKind> values = const [CONST, NORMAL];
9629
9630 const RedirectingConstructorKind(String name, int ordinal)
9631 : super(name, ordinal);
9632 }
9633
9634 /**
9635 * A `ResolvableLibrary` represents a single library during the resolution of
9636 * some (possibly different) library. They are not intended to be used except
9637 * during the resolution process.
9638 */
9639 class ResolvableLibrary {
9640 /**
9641 * An empty array that can be used to initialize lists of libraries.
9642 */
9643 static List<ResolvableLibrary> _EMPTY_ARRAY = new List<ResolvableLibrary>(0);
9644
9645 /**
9646 * The next artificial hash code.
9647 */
9648 static int _NEXT_HASH_CODE = 0;
9649
9650 /**
9651 * The artifitial hash code for this object.
9652 */
9653 final int _hashCode = _nextHashCode();
9654
9655 /**
9656 * The source specifying the defining compilation unit of this library.
9657 */
9658 final Source librarySource;
9659
9660 /**
9661 * A list containing all of the libraries that are imported into this library.
9662 */
9663 List<ResolvableLibrary> _importedLibraries = _EMPTY_ARRAY;
9664
9665 /**
9666 * A flag indicating whether this library explicitly imports core.
9667 */
9668 bool explicitlyImportsCore = false;
9669
9670 /**
9671 * An array containing all of the libraries that are exported from this librar y.
9672 */
9673 List<ResolvableLibrary> _exportedLibraries = _EMPTY_ARRAY;
9674
9675 /**
9676 * An array containing the compilation units that comprise this library. The
9677 * defining compilation unit is always first.
9678 */
9679 List<ResolvableCompilationUnit> _compilationUnits;
9680
9681 /**
9682 * The library element representing this library.
9683 */
9684 LibraryElementImpl _libraryElement;
9685
9686 /**
9687 * The listener to which analysis errors will be reported.
9688 */
9689 AnalysisErrorListener _errorListener;
9690
9691 /**
9692 * The inheritance manager which is used for member lookups in this library.
9693 */
9694 InheritanceManager _inheritanceManager;
9695
9696 /**
9697 * The library scope used when resolving elements within this library's compil ation units.
9698 */
9699 LibraryScope _libraryScope;
9700
9701 /**
9702 * Initialize a newly created data holder that can maintain the data associate d with a library.
9703 *
9704 * @param librarySource the source specifying the defining compilation unit of this library
9705 * @param errorListener the listener to which analysis errors will be reported
9706 */
9707 ResolvableLibrary(this.librarySource);
9708
9709 /**
9710 * Return an array of the [CompilationUnit]s that make up the library. The fir st unit is
9711 * always the defining unit.
9712 *
9713 * @return an array of the [CompilationUnit]s that make up the library. The fi rst unit is
9714 * always the defining unit
9715 */
9716 List<CompilationUnit> get compilationUnits {
9717 int count = _compilationUnits.length;
9718 List<CompilationUnit> units = new List<CompilationUnit>(count);
9719 for (int i = 0; i < count; i++) {
9720 units[i] = _compilationUnits[i].compilationUnit;
9721 }
9722 return units;
9723 }
9724
9725 /**
9726 * Return an array containing the sources for the compilation units in this li brary, including the
9727 * defining compilation unit.
9728 *
9729 * @return the sources for the compilation units in this library
9730 */
9731 List<Source> get compilationUnitSources {
9732 int count = _compilationUnits.length;
9733 List<Source> sources = new List<Source>(count);
9734 for (int i = 0; i < count; i++) {
9735 sources[i] = _compilationUnits[i].source;
9736 }
9737 return sources;
9738 }
9739
9740 /**
9741 * Return the AST structure associated with the defining compilation unit for this library.
9742 *
9743 * @return the AST structure associated with the defining compilation unit for this library
9744 * @throws AnalysisException if an AST structure could not be created for the defining compilation
9745 * unit
9746 */
9747 CompilationUnit get definingCompilationUnit =>
9748 _compilationUnits[0].compilationUnit;
9749
9750 /**
9751 * Set the listener to which analysis errors will be reported to be the given listener.
9752 *
9753 * @param errorListener the listener to which analysis errors will be reported
9754 */
9755 void set errorListener(AnalysisErrorListener errorListener) {
9756 this._errorListener = errorListener;
9757 }
9758
9759 /**
9760 * Set the libraries that are exported by this library to be those in the give n array.
9761 *
9762 * @param exportedLibraries the libraries that are exported by this library
9763 */
9764 void set exportedLibraries(List<ResolvableLibrary> exportedLibraries) {
9765 this._exportedLibraries = exportedLibraries;
9766 }
9767
9768 /**
9769 * Return an array containing the libraries that are exported from this librar y.
9770 *
9771 * @return an array containing the libraries that are exported from this libra ry
9772 */
9773 List<ResolvableLibrary> get exports => _exportedLibraries;
9774
9775 @override
9776 int get hashCode => _hashCode;
9777
9778 /**
9779 * Set the libraries that are imported into this library to be those in the gi ven array.
9780 *
9781 * @param importedLibraries the libraries that are imported into this library
9782 */
9783 void set importedLibraries(List<ResolvableLibrary> importedLibraries) {
9784 this._importedLibraries = importedLibraries;
9785 }
9786
9787 /**
9788 * Return an array containing the libraries that are imported into this librar y.
9789 *
9790 * @return an array containing the libraries that are imported into this libra ry
9791 */
9792 List<ResolvableLibrary> get imports => _importedLibraries;
9793
9794 /**
9795 * Return an array containing the libraries that are either imported or export ed from this
9796 * library.
9797 *
9798 * @return the libraries that are either imported or exported from this librar y
9799 */
9800 List<ResolvableLibrary> get importsAndExports {
9801 HashSet<ResolvableLibrary> libraries = new HashSet<ResolvableLibrary>();
9802 for (ResolvableLibrary library in _importedLibraries) {
9803 libraries.add(library);
9804 }
9805 for (ResolvableLibrary library in _exportedLibraries) {
9806 libraries.add(library);
9807 }
9808 return new List.from(libraries);
9809 }
9810
9811 /**
9812 * Return the inheritance manager for this library.
9813 *
9814 * @return the inheritance manager for this library
9815 */
9816 InheritanceManager get inheritanceManager {
9817 if (_inheritanceManager == null) {
9818 return _inheritanceManager = new InheritanceManager(_libraryElement);
9819 }
9820 return _inheritanceManager;
9821 }
9822
9823 /**
9824 * Return the library element representing this library, creating it if necess ary.
9825 *
9826 * @return the library element representing this library
9827 */
9828 LibraryElementImpl get libraryElement => _libraryElement;
9829
9830 /**
9831 * Set the library element representing this library to the given library elem ent.
9832 *
9833 * @param libraryElement the library element representing this library
9834 */
9835 void set libraryElement(LibraryElementImpl libraryElement) {
9836 this._libraryElement = libraryElement;
9837 if (_inheritanceManager != null) {
9838 _inheritanceManager.libraryElement = libraryElement;
9839 }
9840 }
9841
9842 /**
9843 * Return the library scope used when resolving elements within this library's compilation units.
9844 *
9845 * @return the library scope used when resolving elements within this library' s compilation units
9846 */
9847 LibraryScope get libraryScope {
9848 if (_libraryScope == null) {
9849 _libraryScope = new LibraryScope(_libraryElement, _errorListener);
9850 }
9851 return _libraryScope;
9852 }
9853
9854 /**
9855 * Return an array containing the compilation units that comprise this library . The defining
9856 * compilation unit is always first.
9857 *
9858 * @return the compilation units that comprise this library
9859 */
9860 List<ResolvableCompilationUnit> get resolvableCompilationUnits =>
9861 _compilationUnits;
9862
9863 /**
9864 * Set the compilation unit in this library to the given compilation units. Th e defining
9865 * compilation unit must be the first element of the array.
9866 *
9867 * @param units the compilation units in this library
9868 */
9869 void set resolvableCompilationUnits(List<ResolvableCompilationUnit> units) {
9870 _compilationUnits = units;
9871 }
9872
9873 /**
9874 * Return the AST structure associated with the given source, or `null` if the source does
9875 * not represent a compilation unit that is included in this library.
9876 *
9877 * @param source the source representing the compilation unit whose AST is to be returned
9878 * @return the AST structure associated with the given source
9879 * @throws AnalysisException if an AST structure could not be created for the compilation unit
9880 */
9881 CompilationUnit getAST(Source source) {
9882 int count = _compilationUnits.length;
9883 for (int i = 0; i < count; i++) {
9884 if (_compilationUnits[i].source == source) {
9885 return _compilationUnits[i].compilationUnit;
9886 }
9887 }
9888 return null;
9889 }
9890
9891 @override
9892 String toString() => librarySource.shortName;
9893
9894 static int _nextHashCode() {
9895 int next = (_NEXT_HASH_CODE + 1) & 0xFFFFFF;
9896 _NEXT_HASH_CODE = next;
9897 return next;
9898 }
9899 }
9900
9901 /**
9902 * The enumeration `ResolverErrorCode` defines the error codes used for errors
9903 * detected by the resolver. The convention for this class is for the name of
9904 * the error code to indicate the problem that caused the error to be generated
9905 * and for the error message to explain what is wrong and, when appropriate, how
9906 * the problem can be corrected.
9907 */
9908 class ResolverErrorCode extends ErrorCode {
9909 static const ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER =
9910 const ResolverErrorCode('BREAK_LABEL_ON_SWITCH_MEMBER',
9911 "Break label resolves to case or default statement");
9912
9913 static const ResolverErrorCode CONTINUE_LABEL_ON_SWITCH =
9914 const ResolverErrorCode('CONTINUE_LABEL_ON_SWITCH',
9915 "A continue label resolves to switch, must be loop or switch member");
9916
9917 static const ResolverErrorCode MISSING_LIBRARY_DIRECTIVE_WITH_PART =
9918 const ResolverErrorCode('MISSING_LIBRARY_DIRECTIVE_WITH_PART',
9919 "Libraries that have parts must have a library directive");
9920
9921 /**
9922 * Initialize a newly created error code to have the given [name]. The message
9923 * associated with the error will be created from the given [message]
9924 * template. The correction associated with the error will be created from the
9925 * given [correction] template.
9926 */
9927 const ResolverErrorCode(String name, String message, [String correction])
9928 : super(name, message, correction);
9929
9930 @override
9931 ErrorSeverity get errorSeverity => type.severity;
9932
9933 @override
9934 ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
9935 }
9936
9937 /**
9938 * Instances of the class `ResolverVisitor` are used to resolve the nodes within a single
9939 * compilation unit.
9940 */
9941 class ResolverVisitor extends ScopedVisitor {
9942 /**
9943 * The manager for the inheritance mappings.
9944 */
9945 InheritanceManager _inheritanceManager;
9946
9947 /**
9948 * The object used to resolve the element associated with the current node.
9949 */
9950 ElementResolver elementResolver;
9951
9952 /**
9953 * The object used to compute the type associated with the current node.
9954 */
9955 StaticTypeAnalyzer typeAnalyzer;
9956
9957 /**
9958 * The class element representing the class containing the current node,
9959 * or `null` if the current node is not contained in a class.
9960 */
9961 ClassElement enclosingClass = null;
9962
9963 /**
9964 * The class declaration representing the class containing the current node, o r `null` if
9965 * the current node is not contained in a class.
9966 */
9967 ClassDeclaration _enclosingClassDeclaration = null;
9968
9969 /**
9970 * The function type alias representing the function type containing the curre nt node, or
9971 * `null` if the current node is not contained in a function type alias.
9972 */
9973 FunctionTypeAlias _enclosingFunctionTypeAlias = null;
9974
9975 /**
9976 * The element representing the function containing the current node, or `null ` if the
9977 * current node is not contained in a function.
9978 */
9979 ExecutableElement _enclosingFunction = null;
9980
9981 /**
9982 * The [Comment] before a [FunctionDeclaration] or a [MethodDeclaration] that
9983 * cannot be resolved where we visited it, because it should be resolved in th e scope of the body.
9984 */
9985 Comment _commentBeforeFunction = null;
9986
9987 /**
9988 * The object keeping track of which elements have had their types overridden.
9989 */
9990 TypeOverrideManager _overrideManager = new TypeOverrideManager();
9991
9992 /**
9993 * The object keeping track of which elements have had their types promoted.
9994 */
9995 TypePromotionManager _promoteManager = new TypePromotionManager();
9996
9997 /**
9998 * A comment before a function should be resolved in the context of the
9999 * function. But when we incrementally resolve a comment, we don't want to
10000 * resolve the whole function.
10001 *
10002 * So, this flag is set to `true`, when just context of the function should
10003 * be built and the comment resolved.
10004 */
10005 bool resolveOnlyCommentInFunctionBody = false;
10006
10007 /**
10008 * Initialize a newly created visitor to resolve the nodes in an AST node.
10009 *
10010 * [definingLibrary] is the element for the library containing the node being
10011 * visited.
10012 * [source] is the source representing the compilation unit containing the
10013 * node being visited.
10014 * [typeProvider] the object used to access the types from the core library.
10015 * [errorListener] the error listener that will be informed of any errors
10016 * that are found during resolution.
10017 * [nameScope] is the scope used to resolve identifiers in the node that will
10018 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
10019 * created based on [definingLibrary] and [typeProvider].
10020 * [inheritanceManager] is used to perform inheritance lookups. If `null` or
10021 * unspecified, a new [InheritanceManager] will be created based on
10022 * [definingLibrary].
10023 * [typeAnalyzerFactory] is used to create the type analyzer. If `null` or
10024 * unspecified, a type analyzer of type [StaticTypeAnalyzer] will be created.
10025 */
10026 ResolverVisitor(LibraryElement definingLibrary, Source source,
10027 TypeProvider typeProvider, AnalysisErrorListener errorListener,
10028 {Scope nameScope, InheritanceManager inheritanceManager,
10029 StaticTypeAnalyzerFactory typeAnalyzerFactory})
10030 : super(definingLibrary, source, typeProvider, errorListener,
10031 nameScope: nameScope) {
10032 if (inheritanceManager == null) {
10033 this._inheritanceManager = new InheritanceManager(definingLibrary);
10034 } else {
10035 this._inheritanceManager = inheritanceManager;
10036 }
10037 this.elementResolver = new ElementResolver(this);
10038 if (typeAnalyzerFactory == null) {
10039 this.typeAnalyzer = new StaticTypeAnalyzer(this);
10040 } else {
10041 this.typeAnalyzer = typeAnalyzerFactory(this);
10042 }
10043 }
10044
10045 /**
10046 * Initialize a newly created visitor to resolve the nodes in a compilation un it.
10047 *
10048 * @param library the library containing the compilation unit being resolved
10049 * @param source the source representing the compilation unit being visited
10050 * @param typeProvider the object used to access the types from the core libra ry
10051 *
10052 * Deprecated. Please use unnamed constructor instead.
10053 */
10054 @deprecated
10055 ResolverVisitor.con1(
10056 Library library, Source source, TypeProvider typeProvider,
10057 {StaticTypeAnalyzerFactory typeAnalyzerFactory})
10058 : this(
10059 library.libraryElement, source, typeProvider, library.errorListener,
10060 nameScope: library.libraryScope,
10061 inheritanceManager: library.inheritanceManager,
10062 typeAnalyzerFactory: typeAnalyzerFactory);
10063
10064 /**
10065 * Return the element representing the function containing the current node, o r `null` if
10066 * the current node is not contained in a function.
10067 *
10068 * @return the element representing the function containing the current node
10069 */
10070 ExecutableElement get enclosingFunction => _enclosingFunction;
10071
10072 /**
10073 * Return the object keeping track of which elements have had their types over ridden.
10074 *
10075 * @return the object keeping track of which elements have had their types ove rridden
10076 */
10077 TypeOverrideManager get overrideManager => _overrideManager;
10078
10079 /**
10080 * Return the object keeping track of which elements have had their types prom oted.
10081 *
10082 * @return the object keeping track of which elements have had their types pro moted
10083 */
10084 TypePromotionManager get promoteManager => _promoteManager;
10085
10086 /**
10087 * Return the propagated element associated with the given expression whose ty pe can be
10088 * overridden, or `null` if there is no element whose type can be overridden.
10089 *
10090 * @param expression the expression with which the element is associated
10091 * @return the element associated with the given expression
10092 */
10093 VariableElement getOverridablePropagatedElement(Expression expression) {
10094 Element element = null;
10095 if (expression is SimpleIdentifier) {
10096 element = expression.propagatedElement;
10097 } else if (expression is PrefixedIdentifier) {
10098 element = expression.propagatedElement;
10099 } else if (expression is PropertyAccess) {
10100 element = expression.propertyName.propagatedElement;
10101 }
10102 if (element is VariableElement) {
10103 return element;
10104 }
10105 return null;
10106 }
10107
10108 /**
10109 * Return the static element associated with the given expression whose type c an be overridden, or
10110 * `null` if there is no element whose type can be overridden.
10111 *
10112 * @param expression the expression with which the element is associated
10113 * @return the element associated with the given expression
10114 */
10115 VariableElement getOverridableStaticElement(Expression expression) {
10116 Element element = null;
10117 if (expression is SimpleIdentifier) {
10118 element = expression.staticElement;
10119 } else if (expression is PrefixedIdentifier) {
10120 element = expression.staticElement;
10121 } else if (expression is PropertyAccess) {
10122 element = expression.propertyName.staticElement;
10123 }
10124 if (element is VariableElement) {
10125 return element;
10126 }
10127 return null;
10128 }
10129
10130 /**
10131 * Return the static element associated with the given expression whose type c an be promoted, or
10132 * `null` if there is no element whose type can be promoted.
10133 *
10134 * @param expression the expression with which the element is associated
10135 * @return the element associated with the given expression
10136 */
10137 VariableElement getPromotionStaticElement(Expression expression) {
10138 while (expression is ParenthesizedExpression) {
10139 expression = (expression as ParenthesizedExpression).expression;
10140 }
10141 if (expression is! SimpleIdentifier) {
10142 return null;
10143 }
10144 SimpleIdentifier identifier = expression as SimpleIdentifier;
10145 Element element = identifier.staticElement;
10146 if (element is! VariableElement) {
10147 return null;
10148 }
10149 ElementKind kind = element.kind;
10150 if (kind == ElementKind.LOCAL_VARIABLE) {
10151 return element as VariableElement;
10152 }
10153 if (kind == ElementKind.PARAMETER) {
10154 return element as VariableElement;
10155 }
10156 return null;
10157 }
10158
10159 /**
10160 * Prepares this [ResolverVisitor] to using it for incremental resolution.
10161 */
10162 void initForIncrementalResolution() {
10163 _overrideManager.enterScope();
10164 }
10165
10166 /**
10167 * If it is appropriate to do so, override the current type of the static and propagated elements
10168 * associated with the given expression with the given type. Generally speakin g, it is appropriate
10169 * if the given type is more specific than the current type.
10170 *
10171 * @param expression the expression used to access the static and propagated e lements whose types
10172 * might be overridden
10173 * @param potentialType the potential type of the elements
10174 * @param allowPrecisionLoss see @{code overrideVariable} docs
10175 */
10176 void overrideExpression(Expression expression, DartType potentialType,
10177 bool allowPrecisionLoss, bool setExpressionType) {
10178 VariableElement element = getOverridableStaticElement(expression);
10179 if (element != null) {
10180 DartType newBestType =
10181 overrideVariable(element, potentialType, allowPrecisionLoss);
10182 if (setExpressionType) {
10183 recordPropagatedTypeIfBetter(expression, newBestType);
10184 }
10185 }
10186 element = getOverridablePropagatedElement(expression);
10187 if (element != null) {
10188 overrideVariable(element, potentialType, allowPrecisionLoss);
10189 }
10190 }
10191
10192 /**
10193 * If it is appropriate to do so, override the current type of the given eleme nt with the given
10194 * type.
10195 *
10196 * @param element the element whose type might be overridden
10197 * @param potentialType the potential type of the element
10198 * @param allowPrecisionLoss true if `potentialType` is allowed to be less pre cise than the
10199 * current best type
10200 *
10201 * Return a new better [DartType], or `null` if [potentialType] is not better
10202 * than the current [element] type.
10203 */
10204 DartType overrideVariable(VariableElement element, DartType potentialType,
10205 bool allowPrecisionLoss) {
10206 if (potentialType == null || potentialType.isBottom) {
10207 return null;
10208 }
10209 DartType currentType = _overrideManager.getBestType(element);
10210
10211 if (potentialType == currentType) {
10212 return null;
10213 }
10214
10215 // If we aren't allowing precision loss then the third and fourth conditions
10216 // check that we aren't losing precision.
10217 //
10218 // Let [C] be the current type and [P] be the potential type. When we
10219 // aren't allowing precision loss -- which is the case for is-checks -- we
10220 // check that [! (C << P)] or [P << C]. The second check, that [P << C], is
10221 // analogous to part of the Dart Language Spec rule for type promotion under
10222 // is-checks (in the analogy [T] is [P] and [S] is [C]):
10223 //
10224 // An is-expression of the form [v is T] shows that [v] has type [T] iff
10225 // [T] is more specific than the type [S] of the expression [v] and both
10226 // [T != dynamic] and [S != dynamic].
10227 //
10228 // It also covers an important case that is not applicable in the spec:
10229 // for union types, we want an is-check to promote from an union type to
10230 // (a subtype of) any of its members.
10231 //
10232 // The first check, that [! (C << P)], covers the case where [P] and [C] are
10233 // unrelated types; This case is not addressed in the spec for static types.
10234 if (currentType == null ||
10235 allowPrecisionLoss ||
10236 !currentType.isMoreSpecificThan(potentialType) ||
10237 potentialType.isMoreSpecificThan(currentType)) {
10238 // TODO(scheglov) type propagation for instance/top-level fields
10239 // was disabled because it depends on the order or visiting.
10240 // If both field and its client are in the same unit, and we visit
10241 // the client before the field, then propagated type is not set yet.
10242 // if (element is PropertyInducingElement) {
10243 // PropertyInducingElement variable = element;
10244 // if (!variable.isConst && !variable.isFinal) {
10245 // return;
10246 // }
10247 // (variable as PropertyInducingElementImpl).propagatedType =
10248 // potentialType;
10249 // }
10250 _overrideManager.setType(element, potentialType);
10251 return potentialType;
10252 }
10253 return null;
10254 }
10255
10256 /**
10257 * If the given [type] is valid, strongly more specific than the
10258 * existing static type of the given [expression], record it as a propagated
10259 * type of the given [expression]. Otherwise, reset it to `null`.
10260 *
10261 * If [hasOldPropagatedType] is `true` then the existing propagated type
10262 * should also is checked.
10263 */
10264 void recordPropagatedTypeIfBetter(Expression expression, DartType type,
10265 [bool hasOldPropagatedType = false]) {
10266 // Ensure that propagated type invalid.
10267 if (type == null || type.isDynamic || type.isBottom) {
10268 if (!hasOldPropagatedType) {
10269 expression.propagatedType = null;
10270 }
10271 return;
10272 }
10273 // Ensure that propagated type is more specific than the static type.
10274 DartType staticType = expression.staticType;
10275 if (type == staticType || !type.isMoreSpecificThan(staticType)) {
10276 expression.propagatedType = null;
10277 return;
10278 }
10279 // Ensure that the new propagated type is more specific than the old one.
10280 if (hasOldPropagatedType) {
10281 DartType oldPropagatedType = expression.propagatedType;
10282 if (oldPropagatedType != null &&
10283 !type.isMoreSpecificThan(oldPropagatedType)) {
10284 return;
10285 }
10286 }
10287 // OK
10288 expression.propagatedType = type;
10289 }
10290
10291 @override
10292 Object visitAnnotation(Annotation node) {
10293 AstNode parent = node.parent;
10294 if (identical(parent, _enclosingClassDeclaration) ||
10295 identical(parent, _enclosingFunctionTypeAlias)) {
10296 return null;
10297 }
10298 return super.visitAnnotation(node);
10299 }
10300
10301 @override
10302 Object visitAsExpression(AsExpression node) {
10303 super.visitAsExpression(node);
10304 // Since an as-statement doesn't actually change the type, we don't
10305 // let it affect the propagated type when it would result in a loss
10306 // of precision.
10307 overrideExpression(node.expression, node.type.type, false, false);
10308 return null;
10309 }
10310
10311 @override
10312 Object visitAssertStatement(AssertStatement node) {
10313 super.visitAssertStatement(node);
10314 _propagateTrueState(node.condition);
10315 return null;
10316 }
10317
10318 @override
10319 Object visitBinaryExpression(BinaryExpression node) {
10320 sc.TokenType operatorType = node.operator.type;
10321 Expression leftOperand = node.leftOperand;
10322 Expression rightOperand = node.rightOperand;
10323 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) {
10324 safelyVisit(leftOperand);
10325 if (rightOperand != null) {
10326 _overrideManager.enterScope();
10327 try {
10328 _promoteManager.enterScope();
10329 try {
10330 _propagateTrueState(leftOperand);
10331 // Type promotion.
10332 _promoteTypes(leftOperand);
10333 _clearTypePromotionsIfPotentiallyMutatedIn(leftOperand);
10334 _clearTypePromotionsIfPotentiallyMutatedIn(rightOperand);
10335 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10336 rightOperand);
10337 // Visit right operand.
10338 rightOperand.accept(this);
10339 } finally {
10340 _promoteManager.exitScope();
10341 }
10342 } finally {
10343 _overrideManager.exitScope();
10344 }
10345 }
10346 } else if (operatorType == sc.TokenType.BAR_BAR) {
10347 safelyVisit(leftOperand);
10348 if (rightOperand != null) {
10349 _overrideManager.enterScope();
10350 try {
10351 _propagateFalseState(leftOperand);
10352 rightOperand.accept(this);
10353 } finally {
10354 _overrideManager.exitScope();
10355 }
10356 }
10357 } else {
10358 safelyVisit(leftOperand);
10359 safelyVisit(rightOperand);
10360 }
10361 node.accept(elementResolver);
10362 node.accept(typeAnalyzer);
10363 return null;
10364 }
10365
10366 @override
10367 Object visitBlockFunctionBody(BlockFunctionBody node) {
10368 safelyVisit(_commentBeforeFunction);
10369 _overrideManager.enterScope();
10370 try {
10371 super.visitBlockFunctionBody(node);
10372 } finally {
10373 _overrideManager.exitScope();
10374 }
10375 return null;
10376 }
10377
10378 @override
10379 Object visitBreakStatement(BreakStatement node) {
10380 //
10381 // We do not visit the label because it needs to be visited in the context
10382 // of the statement.
10383 //
10384 node.accept(elementResolver);
10385 node.accept(typeAnalyzer);
10386 return null;
10387 }
10388
10389 @override
10390 Object visitClassDeclaration(ClassDeclaration node) {
10391 //
10392 // Resolve the metadata in the library scope.
10393 //
10394 if (node.metadata != null) {
10395 node.metadata.accept(this);
10396 }
10397 _enclosingClassDeclaration = node;
10398 //
10399 // Continue the class resolution.
10400 //
10401 ClassElement outerType = enclosingClass;
10402 try {
10403 enclosingClass = node.element;
10404 typeAnalyzer.thisType =
10405 enclosingClass == null ? null : enclosingClass.type;
10406 super.visitClassDeclaration(node);
10407 node.accept(elementResolver);
10408 node.accept(typeAnalyzer);
10409 } finally {
10410 typeAnalyzer.thisType = outerType == null ? null : outerType.type;
10411 enclosingClass = outerType;
10412 _enclosingClassDeclaration = null;
10413 }
10414 return null;
10415 }
10416
10417 /**
10418 * Implementation of this method should be synchronized with
10419 * [visitClassDeclaration].
10420 */
10421 visitClassDeclarationIncrementally(ClassDeclaration node) {
10422 //
10423 // Resolve the metadata in the library scope.
10424 //
10425 if (node.metadata != null) {
10426 node.metadata.accept(this);
10427 }
10428 _enclosingClassDeclaration = node;
10429 //
10430 // Continue the class resolution.
10431 //
10432 enclosingClass = node.element;
10433 typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type;
10434 node.accept(elementResolver);
10435 node.accept(typeAnalyzer);
10436 }
10437
10438 @override
10439 Object visitComment(Comment node) {
10440 if (node.parent is FunctionDeclaration ||
10441 node.parent is ConstructorDeclaration ||
10442 node.parent is MethodDeclaration) {
10443 if (!identical(node, _commentBeforeFunction)) {
10444 _commentBeforeFunction = node;
10445 return null;
10446 }
10447 }
10448 super.visitComment(node);
10449 _commentBeforeFunction = null;
10450 return null;
10451 }
10452
10453 @override
10454 Object visitCommentReference(CommentReference node) {
10455 //
10456 // We do not visit the identifier because it needs to be visited in the
10457 // context of the reference.
10458 //
10459 node.accept(elementResolver);
10460 node.accept(typeAnalyzer);
10461 return null;
10462 }
10463
10464 @override
10465 Object visitCompilationUnit(CompilationUnit node) {
10466 //
10467 // TODO(brianwilkerson) The goal of the code below is to visit the
10468 // declarations in such an order that we can infer type information for
10469 // top-level variables before we visit references to them. This is better
10470 // than making no effort, but still doesn't completely satisfy that goal
10471 // (consider for example "final var a = b; final var b = 0;"; we'll infer a
10472 // type of 'int' for 'b', but not for 'a' because of the order of the
10473 // visits). Ideally we would create a dependency graph, but that would
10474 // require references to be resolved, which they are not.
10475 //
10476 _overrideManager.enterScope();
10477 try {
10478 NodeList<Directive> directives = node.directives;
10479 int directiveCount = directives.length;
10480 for (int i = 0; i < directiveCount; i++) {
10481 directives[i].accept(this);
10482 }
10483 NodeList<CompilationUnitMember> declarations = node.declarations;
10484 int declarationCount = declarations.length;
10485 for (int i = 0; i < declarationCount; i++) {
10486 CompilationUnitMember declaration = declarations[i];
10487 if (declaration is! ClassDeclaration) {
10488 declaration.accept(this);
10489 }
10490 }
10491 for (int i = 0; i < declarationCount; i++) {
10492 CompilationUnitMember declaration = declarations[i];
10493 if (declaration is ClassDeclaration) {
10494 declaration.accept(this);
10495 }
10496 }
10497 } finally {
10498 _overrideManager.exitScope();
10499 }
10500 node.accept(elementResolver);
10501 node.accept(typeAnalyzer);
10502 return null;
10503 }
10504
10505 @override
10506 Object visitConditionalExpression(ConditionalExpression node) {
10507 Expression condition = node.condition;
10508 safelyVisit(condition);
10509 Expression thenExpression = node.thenExpression;
10510 if (thenExpression != null) {
10511 _overrideManager.enterScope();
10512 try {
10513 _promoteManager.enterScope();
10514 try {
10515 _propagateTrueState(condition);
10516 // Type promotion.
10517 _promoteTypes(condition);
10518 _clearTypePromotionsIfPotentiallyMutatedIn(thenExpression);
10519 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10520 thenExpression);
10521 // Visit "then" expression.
10522 thenExpression.accept(this);
10523 } finally {
10524 _promoteManager.exitScope();
10525 }
10526 } finally {
10527 _overrideManager.exitScope();
10528 }
10529 }
10530 Expression elseExpression = node.elseExpression;
10531 if (elseExpression != null) {
10532 _overrideManager.enterScope();
10533 try {
10534 _propagateFalseState(condition);
10535 elseExpression.accept(this);
10536 } finally {
10537 _overrideManager.exitScope();
10538 }
10539 }
10540 node.accept(elementResolver);
10541 node.accept(typeAnalyzer);
10542 bool thenIsAbrupt = _isAbruptTerminationExpression(thenExpression);
10543 bool elseIsAbrupt = _isAbruptTerminationExpression(elseExpression);
10544 if (elseIsAbrupt && !thenIsAbrupt) {
10545 _propagateTrueState(condition);
10546 _propagateState(thenExpression);
10547 } else if (thenIsAbrupt && !elseIsAbrupt) {
10548 _propagateFalseState(condition);
10549 _propagateState(elseExpression);
10550 }
10551 return null;
10552 }
10553
10554 @override
10555 Object visitConstructorDeclaration(ConstructorDeclaration node) {
10556 ExecutableElement outerFunction = _enclosingFunction;
10557 try {
10558 _enclosingFunction = node.element;
10559 super.visitConstructorDeclaration(node);
10560 } finally {
10561 _enclosingFunction = outerFunction;
10562 }
10563 ConstructorElementImpl constructor = node.element;
10564 constructor.constantInitializers =
10565 new ConstantAstCloner().cloneNodeList(node.initializers);
10566 return null;
10567 }
10568
10569 @override
10570 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
10571 //
10572 // We visit the expression, but do not visit the field name because it needs
10573 // to be visited in the context of the constructor field initializer node.
10574 //
10575 safelyVisit(node.expression);
10576 node.accept(elementResolver);
10577 node.accept(typeAnalyzer);
10578 return null;
10579 }
10580
10581 @override
10582 Object visitConstructorName(ConstructorName node) {
10583 //
10584 // We do not visit either the type name, because it won't be visited anyway,
10585 // or the name, because it needs to be visited in the context of the
10586 // constructor name.
10587 //
10588 node.accept(elementResolver);
10589 node.accept(typeAnalyzer);
10590 return null;
10591 }
10592
10593 @override
10594 Object visitContinueStatement(ContinueStatement node) {
10595 //
10596 // We do not visit the label because it needs to be visited in the context
10597 // of the statement.
10598 //
10599 node.accept(elementResolver);
10600 node.accept(typeAnalyzer);
10601 return null;
10602 }
10603
10604 @override
10605 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
10606 super.visitDefaultFormalParameter(node);
10607 FormalParameterList parent = node.parent;
10608 AstNode grandparent = parent.parent;
10609 if (grandparent is ConstructorDeclaration &&
10610 grandparent.constKeyword != null) {
10611 // For const constructors, we need to clone the ASTs for default formal
10612 // parameters, so that we can use them during constant evaluation.
10613 ParameterElement element = node.element;
10614 (element as ConstVariableElement).constantInitializer =
10615 new ConstantAstCloner().cloneNode(node.defaultValue);
10616 }
10617 return null;
10618 }
10619
10620 @override
10621 Object visitDoStatement(DoStatement node) {
10622 _overrideManager.enterScope();
10623 try {
10624 super.visitDoStatement(node);
10625 } finally {
10626 _overrideManager.exitScope();
10627 }
10628 // TODO(brianwilkerson) If the loop can only be exited because the condition
10629 // is false, then propagateFalseState(node.getCondition());
10630 return null;
10631 }
10632
10633 @override
10634 Object visitEmptyFunctionBody(EmptyFunctionBody node) {
10635 safelyVisit(_commentBeforeFunction);
10636 if (resolveOnlyCommentInFunctionBody) {
10637 return null;
10638 }
10639 return super.visitEmptyFunctionBody(node);
10640 }
10641
10642 @override
10643 Object visitEnumDeclaration(EnumDeclaration node) {
10644 //
10645 // Resolve the metadata in the library scope
10646 // and associate the annotations with the element.
10647 //
10648 if (node.metadata != null) {
10649 node.metadata.accept(this);
10650 ElementResolver.setMetadata(node.element, node);
10651 }
10652 //
10653 // There is nothing else to do because everything else was resolved by the
10654 // element builder.
10655 //
10656 return null;
10657 }
10658
10659 @override
10660 Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
10661 safelyVisit(_commentBeforeFunction);
10662 if (resolveOnlyCommentInFunctionBody) {
10663 return null;
10664 }
10665 _overrideManager.enterScope();
10666 try {
10667 super.visitExpressionFunctionBody(node);
10668 } finally {
10669 _overrideManager.exitScope();
10670 }
10671 return null;
10672 }
10673
10674 @override
10675 Object visitFieldDeclaration(FieldDeclaration node) {
10676 _overrideManager.enterScope();
10677 try {
10678 super.visitFieldDeclaration(node);
10679 } finally {
10680 Map<VariableElement, DartType> overrides =
10681 _overrideManager.captureOverrides(node.fields);
10682 _overrideManager.exitScope();
10683 _overrideManager.applyOverrides(overrides);
10684 }
10685 return null;
10686 }
10687
10688 @override
10689 Object visitForEachStatement(ForEachStatement node) {
10690 _overrideManager.enterScope();
10691 try {
10692 super.visitForEachStatement(node);
10693 } finally {
10694 _overrideManager.exitScope();
10695 }
10696 return null;
10697 }
10698
10699 @override
10700 void visitForEachStatementInScope(ForEachStatement node) {
10701 //
10702 // We visit the iterator before the loop variable because the loop variable
10703 // cannot be in scope while visiting the iterator.
10704 //
10705 Expression iterable = node.iterable;
10706 safelyVisit(iterable);
10707 DeclaredIdentifier loopVariable = node.loopVariable;
10708 SimpleIdentifier identifier = node.identifier;
10709 safelyVisit(loopVariable);
10710 safelyVisit(identifier);
10711 Statement body = node.body;
10712 if (body != null) {
10713 _overrideManager.enterScope();
10714 try {
10715 if (loopVariable != null && iterable != null) {
10716 LocalVariableElement loopElement = loopVariable.element;
10717 if (loopElement != null) {
10718 DartType iteratorElementType = _getIteratorElementType(iterable);
10719 overrideVariable(loopElement, iteratorElementType, true);
10720 _recordPropagatedType(loopVariable.identifier, iteratorElementType);
10721 }
10722 } else if (identifier != null && iterable != null) {
10723 Element identifierElement = identifier.staticElement;
10724 if (identifierElement is VariableElement) {
10725 DartType iteratorElementType = _getIteratorElementType(iterable);
10726 overrideVariable(identifierElement, iteratorElementType, true);
10727 _recordPropagatedType(identifier, iteratorElementType);
10728 }
10729 }
10730 visitStatementInScope(body);
10731 } finally {
10732 _overrideManager.exitScope();
10733 }
10734 }
10735 node.accept(elementResolver);
10736 node.accept(typeAnalyzer);
10737 }
10738
10739 @override
10740 Object visitForStatement(ForStatement node) {
10741 _overrideManager.enterScope();
10742 try {
10743 super.visitForStatement(node);
10744 } finally {
10745 _overrideManager.exitScope();
10746 }
10747 return null;
10748 }
10749
10750 @override
10751 void visitForStatementInScope(ForStatement node) {
10752 safelyVisit(node.variables);
10753 safelyVisit(node.initialization);
10754 safelyVisit(node.condition);
10755 _overrideManager.enterScope();
10756 try {
10757 _propagateTrueState(node.condition);
10758 visitStatementInScope(node.body);
10759 node.updaters.accept(this);
10760 } finally {
10761 _overrideManager.exitScope();
10762 }
10763 // TODO(brianwilkerson) If the loop can only be exited because the condition
10764 // is false, then propagateFalseState(condition);
10765 }
10766
10767 @override
10768 Object visitFunctionDeclaration(FunctionDeclaration node) {
10769 ExecutableElement outerFunction = _enclosingFunction;
10770 try {
10771 SimpleIdentifier functionName = node.name;
10772 _enclosingFunction = functionName.staticElement as ExecutableElement;
10773 super.visitFunctionDeclaration(node);
10774 } finally {
10775 _enclosingFunction = outerFunction;
10776 }
10777 return null;
10778 }
10779
10780 @override
10781 Object visitFunctionExpression(FunctionExpression node) {
10782 ExecutableElement outerFunction = _enclosingFunction;
10783 try {
10784 _enclosingFunction = node.element;
10785 _overrideManager.enterScope();
10786 try {
10787 super.visitFunctionExpression(node);
10788 } finally {
10789 _overrideManager.exitScope();
10790 }
10791 } finally {
10792 _enclosingFunction = outerFunction;
10793 }
10794 return null;
10795 }
10796
10797 @override
10798 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
10799 safelyVisit(node.function);
10800 node.accept(elementResolver);
10801 _inferFunctionExpressionsParametersTypes(node.argumentList);
10802 safelyVisit(node.argumentList);
10803 node.accept(typeAnalyzer);
10804 return null;
10805 }
10806
10807 @override
10808 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
10809 // Resolve the metadata in the library scope.
10810 if (node.metadata != null) {
10811 node.metadata.accept(this);
10812 }
10813 FunctionTypeAlias outerAlias = _enclosingFunctionTypeAlias;
10814 _enclosingFunctionTypeAlias = node;
10815 try {
10816 super.visitFunctionTypeAlias(node);
10817 } finally {
10818 _enclosingFunctionTypeAlias = outerAlias;
10819 }
10820 return null;
10821 }
10822
10823 @override
10824 Object visitHideCombinator(HideCombinator node) => null;
10825
10826 @override
10827 Object visitIfStatement(IfStatement node) {
10828 Expression condition = node.condition;
10829 safelyVisit(condition);
10830 Map<VariableElement, DartType> thenOverrides =
10831 new HashMap<VariableElement, DartType>();
10832 Statement thenStatement = node.thenStatement;
10833 if (thenStatement != null) {
10834 _overrideManager.enterScope();
10835 try {
10836 _promoteManager.enterScope();
10837 try {
10838 _propagateTrueState(condition);
10839 // Type promotion.
10840 _promoteTypes(condition);
10841 _clearTypePromotionsIfPotentiallyMutatedIn(thenStatement);
10842 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10843 thenStatement);
10844 // Visit "then".
10845 visitStatementInScope(thenStatement);
10846 } finally {
10847 _promoteManager.exitScope();
10848 }
10849 } finally {
10850 thenOverrides = _overrideManager.captureLocalOverrides();
10851 _overrideManager.exitScope();
10852 }
10853 }
10854 Map<VariableElement, DartType> elseOverrides =
10855 new HashMap<VariableElement, DartType>();
10856 Statement elseStatement = node.elseStatement;
10857 if (elseStatement != null) {
10858 _overrideManager.enterScope();
10859 try {
10860 _propagateFalseState(condition);
10861 visitStatementInScope(elseStatement);
10862 } finally {
10863 elseOverrides = _overrideManager.captureLocalOverrides();
10864 _overrideManager.exitScope();
10865 }
10866 }
10867 node.accept(elementResolver);
10868 node.accept(typeAnalyzer);
10869 // Join overrides.
10870 bool thenIsAbrupt = _isAbruptTerminationStatement(thenStatement);
10871 bool elseIsAbrupt = _isAbruptTerminationStatement(elseStatement);
10872 if (elseIsAbrupt && !thenIsAbrupt) {
10873 _propagateTrueState(condition);
10874 _overrideManager.applyOverrides(thenOverrides);
10875 } else if (thenIsAbrupt && !elseIsAbrupt) {
10876 _propagateFalseState(condition);
10877 _overrideManager.applyOverrides(elseOverrides);
10878 } else if (!thenIsAbrupt && !elseIsAbrupt) {
10879 List<Map<VariableElement, DartType>> perBranchOverrides =
10880 new List<Map<VariableElement, DartType>>();
10881 perBranchOverrides.add(thenOverrides);
10882 perBranchOverrides.add(elseOverrides);
10883 _overrideManager.mergeOverrides(perBranchOverrides);
10884 }
10885 return null;
10886 }
10887
10888 @override
10889 Object visitLabel(Label node) => null;
10890
10891 @override
10892 Object visitLibraryIdentifier(LibraryIdentifier node) => null;
10893
10894 @override
10895 Object visitMethodDeclaration(MethodDeclaration node) {
10896 ExecutableElement outerFunction = _enclosingFunction;
10897 try {
10898 _enclosingFunction = node.element;
10899 super.visitMethodDeclaration(node);
10900 } finally {
10901 _enclosingFunction = outerFunction;
10902 }
10903 return null;
10904 }
10905
10906 @override
10907 Object visitMethodInvocation(MethodInvocation node) {
10908 //
10909 // We visit the target and argument list, but do not visit the method name
10910 // because it needs to be visited in the context of the invocation.
10911 //
10912 safelyVisit(node.target);
10913 node.accept(elementResolver);
10914 _inferFunctionExpressionsParametersTypes(node.argumentList);
10915 safelyVisit(node.argumentList);
10916 node.accept(typeAnalyzer);
10917 return null;
10918 }
10919
10920 @override
10921 Object visitNode(AstNode node) {
10922 node.visitChildren(this);
10923 node.accept(elementResolver);
10924 node.accept(typeAnalyzer);
10925 return null;
10926 }
10927
10928 @override
10929 Object visitPrefixedIdentifier(PrefixedIdentifier node) {
10930 //
10931 // We visit the prefix, but do not visit the identifier because it needs to
10932 // be visited in the context of the prefix.
10933 //
10934 safelyVisit(node.prefix);
10935 node.accept(elementResolver);
10936 node.accept(typeAnalyzer);
10937 return null;
10938 }
10939
10940 @override
10941 Object visitPropertyAccess(PropertyAccess node) {
10942 //
10943 // We visit the target, but do not visit the property name because it needs
10944 // to be visited in the context of the property access node.
10945 //
10946 safelyVisit(node.target);
10947 node.accept(elementResolver);
10948 node.accept(typeAnalyzer);
10949 return null;
10950 }
10951
10952 @override
10953 Object visitRedirectingConstructorInvocation(
10954 RedirectingConstructorInvocation node) {
10955 //
10956 // We visit the argument list, but do not visit the optional identifier
10957 // because it needs to be visited in the context of the constructor
10958 // invocation.
10959 //
10960 safelyVisit(node.argumentList);
10961 node.accept(elementResolver);
10962 node.accept(typeAnalyzer);
10963 return null;
10964 }
10965
10966 @override
10967 Object visitShowCombinator(ShowCombinator node) => null;
10968
10969 @override
10970 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
10971 //
10972 // We visit the argument list, but do not visit the optional identifier
10973 // because it needs to be visited in the context of the constructor
10974 // invocation.
10975 //
10976 safelyVisit(node.argumentList);
10977 node.accept(elementResolver);
10978 node.accept(typeAnalyzer);
10979 return null;
10980 }
10981
10982 @override
10983 Object visitSwitchCase(SwitchCase node) {
10984 _overrideManager.enterScope();
10985 try {
10986 super.visitSwitchCase(node);
10987 } finally {
10988 _overrideManager.exitScope();
10989 }
10990 return null;
10991 }
10992
10993 @override
10994 Object visitSwitchDefault(SwitchDefault node) {
10995 _overrideManager.enterScope();
10996 try {
10997 super.visitSwitchDefault(node);
10998 } finally {
10999 _overrideManager.exitScope();
11000 }
11001 return null;
11002 }
11003
11004 @override
11005 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
11006 _overrideManager.enterScope();
11007 try {
11008 super.visitTopLevelVariableDeclaration(node);
11009 } finally {
11010 Map<VariableElement, DartType> overrides =
11011 _overrideManager.captureOverrides(node.variables);
11012 _overrideManager.exitScope();
11013 _overrideManager.applyOverrides(overrides);
11014 }
11015 return null;
11016 }
11017
11018 @override
11019 Object visitTypeName(TypeName node) => null;
11020
11021 @override
11022 Object visitVariableDeclaration(VariableDeclaration node) {
11023 super.visitVariableDeclaration(node);
11024 VariableElement element = node.element;
11025 // Note: in addition to cloning the initializers for const variables, we
11026 // have to clone the initializers for non-static final fields (because if
11027 // they occur in a class with a const constructor, they will be needed to
11028 // evaluate the const constructor).
11029 if ((element.isConst ||
11030 (element is FieldElement &&
11031 element.isFinal &&
11032 !element.isStatic)) &&
11033 node.initializer != null) {
11034 (element as ConstVariableElement).constantInitializer =
11035 new ConstantAstCloner().cloneNode(node.initializer);
11036 }
11037 return null;
11038 }
11039
11040 @override
11041 Object visitWhileStatement(WhileStatement node) {
11042 // Note: since we don't call the base class, we have to maintain
11043 // _implicitLabelScope ourselves.
11044 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
11045 try {
11046 _implicitLabelScope = _implicitLabelScope.nest(node);
11047 Expression condition = node.condition;
11048 safelyVisit(condition);
11049 Statement body = node.body;
11050 if (body != null) {
11051 _overrideManager.enterScope();
11052 try {
11053 _propagateTrueState(condition);
11054 visitStatementInScope(body);
11055 } finally {
11056 _overrideManager.exitScope();
11057 }
11058 }
11059 } finally {
11060 _implicitLabelScope = outerImplicitScope;
11061 }
11062 // TODO(brianwilkerson) If the loop can only be exited because the condition
11063 // is false, then propagateFalseState(condition);
11064 node.accept(elementResolver);
11065 node.accept(typeAnalyzer);
11066 return null;
11067 }
11068
11069 /**
11070 * Checks each promoted variable in the current scope for compliance with the following
11071 * specification statement:
11072 *
11073 * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> t hen the variable
11074 * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>.
11075 */
11076 void _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
11077 AstNode target) {
11078 for (Element element in _promoteManager.promotedElements) {
11079 if ((element as VariableElementImpl).isPotentiallyMutatedInScope) {
11080 if (_isVariableAccessedInClosure(element, target)) {
11081 _promoteManager.setType(element, null);
11082 }
11083 }
11084 }
11085 }
11086
11087 /**
11088 * Checks each promoted variable in the current scope for compliance with the following
11089 * specification statement:
11090 *
11091 * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a clo sure.
11092 */
11093 void _clearTypePromotionsIfPotentiallyMutatedIn(AstNode target) {
11094 for (Element element in _promoteManager.promotedElements) {
11095 if (_isVariablePotentiallyMutatedIn(element, target)) {
11096 _promoteManager.setType(element, null);
11097 }
11098 }
11099 }
11100
11101 /**
11102 * The given expression is the expression used to compute the iterator for a f or-each statement.
11103 * Attempt to compute the type of objects that will be assigned to the loop va riable and return
11104 * that type. Return `null` if the type could not be determined.
11105 *
11106 * @param iterator the iterator for a for-each statement
11107 * @return the type of objects that will be assigned to the loop variable
11108 */
11109 DartType _getIteratorElementType(Expression iteratorExpression) {
11110 DartType expressionType = iteratorExpression.bestType;
11111 if (expressionType is InterfaceType) {
11112 InterfaceType interfaceType = expressionType;
11113 FunctionType iteratorFunction =
11114 _inheritanceManager.lookupMemberType(interfaceType, "iterator");
11115 if (iteratorFunction == null) {
11116 // TODO(brianwilkerson) Should we report this error?
11117 return null;
11118 }
11119 DartType iteratorType = iteratorFunction.returnType;
11120 if (iteratorType is InterfaceType) {
11121 InterfaceType iteratorInterfaceType = iteratorType;
11122 FunctionType currentFunction = _inheritanceManager.lookupMemberType(
11123 iteratorInterfaceType, "current");
11124 if (currentFunction == null) {
11125 // TODO(brianwilkerson) Should we report this error?
11126 return null;
11127 }
11128 return currentFunction.returnType;
11129 }
11130 }
11131 return null;
11132 }
11133
11134 /**
11135 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
11136 * required type is [FunctionType], then infer parameters types from [Function Type].
11137 */
11138 void _inferFunctionExpressionParametersTypes(
11139 Expression mayBeClosure, DartType mayByFunctionType) {
11140 // prepare closure
11141 if (mayBeClosure is! FunctionExpression) {
11142 return;
11143 }
11144 FunctionExpression closure = mayBeClosure as FunctionExpression;
11145 // prepare expected closure type
11146 if (mayByFunctionType is! FunctionType) {
11147 return;
11148 }
11149 FunctionType expectedClosureType = mayByFunctionType as FunctionType;
11150 // If the expectedClosureType is not more specific than the static type,
11151 // return.
11152 DartType staticClosureType =
11153 (closure.element != null ? closure.element.type : null) as DartType;
11154 if (staticClosureType != null &&
11155 !expectedClosureType.isMoreSpecificThan(staticClosureType)) {
11156 return;
11157 }
11158 // set propagated type for the closure
11159 closure.propagatedType = expectedClosureType;
11160 // set inferred types for parameters
11161 NodeList<FormalParameter> parameters = closure.parameters.parameters;
11162 List<ParameterElement> expectedParameters = expectedClosureType.parameters;
11163 for (int i = 0;
11164 i < parameters.length && i < expectedParameters.length;
11165 i++) {
11166 FormalParameter parameter = parameters[i];
11167 ParameterElement element = parameter.element;
11168 DartType currentType = _overrideManager.getBestType(element);
11169 // may be override the type
11170 DartType expectedType = expectedParameters[i].type;
11171 if (currentType == null || expectedType.isMoreSpecificThan(currentType)) {
11172 _overrideManager.setType(element, expectedType);
11173 }
11174 }
11175 }
11176
11177 /**
11178 * Try to infer types of parameters of the [FunctionExpression] arguments.
11179 */
11180 void _inferFunctionExpressionsParametersTypes(ArgumentList argumentList) {
11181 for (Expression argument in argumentList.arguments) {
11182 ParameterElement parameter = argument.propagatedParameterElement;
11183 if (parameter == null) {
11184 parameter = argument.staticParameterElement;
11185 }
11186 if (parameter != null) {
11187 _inferFunctionExpressionParametersTypes(argument, parameter.type);
11188 }
11189 }
11190 }
11191
11192 /**
11193 * Return `true` if the given expression terminates abruptly (that is, if any expression
11194 * following the given expression will not be reached).
11195 *
11196 * @param expression the expression being tested
11197 * @return `true` if the given expression terminates abruptly
11198 */
11199 bool _isAbruptTerminationExpression(Expression expression) {
11200 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we
11201 // would eventually turn this into a method on Expression that returns a
11202 // termination indication (normal, abrupt with no exception, abrupt with an
11203 // exception).
11204 while (expression is ParenthesizedExpression) {
11205 expression = (expression as ParenthesizedExpression).expression;
11206 }
11207 return expression is ThrowExpression || expression is RethrowExpression;
11208 }
11209
11210 /**
11211 * Return `true` if the given statement terminates abruptly (that is, if any s tatement
11212 * following the given statement will not be reached).
11213 *
11214 * @param statement the statement being tested
11215 * @return `true` if the given statement terminates abruptly
11216 */
11217 bool _isAbruptTerminationStatement(Statement statement) {
11218 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we
11219 // would eventually turn this into a method on Statement that returns a
11220 // termination indication (normal, abrupt with no exception, abrupt with an
11221 // exception).
11222 //
11223 // collinsn: it is unsound to assume that [break] and [continue] are
11224 // "abrupt". See: https://code.google.com/p/dart/issues/detail?id=19929#c4
11225 // (tests are included in TypePropagationTest.java).
11226 // In general, the difficulty is loopy control flow.
11227 //
11228 // In the presence of exceptions things become much more complicated, but
11229 // while we only use this to propagate at [if]-statement join points,
11230 // checking for [return] may work well enough in the common case.
11231 if (statement is ReturnStatement) {
11232 return true;
11233 } else if (statement is ExpressionStatement) {
11234 return _isAbruptTerminationExpression(statement.expression);
11235 } else if (statement is Block) {
11236 NodeList<Statement> statements = statement.statements;
11237 int size = statements.length;
11238 if (size == 0) {
11239 return false;
11240 }
11241
11242 // This last-statement-is-return heuristic is unsound for adversarial
11243 // code, but probably works well in the common case:
11244 //
11245 // var x = 123;
11246 // var c = true;
11247 // L: if (c) {
11248 // x = "hello";
11249 // c = false;
11250 // break L;
11251 // return;
11252 // }
11253 // print(x);
11254 //
11255 // Unsound to assume that [x = "hello";] never executed after the
11256 // if-statement. Of course, a dead-code analysis could point out that
11257 // [return] here is dead.
11258 return _isAbruptTerminationStatement(statements[size - 1]);
11259 }
11260 return false;
11261 }
11262
11263 /**
11264 * Return `true` if the given variable is accessed within a closure in the giv en
11265 * [AstNode] and also mutated somewhere in variable scope. This information is only
11266 * available for local variables (including parameters).
11267 *
11268 * @param variable the variable to check
11269 * @param target the [AstNode] to check within
11270 * @return `true` if this variable is potentially mutated somewhere in the giv en ASTNode
11271 */
11272 bool _isVariableAccessedInClosure(Element variable, AstNode target) {
11273 _ResolverVisitor_isVariableAccessedInClosure visitor =
11274 new _ResolverVisitor_isVariableAccessedInClosure(variable);
11275 target.accept(visitor);
11276 return visitor.result;
11277 }
11278
11279 /**
11280 * Return `true` if the given variable is potentially mutated somewhere in the given
11281 * [AstNode]. This information is only available for local variables (includin g parameters).
11282 *
11283 * @param variable the variable to check
11284 * @param target the [AstNode] to check within
11285 * @return `true` if this variable is potentially mutated somewhere in the giv en ASTNode
11286 */
11287 bool _isVariablePotentiallyMutatedIn(Element variable, AstNode target) {
11288 _ResolverVisitor_isVariablePotentiallyMutatedIn visitor =
11289 new _ResolverVisitor_isVariablePotentiallyMutatedIn(variable);
11290 target.accept(visitor);
11291 return visitor.result;
11292 }
11293
11294 /**
11295 * If it is appropriate to do so, promotes the current type of the static elem ent associated with
11296 * the given expression with the given type. Generally speaking, it is appropr iate if the given
11297 * type is more specific than the current type.
11298 *
11299 * @param expression the expression used to access the static element whose ty pes might be
11300 * promoted
11301 * @param potentialType the potential type of the elements
11302 */
11303 void _promote(Expression expression, DartType potentialType) {
11304 VariableElement element = getPromotionStaticElement(expression);
11305 if (element != null) {
11306 // may be mutated somewhere in closure
11307 if (element.isPotentiallyMutatedInClosure) {
11308 return;
11309 }
11310 // prepare current variable type
11311 DartType type = _promoteManager.getType(element);
11312 if (type == null) {
11313 type = expression.staticType;
11314 }
11315 // Declared type should not be "dynamic".
11316 if (type == null || type.isDynamic) {
11317 return;
11318 }
11319 // Promoted type should not be "dynamic".
11320 if (potentialType == null || potentialType.isDynamic) {
11321 return;
11322 }
11323 // Promoted type should be more specific than declared.
11324 if (!potentialType.isMoreSpecificThan(type)) {
11325 return;
11326 }
11327 // Do promote type of variable.
11328 _promoteManager.setType(element, potentialType);
11329 }
11330 }
11331
11332 /**
11333 * Promotes type information using given condition.
11334 */
11335 void _promoteTypes(Expression condition) {
11336 if (condition is BinaryExpression) {
11337 BinaryExpression binary = condition;
11338 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) {
11339 Expression left = binary.leftOperand;
11340 Expression right = binary.rightOperand;
11341 _promoteTypes(left);
11342 _promoteTypes(right);
11343 _clearTypePromotionsIfPotentiallyMutatedIn(right);
11344 }
11345 } else if (condition is IsExpression) {
11346 IsExpression is2 = condition;
11347 if (is2.notOperator == null) {
11348 _promote(is2.expression, is2.type.type);
11349 }
11350 } else if (condition is ParenthesizedExpression) {
11351 _promoteTypes(condition.expression);
11352 }
11353 }
11354
11355 /**
11356 * Propagate any type information that results from knowing that the given con dition will have
11357 * been evaluated to 'false'.
11358 *
11359 * @param condition the condition that will have evaluated to 'false'
11360 */
11361 void _propagateFalseState(Expression condition) {
11362 if (condition is BinaryExpression) {
11363 BinaryExpression binary = condition;
11364 if (binary.operator.type == sc.TokenType.BAR_BAR) {
11365 _propagateFalseState(binary.leftOperand);
11366 _propagateFalseState(binary.rightOperand);
11367 }
11368 } else if (condition is IsExpression) {
11369 IsExpression is2 = condition;
11370 if (is2.notOperator != null) {
11371 // Since an is-statement doesn't actually change the type, we don't
11372 // let it affect the propagated type when it would result in a loss
11373 // of precision.
11374 overrideExpression(is2.expression, is2.type.type, false, false);
11375 }
11376 } else if (condition is PrefixExpression) {
11377 PrefixExpression prefix = condition;
11378 if (prefix.operator.type == sc.TokenType.BANG) {
11379 _propagateTrueState(prefix.operand);
11380 }
11381 } else if (condition is ParenthesizedExpression) {
11382 _propagateFalseState(condition.expression);
11383 }
11384 }
11385
11386 /**
11387 * Propagate any type information that results from knowing that the given exp ression will have
11388 * been evaluated without altering the flow of execution.
11389 *
11390 * @param expression the expression that will have been evaluated
11391 */
11392 void _propagateState(Expression expression) {
11393 // TODO(brianwilkerson) Implement this.
11394 }
11395
11396 /**
11397 * Propagate any type information that results from knowing that the given con dition will have
11398 * been evaluated to 'true'.
11399 *
11400 * @param condition the condition that will have evaluated to 'true'
11401 */
11402 void _propagateTrueState(Expression condition) {
11403 if (condition is BinaryExpression) {
11404 BinaryExpression binary = condition;
11405 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) {
11406 _propagateTrueState(binary.leftOperand);
11407 _propagateTrueState(binary.rightOperand);
11408 }
11409 } else if (condition is IsExpression) {
11410 IsExpression is2 = condition;
11411 if (is2.notOperator == null) {
11412 // Since an is-statement doesn't actually change the type, we don't
11413 // let it affect the propagated type when it would result in a loss
11414 // of precision.
11415 overrideExpression(is2.expression, is2.type.type, false, false);
11416 }
11417 } else if (condition is PrefixExpression) {
11418 PrefixExpression prefix = condition;
11419 if (prefix.operator.type == sc.TokenType.BANG) {
11420 _propagateFalseState(prefix.operand);
11421 }
11422 } else if (condition is ParenthesizedExpression) {
11423 _propagateTrueState(condition.expression);
11424 }
11425 }
11426
11427 /**
11428 * Record that the propagated type of the given node is the given type.
11429 *
11430 * @param expression the node whose type is to be recorded
11431 * @param type the propagated type of the node
11432 */
11433 void _recordPropagatedType(Expression expression, DartType type) {
11434 if (type != null && !type.isDynamic) {
11435 expression.propagatedType = type;
11436 }
11437 }
11438 }
11439
11440 /**
11441 * The abstract class `Scope` defines the behavior common to name scopes used by the resolver
11442 * to determine which names are visible at any given point in the code.
11443 */
11444 abstract class Scope {
11445 /**
11446 * The prefix used to mark an identifier as being private to its library.
11447 */
11448 static int PRIVATE_NAME_PREFIX = 0x5F;
11449
11450 /**
11451 * The suffix added to the declared name of a setter when looking up the sette r. Used to
11452 * disambiguate between a getter and a setter that have the same name.
11453 */
11454 static String SETTER_SUFFIX = "=";
11455
11456 /**
11457 * The name used to look up the method used to implement the unary minus opera tor. Used to
11458 * disambiguate between the unary and binary operators.
11459 */
11460 static String UNARY_MINUS = "unary-";
11461
11462 /**
11463 * A table mapping names that are defined in this scope to the element represe nting the thing
11464 * declared with that name.
11465 */
11466 HashMap<String, Element> _definedNames = new HashMap<String, Element>();
11467
11468 /**
11469 * A flag indicating whether there are any names defined in this scope.
11470 */
11471 bool _hasName = false;
11472
11473 /**
11474 * Return the scope in which this scope is lexically enclosed.
11475 *
11476 * @return the scope in which this scope is lexically enclosed
11477 */
11478 Scope get enclosingScope => null;
11479
11480 /**
11481 * Return the listener that is to be informed when an error is encountered.
11482 *
11483 * @return the listener that is to be informed when an error is encountered
11484 */
11485 AnalysisErrorListener get errorListener;
11486
11487 /**
11488 * Add the given element to this scope. If there is already an element with th e given name defined
11489 * in this scope, then an error will be generated and the original element wil l continue to be
11490 * mapped to the name. If there is an element with the given name in an enclos ing scope, then a
11491 * warning will be generated but the given element will hide the inherited ele ment.
11492 *
11493 * @param element the element to be added to this scope
11494 */
11495 void define(Element element) {
11496 String name = _getName(element);
11497 if (name != null && !name.isEmpty) {
11498 if (_definedNames.containsKey(name)) {
11499 errorListener
11500 .onError(getErrorForDuplicate(_definedNames[name], element));
11501 } else {
11502 _definedNames[name] = element;
11503 _hasName = true;
11504 }
11505 }
11506 }
11507
11508 /**
11509 * Add the given element to this scope without checking for duplication or hid ing.
11510 *
11511 * @param name the name of the element to be added
11512 * @param element the element to be added to this scope
11513 */
11514 void defineNameWithoutChecking(String name, Element element) {
11515 _definedNames[name] = element;
11516 _hasName = true;
11517 }
11518
11519 /**
11520 * Add the given element to this scope without checking for duplication or hid ing.
11521 *
11522 * @param element the element to be added to this scope
11523 */
11524 void defineWithoutChecking(Element element) {
11525 _definedNames[_getName(element)] = element;
11526 _hasName = true;
11527 }
11528
11529 /**
11530 * Return the error code to be used when reporting that a name being defined l ocally conflicts
11531 * with another element of the same name in the local scope.
11532 *
11533 * @param existing the first element to be declared with the conflicting name
11534 * @param duplicate another element declared with the conflicting name
11535 * @return the error code used to report duplicate names within a scope
11536 */
11537 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
11538 // TODO(brianwilkerson) Customize the error message based on the types of
11539 // elements that share the same name.
11540 // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being
11541 // generated.
11542 Source source = duplicate.source;
11543 return new AnalysisError(source, duplicate.nameOffset,
11544 duplicate.displayName.length, CompileTimeErrorCode.DUPLICATE_DEFINITION,
11545 [existing.displayName]);
11546 }
11547
11548 /**
11549 * Return the source that contains the given identifier, or the source associa ted with this scope
11550 * if the source containing the identifier could not be determined.
11551 *
11552 * @param identifier the identifier whose source is to be returned
11553 * @return the source that contains the given identifier
11554 */
11555 Source getSource(AstNode node) {
11556 CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit);
11557 if (unit != null) {
11558 CompilationUnitElement unitElement = unit.element;
11559 if (unitElement != null) {
11560 return unitElement.source;
11561 }
11562 }
11563 return null;
11564 }
11565
11566 /**
11567 * Return the element with which the given name is associated, or `null` if th e name is not
11568 * defined within this scope.
11569 *
11570 * @param identifier the identifier node to lookup element for, used to report correct kind of a
11571 * problem and associate problem with
11572 * @param name the name associated with the element to be returned
11573 * @param referencingLibrary the library that contains the reference to the na me, used to
11574 * implement library-level privacy
11575 * @return the element with which the given name is associated
11576 */
11577 Element internalLookup(
11578 Identifier identifier, String name, LibraryElement referencingLibrary);
11579
11580 /**
11581 * Return the element with which the given name is associated, or `null` if th e name is not
11582 * defined within this scope. This method only returns elements that are direc tly defined within
11583 * this scope, not elements that are defined in an enclosing scope.
11584 *
11585 * @param name the name associated with the element to be returned
11586 * @param referencingLibrary the library that contains the reference to the na me, used to
11587 * implement library-level privacy
11588 * @return the element with which the given name is associated
11589 */
11590 Element localLookup(String name, LibraryElement referencingLibrary) {
11591 if (_hasName) {
11592 return _definedNames[name];
11593 }
11594 return null;
11595 }
11596
11597 /**
11598 * Return the element with which the given identifier is associated, or `null` if the name
11599 * is not defined within this scope.
11600 *
11601 * @param identifier the identifier associated with the element to be returned
11602 * @param referencingLibrary the library that contains the reference to the na me, used to
11603 * implement library-level privacy
11604 * @return the element with which the given identifier is associated
11605 */
11606 Element lookup(Identifier identifier, LibraryElement referencingLibrary) =>
11607 internalLookup(identifier, identifier.name, referencingLibrary);
11608
11609 /**
11610 * Return the name that will be used to look up the given element.
11611 *
11612 * @param element the element whose look-up name is to be returned
11613 * @return the name that will be used to look up the given element
11614 */
11615 String _getName(Element element) {
11616 if (element is MethodElement) {
11617 MethodElement method = element;
11618 if (method.name == "-" && method.parameters.length == 0) {
11619 return UNARY_MINUS;
11620 }
11621 }
11622 return element.name;
11623 }
11624
11625 /**
11626 * Return `true` if the given name is a library-private name.
11627 *
11628 * @param name the name being tested
11629 * @return `true` if the given name is a library-private name
11630 */
11631 static bool isPrivateName(String name) =>
11632 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX);
11633 }
11634
11635 /**
11636 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST structure is
11637 * being visited.
11638 */
11639 abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
11640 /**
11641 * The element for the library containing the compilation unit being visited.
11642 */
11643 LibraryElement _definingLibrary;
11644
11645 /**
11646 * The source representing the compilation unit being visited.
11647 */
11648 final Source source;
11649
11650 /**
11651 * The error listener that will be informed of any errors that are found durin g resolution.
11652 */
11653 AnalysisErrorListener _errorListener;
11654
11655 /**
11656 * The scope used to resolve identifiers.
11657 */
11658 Scope nameScope;
11659
11660 /**
11661 * The object used to access the types from the core library.
11662 */
11663 final TypeProvider typeProvider;
11664
11665 /**
11666 * The scope used to resolve unlabeled `break` and `continue` statements.
11667 */
11668 ImplicitLabelScope _implicitLabelScope = ImplicitLabelScope.ROOT;
11669
11670 /**
11671 * The scope used to resolve labels for `break` and `continue` statements, or
11672 * `null` if no labels have been defined in the current context.
11673 */
11674 LabelScope labelScope;
11675
11676 /**
11677 * The class containing the AST nodes being visited,
11678 * or `null` if we are not in the scope of a class.
11679 */
11680 ClassElement enclosingClass;
11681
11682 /**
11683 * Initialize a newly created visitor to resolve the nodes in a compilation
11684 * unit.
11685 *
11686 * [definingLibrary] is the element for the library containing the
11687 * compilation unit being visited.
11688 * [source] is the source representing the compilation unit being visited.
11689 * [typeProvider] is the object used to access the types from the core
11690 * library.
11691 * [errorListener] is the error listener that will be informed of any errors
11692 * that are found during resolution.
11693 * [nameScope] is the scope used to resolve identifiers in the node that will
11694 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
11695 * created based on [definingLibrary] and [typeProvider].
11696 */
11697 ScopedVisitor(LibraryElement definingLibrary, this.source, this.typeProvider,
11698 AnalysisErrorListener errorListener, {Scope nameScope}) {
11699 this._definingLibrary = definingLibrary;
11700 this._errorListener = errorListener;
11701 if (nameScope == null) {
11702 this.nameScope = new LibraryScope(definingLibrary, errorListener);
11703 } else {
11704 this.nameScope = nameScope;
11705 }
11706 }
11707
11708 /**
11709 * Return the library element for the library containing the compilation unit being resolved.
11710 *
11711 * @return the library element for the library containing the compilation unit being resolved
11712 */
11713 LibraryElement get definingLibrary => _definingLibrary;
11714
11715 /**
11716 * Return the implicit label scope in which the current node is being
11717 * resolved.
11718 */
11719 ImplicitLabelScope get implicitLabelScope => _implicitLabelScope;
11720
11721 /**
11722 * Replaces the current [Scope] with the enclosing [Scope].
11723 *
11724 * @return the enclosing [Scope].
11725 */
11726 Scope popNameScope() {
11727 nameScope = nameScope.enclosingScope;
11728 return nameScope;
11729 }
11730
11731 /**
11732 * Pushes a new [Scope] into the visitor.
11733 *
11734 * @return the new [Scope].
11735 */
11736 Scope pushNameScope() {
11737 Scope newScope = new EnclosedScope(nameScope);
11738 nameScope = newScope;
11739 return nameScope;
11740 }
11741
11742 /**
11743 * Report an error with the given error code and arguments.
11744 *
11745 * @param errorCode the error code of the error to be reported
11746 * @param node the node specifying the location of the error
11747 * @param arguments the arguments to the error, used to compose the error mess age
11748 */
11749 void reportErrorForNode(ErrorCode errorCode, AstNode node,
11750 [List<Object> arguments]) {
11751 _errorListener.onError(new AnalysisError(
11752 source, node.offset, node.length, errorCode, arguments));
11753 }
11754
11755 /**
11756 * Report an error with the given error code and arguments.
11757 *
11758 * @param errorCode the error code of the error to be reported
11759 * @param offset the offset of the location of the error
11760 * @param length the length of the location of the error
11761 * @param arguments the arguments to the error, used to compose the error mess age
11762 */
11763 void reportErrorForOffset(ErrorCode errorCode, int offset, int length,
11764 [List<Object> arguments]) {
11765 _errorListener.onError(
11766 new AnalysisError(source, offset, length, errorCode, arguments));
11767 }
11768
11769 /**
11770 * Report an error with the given error code and arguments.
11771 *
11772 * @param errorCode the error code of the error to be reported
11773 * @param token the token specifying the location of the error
11774 * @param arguments the arguments to the error, used to compose the error mess age
11775 */
11776 void reportErrorForToken(ErrorCode errorCode, sc.Token token,
11777 [List<Object> arguments]) {
11778 _errorListener.onError(new AnalysisError(
11779 source, token.offset, token.length, errorCode, arguments));
11780 }
11781
11782 /**
11783 * Visit the given AST node if it is not null.
11784 *
11785 * @param node the node to be visited
11786 */
11787 void safelyVisit(AstNode node) {
11788 if (node != null) {
11789 node.accept(this);
11790 }
11791 }
11792
11793 @override
11794 Object visitBlock(Block node) {
11795 Scope outerScope = nameScope;
11796 try {
11797 EnclosedScope enclosedScope = new EnclosedScope(nameScope);
11798 _hideNamesDefinedInBlock(enclosedScope, node);
11799 nameScope = enclosedScope;
11800 super.visitBlock(node);
11801 } finally {
11802 nameScope = outerScope;
11803 }
11804 return null;
11805 }
11806
11807 @override
11808 Object visitBlockFunctionBody(BlockFunctionBody node) {
11809 ImplicitLabelScope implicitOuterScope = _implicitLabelScope;
11810 try {
11811 _implicitLabelScope = ImplicitLabelScope.ROOT;
11812 super.visitBlockFunctionBody(node);
11813 } finally {
11814 _implicitLabelScope = implicitOuterScope;
11815 }
11816 return null;
11817 }
11818
11819 @override
11820 Object visitCatchClause(CatchClause node) {
11821 SimpleIdentifier exception = node.exceptionParameter;
11822 if (exception != null) {
11823 Scope outerScope = nameScope;
11824 try {
11825 nameScope = new EnclosedScope(nameScope);
11826 nameScope.define(exception.staticElement);
11827 SimpleIdentifier stackTrace = node.stackTraceParameter;
11828 if (stackTrace != null) {
11829 nameScope.define(stackTrace.staticElement);
11830 }
11831 super.visitCatchClause(node);
11832 } finally {
11833 nameScope = outerScope;
11834 }
11835 } else {
11836 super.visitCatchClause(node);
11837 }
11838 return null;
11839 }
11840
11841 @override
11842 Object visitClassDeclaration(ClassDeclaration node) {
11843 ClassElement classElement = node.element;
11844 Scope outerScope = nameScope;
11845 try {
11846 if (classElement == null) {
11847 AnalysisEngine.instance.logger.logInformation(
11848 "Missing element for class declaration ${node.name.name} in ${defini ngLibrary.source.fullName}",
11849 new CaughtException(new AnalysisException(), null));
11850 super.visitClassDeclaration(node);
11851 } else {
11852 ClassElement outerClass = enclosingClass;
11853 try {
11854 enclosingClass = node.element;
11855 nameScope = new TypeParameterScope(nameScope, classElement);
11856 visitClassDeclarationInScope(node);
11857 nameScope = new ClassScope(nameScope, classElement);
11858 visitClassMembersInScope(node);
11859 } finally {
11860 enclosingClass = outerClass;
11861 }
11862 }
11863 } finally {
11864 nameScope = outerScope;
11865 }
11866 return null;
11867 }
11868
11869 void visitClassDeclarationInScope(ClassDeclaration node) {
11870 safelyVisit(node.name);
11871 safelyVisit(node.typeParameters);
11872 safelyVisit(node.extendsClause);
11873 safelyVisit(node.withClause);
11874 safelyVisit(node.implementsClause);
11875 safelyVisit(node.nativeClause);
11876 }
11877
11878 void visitClassMembersInScope(ClassDeclaration node) {
11879 safelyVisit(node.documentationComment);
11880 node.metadata.accept(this);
11881 node.members.accept(this);
11882 }
11883
11884 @override
11885 Object visitClassTypeAlias(ClassTypeAlias node) {
11886 Scope outerScope = nameScope;
11887 try {
11888 ClassElement element = node.element;
11889 nameScope =
11890 new ClassScope(new TypeParameterScope(nameScope, element), element);
11891 super.visitClassTypeAlias(node);
11892 } finally {
11893 nameScope = outerScope;
11894 }
11895 return null;
11896 }
11897
11898 @override
11899 Object visitConstructorDeclaration(ConstructorDeclaration node) {
11900 ConstructorElement constructorElement = node.element;
11901 Scope outerScope = nameScope;
11902 try {
11903 if (constructorElement == null) {
11904 StringBuffer buffer = new StringBuffer();
11905 buffer.write("Missing element for constructor ");
11906 buffer.write(node.returnType.name);
11907 if (node.name != null) {
11908 buffer.write(".");
11909 buffer.write(node.name.name);
11910 }
11911 buffer.write(" in ");
11912 buffer.write(definingLibrary.source.fullName);
11913 AnalysisEngine.instance.logger.logInformation(buffer.toString(),
11914 new CaughtException(new AnalysisException(), null));
11915 } else {
11916 nameScope = new FunctionScope(nameScope, constructorElement);
11917 }
11918 super.visitConstructorDeclaration(node);
11919 } finally {
11920 nameScope = outerScope;
11921 }
11922 return null;
11923 }
11924
11925 @override
11926 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
11927 VariableElement element = node.element;
11928 if (element != null) {
11929 nameScope.define(element);
11930 }
11931 super.visitDeclaredIdentifier(node);
11932 return null;
11933 }
11934
11935 @override
11936 Object visitDoStatement(DoStatement node) {
11937 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
11938 try {
11939 _implicitLabelScope = _implicitLabelScope.nest(node);
11940 visitStatementInScope(node.body);
11941 safelyVisit(node.condition);
11942 } finally {
11943 _implicitLabelScope = outerImplicitScope;
11944 }
11945 return null;
11946 }
11947
11948 @override
11949 Object visitForEachStatement(ForEachStatement node) {
11950 Scope outerNameScope = nameScope;
11951 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
11952 try {
11953 nameScope = new EnclosedScope(nameScope);
11954 _implicitLabelScope = _implicitLabelScope.nest(node);
11955 visitForEachStatementInScope(node);
11956 } finally {
11957 nameScope = outerNameScope;
11958 _implicitLabelScope = outerImplicitScope;
11959 }
11960 return null;
11961 }
11962
11963 /**
11964 * Visit the given statement after it's scope has been created. This replaces the normal call to
11965 * the inherited visit method so that ResolverVisitor can intervene when type propagation is
11966 * enabled.
11967 *
11968 * @param node the statement to be visited
11969 */
11970 void visitForEachStatementInScope(ForEachStatement node) {
11971 //
11972 // We visit the iterator before the loop variable because the loop variable
11973 // cannot be in scope while visiting the iterator.
11974 //
11975 safelyVisit(node.identifier);
11976 safelyVisit(node.iterable);
11977 safelyVisit(node.loopVariable);
11978 visitStatementInScope(node.body);
11979 }
11980
11981 @override
11982 Object visitFormalParameterList(FormalParameterList node) {
11983 super.visitFormalParameterList(node);
11984 // We finished resolving function signature, now include formal parameters
11985 // scope. Note: we must not do this if the parent is a
11986 // FunctionTypedFormalParameter, because in that case we aren't finished
11987 // resolving the full function signature, just a part of it.
11988 if (nameScope is FunctionScope &&
11989 node.parent is! FunctionTypedFormalParameter) {
11990 (nameScope as FunctionScope).defineParameters();
11991 }
11992 if (nameScope is FunctionTypeScope) {
11993 (nameScope as FunctionTypeScope).defineParameters();
11994 }
11995 return null;
11996 }
11997
11998 @override
11999 Object visitForStatement(ForStatement node) {
12000 Scope outerNameScope = nameScope;
12001 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12002 try {
12003 nameScope = new EnclosedScope(nameScope);
12004 _implicitLabelScope = _implicitLabelScope.nest(node);
12005 visitForStatementInScope(node);
12006 } finally {
12007 nameScope = outerNameScope;
12008 _implicitLabelScope = outerImplicitScope;
12009 }
12010 return null;
12011 }
12012
12013 /**
12014 * Visit the given statement after it's scope has been created. This replaces the normal call to
12015 * the inherited visit method so that ResolverVisitor can intervene when type propagation is
12016 * enabled.
12017 *
12018 * @param node the statement to be visited
12019 */
12020 void visitForStatementInScope(ForStatement node) {
12021 safelyVisit(node.variables);
12022 safelyVisit(node.initialization);
12023 safelyVisit(node.condition);
12024 node.updaters.accept(this);
12025 visitStatementInScope(node.body);
12026 }
12027
12028 @override
12029 Object visitFunctionDeclaration(FunctionDeclaration node) {
12030 ExecutableElement functionElement = node.element;
12031 if (functionElement != null &&
12032 functionElement.enclosingElement is! CompilationUnitElement) {
12033 nameScope.define(functionElement);
12034 }
12035 Scope outerScope = nameScope;
12036 try {
12037 if (functionElement == null) {
12038 AnalysisEngine.instance.logger.logInformation(
12039 "Missing element for top-level function ${node.name.name} in ${defin ingLibrary.source.fullName}",
12040 new CaughtException(new AnalysisException(), null));
12041 } else {
12042 nameScope = new FunctionScope(nameScope, functionElement);
12043 }
12044 super.visitFunctionDeclaration(node);
12045 } finally {
12046 nameScope = outerScope;
12047 }
12048 return null;
12049 }
12050
12051 @override
12052 Object visitFunctionExpression(FunctionExpression node) {
12053 if (node.parent is FunctionDeclaration) {
12054 // We have already created a function scope and don't need to do so again.
12055 super.visitFunctionExpression(node);
12056 } else {
12057 Scope outerScope = nameScope;
12058 try {
12059 ExecutableElement functionElement = node.element;
12060 if (functionElement == null) {
12061 StringBuffer buffer = new StringBuffer();
12062 buffer.write("Missing element for function ");
12063 AstNode parent = node.parent;
12064 while (parent != null) {
12065 if (parent is Declaration) {
12066 Element parentElement = parent.element;
12067 buffer.write(parentElement == null
12068 ? "<unknown> "
12069 : "${parentElement.name} ");
12070 }
12071 parent = parent.parent;
12072 }
12073 buffer.write("in ");
12074 buffer.write(definingLibrary.source.fullName);
12075 AnalysisEngine.instance.logger.logInformation(buffer.toString(),
12076 new CaughtException(new AnalysisException(), null));
12077 } else {
12078 nameScope = new FunctionScope(nameScope, functionElement);
12079 }
12080 super.visitFunctionExpression(node);
12081 } finally {
12082 nameScope = outerScope;
12083 }
12084 }
12085 return null;
12086 }
12087
12088 @override
12089 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
12090 Scope outerScope = nameScope;
12091 try {
12092 nameScope = new FunctionTypeScope(nameScope, node.element);
12093 super.visitFunctionTypeAlias(node);
12094 } finally {
12095 nameScope = outerScope;
12096 }
12097 return null;
12098 }
12099
12100 @override
12101 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
12102 Scope outerScope = nameScope;
12103 try {
12104 ParameterElement parameterElement = node.element;
12105 if (parameterElement == null) {
12106 AnalysisEngine.instance.logger.logInformation(
12107 "Missing element for function typed formal parameter ${node.identifi er.name} in ${definingLibrary.source.fullName}",
12108 new CaughtException(new AnalysisException(), null));
12109 } else {
12110 nameScope = new EnclosedScope(nameScope);
12111 for (TypeParameterElement typeParameter
12112 in parameterElement.typeParameters) {
12113 nameScope.define(typeParameter);
12114 }
12115 }
12116 super.visitFunctionTypedFormalParameter(node);
12117 } finally {
12118 nameScope = outerScope;
12119 }
12120 return null;
12121 }
12122
12123 @override
12124 Object visitIfStatement(IfStatement node) {
12125 safelyVisit(node.condition);
12126 visitStatementInScope(node.thenStatement);
12127 visitStatementInScope(node.elseStatement);
12128 return null;
12129 }
12130
12131 @override
12132 Object visitLabeledStatement(LabeledStatement node) {
12133 LabelScope outerScope = _addScopesFor(node.labels, node.unlabeled);
12134 try {
12135 super.visitLabeledStatement(node);
12136 } finally {
12137 labelScope = outerScope;
12138 }
12139 return null;
12140 }
12141
12142 @override
12143 Object visitMethodDeclaration(MethodDeclaration node) {
12144 Scope outerScope = nameScope;
12145 try {
12146 ExecutableElement methodElement = node.element;
12147 if (methodElement == null) {
12148 AnalysisEngine.instance.logger.logInformation(
12149 "Missing element for method ${node.name.name} in ${definingLibrary.s ource.fullName}",
12150 new CaughtException(new AnalysisException(), null));
12151 } else {
12152 nameScope = new FunctionScope(nameScope, methodElement);
12153 }
12154 super.visitMethodDeclaration(node);
12155 } finally {
12156 nameScope = outerScope;
12157 }
12158 return null;
12159 }
12160
12161 /**
12162 * Visit the given statement after it's scope has been created. This is used b y ResolverVisitor to
12163 * correctly visit the 'then' and 'else' statements of an 'if' statement.
12164 *
12165 * @param node the statement to be visited
12166 */
12167 void visitStatementInScope(Statement node) {
12168 if (node is Block) {
12169 // Don't create a scope around a block because the block will create it's
12170 // own scope.
12171 visitBlock(node);
12172 } else if (node != null) {
12173 Scope outerNameScope = nameScope;
12174 try {
12175 nameScope = new EnclosedScope(nameScope);
12176 node.accept(this);
12177 } finally {
12178 nameScope = outerNameScope;
12179 }
12180 }
12181 }
12182
12183 @override
12184 Object visitSwitchCase(SwitchCase node) {
12185 node.expression.accept(this);
12186 Scope outerNameScope = nameScope;
12187 try {
12188 nameScope = new EnclosedScope(nameScope);
12189 node.statements.accept(this);
12190 } finally {
12191 nameScope = outerNameScope;
12192 }
12193 return null;
12194 }
12195
12196 @override
12197 Object visitSwitchDefault(SwitchDefault node) {
12198 Scope outerNameScope = nameScope;
12199 try {
12200 nameScope = new EnclosedScope(nameScope);
12201 node.statements.accept(this);
12202 } finally {
12203 nameScope = outerNameScope;
12204 }
12205 return null;
12206 }
12207
12208 @override
12209 Object visitSwitchStatement(SwitchStatement node) {
12210 LabelScope outerScope = labelScope;
12211 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12212 try {
12213 _implicitLabelScope = _implicitLabelScope.nest(node);
12214 for (SwitchMember member in node.members) {
12215 for (Label label in member.labels) {
12216 SimpleIdentifier labelName = label.label;
12217 LabelElement labelElement = labelName.staticElement as LabelElement;
12218 labelScope =
12219 new LabelScope(labelScope, labelName.name, member, labelElement);
12220 }
12221 }
12222 super.visitSwitchStatement(node);
12223 } finally {
12224 labelScope = outerScope;
12225 _implicitLabelScope = outerImplicitScope;
12226 }
12227 return null;
12228 }
12229
12230 @override
12231 Object visitVariableDeclaration(VariableDeclaration node) {
12232 super.visitVariableDeclaration(node);
12233 if (node.parent.parent is! TopLevelVariableDeclaration &&
12234 node.parent.parent is! FieldDeclaration) {
12235 VariableElement element = node.element;
12236 if (element != null) {
12237 nameScope.define(element);
12238 }
12239 }
12240 return null;
12241 }
12242
12243 @override
12244 Object visitWhileStatement(WhileStatement node) {
12245 safelyVisit(node.condition);
12246 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12247 try {
12248 _implicitLabelScope = _implicitLabelScope.nest(node);
12249 visitStatementInScope(node.body);
12250 } finally {
12251 _implicitLabelScope = outerImplicitScope;
12252 }
12253 return null;
12254 }
12255
12256 /**
12257 * Add scopes for each of the given labels.
12258 *
12259 * @param labels the labels for which new scopes are to be added
12260 * @return the scope that was in effect before the new scopes were added
12261 */
12262 LabelScope _addScopesFor(NodeList<Label> labels, AstNode node) {
12263 LabelScope outerScope = labelScope;
12264 for (Label label in labels) {
12265 SimpleIdentifier labelNameNode = label.label;
12266 String labelName = labelNameNode.name;
12267 LabelElement labelElement = labelNameNode.staticElement as LabelElement;
12268 labelScope = new LabelScope(labelScope, labelName, node, labelElement);
12269 }
12270 return outerScope;
12271 }
12272
12273 /**
12274 * Marks the local declarations of the given [Block] hidden in the enclosing s cope.
12275 * According to the scoping rules name is hidden if block defines it, but name is defined after
12276 * its declaration statement.
12277 */
12278 void _hideNamesDefinedInBlock(EnclosedScope scope, Block block) {
12279 NodeList<Statement> statements = block.statements;
12280 int statementCount = statements.length;
12281 for (int i = 0; i < statementCount; i++) {
12282 Statement statement = statements[i];
12283 if (statement is VariableDeclarationStatement) {
12284 VariableDeclarationStatement vds = statement;
12285 NodeList<VariableDeclaration> variables = vds.variables.variables;
12286 int variableCount = variables.length;
12287 for (int j = 0; j < variableCount; j++) {
12288 scope.hide(variables[j].element);
12289 }
12290 } else if (statement is FunctionDeclarationStatement) {
12291 FunctionDeclarationStatement fds = statement;
12292 scope.hide(fds.functionDeclaration.element);
12293 }
12294 }
12295 }
12296 }
12297
12298 /**
12299 * Instances of this class manage the knowledge of what the set of subtypes are for a given type.
12300 */
12301 class SubtypeManager {
12302 /**
12303 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype s of the
12304 * key.
12305 */
12306 HashMap<ClassElement, HashSet<ClassElement>> _subtypeMap =
12307 new HashMap<ClassElement, HashSet<ClassElement>>();
12308
12309 /**
12310 * The set of all [LibraryElement]s that have been visited by the manager. Thi s is used both
12311 * to prevent infinite loops in the recursive methods, and also as a marker fo r the scope of the
12312 * libraries visited by this manager.
12313 */
12314 HashSet<LibraryElement> _visitedLibraries = new HashSet<LibraryElement>();
12315
12316 /**
12317 * Given some [ClassElement], return the set of all subtypes, and subtypes of subtypes.
12318 *
12319 * @param classElement the class to recursively return the set of subtypes of
12320 */
12321 HashSet<ClassElement> computeAllSubtypes(ClassElement classElement) {
12322 // Ensure that we have generated the subtype map for the library
12323 _computeSubtypesInLibrary(classElement.library);
12324 // use the subtypeMap to compute the set of all subtypes and subtype's
12325 // subtypes
12326 HashSet<ClassElement> allSubtypes = new HashSet<ClassElement>();
12327 _safelyComputeAllSubtypes(
12328 classElement, new HashSet<ClassElement>(), allSubtypes);
12329 return allSubtypes;
12330 }
12331
12332 /**
12333 * Given some [LibraryElement], visit all of the types in the library, the pas sed library,
12334 * and any imported libraries, will be in the [visitedLibraries] set.
12335 *
12336 * @param libraryElement the library to visit, it it hasn't been visited alrea dy
12337 */
12338 void ensureLibraryVisited(LibraryElement libraryElement) {
12339 _computeSubtypesInLibrary(libraryElement);
12340 }
12341
12342 /**
12343 * Given some [ClassElement], this method adds all of the pairs combinations o f itself and
12344 * all of its supertypes to the [subtypeMap] map.
12345 *
12346 * @param classElement the class element
12347 */
12348 void _computeSubtypesInClass(ClassElement classElement) {
12349 InterfaceType supertypeType = classElement.supertype;
12350 if (supertypeType != null) {
12351 ClassElement supertypeElement = supertypeType.element;
12352 if (supertypeElement != null) {
12353 _putInSubtypeMap(supertypeElement, classElement);
12354 }
12355 }
12356 List<InterfaceType> interfaceTypes = classElement.interfaces;
12357 for (InterfaceType interfaceType in interfaceTypes) {
12358 ClassElement interfaceElement = interfaceType.element;
12359 if (interfaceElement != null) {
12360 _putInSubtypeMap(interfaceElement, classElement);
12361 }
12362 }
12363 List<InterfaceType> mixinTypes = classElement.mixins;
12364 for (InterfaceType mixinType in mixinTypes) {
12365 ClassElement mixinElement = mixinType.element;
12366 if (mixinElement != null) {
12367 _putInSubtypeMap(mixinElement, classElement);
12368 }
12369 }
12370 }
12371
12372 /**
12373 * Given some [CompilationUnitElement], this method calls
12374 * [computeAllSubtypes] on all of the [ClassElement]s in the
12375 * compilation unit.
12376 *
12377 * @param unitElement the compilation unit element
12378 */
12379 void _computeSubtypesInCompilationUnit(CompilationUnitElement unitElement) {
12380 List<ClassElement> classElements = unitElement.types;
12381 for (ClassElement classElement in classElements) {
12382 _computeSubtypesInClass(classElement);
12383 }
12384 }
12385
12386 /**
12387 * Given some [LibraryElement], this method calls
12388 * [computeAllSubtypes] on all of the [ClassElement]s in the
12389 * compilation unit, and itself for all imported and exported libraries. All v isited libraries are
12390 * added to the [visitedLibraries] set.
12391 *
12392 * @param libraryElement the library element
12393 */
12394 void _computeSubtypesInLibrary(LibraryElement libraryElement) {
12395 if (libraryElement == null || _visitedLibraries.contains(libraryElement)) {
12396 return;
12397 }
12398 _visitedLibraries.add(libraryElement);
12399 _computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit);
12400 List<CompilationUnitElement> parts = libraryElement.parts;
12401 for (CompilationUnitElement part in parts) {
12402 _computeSubtypesInCompilationUnit(part);
12403 }
12404 List<LibraryElement> imports = libraryElement.importedLibraries;
12405 for (LibraryElement importElt in imports) {
12406 _computeSubtypesInLibrary(importElt.library);
12407 }
12408 List<LibraryElement> exports = libraryElement.exportedLibraries;
12409 for (LibraryElement exportElt in exports) {
12410 _computeSubtypesInLibrary(exportElt.library);
12411 }
12412 }
12413
12414 /**
12415 * Add some key/ value pair into the [subtypeMap] map.
12416 *
12417 * @param supertypeElement the key for the [subtypeMap] map
12418 * @param subtypeElement the value for the [subtypeMap] map
12419 */
12420 void _putInSubtypeMap(
12421 ClassElement supertypeElement, ClassElement subtypeElement) {
12422 HashSet<ClassElement> subtypes = _subtypeMap[supertypeElement];
12423 if (subtypes == null) {
12424 subtypes = new HashSet<ClassElement>();
12425 _subtypeMap[supertypeElement] = subtypes;
12426 }
12427 subtypes.add(subtypeElement);
12428 }
12429
12430 /**
12431 * Given some [ClassElement] and a [HashSet<ClassElement>], this method recurs ively
12432 * adds all of the subtypes of the [ClassElement] to the passed array.
12433 *
12434 * @param classElement the type to compute the set of subtypes of
12435 * @param visitedClasses the set of class elements that this method has alread y recursively seen
12436 * @param allSubtypes the computed set of subtypes of the passed class element
12437 */
12438 void _safelyComputeAllSubtypes(ClassElement classElement,
12439 HashSet<ClassElement> visitedClasses, HashSet<ClassElement> allSubtypes) {
12440 if (!visitedClasses.add(classElement)) {
12441 // if this class has already been called on this class element
12442 return;
12443 }
12444 HashSet<ClassElement> subtypes = _subtypeMap[classElement];
12445 if (subtypes == null) {
12446 return;
12447 }
12448 for (ClassElement subtype in subtypes) {
12449 _safelyComputeAllSubtypes(subtype, visitedClasses, allSubtypes);
12450 }
12451 allSubtypes.addAll(subtypes);
12452 }
12453 }
12454
12455 /**
12456 * Instances of the class `ToDoFinder` find to-do comments in Dart code.
12457 */
12458 class ToDoFinder {
12459 /**
12460 * The error reporter by which to-do comments will be reported.
12461 */
12462 final ErrorReporter _errorReporter;
12463
12464 /**
12465 * Initialize a newly created to-do finder to report to-do comments to the giv en reporter.
12466 *
12467 * @param errorReporter the error reporter by which to-do comments will be rep orted
12468 */
12469 ToDoFinder(this._errorReporter);
12470
12471 /**
12472 * Search the comments in the given compilation unit for to-do comments and re port an error for
12473 * each.
12474 *
12475 * @param unit the compilation unit containing the to-do comments
12476 */
12477 void findIn(CompilationUnit unit) {
12478 _gatherTodoComments(unit.beginToken);
12479 }
12480
12481 /**
12482 * Search the comment tokens reachable from the given token and create errors for each to-do
12483 * comment.
12484 *
12485 * @param token the head of the list of tokens being searched
12486 */
12487 void _gatherTodoComments(sc.Token token) {
12488 while (token != null && token.type != sc.TokenType.EOF) {
12489 sc.Token commentToken = token.precedingComments;
12490 while (commentToken != null) {
12491 if (commentToken.type == sc.TokenType.SINGLE_LINE_COMMENT ||
12492 commentToken.type == sc.TokenType.MULTI_LINE_COMMENT) {
12493 _scrapeTodoComment(commentToken);
12494 }
12495 commentToken = commentToken.next;
12496 }
12497 token = token.next;
12498 }
12499 }
12500
12501 /**
12502 * Look for user defined tasks in comments and convert them into info level an alysis issues.
12503 *
12504 * @param commentToken the comment token to analyze
12505 */
12506 void _scrapeTodoComment(sc.Token commentToken) {
12507 JavaPatternMatcher matcher =
12508 new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme);
12509 if (matcher.find()) {
12510 int offset =
12511 commentToken.offset + matcher.start() + matcher.group(1).length;
12512 int length = matcher.group(2).length;
12513 _errorReporter.reportErrorForOffset(
12514 TodoCode.TODO, offset, length, [matcher.group(2)]);
12515 }
12516 }
12517 }
12518
12519 /**
12520 * Instances of the class `TypeOverrideManager` manage the ability to override t he type of an
12521 * element within a given context.
12522 */
12523 class TypeOverrideManager {
12524 /**
12525 * The current override scope, or `null` if no scope has been entered.
12526 */
12527 TypeOverrideManager_TypeOverrideScope currentScope;
12528
12529 /**
12530 * Apply a set of overrides that were previously captured.
12531 *
12532 * @param overrides the overrides to be applied
12533 */
12534 void applyOverrides(Map<VariableElement, DartType> overrides) {
12535 if (currentScope == null) {
12536 throw new IllegalStateException("Cannot apply overrides without a scope");
12537 }
12538 currentScope.applyOverrides(overrides);
12539 }
12540
12541 /**
12542 * Return a table mapping the elements whose type is overridden in the current scope to the
12543 * overriding type.
12544 *
12545 * @return the overrides in the current scope
12546 */
12547 Map<VariableElement, DartType> captureLocalOverrides() {
12548 if (currentScope == null) {
12549 throw new IllegalStateException(
12550 "Cannot capture local overrides without a scope");
12551 }
12552 return currentScope.captureLocalOverrides();
12553 }
12554
12555 /**
12556 * Return a map from the elements for the variables in the given list that hav e their types
12557 * overridden to the overriding type.
12558 *
12559 * @param variableList the list of variables whose overriding types are to be captured
12560 * @return a table mapping elements to their overriding types
12561 */
12562 Map<VariableElement, DartType> captureOverrides(
12563 VariableDeclarationList variableList) {
12564 if (currentScope == null) {
12565 throw new IllegalStateException(
12566 "Cannot capture overrides without a scope");
12567 }
12568 return currentScope.captureOverrides(variableList);
12569 }
12570
12571 /**
12572 * Enter a new override scope.
12573 */
12574 void enterScope() {
12575 currentScope = new TypeOverrideManager_TypeOverrideScope(currentScope);
12576 }
12577
12578 /**
12579 * Exit the current override scope.
12580 */
12581 void exitScope() {
12582 if (currentScope == null) {
12583 throw new IllegalStateException("No scope to exit");
12584 }
12585 currentScope = currentScope._outerScope;
12586 }
12587
12588 /**
12589 * Return the best type information available for the given element. If the ty pe of the element
12590 * has been overridden, then return the overriding type. Otherwise, return the static type.
12591 *
12592 * @param element the element for which type information is to be returned
12593 * @return the best type information available for the given element
12594 */
12595 DartType getBestType(VariableElement element) {
12596 DartType bestType = getType(element);
12597 return bestType == null ? element.type : bestType;
12598 }
12599
12600 /**
12601 * Return the overridden type of the given element, or `null` if the type of t he element has
12602 * not been overridden.
12603 *
12604 * @param element the element whose type might have been overridden
12605 * @return the overridden type of the given element
12606 */
12607 DartType getType(Element element) {
12608 if (currentScope == null) {
12609 return null;
12610 }
12611 return currentScope.getType(element);
12612 }
12613
12614 /**
12615 * Update overrides assuming [perBranchOverrides] is the collection of
12616 * per-branch overrides for *all* branches flowing into a join point.
12617 *
12618 * If a variable type in any of branches is not the same as its type before
12619 * the branching, then its propagated type is reset to `null`.
12620 */
12621 void mergeOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) {
12622 for (Map<VariableElement, DartType> branch in perBranchOverrides) {
12623 branch.forEach((VariableElement variable, DartType branchType) {
12624 DartType currentType = currentScope.getType(variable);
12625 if (currentType != branchType) {
12626 currentScope.resetType(variable);
12627 }
12628 });
12629 }
12630 }
12631
12632 /**
12633 * Set the overridden type of the given element to the given type
12634 *
12635 * @param element the element whose type might have been overridden
12636 * @param type the overridden type of the given element
12637 */
12638 void setType(VariableElement element, DartType type) {
12639 if (currentScope == null) {
12640 throw new IllegalStateException("Cannot override without a scope");
12641 }
12642 currentScope.setType(element, type);
12643 }
12644 }
12645
12646 /**
12647 * Instances of the class `TypeOverrideScope` represent a scope in which the typ es of
12648 * elements can be overridden.
12649 */
12650 class TypeOverrideManager_TypeOverrideScope {
12651 /**
12652 * The outer scope in which types might be overridden.
12653 */
12654 final TypeOverrideManager_TypeOverrideScope _outerScope;
12655
12656 /**
12657 * A table mapping elements to the overridden type of that element.
12658 */
12659 Map<VariableElement, DartType> _overridenTypes =
12660 new HashMap<VariableElement, DartType>();
12661
12662 /**
12663 * Initialize a newly created scope to be an empty child of the given scope.
12664 *
12665 * @param outerScope the outer scope in which types might be overridden
12666 */
12667 TypeOverrideManager_TypeOverrideScope(this._outerScope);
12668
12669 /**
12670 * Apply a set of overrides that were previously captured.
12671 *
12672 * @param overrides the overrides to be applied
12673 */
12674 void applyOverrides(Map<VariableElement, DartType> overrides) {
12675 _overridenTypes.addAll(overrides);
12676 }
12677
12678 /**
12679 * Return a table mapping the elements whose type is overridden in the current scope to the
12680 * overriding type.
12681 *
12682 * @return the overrides in the current scope
12683 */
12684 Map<VariableElement, DartType> captureLocalOverrides() => _overridenTypes;
12685
12686 /**
12687 * Return a map from the elements for the variables in the given list that hav e their types
12688 * overridden to the overriding type.
12689 *
12690 * @param variableList the list of variables whose overriding types are to be captured
12691 * @return a table mapping elements to their overriding types
12692 */
12693 Map<VariableElement, DartType> captureOverrides(
12694 VariableDeclarationList variableList) {
12695 Map<VariableElement, DartType> overrides =
12696 new HashMap<VariableElement, DartType>();
12697 if (variableList.isConst || variableList.isFinal) {
12698 for (VariableDeclaration variable in variableList.variables) {
12699 VariableElement element = variable.element;
12700 if (element != null) {
12701 DartType type = _overridenTypes[element];
12702 if (type != null) {
12703 overrides[element] = type;
12704 }
12705 }
12706 }
12707 }
12708 return overrides;
12709 }
12710
12711 /**
12712 * Return the overridden type of the given element, or `null` if the type of t he element
12713 * has not been overridden.
12714 *
12715 * @param element the element whose type might have been overridden
12716 * @return the overridden type of the given element
12717 */
12718 DartType getType(Element element) {
12719 if (element is PropertyAccessorElement) {
12720 element = (element as PropertyAccessorElement).variable;
12721 }
12722 DartType type = _overridenTypes[element];
12723 if (_overridenTypes.containsKey(element)) {
12724 return type;
12725 }
12726 if (type != null) {
12727 return type;
12728 } else if (_outerScope != null) {
12729 return _outerScope.getType(element);
12730 }
12731 return null;
12732 }
12733
12734 /**
12735 * Clears the overridden type of the given [element].
12736 */
12737 void resetType(VariableElement element) {
12738 _overridenTypes[element] = null;
12739 }
12740
12741 /**
12742 * Set the overridden type of the given element to the given type
12743 *
12744 * @param element the element whose type might have been overridden
12745 * @param type the overridden type of the given element
12746 */
12747 void setType(VariableElement element, DartType type) {
12748 _overridenTypes[element] = type;
12749 }
12750 }
12751
12752 /**
12753 * Instances of the class `TypeParameterScope` implement the scope defined by th e type
12754 * parameters in a class.
12755 */
12756 class TypeParameterScope extends EnclosedScope {
12757 /**
12758 * Initialize a newly created scope enclosed within another scope.
12759 *
12760 * @param enclosingScope the scope in which this scope is lexically enclosed
12761 * @param typeElement the element representing the type represented by this sc ope
12762 */
12763 TypeParameterScope(Scope enclosingScope, ClassElement typeElement)
12764 : super(enclosingScope) {
12765 if (typeElement == null) {
12766 throw new IllegalArgumentException("class element cannot be null");
12767 }
12768 _defineTypeParameters(typeElement);
12769 }
12770
12771 /**
12772 * Define the type parameters for the class.
12773 *
12774 * @param typeElement the element representing the type represented by this sc ope
12775 */
12776 void _defineTypeParameters(ClassElement typeElement) {
12777 for (TypeParameterElement typeParameter in typeElement.typeParameters) {
12778 define(typeParameter);
12779 }
12780 }
12781 }
12782
12783 /**
12784 * Instances of the class `TypePromotionManager` manage the ability to promote t ypes of local
12785 * variables and formal parameters from their declared types based on control fl ow.
12786 */
12787 class TypePromotionManager {
12788 /**
12789 * The current promotion scope, or `null` if no scope has been entered.
12790 */
12791 TypePromotionManager_TypePromoteScope currentScope;
12792
12793 /**
12794 * Returns the elements with promoted types.
12795 */
12796 Iterable<Element> get promotedElements => currentScope.promotedElements;
12797
12798 /**
12799 * Enter a new promotions scope.
12800 */
12801 void enterScope() {
12802 currentScope = new TypePromotionManager_TypePromoteScope(currentScope);
12803 }
12804
12805 /**
12806 * Exit the current promotion scope.
12807 */
12808 void exitScope() {
12809 if (currentScope == null) {
12810 throw new IllegalStateException("No scope to exit");
12811 }
12812 currentScope = currentScope._outerScope;
12813 }
12814
12815 /**
12816 * Returns static type of the given variable - declared or promoted.
12817 *
12818 * @return the static type of the given variable - declared or promoted
12819 */
12820 DartType getStaticType(VariableElement variable) {
12821 DartType staticType = getType(variable);
12822 if (staticType == null) {
12823 staticType = variable.type;
12824 }
12825 return staticType;
12826 }
12827
12828 /**
12829 * Return the promoted type of the given element, or `null` if the type of the element has
12830 * not been promoted.
12831 *
12832 * @param element the element whose type might have been promoted
12833 * @return the promoted type of the given element
12834 */
12835 DartType getType(Element element) {
12836 if (currentScope == null) {
12837 return null;
12838 }
12839 return currentScope.getType(element);
12840 }
12841
12842 /**
12843 * Set the promoted type of the given element to the given type.
12844 *
12845 * @param element the element whose type might have been promoted
12846 * @param type the promoted type of the given element
12847 */
12848 void setType(Element element, DartType type) {
12849 if (currentScope == null) {
12850 throw new IllegalStateException("Cannot promote without a scope");
12851 }
12852 currentScope.setType(element, type);
12853 }
12854 }
12855
12856 /**
12857 * Instances of the class `TypePromoteScope` represent a scope in which the type s of
12858 * elements can be promoted.
12859 */
12860 class TypePromotionManager_TypePromoteScope {
12861 /**
12862 * The outer scope in which types might be promoter.
12863 */
12864 final TypePromotionManager_TypePromoteScope _outerScope;
12865
12866 /**
12867 * A table mapping elements to the promoted type of that element.
12868 */
12869 HashMap<Element, DartType> _promotedTypes = new HashMap<Element, DartType>();
12870
12871 /**
12872 * Initialize a newly created scope to be an empty child of the given scope.
12873 *
12874 * @param outerScope the outer scope in which types might be promoted
12875 */
12876 TypePromotionManager_TypePromoteScope(this._outerScope);
12877
12878 /**
12879 * Returns the elements with promoted types.
12880 */
12881 Iterable<Element> get promotedElements => _promotedTypes.keys.toSet();
12882
12883 /**
12884 * Return the promoted type of the given element, or `null` if the type of the element has
12885 * not been promoted.
12886 *
12887 * @param element the element whose type might have been promoted
12888 * @return the promoted type of the given element
12889 */
12890 DartType getType(Element element) {
12891 DartType type = _promotedTypes[element];
12892 if (type == null && element is PropertyAccessorElement) {
12893 type = _promotedTypes[element.variable];
12894 }
12895 if (type != null) {
12896 return type;
12897 } else if (_outerScope != null) {
12898 return _outerScope.getType(element);
12899 }
12900 return null;
12901 }
12902
12903 /**
12904 * Set the promoted type of the given element to the given type.
12905 *
12906 * @param element the element whose type might have been promoted
12907 * @param type the promoted type of the given element
12908 */
12909 void setType(Element element, DartType type) {
12910 _promotedTypes[element] = type;
12911 }
12912 }
12913
12914 /**
12915 * The interface `TypeProvider` defines the behavior of objects that provide acc ess to types
12916 * defined by the language.
12917 */
12918 abstract class TypeProvider {
12919 /**
12920 * Return the type representing the built-in type 'bool'.
12921 */
12922 InterfaceType get boolType;
12923
12924 /**
12925 * Return the type representing the type 'bottom'.
12926 */
12927 DartType get bottomType;
12928
12929 /**
12930 * Return the type representing the built-in type 'Deprecated'.
12931 */
12932 InterfaceType get deprecatedType;
12933
12934 /**
12935 * Return the type representing the built-in type 'double'.
12936 */
12937 InterfaceType get doubleType;
12938
12939 /**
12940 * Return the type representing the built-in type 'dynamic'.
12941 */
12942 DartType get dynamicType;
12943
12944 /**
12945 * Return the type representing the built-in type 'Function'.
12946 */
12947 InterfaceType get functionType;
12948
12949 /**
12950 * Return the type representing 'Future<dynamic>'.
12951 */
12952 InterfaceType get futureDynamicType;
12953
12954 /**
12955 * Return the type representing 'Future<Null>'.
12956 */
12957 InterfaceType get futureNullType;
12958
12959 /**
12960 * Return the type representing the built-in type 'Future'.
12961 */
12962 InterfaceType get futureType;
12963
12964 /**
12965 * Return the type representing the built-in type 'int'.
12966 */
12967 InterfaceType get intType;
12968
12969 /**
12970 * Return the type representing the type 'Iterable<dynamic>'.
12971 */
12972 InterfaceType get iterableDynamicType;
12973
12974 /**
12975 * Return the type representing the built-in type 'Iterable'.
12976 */
12977 InterfaceType get iterableType;
12978
12979 /**
12980 * Return the type representing the built-in type 'List'.
12981 */
12982 InterfaceType get listType;
12983
12984 /**
12985 * Return the type representing the built-in type 'Map'.
12986 */
12987 InterfaceType get mapType;
12988
12989 /**
12990 * Return a list containing all of the types that cannot be either extended or
12991 * implemented.
12992 */
12993 List<InterfaceType> get nonSubtypableTypes;
12994
12995 /**
12996 * Return a [DartObjectImpl] representing the `null` object.
12997 */
12998 DartObjectImpl get nullObject;
12999
13000 /**
13001 * Return the type representing the built-in type 'Null'.
13002 */
13003 InterfaceType get nullType;
13004
13005 /**
13006 * Return the type representing the built-in type 'num'.
13007 */
13008 InterfaceType get numType;
13009
13010 /**
13011 * Return the type representing the built-in type 'Object'.
13012 */
13013 InterfaceType get objectType;
13014
13015 /**
13016 * Return the type representing the built-in type 'StackTrace'.
13017 */
13018 InterfaceType get stackTraceType;
13019
13020 /**
13021 * Return the type representing 'Stream<dynamic>'.
13022 */
13023 InterfaceType get streamDynamicType;
13024
13025 /**
13026 * Return the type representing the built-in type 'Stream'.
13027 */
13028 InterfaceType get streamType;
13029
13030 /**
13031 * Return the type representing the built-in type 'String'.
13032 */
13033 InterfaceType get stringType;
13034
13035 /**
13036 * Return the type representing the built-in type 'Symbol'.
13037 */
13038 InterfaceType get symbolType;
13039
13040 /**
13041 * Return the type representing the built-in type 'Type'.
13042 */
13043 InterfaceType get typeType;
13044
13045 /**
13046 * Return the type representing typenames that can't be resolved.
13047 */
13048 DartType get undefinedType;
13049 }
13050
13051 /**
13052 * Instances of the class `TypeProviderImpl` provide access to types defined by the language
13053 * by looking for those types in the element model for the core library.
13054 */
13055 class TypeProviderImpl implements TypeProvider {
13056 /**
13057 * The type representing the built-in type 'bool'.
13058 */
13059 InterfaceType _boolType;
13060
13061 /**
13062 * The type representing the type 'bottom'.
13063 */
13064 DartType _bottomType;
13065
13066 /**
13067 * The type representing the built-in type 'double'.
13068 */
13069 InterfaceType _doubleType;
13070
13071 /**
13072 * The type representing the built-in type 'Deprecated'.
13073 */
13074 InterfaceType _deprecatedType;
13075
13076 /**
13077 * The type representing the built-in type 'dynamic'.
13078 */
13079 DartType _dynamicType;
13080
13081 /**
13082 * The type representing the built-in type 'Function'.
13083 */
13084 InterfaceType _functionType;
13085
13086 /**
13087 * The type representing 'Future<dynamic>'.
13088 */
13089 InterfaceType _futureDynamicType;
13090
13091 /**
13092 * The type representing 'Future<Null>'.
13093 */
13094 InterfaceType _futureNullType;
13095
13096 /**
13097 * The type representing the built-in type 'Future'.
13098 */
13099 InterfaceType _futureType;
13100
13101 /**
13102 * The type representing the built-in type 'int'.
13103 */
13104 InterfaceType _intType;
13105
13106 /**
13107 * The type representing 'Iterable<dynamic>'.
13108 */
13109 InterfaceType _iterableDynamicType;
13110
13111 /**
13112 * The type representing the built-in type 'Iterable'.
13113 */
13114 InterfaceType _iterableType;
13115
13116 /**
13117 * The type representing the built-in type 'List'.
13118 */
13119 InterfaceType _listType;
13120
13121 /**
13122 * The type representing the built-in type 'Map'.
13123 */
13124 InterfaceType _mapType;
13125
13126 /**
13127 * An shared object representing the value 'null'.
13128 */
13129 DartObjectImpl _nullObject;
13130
13131 /**
13132 * The type representing the type 'Null'.
13133 */
13134 InterfaceType _nullType;
13135
13136 /**
13137 * The type representing the built-in type 'num'.
13138 */
13139 InterfaceType _numType;
13140
13141 /**
13142 * The type representing the built-in type 'Object'.
13143 */
13144 InterfaceType _objectType;
13145
13146 /**
13147 * The type representing the built-in type 'StackTrace'.
13148 */
13149 InterfaceType _stackTraceType;
13150
13151 /**
13152 * The type representing 'Stream<dynamic>'.
13153 */
13154 InterfaceType _streamDynamicType;
13155
13156 /**
13157 * The type representing the built-in type 'Stream'.
13158 */
13159 InterfaceType _streamType;
13160
13161 /**
13162 * The type representing the built-in type 'String'.
13163 */
13164 InterfaceType _stringType;
13165
13166 /**
13167 * The type representing the built-in type 'Symbol'.
13168 */
13169 InterfaceType _symbolType;
13170
13171 /**
13172 * The type representing the built-in type 'Type'.
13173 */
13174 InterfaceType _typeType;
13175
13176 /**
13177 * The type representing typenames that can't be resolved.
13178 */
13179 DartType _undefinedType;
13180
13181 /**
13182 * Initialize a newly created type provider to provide the types defined in
13183 * the given [coreLibrary] and [asyncLibrary].
13184 */
13185 TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) {
13186 Namespace coreNamespace =
13187 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary);
13188 Namespace asyncNamespace =
13189 new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary);
13190 _initializeFrom(coreNamespace, asyncNamespace);
13191 }
13192
13193 /**
13194 * Initialize a newly created type provider to provide the types defined in
13195 * the given [Namespace]s.
13196 */
13197 TypeProviderImpl.forNamespaces(
13198 Namespace coreNamespace, Namespace asyncNamespace) {
13199 _initializeFrom(coreNamespace, asyncNamespace);
13200 }
13201
13202 @override
13203 InterfaceType get boolType => _boolType;
13204
13205 @override
13206 DartType get bottomType => _bottomType;
13207
13208 @override
13209 InterfaceType get deprecatedType => _deprecatedType;
13210
13211 @override
13212 InterfaceType get doubleType => _doubleType;
13213
13214 @override
13215 DartType get dynamicType => _dynamicType;
13216
13217 @override
13218 InterfaceType get functionType => _functionType;
13219
13220 @override
13221 InterfaceType get futureDynamicType => _futureDynamicType;
13222
13223 @override
13224 InterfaceType get futureNullType => _futureNullType;
13225
13226 @override
13227 InterfaceType get futureType => _futureType;
13228
13229 @override
13230 InterfaceType get intType => _intType;
13231
13232 @override
13233 InterfaceType get iterableDynamicType => _iterableDynamicType;
13234
13235 @override
13236 InterfaceType get iterableType => _iterableType;
13237
13238 @override
13239 InterfaceType get listType => _listType;
13240
13241 @override
13242 InterfaceType get mapType => _mapType;
13243
13244 @override
13245 List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
13246 nullType,
13247 numType,
13248 intType,
13249 doubleType,
13250 boolType,
13251 stringType
13252 ];
13253
13254 @override
13255 DartObjectImpl get nullObject {
13256 if (_nullObject == null) {
13257 _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
13258 }
13259 return _nullObject;
13260 }
13261
13262 @override
13263 InterfaceType get nullType => _nullType;
13264
13265 @override
13266 InterfaceType get numType => _numType;
13267
13268 @override
13269 InterfaceType get objectType => _objectType;
13270
13271 @override
13272 InterfaceType get stackTraceType => _stackTraceType;
13273
13274 @override
13275 InterfaceType get streamDynamicType => _streamDynamicType;
13276
13277 @override
13278 InterfaceType get streamType => _streamType;
13279
13280 @override
13281 InterfaceType get stringType => _stringType;
13282
13283 @override
13284 InterfaceType get symbolType => _symbolType;
13285
13286 @override
13287 InterfaceType get typeType => _typeType;
13288
13289 @override
13290 DartType get undefinedType => _undefinedType;
13291
13292 /**
13293 * Return the type with the given name from the given namespace, or `null` if there is no
13294 * class with the given name.
13295 *
13296 * @param namespace the namespace in which to search for the given name
13297 * @param typeName the name of the type being searched for
13298 * @return the type that was found
13299 */
13300 InterfaceType _getType(Namespace namespace, String typeName) {
13301 Element element = namespace.get(typeName);
13302 if (element == null) {
13303 AnalysisEngine.instance.logger
13304 .logInformation("No definition of type $typeName");
13305 return null;
13306 }
13307 return (element as ClassElement).type;
13308 }
13309
13310 /**
13311 * Initialize the types provided by this type provider from the given
13312 * [Namespace]s.
13313 */
13314 void _initializeFrom(Namespace coreNamespace, Namespace asyncNamespace) {
13315 _boolType = _getType(coreNamespace, "bool");
13316 _bottomType = BottomTypeImpl.instance;
13317 _deprecatedType = _getType(coreNamespace, "Deprecated");
13318 _doubleType = _getType(coreNamespace, "double");
13319 _dynamicType = DynamicTypeImpl.instance;
13320 _functionType = _getType(coreNamespace, "Function");
13321 _futureType = _getType(asyncNamespace, "Future");
13322 _intType = _getType(coreNamespace, "int");
13323 _iterableType = _getType(coreNamespace, "Iterable");
13324 _listType = _getType(coreNamespace, "List");
13325 _mapType = _getType(coreNamespace, "Map");
13326 _nullType = _getType(coreNamespace, "Null");
13327 _numType = _getType(coreNamespace, "num");
13328 _objectType = _getType(coreNamespace, "Object");
13329 _stackTraceType = _getType(coreNamespace, "StackTrace");
13330 _streamType = _getType(asyncNamespace, "Stream");
13331 _stringType = _getType(coreNamespace, "String");
13332 _symbolType = _getType(coreNamespace, "Symbol");
13333 _typeType = _getType(coreNamespace, "Type");
13334 _undefinedType = UndefinedTypeImpl.instance;
13335 _futureDynamicType = _futureType.substitute4(<DartType>[_dynamicType]);
13336 _futureNullType = _futureType.substitute4(<DartType>[_nullType]);
13337 _iterableDynamicType = _iterableType.substitute4(<DartType>[_dynamicType]);
13338 _streamDynamicType = _streamType.substitute4(<DartType>[_dynamicType]);
13339 }
13340 }
13341
13342 /**
13343 * Instances of the class `TypeResolverVisitor` are used to resolve the types as sociated with
13344 * the elements in the element model. This includes the types of superclasses, m ixins, interfaces,
13345 * fields, methods, parameters, and local variables. As a side-effect, this also finishes building
13346 * the type hierarchy.
13347 */
13348 class TypeResolverVisitor extends ScopedVisitor {
13349 /**
13350 * The type representing the type 'dynamic'.
13351 */
13352 DartType _dynamicType;
13353
13354 /**
13355 * The type representing typenames that can't be resolved.
13356 */
13357 DartType _undefinedType;
13358
13359 /**
13360 * The flag specifying if currently visited class references 'super' expressio n.
13361 */
13362 bool _hasReferenceToSuper = false;
13363
13364 /**
13365 * Initialize a newly created visitor to resolve the nodes in an AST node.
13366 *
13367 * [definingLibrary] is the element for the library containing the node being
13368 * visited.
13369 * [source] is the source representing the compilation unit containing the
13370 * node being visited.
13371 * [typeProvider] is the object used to access the types from the core
13372 * library.
13373 * [errorListener] is the error listener that will be informed of any errors
13374 * that are found during resolution.
13375 * [nameScope] is the scope used to resolve identifiers in the node that will
13376 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
13377 * created based on [definingLibrary] and [typeProvider].
13378 */
13379 TypeResolverVisitor(LibraryElement definingLibrary, Source source,
13380 TypeProvider typeProvider, AnalysisErrorListener errorListener,
13381 {Scope nameScope})
13382 : super(definingLibrary, source, typeProvider, errorListener,
13383 nameScope: nameScope) {
13384 _dynamicType = typeProvider.dynamicType;
13385 _undefinedType = typeProvider.undefinedType;
13386 }
13387
13388 @override
13389 Object visitAnnotation(Annotation node) {
13390 //
13391 // Visit annotations, if the annotation is @proxy, on a class, and "proxy"
13392 // resolves to the proxy annotation in dart.core, then create create the
13393 // ElementAnnotationImpl and set it as the metadata on the enclosing class.
13394 //
13395 // Element resolution is done in the ElementResolver, and this work will be
13396 // done in the general case for all annotations in the ElementResolver.
13397 // The reason we resolve this particular element early is so that
13398 // ClassElement.isProxy() returns the correct information during all
13399 // phases of the ElementResolver.
13400 //
13401 super.visitAnnotation(node);
13402 Identifier identifier = node.name;
13403 if (identifier.name.endsWith(ElementAnnotationImpl.PROXY_VARIABLE_NAME) &&
13404 node.parent is ClassDeclaration) {
13405 Element element = nameScope.lookup(identifier, definingLibrary);
13406 if (element != null &&
13407 element.library.isDartCore &&
13408 element is PropertyAccessorElement) {
13409 // This is the @proxy from dart.core
13410 ClassDeclaration classDeclaration = node.parent as ClassDeclaration;
13411 ElementAnnotationImpl elementAnnotation =
13412 new ElementAnnotationImpl(element);
13413 node.elementAnnotation = elementAnnotation;
13414 (classDeclaration.element as ClassElementImpl).metadata =
13415 <ElementAnnotationImpl>[elementAnnotation];
13416 }
13417 }
13418 return null;
13419 }
13420
13421 @override
13422 Object visitCatchClause(CatchClause node) {
13423 super.visitCatchClause(node);
13424 SimpleIdentifier exception = node.exceptionParameter;
13425 if (exception != null) {
13426 // If an 'on' clause is provided the type of the exception parameter is
13427 // the type in the 'on' clause. Otherwise, the type of the exception
13428 // parameter is 'Object'.
13429 TypeName exceptionTypeName = node.exceptionType;
13430 DartType exceptionType;
13431 if (exceptionTypeName == null) {
13432 exceptionType = typeProvider.dynamicType;
13433 } else {
13434 exceptionType = _getType(exceptionTypeName);
13435 }
13436 _recordType(exception, exceptionType);
13437 Element element = exception.staticElement;
13438 if (element is VariableElementImpl) {
13439 element.type = exceptionType;
13440 } else {
13441 // TODO(brianwilkerson) Report the internal error
13442 }
13443 }
13444 SimpleIdentifier stackTrace = node.stackTraceParameter;
13445 if (stackTrace != null) {
13446 _recordType(stackTrace, typeProvider.stackTraceType);
13447 Element element = stackTrace.staticElement;
13448 if (element is VariableElementImpl) {
13449 element.type = typeProvider.stackTraceType;
13450 } else {
13451 // TODO(brianwilkerson) Report the internal error
13452 }
13453 }
13454 return null;
13455 }
13456
13457 @override
13458 Object visitClassDeclaration(ClassDeclaration node) {
13459 _hasReferenceToSuper = false;
13460 super.visitClassDeclaration(node);
13461 ClassElementImpl classElement = _getClassElement(node.name);
13462 if (classElement != null) {
13463 classElement.hasReferenceToSuper = _hasReferenceToSuper;
13464 }
13465 return null;
13466 }
13467
13468 @override
13469 void visitClassDeclarationInScope(ClassDeclaration node) {
13470 super.visitClassDeclarationInScope(node);
13471 ExtendsClause extendsClause = node.extendsClause;
13472 WithClause withClause = node.withClause;
13473 ImplementsClause implementsClause = node.implementsClause;
13474 ClassElementImpl classElement = _getClassElement(node.name);
13475 InterfaceType superclassType = null;
13476 if (extendsClause != null) {
13477 ErrorCode errorCode = (withClause == null
13478 ? CompileTimeErrorCode.EXTENDS_NON_CLASS
13479 : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
13480 superclassType = _resolveType(extendsClause.superclass, errorCode,
13481 CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
13482 if (!identical(superclassType, typeProvider.objectType)) {
13483 classElement.validMixin = false;
13484 }
13485 }
13486 if (classElement != null) {
13487 if (superclassType == null) {
13488 InterfaceType objectType = typeProvider.objectType;
13489 if (!identical(classElement.type, objectType)) {
13490 superclassType = objectType;
13491 }
13492 }
13493 classElement.supertype = superclassType;
13494 }
13495 _resolve(classElement, withClause, implementsClause);
13496 return null;
13497 }
13498
13499 @override
13500 void visitClassMembersInScope(ClassDeclaration node) {
13501 //
13502 // Process field declarations before constructors and methods so that the
13503 // types of field formal parameters can be correctly resolved.
13504 //
13505 List<ClassMember> nonFields = new List<ClassMember>();
13506 node.visitChildren(
13507 new _TypeResolverVisitor_visitClassMembersInScope(this, nonFields));
13508 int count = nonFields.length;
13509 for (int i = 0; i < count; i++) {
13510 nonFields[i].accept(this);
13511 }
13512 }
13513
13514 @override
13515 Object visitClassTypeAlias(ClassTypeAlias node) {
13516 super.visitClassTypeAlias(node);
13517 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
13518 InterfaceType superclassType = _resolveType(node.superclass, errorCode,
13519 CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
13520 if (superclassType == null) {
13521 superclassType = typeProvider.objectType;
13522 }
13523 ClassElementImpl classElement = _getClassElement(node.name);
13524 if (classElement != null) {
13525 classElement.supertype = superclassType;
13526 }
13527 _resolve(classElement, node.withClause, node.implementsClause);
13528 return null;
13529 }
13530
13531 @override
13532 Object visitConstructorDeclaration(ConstructorDeclaration node) {
13533 super.visitConstructorDeclaration(node);
13534 ExecutableElementImpl element = node.element as ExecutableElementImpl;
13535 if (element == null) {
13536 ClassDeclaration classNode =
13537 node.getAncestor((node) => node is ClassDeclaration);
13538 StringBuffer buffer = new StringBuffer();
13539 buffer.write("The element for the constructor ");
13540 buffer.write(node.name == null ? "<unnamed>" : node.name.name);
13541 buffer.write(" in ");
13542 if (classNode == null) {
13543 buffer.write("<unknown class>");
13544 } else {
13545 buffer.write(classNode.name.name);
13546 }
13547 buffer.write(" in ");
13548 buffer.write(source.fullName);
13549 buffer.write(" was not set while trying to resolve types.");
13550 AnalysisEngine.instance.logger.logError(buffer.toString(),
13551 new CaughtException(new AnalysisException(), null));
13552 } else {
13553 ClassElement definingClass = element.enclosingElement as ClassElement;
13554 element.returnType = definingClass.type;
13555 FunctionTypeImpl type = new FunctionTypeImpl(element);
13556 type.typeArguments = definingClass.type.typeArguments;
13557 element.type = type;
13558 }
13559 return null;
13560 }
13561
13562 @override
13563 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
13564 super.visitDeclaredIdentifier(node);
13565 DartType declaredType;
13566 TypeName typeName = node.type;
13567 if (typeName == null) {
13568 declaredType = _dynamicType;
13569 } else {
13570 declaredType = _getType(typeName);
13571 }
13572 LocalVariableElementImpl element = node.element as LocalVariableElementImpl;
13573 element.type = declaredType;
13574 return null;
13575 }
13576
13577 @override
13578 Object visitFieldFormalParameter(FieldFormalParameter node) {
13579 super.visitFieldFormalParameter(node);
13580 Element element = node.identifier.staticElement;
13581 if (element is ParameterElementImpl) {
13582 ParameterElementImpl parameter = element;
13583 FormalParameterList parameterList = node.parameters;
13584 if (parameterList == null) {
13585 DartType type;
13586 TypeName typeName = node.type;
13587 if (typeName == null) {
13588 type = _dynamicType;
13589 if (parameter is FieldFormalParameterElement) {
13590 FieldElement fieldElement =
13591 (parameter as FieldFormalParameterElement).field;
13592 if (fieldElement != null) {
13593 type = fieldElement.type;
13594 }
13595 }
13596 } else {
13597 type = _getType(typeName);
13598 }
13599 parameter.type = type;
13600 } else {
13601 _setFunctionTypedParameterType(parameter, node.type, node.parameters);
13602 }
13603 } else {
13604 // TODO(brianwilkerson) Report this internal error
13605 }
13606 return null;
13607 }
13608
13609 @override
13610 Object visitFunctionDeclaration(FunctionDeclaration node) {
13611 super.visitFunctionDeclaration(node);
13612 ExecutableElementImpl element = node.element as ExecutableElementImpl;
13613 if (element == null) {
13614 StringBuffer buffer = new StringBuffer();
13615 buffer.write("The element for the top-level function ");
13616 buffer.write(node.name);
13617 buffer.write(" in ");
13618 buffer.write(source.fullName);
13619 buffer.write(" was not set while trying to resolve types.");
13620 AnalysisEngine.instance.logger.logError(buffer.toString(),
13621 new CaughtException(new AnalysisException(), null));
13622 }
13623 element.returnType = _computeReturnType(node.returnType);
13624 FunctionTypeImpl type = new FunctionTypeImpl(element);
13625 ClassElement definingClass =
13626 element.getAncestor((element) => element is ClassElement);
13627 if (definingClass != null) {
13628 type.typeArguments = definingClass.type.typeArguments;
13629 }
13630 element.type = type;
13631 return null;
13632 }
13633
13634 @override
13635 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
13636 FunctionTypeAliasElementImpl element =
13637 node.element as FunctionTypeAliasElementImpl;
13638 super.visitFunctionTypeAlias(node);
13639 element.returnType = _computeReturnType(node.returnType);
13640 return null;
13641 }
13642
13643 @override
13644 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
13645 super.visitFunctionTypedFormalParameter(node);
13646 Element element = node.identifier.staticElement;
13647 if (element is ParameterElementImpl) {
13648 _setFunctionTypedParameterType(element, node.returnType, node.parameters);
13649 } else {
13650 // TODO(brianwilkerson) Report this internal error
13651 }
13652 return null;
13653 }
13654
13655 @override
13656 Object visitMethodDeclaration(MethodDeclaration node) {
13657 super.visitMethodDeclaration(node);
13658 ExecutableElementImpl element = node.element as ExecutableElementImpl;
13659 if (element == null) {
13660 ClassDeclaration classNode =
13661 node.getAncestor((node) => node is ClassDeclaration);
13662 StringBuffer buffer = new StringBuffer();
13663 buffer.write("The element for the method ");
13664 buffer.write(node.name.name);
13665 buffer.write(" in ");
13666 if (classNode == null) {
13667 buffer.write("<unknown class>");
13668 } else {
13669 buffer.write(classNode.name.name);
13670 }
13671 buffer.write(" in ");
13672 buffer.write(source.fullName);
13673 buffer.write(" was not set while trying to resolve types.");
13674 AnalysisEngine.instance.logger.logError(buffer.toString(),
13675 new CaughtException(new AnalysisException(), null));
13676 }
13677 element.returnType = _computeReturnType(node.returnType);
13678 FunctionTypeImpl type = new FunctionTypeImpl(element);
13679 ClassElement definingClass =
13680 element.getAncestor((element) => element is ClassElement);
13681 if (definingClass != null) {
13682 type.typeArguments = definingClass.type.typeArguments;
13683 }
13684 element.type = type;
13685 if (element is PropertyAccessorElement) {
13686 PropertyAccessorElement accessor = element as PropertyAccessorElement;
13687 PropertyInducingElementImpl variable =
13688 accessor.variable as PropertyInducingElementImpl;
13689 if (accessor.isGetter) {
13690 variable.type = type.returnType;
13691 } else if (variable.type == null) {
13692 List<DartType> parameterTypes = type.normalParameterTypes;
13693 if (parameterTypes != null && parameterTypes.length > 0) {
13694 variable.type = parameterTypes[0];
13695 }
13696 }
13697 }
13698 return null;
13699 }
13700
13701 @override
13702 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
13703 super.visitSimpleFormalParameter(node);
13704 DartType declaredType;
13705 TypeName typeName = node.type;
13706 if (typeName == null) {
13707 declaredType = _dynamicType;
13708 } else {
13709 declaredType = _getType(typeName);
13710 }
13711 Element element = node.identifier.staticElement;
13712 if (element is ParameterElement) {
13713 (element as ParameterElementImpl).type = declaredType;
13714 } else {
13715 // TODO(brianwilkerson) Report the internal error.
13716 }
13717 return null;
13718 }
13719
13720 @override
13721 Object visitSuperExpression(SuperExpression node) {
13722 _hasReferenceToSuper = true;
13723 return super.visitSuperExpression(node);
13724 }
13725
13726 @override
13727 Object visitTypeName(TypeName node) {
13728 super.visitTypeName(node);
13729 Identifier typeName = node.name;
13730 TypeArgumentList argumentList = node.typeArguments;
13731 Element element = nameScope.lookup(typeName, definingLibrary);
13732 if (element == null) {
13733 //
13734 // Check to see whether the type name is either 'dynamic' or 'void',
13735 // neither of which are in the name scope and hence will not be found by
13736 // normal means.
13737 //
13738 if (typeName.name == _dynamicType.name) {
13739 _setElement(typeName, _dynamicType.element);
13740 if (argumentList != null) {
13741 // TODO(brianwilkerson) Report this error
13742 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, dynamicType.getName(), 0, argumentList.getArguments().size());
13743 }
13744 typeName.staticType = _dynamicType;
13745 node.type = _dynamicType;
13746 return null;
13747 }
13748 VoidTypeImpl voidType = VoidTypeImpl.instance;
13749 if (typeName.name == voidType.name) {
13750 // There is no element for 'void'.
13751 if (argumentList != null) {
13752 // TODO(brianwilkerson) Report this error
13753 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, voidType.getName(), 0, argumentList.getArguments().size());
13754 }
13755 typeName.staticType = voidType;
13756 node.type = voidType;
13757 return null;
13758 }
13759 //
13760 // If not, the look to see whether we might have created the wrong AST
13761 // structure for a constructor name. If so, fix the AST structure and then
13762 // proceed.
13763 //
13764 AstNode parent = node.parent;
13765 if (typeName is PrefixedIdentifier &&
13766 parent is ConstructorName &&
13767 argumentList == null) {
13768 ConstructorName name = parent;
13769 if (name.name == null) {
13770 PrefixedIdentifier prefixedIdentifier =
13771 typeName as PrefixedIdentifier;
13772 SimpleIdentifier prefix = prefixedIdentifier.prefix;
13773 element = nameScope.lookup(prefix, definingLibrary);
13774 if (element is PrefixElement) {
13775 if (parent.parent is InstanceCreationExpression &&
13776 (parent.parent as InstanceCreationExpression).isConst) {
13777 // If, if this is a const expression, then generate a
13778 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
13779 reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE,
13780 prefixedIdentifier.identifier,
13781 [prefixedIdentifier.identifier.name]);
13782 } else {
13783 // Else, if this expression is a new expression, report a
13784 // NEW_WITH_NON_TYPE warning.
13785 reportErrorForNode(StaticWarningCode.NEW_WITH_NON_TYPE,
13786 prefixedIdentifier.identifier,
13787 [prefixedIdentifier.identifier.name]);
13788 }
13789 _setElement(prefix, element);
13790 return null;
13791 } else if (element != null) {
13792 //
13793 // Rewrite the constructor name. The parser, when it sees a
13794 // constructor named "a.b", cannot tell whether "a" is a prefix and
13795 // "b" is a class name, or whether "a" is a class name and "b" is a
13796 // constructor name. It arbitrarily chooses the former, but in this
13797 // case was wrong.
13798 //
13799 name.name = prefixedIdentifier.identifier;
13800 name.period = prefixedIdentifier.period;
13801 node.name = prefix;
13802 typeName = prefix;
13803 }
13804 }
13805 }
13806 }
13807 // check element
13808 bool elementValid = element is! MultiplyDefinedElement;
13809 if (elementValid &&
13810 element is! ClassElement &&
13811 _isTypeNameInInstanceCreationExpression(node)) {
13812 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
13813 InstanceCreationExpression creation =
13814 node.parent.parent as InstanceCreationExpression;
13815 if (creation.isConst) {
13816 if (element == null) {
13817 reportErrorForNode(
13818 CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
13819 } else {
13820 reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE,
13821 typeNameSimple, [typeName]);
13822 }
13823 elementValid = false;
13824 } else {
13825 if (element != null) {
13826 reportErrorForNode(
13827 StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
13828 elementValid = false;
13829 }
13830 }
13831 }
13832 if (elementValid && element == null) {
13833 // We couldn't resolve the type name.
13834 // TODO(jwren) Consider moving the check for
13835 // CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE from the
13836 // ErrorVerifier, so that we don't have two errors on a built in
13837 // identifier being used as a class name.
13838 // See CompileTimeErrorCodeTest.test_builtInIdentifierAsType().
13839 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
13840 RedirectingConstructorKind redirectingConstructorKind;
13841 if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) {
13842 reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
13843 typeName, [typeName.name]);
13844 } else if (typeNameSimple.name == "boolean") {
13845 reportErrorForNode(
13846 StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
13847 } else if (_isTypeNameInCatchClause(node)) {
13848 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
13849 [typeName.name]);
13850 } else if (_isTypeNameInAsExpression(node)) {
13851 reportErrorForNode(
13852 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
13853 } else if (_isTypeNameInIsExpression(node)) {
13854 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
13855 typeName, [typeName.name]);
13856 } else if ((redirectingConstructorKind =
13857 _getRedirectingConstructorKind(node)) !=
13858 null) {
13859 ErrorCode errorCode = (redirectingConstructorKind ==
13860 RedirectingConstructorKind.CONST
13861 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
13862 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
13863 reportErrorForNode(errorCode, typeName, [typeName.name]);
13864 } else if (_isTypeNameInTypeArgumentList(node)) {
13865 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
13866 typeName, [typeName.name]);
13867 } else {
13868 reportErrorForNode(
13869 StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
13870 }
13871 elementValid = false;
13872 }
13873 if (!elementValid) {
13874 if (element is MultiplyDefinedElement) {
13875 _setElement(typeName, element);
13876 } else {
13877 _setElement(typeName, _dynamicType.element);
13878 }
13879 typeName.staticType = _undefinedType;
13880 node.type = _undefinedType;
13881 return null;
13882 }
13883 DartType type = null;
13884 if (element is ClassElement) {
13885 _setElement(typeName, element);
13886 type = element.type;
13887 } else if (element is FunctionTypeAliasElement) {
13888 _setElement(typeName, element);
13889 type = element.type;
13890 } else if (element is TypeParameterElement) {
13891 _setElement(typeName, element);
13892 type = element.type;
13893 if (argumentList != null) {
13894 // Type parameters cannot have type arguments.
13895 // TODO(brianwilkerson) Report this error.
13896 // resolver.reportError(ResolverErrorCode.?, keyType);
13897 }
13898 } else if (element is MultiplyDefinedElement) {
13899 List<Element> elements = element.conflictingElements;
13900 type = _getTypeWhenMultiplyDefined(elements);
13901 if (type != null) {
13902 node.type = type;
13903 }
13904 } else {
13905 // The name does not represent a type.
13906 RedirectingConstructorKind redirectingConstructorKind;
13907 if (_isTypeNameInCatchClause(node)) {
13908 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
13909 [typeName.name]);
13910 } else if (_isTypeNameInAsExpression(node)) {
13911 reportErrorForNode(
13912 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
13913 } else if (_isTypeNameInIsExpression(node)) {
13914 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName,
13915 [typeName.name]);
13916 } else if ((redirectingConstructorKind =
13917 _getRedirectingConstructorKind(node)) !=
13918 null) {
13919 ErrorCode errorCode = (redirectingConstructorKind ==
13920 RedirectingConstructorKind.CONST
13921 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
13922 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
13923 reportErrorForNode(errorCode, typeName, [typeName.name]);
13924 } else if (_isTypeNameInTypeArgumentList(node)) {
13925 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
13926 typeName, [typeName.name]);
13927 } else {
13928 AstNode parent = typeName.parent;
13929 while (parent is TypeName) {
13930 parent = parent.parent;
13931 }
13932 if (parent is ExtendsClause ||
13933 parent is ImplementsClause ||
13934 parent is WithClause ||
13935 parent is ClassTypeAlias) {
13936 // Ignored. The error will be reported elsewhere.
13937 } else {
13938 reportErrorForNode(
13939 StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
13940 }
13941 }
13942 _setElement(typeName, _dynamicType.element);
13943 typeName.staticType = _dynamicType;
13944 node.type = _dynamicType;
13945 return null;
13946 }
13947 if (argumentList != null) {
13948 NodeList<TypeName> arguments = argumentList.arguments;
13949 int argumentCount = arguments.length;
13950 List<DartType> parameters = _getTypeArguments(type);
13951 int parameterCount = parameters.length;
13952 List<DartType> typeArguments = new List<DartType>(parameterCount);
13953 if (argumentCount == parameterCount) {
13954 for (int i = 0; i < parameterCount; i++) {
13955 TypeName argumentTypeName = arguments[i];
13956 DartType argumentType = _getType(argumentTypeName);
13957 if (argumentType == null) {
13958 argumentType = _dynamicType;
13959 }
13960 typeArguments[i] = argumentType;
13961 }
13962 } else {
13963 reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node, [
13964 typeName.name,
13965 parameterCount,
13966 argumentCount
13967 ]);
13968 for (int i = 0; i < parameterCount; i++) {
13969 typeArguments[i] = _dynamicType;
13970 }
13971 }
13972 if (type is InterfaceTypeImpl) {
13973 InterfaceTypeImpl interfaceType = type as InterfaceTypeImpl;
13974 type = interfaceType.substitute4(typeArguments);
13975 } else if (type is FunctionTypeImpl) {
13976 FunctionTypeImpl functionType = type as FunctionTypeImpl;
13977 type = functionType.substitute3(typeArguments);
13978 } else {
13979 // TODO(brianwilkerson) Report this internal error.
13980 }
13981 } else {
13982 //
13983 // Check for the case where there are no type arguments given for a
13984 // parameterized type.
13985 //
13986 List<DartType> parameters = _getTypeArguments(type);
13987 int parameterCount = parameters.length;
13988 if (parameterCount > 0) {
13989 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
13990 List<DartType> arguments = new List<DartType>(parameterCount);
13991 for (int i = 0; i < parameterCount; i++) {
13992 arguments[i] = dynamicType;
13993 }
13994 type = type.substitute2(arguments, parameters);
13995 }
13996 }
13997 typeName.staticType = type;
13998 node.type = type;
13999 return null;
14000 }
14001
14002 @override
14003 Object visitTypeParameter(TypeParameter node) {
14004 super.visitTypeParameter(node);
14005 TypeName bound = node.bound;
14006 if (bound != null) {
14007 TypeParameterElementImpl typeParameter =
14008 node.name.staticElement as TypeParameterElementImpl;
14009 if (typeParameter != null) {
14010 typeParameter.bound = bound.type;
14011 }
14012 }
14013 return null;
14014 }
14015
14016 @override
14017 Object visitVariableDeclaration(VariableDeclaration node) {
14018 super.visitVariableDeclaration(node);
14019 DartType declaredType;
14020 TypeName typeName = (node.parent as VariableDeclarationList).type;
14021 if (typeName == null) {
14022 declaredType = _dynamicType;
14023 } else {
14024 declaredType = _getType(typeName);
14025 }
14026 Element element = node.name.staticElement;
14027 if (element is VariableElement) {
14028 (element as VariableElementImpl).type = declaredType;
14029 if (element is PropertyInducingElement) {
14030 PropertyInducingElement variableElement = element;
14031 PropertyAccessorElementImpl getter =
14032 variableElement.getter as PropertyAccessorElementImpl;
14033 getter.returnType = declaredType;
14034 FunctionTypeImpl getterType = new FunctionTypeImpl(getter);
14035 ClassElement definingClass =
14036 element.getAncestor((element) => element is ClassElement);
14037 if (definingClass != null) {
14038 getterType.typeArguments = definingClass.type.typeArguments;
14039 }
14040 getter.type = getterType;
14041 PropertyAccessorElementImpl setter =
14042 variableElement.setter as PropertyAccessorElementImpl;
14043 if (setter != null) {
14044 List<ParameterElement> parameters = setter.parameters;
14045 if (parameters.length > 0) {
14046 (parameters[0] as ParameterElementImpl).type = declaredType;
14047 }
14048 setter.returnType = VoidTypeImpl.instance;
14049 FunctionTypeImpl setterType = new FunctionTypeImpl(setter);
14050 if (definingClass != null) {
14051 setterType.typeArguments = definingClass.type.typeArguments;
14052 }
14053 setter.type = setterType;
14054 }
14055 }
14056 } else {
14057 // TODO(brianwilkerson) Report the internal error.
14058 }
14059 return null;
14060 }
14061
14062 /**
14063 * Given a type name representing the return type of a function, compute the r eturn type of the
14064 * function.
14065 *
14066 * @param returnType the type name representing the return type of the functio n
14067 * @return the return type that was computed
14068 */
14069 DartType _computeReturnType(TypeName returnType) {
14070 if (returnType == null) {
14071 return _dynamicType;
14072 } else {
14073 return returnType.type;
14074 }
14075 }
14076
14077 /**
14078 * Return the class element that represents the class whose name was provided.
14079 *
14080 * @param identifier the name from the declaration of a class
14081 * @return the class element that represents the class
14082 */
14083 ClassElementImpl _getClassElement(SimpleIdentifier identifier) {
14084 // TODO(brianwilkerson) Seems like we should be using
14085 // ClassDeclaration.getElement().
14086 if (identifier == null) {
14087 // TODO(brianwilkerson) Report this
14088 // Internal error: We should never build a class declaration without a
14089 // name.
14090 return null;
14091 }
14092 Element element = identifier.staticElement;
14093 if (element is! ClassElementImpl) {
14094 // TODO(brianwilkerson) Report this
14095 // Internal error: Failed to create an element for a class declaration.
14096 return null;
14097 }
14098 return element as ClassElementImpl;
14099 }
14100
14101 /**
14102 * Return an array containing all of the elements associated with the paramete rs in the given
14103 * list.
14104 *
14105 * @param parameterList the list of parameters whose elements are to be return ed
14106 * @return the elements associated with the parameters
14107 */
14108 List<ParameterElement> _getElements(FormalParameterList parameterList) {
14109 List<ParameterElement> elements = new List<ParameterElement>();
14110 for (FormalParameter parameter in parameterList.parameters) {
14111 ParameterElement element =
14112 parameter.identifier.staticElement as ParameterElement;
14113 // TODO(brianwilkerson) Understand why the element would be null.
14114 if (element != null) {
14115 elements.add(element);
14116 }
14117 }
14118 return elements;
14119 }
14120
14121 /**
14122 * The number of type arguments in the given type name does not match the numb er of parameters in
14123 * the corresponding class element. Return the error code that should be used to report this
14124 * error.
14125 *
14126 * @param node the type name with the wrong number of type arguments
14127 * @return the error code that should be used to report that the wrong number of type arguments
14128 * were provided
14129 */
14130 ErrorCode _getInvalidTypeParametersErrorCode(TypeName node) {
14131 AstNode parent = node.parent;
14132 if (parent is ConstructorName) {
14133 parent = parent.parent;
14134 if (parent is InstanceCreationExpression) {
14135 if (parent.isConst) {
14136 return CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS;
14137 } else {
14138 return StaticWarningCode.NEW_WITH_INVALID_TYPE_PARAMETERS;
14139 }
14140 }
14141 }
14142 return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
14143 }
14144
14145 /**
14146 * Checks if the given type name is the target in a redirected constructor.
14147 *
14148 * @param typeName the type name to analyze
14149 * @return some [RedirectingConstructorKind] if the given type name is used as the type in a
14150 * redirected constructor, or `null` otherwise
14151 */
14152 RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
14153 AstNode parent = typeName.parent;
14154 if (parent is ConstructorName) {
14155 ConstructorName constructorName = parent as ConstructorName;
14156 parent = constructorName.parent;
14157 if (parent is ConstructorDeclaration) {
14158 if (identical(parent.redirectedConstructor, constructorName)) {
14159 if (parent.constKeyword != null) {
14160 return RedirectingConstructorKind.CONST;
14161 }
14162 return RedirectingConstructorKind.NORMAL;
14163 }
14164 }
14165 }
14166 return null;
14167 }
14168
14169 /**
14170 * Return the type represented by the given type name.
14171 *
14172 * @param typeName the type name representing the type to be returned
14173 * @return the type represented by the type name
14174 */
14175 DartType _getType(TypeName typeName) {
14176 DartType type = typeName.type;
14177 if (type == null) {
14178 return _undefinedType;
14179 }
14180 return type;
14181 }
14182
14183 /**
14184 * Return the type arguments associated with the given type.
14185 *
14186 * @param type the type whole type arguments are to be returned
14187 * @return the type arguments associated with the given type
14188 */
14189 List<DartType> _getTypeArguments(DartType type) {
14190 if (type is InterfaceType) {
14191 return type.typeArguments;
14192 } else if (type is FunctionType) {
14193 return type.typeArguments;
14194 }
14195 return DartType.EMPTY_LIST;
14196 }
14197
14198 /**
14199 * Returns the simple identifier of the given (may be qualified) type name.
14200 *
14201 * @param typeName the (may be qualified) qualified type name
14202 * @return the simple identifier of the given (may be qualified) type name.
14203 */
14204 SimpleIdentifier _getTypeSimpleIdentifier(Identifier typeName) {
14205 if (typeName is SimpleIdentifier) {
14206 return typeName;
14207 } else {
14208 return (typeName as PrefixedIdentifier).identifier;
14209 }
14210 }
14211
14212 /**
14213 * Given the multiple elements to which a single name could potentially be res olved, return the
14214 * single interface type that should be used, or `null` if there is no clear c hoice.
14215 *
14216 * @param elements the elements to which a single name could potentially be re solved
14217 * @return the single interface type that should be used for the type name
14218 */
14219 InterfaceType _getTypeWhenMultiplyDefined(List<Element> elements) {
14220 InterfaceType type = null;
14221 for (Element element in elements) {
14222 if (element is ClassElement) {
14223 if (type != null) {
14224 return null;
14225 }
14226 type = element.type;
14227 }
14228 }
14229 return type;
14230 }
14231
14232 /**
14233 * Checks if the given type name is used as the type in an as expression.
14234 *
14235 * @param typeName the type name to analyzer
14236 * @return `true` if the given type name is used as the type in an as expressi on
14237 */
14238 bool _isTypeNameInAsExpression(TypeName typeName) {
14239 AstNode parent = typeName.parent;
14240 if (parent is AsExpression) {
14241 AsExpression asExpression = parent;
14242 return identical(asExpression.type, typeName);
14243 }
14244 return false;
14245 }
14246
14247 /**
14248 * Checks if the given type name is used as the exception type in a catch clau se.
14249 *
14250 * @param typeName the type name to analyzer
14251 * @return `true` if the given type name is used as the exception type in a ca tch clause
14252 */
14253 bool _isTypeNameInCatchClause(TypeName typeName) {
14254 AstNode parent = typeName.parent;
14255 if (parent is CatchClause) {
14256 CatchClause catchClause = parent;
14257 return identical(catchClause.exceptionType, typeName);
14258 }
14259 return false;
14260 }
14261
14262 /**
14263 * Checks if the given type name is used as the type in an instance creation e xpression.
14264 *
14265 * @param typeName the type name to analyzer
14266 * @return `true` if the given type name is used as the type in an instance cr eation
14267 * expression
14268 */
14269 bool _isTypeNameInInstanceCreationExpression(TypeName typeName) {
14270 AstNode parent = typeName.parent;
14271 if (parent is ConstructorName &&
14272 parent.parent is InstanceCreationExpression) {
14273 ConstructorName constructorName = parent;
14274 return constructorName != null &&
14275 identical(constructorName.type, typeName);
14276 }
14277 return false;
14278 }
14279
14280 /**
14281 * Checks if the given type name is used as the type in an is expression.
14282 *
14283 * @param typeName the type name to analyzer
14284 * @return `true` if the given type name is used as the type in an is expressi on
14285 */
14286 bool _isTypeNameInIsExpression(TypeName typeName) {
14287 AstNode parent = typeName.parent;
14288 if (parent is IsExpression) {
14289 IsExpression isExpression = parent;
14290 return identical(isExpression.type, typeName);
14291 }
14292 return false;
14293 }
14294
14295 /**
14296 * Checks if the given type name used in a type argument list.
14297 *
14298 * @param typeName the type name to analyzer
14299 * @return `true` if the given type name is in a type argument list
14300 */
14301 bool _isTypeNameInTypeArgumentList(TypeName typeName) =>
14302 typeName.parent is TypeArgumentList;
14303
14304 /**
14305 * Record that the static type of the given node is the given type.
14306 *
14307 * @param expression the node whose type is to be recorded
14308 * @param type the static type of the node
14309 */
14310 Object _recordType(Expression expression, DartType type) {
14311 if (type == null) {
14312 expression.staticType = _dynamicType;
14313 } else {
14314 expression.staticType = type;
14315 }
14316 return null;
14317 }
14318
14319 /**
14320 * Resolve the types in the given with and implements clauses and associate th ose types with the
14321 * given class element.
14322 *
14323 * @param classElement the class element with which the mixin and interface ty pes are to be
14324 * associated
14325 * @param withClause the with clause to be resolved
14326 * @param implementsClause the implements clause to be resolved
14327 */
14328 void _resolve(ClassElementImpl classElement, WithClause withClause,
14329 ImplementsClause implementsClause) {
14330 if (withClause != null) {
14331 List<InterfaceType> mixinTypes = _resolveTypes(withClause.mixinTypes,
14332 CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
14333 CompileTimeErrorCode.MIXIN_OF_ENUM,
14334 CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
14335 if (classElement != null) {
14336 classElement.mixins = mixinTypes;
14337 classElement.withClauseRange =
14338 new SourceRange(withClause.offset, withClause.length);
14339 }
14340 }
14341 if (implementsClause != null) {
14342 NodeList<TypeName> interfaces = implementsClause.interfaces;
14343 List<InterfaceType> interfaceTypes = _resolveTypes(interfaces,
14344 CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
14345 CompileTimeErrorCode.IMPLEMENTS_ENUM,
14346 CompileTimeErrorCode.IMPLEMENTS_DYNAMIC);
14347 if (classElement != null) {
14348 classElement.interfaces = interfaceTypes;
14349 }
14350 // TODO(brianwilkerson) Move the following checks to ErrorVerifier.
14351 int count = interfaces.length;
14352 List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false);
14353 for (int i = 0; i < detectedRepeatOnIndex.length; i++) {
14354 detectedRepeatOnIndex[i] = false;
14355 }
14356 for (int i = 0; i < count; i++) {
14357 TypeName typeName = interfaces[i];
14358 if (!detectedRepeatOnIndex[i]) {
14359 Element element = typeName.name.staticElement;
14360 for (int j = i + 1; j < count; j++) {
14361 TypeName typeName2 = interfaces[j];
14362 Identifier identifier2 = typeName2.name;
14363 String name2 = identifier2.name;
14364 Element element2 = identifier2.staticElement;
14365 if (element != null && element == element2) {
14366 detectedRepeatOnIndex[j] = true;
14367 reportErrorForNode(
14368 CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
14369 }
14370 }
14371 }
14372 }
14373 }
14374 }
14375
14376 /**
14377 * Return the type specified by the given name.
14378 *
14379 * @param typeName the type name specifying the type to be returned
14380 * @param nonTypeError the error to produce if the type name is defined to be something other than
14381 * a type
14382 * @param enumTypeError the error to produce if the type name is defined to be an enum
14383 * @param dynamicTypeError the error to produce if the type name is "dynamic"
14384 * @return the type specified by the type name
14385 */
14386 InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError,
14387 ErrorCode enumTypeError, ErrorCode dynamicTypeError) {
14388 DartType type = typeName.type;
14389 if (type is InterfaceType) {
14390 ClassElement element = type.element;
14391 if (element != null && element.isEnum) {
14392 reportErrorForNode(enumTypeError, typeName);
14393 return null;
14394 }
14395 return type;
14396 }
14397 // If the type is not an InterfaceType, then visitTypeName() sets the type
14398 // to be a DynamicTypeImpl
14399 Identifier name = typeName.name;
14400 if (name.name == sc.Keyword.DYNAMIC.syntax) {
14401 reportErrorForNode(dynamicTypeError, name, [name.name]);
14402 } else {
14403 reportErrorForNode(nonTypeError, name, [name.name]);
14404 }
14405 return null;
14406 }
14407
14408 /**
14409 * Resolve the types in the given list of type names.
14410 *
14411 * @param typeNames the type names to be resolved
14412 * @param nonTypeError the error to produce if the type name is defined to be something other than
14413 * a type
14414 * @param enumTypeError the error to produce if the type name is defined to be an enum
14415 * @param dynamicTypeError the error to produce if the type name is "dynamic"
14416 * @return an array containing all of the types that were resolved.
14417 */
14418 List<InterfaceType> _resolveTypes(NodeList<TypeName> typeNames,
14419 ErrorCode nonTypeError, ErrorCode enumTypeError,
14420 ErrorCode dynamicTypeError) {
14421 List<InterfaceType> types = new List<InterfaceType>();
14422 for (TypeName typeName in typeNames) {
14423 InterfaceType type =
14424 _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError);
14425 if (type != null) {
14426 types.add(type);
14427 }
14428 }
14429 return types;
14430 }
14431
14432 void _setElement(Identifier typeName, Element element) {
14433 if (element != null) {
14434 if (typeName is SimpleIdentifier) {
14435 typeName.staticElement = element;
14436 } else if (typeName is PrefixedIdentifier) {
14437 PrefixedIdentifier identifier = typeName;
14438 identifier.identifier.staticElement = element;
14439 SimpleIdentifier prefix = identifier.prefix;
14440 Element prefixElement = nameScope.lookup(prefix, definingLibrary);
14441 if (prefixElement != null) {
14442 prefix.staticElement = prefixElement;
14443 }
14444 }
14445 }
14446 }
14447
14448 /**
14449 * Given a parameter element, create a function type based on the given return type and parameter
14450 * list and associate the created type with the element.
14451 *
14452 * @param element the parameter element whose type is to be set
14453 * @param returnType the (possibly `null`) return type of the function
14454 * @param parameterList the list of parameters to the function
14455 */
14456 void _setFunctionTypedParameterType(ParameterElementImpl element,
14457 TypeName returnType, FormalParameterList parameterList) {
14458 List<ParameterElement> parameters = _getElements(parameterList);
14459 FunctionTypeAliasElementImpl aliasElement =
14460 new FunctionTypeAliasElementImpl.forNode(null);
14461 aliasElement.synthetic = true;
14462 aliasElement.shareParameters(parameters);
14463 aliasElement.returnType = _computeReturnType(returnType);
14464 // FunctionTypeAliasElementImpl assumes the enclosing element is a
14465 // CompilationUnitElement (because non-synthetic function types can only be
14466 // declared at top level), so to avoid breaking things, go find the
14467 // compilation unit element.
14468 aliasElement.enclosingElement =
14469 element.getAncestor((element) => element is CompilationUnitElement);
14470 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(aliasElement);
14471 ClassElement definingClass =
14472 element.getAncestor((element) => element is ClassElement);
14473 if (definingClass != null) {
14474 aliasElement.shareTypeParameters(definingClass.typeParameters);
14475 type.typeArguments = definingClass.type.typeArguments;
14476 } else {
14477 FunctionTypeAliasElement alias =
14478 element.getAncestor((element) => element is FunctionTypeAliasElement);
14479 while (alias != null && alias.isSynthetic) {
14480 alias =
14481 alias.getAncestor((element) => element is FunctionTypeAliasElement);
14482 }
14483 if (alias != null) {
14484 aliasElement.typeParameters = alias.typeParameters;
14485 type.typeArguments = alias.type.typeArguments;
14486 } else {
14487 type.typeArguments = DartType.EMPTY_LIST;
14488 }
14489 }
14490 element.type = type;
14491 }
14492
14493 /**
14494 * @return `true` if the name of the given [TypeName] is an built-in identifie r.
14495 */
14496 static bool _isBuiltInIdentifier(TypeName node) {
14497 sc.Token token = node.name.beginToken;
14498 return token.type == sc.TokenType.KEYWORD;
14499 }
14500
14501 /**
14502 * @return `true` if given [TypeName] is used as a type annotation.
14503 */
14504 static bool _isTypeAnnotation(TypeName node) {
14505 AstNode parent = node.parent;
14506 if (parent is VariableDeclarationList) {
14507 return identical(parent.type, node);
14508 }
14509 if (parent is FieldFormalParameter) {
14510 return identical(parent.type, node);
14511 }
14512 if (parent is SimpleFormalParameter) {
14513 return identical(parent.type, node);
14514 }
14515 return false;
14516 }
14517 }
14518
14519 /**
14520 * The interface `TypeSystem` defines the behavior of an object representing
14521 * the type system. This provides a common location to put methods that act on
14522 * types but may need access to more global data structures, and it paves the
14523 * way for a possible future where we may wish to make the type system
14524 * pluggable.
14525 */
14526 abstract class TypeSystem {
14527 /**
14528 * Return the [TypeProvider] associated with this [TypeSystem].
14529 */
14530 TypeProvider get typeProvider;
14531
14532 /**
14533 * Compute the least upper bound of two types.
14534 */
14535 DartType getLeastUpperBound(DartType type1, DartType type2);
14536 }
14537
14538 /**
14539 * Implementation of [TypeSystem] using the rules in the Dart specification.
14540 */
14541 class TypeSystemImpl implements TypeSystem {
14542 @override
14543 final TypeProvider typeProvider;
14544
14545 TypeSystemImpl(this.typeProvider);
14546
14547 @override
14548 DartType getLeastUpperBound(DartType type1, DartType type2) {
14549 // The least upper bound relation is reflexive.
14550 if (identical(type1, type2)) {
14551 return type1;
14552 }
14553 // The least upper bound of dynamic and any type T is dynamic.
14554 if (type1.isDynamic) {
14555 return type1;
14556 }
14557 if (type2.isDynamic) {
14558 return type2;
14559 }
14560 // The least upper bound of void and any type T != dynamic is void.
14561 if (type1.isVoid) {
14562 return type1;
14563 }
14564 if (type2.isVoid) {
14565 return type2;
14566 }
14567 // The least upper bound of bottom and any type T is T.
14568 if (type1.isBottom) {
14569 return type2;
14570 }
14571 if (type2.isBottom) {
14572 return type1;
14573 }
14574 // Let U be a type variable with upper bound B. The least upper bound of U
14575 // and a type T is the least upper bound of B and T.
14576 while (type1 is TypeParameterType) {
14577 // TODO(paulberry): is this correct in the complex of F-bounded
14578 // polymorphism?
14579 DartType bound = (type1 as TypeParameterType).element.bound;
14580 if (bound == null) {
14581 bound = typeProvider.objectType;
14582 }
14583 type1 = bound;
14584 }
14585 while (type2 is TypeParameterType) {
14586 // TODO(paulberry): is this correct in the context of F-bounded
14587 // polymorphism?
14588 DartType bound = (type2 as TypeParameterType).element.bound;
14589 if (bound == null) {
14590 bound = typeProvider.objectType;
14591 }
14592 type2 = bound;
14593 }
14594 // The least upper bound of a function type and an interface type T is the
14595 // least upper bound of Function and T.
14596 if (type1 is FunctionType && type2 is InterfaceType) {
14597 type1 = typeProvider.functionType;
14598 }
14599 if (type2 is FunctionType && type1 is InterfaceType) {
14600 type2 = typeProvider.functionType;
14601 }
14602
14603 // At this point type1 and type2 should both either be interface types or
14604 // function types.
14605 if (type1 is InterfaceType && type2 is InterfaceType) {
14606 InterfaceType result =
14607 InterfaceTypeImpl.computeLeastUpperBound(type1, type2);
14608 if (result == null) {
14609 return typeProvider.dynamicType;
14610 }
14611 return result;
14612 } else if (type1 is FunctionType && type2 is FunctionType) {
14613 FunctionType result =
14614 FunctionTypeImpl.computeLeastUpperBound(type1, type2);
14615 if (result == null) {
14616 return typeProvider.functionType;
14617 }
14618 return result;
14619 } else {
14620 // Should never happen. As a defensive measure, return the dynamic type.
14621 assert(false);
14622 return typeProvider.dynamicType;
14623 }
14624 }
14625 }
14626
14627 /**
14628 * Instances of the class [UnusedLocalElementsVerifier] traverse an element
14629 * structure looking for cases of [HintCode.UNUSED_ELEMENT],
14630 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc.
14631 */
14632 class UnusedLocalElementsVerifier extends RecursiveElementVisitor {
14633 /**
14634 * The error listener to which errors will be reported.
14635 */
14636 final AnalysisErrorListener _errorListener;
14637
14638 /**
14639 * The elements know to be used.
14640 */
14641 final UsedLocalElements _usedElements;
14642
14643 /**
14644 * Create a new instance of the [UnusedLocalElementsVerifier].
14645 */
14646 UnusedLocalElementsVerifier(this._errorListener, this._usedElements);
14647
14648 @override
14649 visitClassElement(ClassElement element) {
14650 if (!_isUsedElement(element)) {
14651 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
14652 element.kind.displayName,
14653 element.displayName
14654 ]);
14655 }
14656 super.visitClassElement(element);
14657 }
14658
14659 @override
14660 visitFieldElement(FieldElement element) {
14661 if (!_isReadMember(element)) {
14662 _reportErrorForElement(
14663 HintCode.UNUSED_FIELD, element, [element.displayName]);
14664 }
14665 super.visitFieldElement(element);
14666 }
14667
14668 @override
14669 visitFunctionElement(FunctionElement element) {
14670 if (!_isUsedElement(element)) {
14671 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
14672 element.kind.displayName,
14673 element.displayName
14674 ]);
14675 }
14676 super.visitFunctionElement(element);
14677 }
14678
14679 @override
14680 visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
14681 if (!_isUsedElement(element)) {
14682 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
14683 element.kind.displayName,
14684 element.displayName
14685 ]);
14686 }
14687 super.visitFunctionTypeAliasElement(element);
14688 }
14689
14690 @override
14691 visitLocalVariableElement(LocalVariableElement element) {
14692 if (!_isUsedElement(element) && !_isNamedUnderscore(element)) {
14693 HintCode errorCode;
14694 if (_usedElements.isCatchException(element)) {
14695 errorCode = HintCode.UNUSED_CATCH_CLAUSE;
14696 } else if (_usedElements.isCatchStackTrace(element)) {
14697 errorCode = HintCode.UNUSED_CATCH_STACK;
14698 } else {
14699 errorCode = HintCode.UNUSED_LOCAL_VARIABLE;
14700 }
14701 _reportErrorForElement(errorCode, element, [element.displayName]);
14702 }
14703 }
14704
14705 @override
14706 visitMethodElement(MethodElement element) {
14707 if (!_isUsedMember(element)) {
14708 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
14709 element.kind.displayName,
14710 element.displayName
14711 ]);
14712 }
14713 super.visitMethodElement(element);
14714 }
14715
14716 @override
14717 visitPropertyAccessorElement(PropertyAccessorElement element) {
14718 if (!_isUsedMember(element)) {
14719 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
14720 element.kind.displayName,
14721 element.displayName
14722 ]);
14723 }
14724 super.visitPropertyAccessorElement(element);
14725 }
14726
14727 bool _isNamedUnderscore(LocalVariableElement element) {
14728 String name = element.name;
14729 if (name != null) {
14730 for (int index = name.length - 1; index >= 0; --index) {
14731 if (name.codeUnitAt(index) != 0x5F) {
14732 // 0x5F => '_'
14733 return false;
14734 }
14735 }
14736 return true;
14737 }
14738 return false;
14739 }
14740
14741 bool _isReadMember(Element element) {
14742 if (element.isPublic) {
14743 return true;
14744 }
14745 if (element.isSynthetic) {
14746 return true;
14747 }
14748 return _usedElements.readMembers.contains(element.displayName);
14749 }
14750
14751 bool _isUsedElement(Element element) {
14752 if (element.isSynthetic) {
14753 return true;
14754 }
14755 if (element is LocalVariableElement ||
14756 element is FunctionElement && !element.isStatic) {
14757 // local variable or function
14758 } else {
14759 if (element.isPublic) {
14760 return true;
14761 }
14762 }
14763 return _usedElements.elements.contains(element);
14764 }
14765
14766 bool _isUsedMember(Element element) {
14767 if (element.isPublic) {
14768 return true;
14769 }
14770 if (element.isSynthetic) {
14771 return true;
14772 }
14773 if (_usedElements.members.contains(element.displayName)) {
14774 return true;
14775 }
14776 return _usedElements.elements.contains(element);
14777 }
14778
14779 void _reportErrorForElement(
14780 ErrorCode errorCode, Element element, List<Object> arguments) {
14781 if (element != null) {
14782 _errorListener.onError(new AnalysisError(element.source,
14783 element.nameOffset, element.displayName.length, errorCode,
14784 arguments));
14785 }
14786 }
14787 }
14788
14789 /**
14790 * A container with information about used imports prefixes and used imported
14791 * elements.
14792 */
14793 class UsedImportedElements {
14794 /**
14795 * The set of referenced [PrefixElement]s.
14796 */
14797 final Set<PrefixElement> prefixes = new HashSet<PrefixElement>();
14798
14799 /**
14800 * The set of referenced top-level [Element]s.
14801 */
14802 final Set<Element> elements = new HashSet<Element>();
14803 }
14804
14805 /**
14806 * A container with sets of used [Element]s.
14807 * All these elements are defined in a single compilation unit or a library.
14808 */
14809 class UsedLocalElements {
14810 /**
14811 * Resolved, locally defined elements that are used or potentially can be
14812 * used.
14813 */
14814 final HashSet<Element> elements = new HashSet<Element>();
14815
14816 /**
14817 * [LocalVariableElement]s that represent exceptions in [CatchClause]s.
14818 */
14819 final HashSet<LocalVariableElement> catchExceptionElements =
14820 new HashSet<LocalVariableElement>();
14821
14822 /**
14823 * [LocalVariableElement]s that represent stack traces in [CatchClause]s.
14824 */
14825 final HashSet<LocalVariableElement> catchStackTraceElements =
14826 new HashSet<LocalVariableElement>();
14827
14828 /**
14829 * Names of resolved or unresolved class members that are referenced in the
14830 * library.
14831 */
14832 final HashSet<String> members = new HashSet<String>();
14833
14834 /**
14835 * Names of resolved or unresolved class members that are read in the
14836 * library.
14837 */
14838 final HashSet<String> readMembers = new HashSet<String>();
14839
14840 UsedLocalElements();
14841
14842 factory UsedLocalElements.merge(List<UsedLocalElements> parts) {
14843 UsedLocalElements result = new UsedLocalElements();
14844 for (UsedLocalElements part in parts) {
14845 result.elements.addAll(part.elements);
14846 result.catchExceptionElements.addAll(part.catchExceptionElements);
14847 result.catchStackTraceElements.addAll(part.catchStackTraceElements);
14848 result.members.addAll(part.members);
14849 result.readMembers.addAll(part.readMembers);
14850 }
14851 return result;
14852 }
14853
14854 void addCatchException(LocalVariableElement element) {
14855 if (element != null) {
14856 catchExceptionElements.add(element);
14857 }
14858 }
14859
14860 void addCatchStackTrace(LocalVariableElement element) {
14861 if (element != null) {
14862 catchStackTraceElements.add(element);
14863 }
14864 }
14865
14866 void addElement(Element element) {
14867 if (element != null) {
14868 elements.add(element);
14869 }
14870 }
14871
14872 bool isCatchException(LocalVariableElement element) {
14873 return catchExceptionElements.contains(element);
14874 }
14875
14876 bool isCatchStackTrace(LocalVariableElement element) {
14877 return catchStackTraceElements.contains(element);
14878 }
14879 }
14880
14881 /**
14882 * Instances of the class `VariableResolverVisitor` are used to resolve
14883 * [SimpleIdentifier]s to local variables and formal parameters.
14884 */
14885 class VariableResolverVisitor extends ScopedVisitor {
14886 /**
14887 * The method or function that we are currently visiting, or `null` if we are not inside a
14888 * method or function.
14889 */
14890 ExecutableElement _enclosingFunction;
14891
14892 /**
14893 * Initialize a newly created visitor to resolve the nodes in an AST node.
14894 *
14895 * [definingLibrary] is the element for the library containing the node being
14896 * visited.
14897 * [source] is the source representing the compilation unit containing the
14898 * node being visited
14899 * [typeProvider] is the object used to access the types from the core
14900 * library.
14901 * [errorListener] is the error listener that will be informed of any errors
14902 * that are found during resolution.
14903 * [nameScope] is the scope used to resolve identifiers in the node that will
14904 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
14905 * created based on [definingLibrary] and [typeProvider].
14906 */
14907 VariableResolverVisitor(LibraryElement definingLibrary, Source source,
14908 TypeProvider typeProvider, AnalysisErrorListener errorListener,
14909 {Scope nameScope})
14910 : super(definingLibrary, source, typeProvider, errorListener,
14911 nameScope: nameScope);
14912
14913 /**
14914 * Initialize a newly created visitor to resolve the nodes in a compilation un it.
14915 *
14916 * @param library the library containing the compilation unit being resolved
14917 * @param source the source representing the compilation unit being visited
14918 * @param typeProvider the object used to access the types from the core libra ry
14919 *
14920 * Deprecated. Please use unnamed constructor instead.
14921 */
14922 @deprecated
14923 VariableResolverVisitor.con1(
14924 Library library, Source source, TypeProvider typeProvider)
14925 : this(
14926 library.libraryElement, source, typeProvider, library.errorListener,
14927 nameScope: library.libraryScope);
14928
14929 @override
14930 Object visitExportDirective(ExportDirective node) => null;
14931
14932 @override
14933 Object visitFunctionDeclaration(FunctionDeclaration node) {
14934 ExecutableElement outerFunction = _enclosingFunction;
14935 try {
14936 _enclosingFunction = node.element;
14937 return super.visitFunctionDeclaration(node);
14938 } finally {
14939 _enclosingFunction = outerFunction;
14940 }
14941 }
14942
14943 @override
14944 Object visitFunctionExpression(FunctionExpression node) {
14945 if (node.parent is! FunctionDeclaration) {
14946 ExecutableElement outerFunction = _enclosingFunction;
14947 try {
14948 _enclosingFunction = node.element;
14949 return super.visitFunctionExpression(node);
14950 } finally {
14951 _enclosingFunction = outerFunction;
14952 }
14953 } else {
14954 return super.visitFunctionExpression(node);
14955 }
14956 }
14957
14958 @override
14959 Object visitImportDirective(ImportDirective node) => null;
14960
14961 @override
14962 Object visitMethodDeclaration(MethodDeclaration node) {
14963 ExecutableElement outerFunction = _enclosingFunction;
14964 try {
14965 _enclosingFunction = node.element;
14966 return super.visitMethodDeclaration(node);
14967 } finally {
14968 _enclosingFunction = outerFunction;
14969 }
14970 }
14971
14972 @override
14973 Object visitSimpleIdentifier(SimpleIdentifier node) {
14974 // Ignore if already resolved - declaration or type.
14975 if (node.staticElement != null) {
14976 return null;
14977 }
14978 // Ignore if qualified.
14979 AstNode parent = node.parent;
14980 if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
14981 return null;
14982 }
14983 if (parent is PropertyAccess && identical(parent.propertyName, node)) {
14984 return null;
14985 }
14986 if (parent is MethodInvocation &&
14987 identical(parent.methodName, node) &&
14988 parent.realTarget != null) {
14989 return null;
14990 }
14991 if (parent is ConstructorName) {
14992 return null;
14993 }
14994 if (parent is Label) {
14995 return null;
14996 }
14997 // Prepare VariableElement.
14998 Element element = nameScope.lookup(node, definingLibrary);
14999 if (element is! VariableElement) {
15000 return null;
15001 }
15002 // Must be local or parameter.
15003 ElementKind kind = element.kind;
15004 if (kind == ElementKind.LOCAL_VARIABLE) {
15005 node.staticElement = element;
15006 LocalVariableElementImpl variableImpl =
15007 element as LocalVariableElementImpl;
15008 if (node.inSetterContext()) {
15009 variableImpl.markPotentiallyMutatedInScope();
15010 if (element.enclosingElement != _enclosingFunction) {
15011 variableImpl.markPotentiallyMutatedInClosure();
15012 }
15013 }
15014 } else if (kind == ElementKind.PARAMETER) {
15015 node.staticElement = element;
15016 if (node.inSetterContext()) {
15017 ParameterElementImpl parameterImpl = element as ParameterElementImpl;
15018 parameterImpl.markPotentiallyMutatedInScope();
15019 // If we are in some closure, check if it is not the same as where
15020 // variable is declared.
15021 if (_enclosingFunction != null &&
15022 (element.enclosingElement != _enclosingFunction)) {
15023 parameterImpl.markPotentiallyMutatedInClosure();
15024 }
15025 }
15026 }
15027 return null;
15028 }
15029 }
15030
15031 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor {
15032 final ConstantVerifier verifier;
15033
15034 List<ParameterElement> parameterElements;
15035
15036 _ConstantVerifier_validateInitializerExpression(TypeProvider typeProvider,
15037 ErrorReporter errorReporter, this.verifier, this.parameterElements,
15038 DeclaredVariables declaredVariables)
15039 : super(new ConstantEvaluationEngine(typeProvider, declaredVariables),
15040 errorReporter);
15041
15042 @override
15043 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
15044 Element element = node.staticElement;
15045 for (ParameterElement parameterElement in parameterElements) {
15046 if (identical(parameterElement, element) && parameterElement != null) {
15047 DartType type = parameterElement.type;
15048 if (type != null) {
15049 if (type.isDynamic) {
15050 return new DartObjectImpl(
15051 verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE);
15052 } else if (type.isSubtypeOf(verifier._boolType)) {
15053 return new DartObjectImpl(
15054 verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE);
15055 } else if (type.isSubtypeOf(verifier._typeProvider.doubleType)) {
15056 return new DartObjectImpl(
15057 verifier._typeProvider.doubleType, DoubleState.UNKNOWN_VALUE);
15058 } else if (type.isSubtypeOf(verifier._intType)) {
15059 return new DartObjectImpl(
15060 verifier._typeProvider.intType, IntState.UNKNOWN_VALUE);
15061 } else if (type.isSubtypeOf(verifier._numType)) {
15062 return new DartObjectImpl(
15063 verifier._typeProvider.numType, NumState.UNKNOWN_VALUE);
15064 } else if (type.isSubtypeOf(verifier._stringType)) {
15065 return new DartObjectImpl(
15066 verifier._typeProvider.stringType, StringState.UNKNOWN_VALUE);
15067 }
15068 //
15069 // We don't test for other types of objects (such as List, Map,
15070 // Function or Type) because there are no operations allowed on such
15071 // types other than '==' and '!=', which means that we don't need to
15072 // know the type when there is no specific data about the state of
15073 // such objects.
15074 //
15075 }
15076 return new DartObjectImpl(
15077 type is InterfaceType ? type : verifier._typeProvider.objectType,
15078 GenericState.UNKNOWN_VALUE);
15079 }
15080 }
15081 return super.visitSimpleIdentifier(node);
15082 }
15083 }
15084
15085 class _ElementBuilder_visitClassDeclaration extends UnifyingAstVisitor<Object> {
15086 final ElementBuilder builder;
15087
15088 List<ClassMember> nonFields;
15089
15090 _ElementBuilder_visitClassDeclaration(this.builder, this.nonFields) : super();
15091
15092 @override
15093 Object visitConstructorDeclaration(ConstructorDeclaration node) {
15094 nonFields.add(node);
15095 return null;
15096 }
15097
15098 @override
15099 Object visitMethodDeclaration(MethodDeclaration node) {
15100 nonFields.add(node);
15101 return null;
15102 }
15103
15104 @override
15105 Object visitNode(AstNode node) => node.accept(builder);
15106 }
15107
15108 class _ResolverVisitor_isVariableAccessedInClosure
15109 extends RecursiveAstVisitor<Object> {
15110 final Element variable;
15111
15112 bool result = false;
15113
15114 bool _inClosure = false;
15115
15116 _ResolverVisitor_isVariableAccessedInClosure(this.variable);
15117
15118 @override
15119 Object visitFunctionExpression(FunctionExpression node) {
15120 bool inClosure = this._inClosure;
15121 try {
15122 this._inClosure = true;
15123 return super.visitFunctionExpression(node);
15124 } finally {
15125 this._inClosure = inClosure;
15126 }
15127 }
15128
15129 @override
15130 Object visitSimpleIdentifier(SimpleIdentifier node) {
15131 if (result) {
15132 return null;
15133 }
15134 if (_inClosure && identical(node.staticElement, variable)) {
15135 result = true;
15136 }
15137 return null;
15138 }
15139 }
15140
15141 class _ResolverVisitor_isVariablePotentiallyMutatedIn
15142 extends RecursiveAstVisitor<Object> {
15143 final Element variable;
15144
15145 bool result = false;
15146
15147 _ResolverVisitor_isVariablePotentiallyMutatedIn(this.variable);
15148
15149 @override
15150 Object visitSimpleIdentifier(SimpleIdentifier node) {
15151 if (result) {
15152 return null;
15153 }
15154 if (identical(node.staticElement, variable)) {
15155 if (node.inSetterContext()) {
15156 result = true;
15157 }
15158 }
15159 return null;
15160 }
15161 }
15162
15163 class _TypeResolverVisitor_visitClassMembersInScope
15164 extends UnifyingAstVisitor<Object> {
15165 final TypeResolverVisitor TypeResolverVisitor_this;
15166
15167 List<ClassMember> nonFields;
15168
15169 _TypeResolverVisitor_visitClassMembersInScope(
15170 this.TypeResolverVisitor_this, this.nonFields)
15171 : super();
15172
15173 @override
15174 Object visitConstructorDeclaration(ConstructorDeclaration node) {
15175 nonFields.add(node);
15176 return null;
15177 }
15178
15179 @override
15180 Object visitExtendsClause(ExtendsClause node) => null;
15181
15182 @override
15183 Object visitImplementsClause(ImplementsClause node) => null;
15184
15185 @override
15186 Object visitMethodDeclaration(MethodDeclaration node) {
15187 nonFields.add(node);
15188 return null;
15189 }
15190
15191 @override
15192 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this);
15193
15194 @override
15195 Object visitWithClause(WithClause node) => null;
15196 }
OLDNEW
« no previous file with comments | « analyzer/lib/src/generated/parser.dart ('k') | analyzer/lib/src/generated/scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698