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

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

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library engine.resolver;
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(
297 Expression expression,
298 DartType expectedStaticType,
299 DartType actualStaticType,
300 DartType expectedPropagatedType,
301 DartType actualPropagatedType,
302 ErrorCode hintCode) {
303 //
304 // Warning case: test static type information
305 //
306 if (actualStaticType != null && expectedStaticType != null) {
307 if (!actualStaticType.isAssignableTo(expectedStaticType)) {
308 // A warning was created in the ErrorVerifier, return false, don't
309 // create a hint when a warning has already been created.
310 return false;
311 }
312 }
313 //
314 // Hint case: test propagated type information
315 //
316 // Compute the best types to use.
317 DartType expectedBestType = expectedPropagatedType != null
318 ? expectedPropagatedType
319 : expectedStaticType;
320 DartType actualBestType =
321 actualPropagatedType != null ? actualPropagatedType : actualStaticType;
322 if (actualBestType != null && expectedBestType != null) {
323 if (!actualBestType.isAssignableTo(expectedBestType)) {
324 _errorReporter.reportTypeErrorForNode(
325 hintCode, expression, [actualBestType, expectedBestType]);
326 return true;
327 }
328 }
329 return false;
330 }
331
332 /**
333 * This verifies that the passed argument can be assigned to its corresponding parameter.
334 *
335 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableForAr gument.
336 *
337 * @param argument the argument to evaluate
338 * @return `true` if and only if an hint code is generated on the passed node
339 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
340 */
341 bool _checkForArgumentTypeNotAssignableForArgument(Expression argument) {
342 if (argument == null) {
343 return false;
344 }
345 ParameterElement staticParameterElement = argument.staticParameterElement;
346 DartType staticParameterType =
347 staticParameterElement == null ? null : staticParameterElement.type;
348 ParameterElement propagatedParameterElement =
349 argument.propagatedParameterElement;
350 DartType propagatedParameterType = propagatedParameterElement == null
351 ? null
352 : propagatedParameterElement.type;
353 return _checkForArgumentTypeNotAssignableWithExpectedTypes(
354 argument,
355 staticParameterType,
356 propagatedParameterType,
357 HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE);
358 }
359
360 /**
361 * This verifies that the passed expression can be assigned to its correspondi ng parameters.
362 *
363 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableWithE xpectedTypes.
364 *
365 * @param expression the expression to evaluate
366 * @param expectedStaticType the expected static type
367 * @param expectedPropagatedType the expected propagated type, may be `null`
368 * @return `true` if and only if an hint code is generated on the passed node
369 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
370 */
371 bool _checkForArgumentTypeNotAssignableWithExpectedTypes(
372 Expression expression,
373 DartType expectedStaticType,
374 DartType expectedPropagatedType,
375 ErrorCode errorCode) =>
376 _checkForArgumentTypeNotAssignable(
377 expression,
378 expectedStaticType,
379 expression.staticType,
380 expectedPropagatedType,
381 expression.propagatedType,
382 errorCode);
383
384 /**
385 * This verifies that the passed arguments can be assigned to their correspond ing parameters.
386 *
387 * This method corresponds to ErrorCode.checkForArgumentTypesNotAssignableInLi st.
388 *
389 * @param node the arguments to evaluate
390 * @return `true` if and only if an hint code is generated on the passed node
391 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
392 */
393 bool _checkForArgumentTypesNotAssignableInList(ArgumentList argumentList) {
394 if (argumentList == null) {
395 return false;
396 }
397 bool problemReported = false;
398 for (Expression argument in argumentList.arguments) {
399 if (_checkForArgumentTypeNotAssignableForArgument(argument)) {
400 problemReported = true;
401 }
402 }
403 return problemReported;
404 }
405
406 /**
407 * Given some [Element], look at the associated metadata and report the use of the member if
408 * it is declared as deprecated.
409 *
410 * @param element some element to check for deprecated use of
411 * @param node the node use for the location of the error
412 * @return `true` if and only if a hint code is generated on the passed node
413 * See [HintCode.DEPRECATED_MEMBER_USE].
414 */
415 bool _checkForDeprecatedMemberUse(Element element, AstNode node) {
416 if (element != null && element.isDeprecated) {
417 String displayName = element.displayName;
418 if (element is ConstructorElement) {
419 // TODO(jwren) We should modify ConstructorElement.getDisplayName(),
420 // or have the logic centralized elsewhere, instead of doing this logic
421 // here.
422 ConstructorElement constructorElement = element;
423 displayName = constructorElement.enclosingElement.displayName;
424 if (!constructorElement.displayName.isEmpty) {
425 displayName = "$displayName.${constructorElement.displayName}";
426 }
427 }
428 _errorReporter.reportErrorForNode(
429 HintCode.DEPRECATED_MEMBER_USE, node, [displayName]);
430 return true;
431 }
432 return false;
433 }
434
435 /**
436 * For [SimpleIdentifier]s, only call [checkForDeprecatedMemberUse]
437 * if the node is not in a declaration context.
438 *
439 * Also, if the identifier is a constructor name in a constructor invocation, then calls to the
440 * deprecated constructor will be caught by
441 * [visitInstanceCreationExpression] and
442 * [visitSuperConstructorInvocation], and can be ignored by
443 * this visit method.
444 *
445 * @param identifier some simple identifier to check for deprecated use of
446 * @return `true` if and only if a hint code is generated on the passed node
447 * See [HintCode.DEPRECATED_MEMBER_USE].
448 */
449 bool _checkForDeprecatedMemberUseAtIdentifier(SimpleIdentifier identifier) {
450 if (identifier.inDeclarationContext()) {
451 return false;
452 }
453 AstNode parent = identifier.parent;
454 if ((parent is ConstructorName && identical(identifier, parent.name)) ||
455 (parent is SuperConstructorInvocation &&
456 identical(identifier, parent.constructorName)) ||
457 parent is HideCombinator) {
458 return false;
459 }
460 return _checkForDeprecatedMemberUse(identifier.bestElement, identifier);
461 }
462
463 /**
464 * Check for the passed binary expression for the [HintCode.DIVISION_OPTIMIZAT ION].
465 *
466 * @param node the binary expression to check
467 * @return `true` if and only if a hint code is generated on the passed node
468 * See [HintCode.DIVISION_OPTIMIZATION].
469 */
470 bool _checkForDivisionOptimizationHint(BinaryExpression node) {
471 // Return if the operator is not '/'
472 if (node.operator.type != sc.TokenType.SLASH) {
473 return false;
474 }
475 // Return if the '/' operator is not defined in core, or if we don't know
476 // its static or propagated type
477 MethodElement methodElement = node.bestElement;
478 if (methodElement == null) {
479 return false;
480 }
481 LibraryElement libraryElement = methodElement.library;
482 if (libraryElement != null && !libraryElement.isDartCore) {
483 return false;
484 }
485 // Report error if the (x/y) has toInt() invoked on it
486 if (node.parent is ParenthesizedExpression) {
487 ParenthesizedExpression parenthesizedExpression =
488 _wrapParenthesizedExpression(node.parent as ParenthesizedExpression);
489 if (parenthesizedExpression.parent is MethodInvocation) {
490 MethodInvocation methodInvocation =
491 parenthesizedExpression.parent as MethodInvocation;
492 if (_TO_INT_METHOD_NAME == methodInvocation.methodName.name &&
493 methodInvocation.argumentList.arguments.isEmpty) {
494 _errorReporter.reportErrorForNode(
495 HintCode.DIVISION_OPTIMIZATION, methodInvocation);
496 return true;
497 }
498 }
499 }
500 return false;
501 }
502
503 /**
504 * This verifies that the passed left hand side and right hand side represent a valid assignment.
505 *
506 * This method corresponds to ErrorVerifier.checkForInvalidAssignment.
507 *
508 * @param lhs the left hand side expression
509 * @param rhs the right hand side expression
510 * @return `true` if and only if an error code is generated on the passed node
511 * See [HintCode.INVALID_ASSIGNMENT].
512 */
513 bool _checkForInvalidAssignment(Expression lhs, Expression rhs) {
514 if (lhs == null || rhs == null) {
515 return false;
516 }
517 VariableElement leftVariableElement = ErrorVerifier.getVariableElement(lhs);
518 DartType leftType = (leftVariableElement == null)
519 ? ErrorVerifier.getStaticType(lhs)
520 : leftVariableElement.type;
521 DartType staticRightType = ErrorVerifier.getStaticType(rhs);
522 if (!staticRightType.isAssignableTo(leftType)) {
523 // The warning was generated on this rhs
524 return false;
525 }
526 // Test for, and then generate the hint
527 DartType bestRightType = rhs.bestType;
528 if (leftType != null && bestRightType != null) {
529 if (!bestRightType.isAssignableTo(leftType)) {
530 _errorReporter.reportTypeErrorForNode(
531 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]);
532 return true;
533 }
534 }
535 return false;
536 }
537
538 /**
539 * Check that the imported library does not define a loadLibrary function. The import has already
540 * been determined to be deferred when this is called.
541 *
542 * @param node the import directive to evaluate
543 * @param importElement the [ImportElement] retrieved from the node
544 * @return `true` if and only if an error code is generated on the passed node
545 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION].
546 */
547 bool _checkForLoadLibraryFunction(
548 ImportDirective node, ImportElement importElement) {
549 LibraryElement importedLibrary = importElement.importedLibrary;
550 if (importedLibrary == null) {
551 return false;
552 }
553 if (importedLibrary.hasLoadLibraryFunction) {
554 _errorReporter.reportErrorForNode(
555 HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION,
556 node,
557 [importedLibrary.name]);
558 return true;
559 }
560 return false;
561 }
562
563 /**
564 * Generate a hint for functions or methods that have a return type, but do no t have a return
565 * statement on all branches. At the end of blocks with no return, Dart implic itly returns
566 * `null`, avoiding these implicit returns is considered a best practice.
567 *
568 * Note: for async functions/methods, this hint only applies when the
569 * function has a return type that Future<Null> is not assignable to.
570 *
571 * @param node the binary expression to check
572 * @param body the function body
573 * @return `true` if and only if a hint code is generated on the passed node
574 * See [HintCode.MISSING_RETURN].
575 */
576 bool _checkForMissingReturn(TypeName returnType, FunctionBody body) {
577 // Check that the method or function has a return type, and a function body
578 if (returnType == null || body == null) {
579 return false;
580 }
581 // Check that the body is a BlockFunctionBody
582 if (body is! BlockFunctionBody) {
583 return false;
584 }
585 // Generators are never required to have a return statement.
586 if (body.isGenerator) {
587 return false;
588 }
589 // Check that the type is resolvable, and is not "void"
590 DartType returnTypeType = returnType.type;
591 if (returnTypeType == null || returnTypeType.isVoid) {
592 return false;
593 }
594 // For async, give no hint if Future<Null> is assignable to the return
595 // type.
596 if (body.isAsynchronous && _futureNullType.isAssignableTo(returnTypeType)) {
597 return false;
598 }
599 // Check the block for a return statement, if not, create the hint
600 BlockFunctionBody blockFunctionBody = body as BlockFunctionBody;
601 if (!ExitDetector.exits(blockFunctionBody)) {
602 _errorReporter.reportErrorForNode(
603 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
604 return true;
605 }
606 return false;
607 }
608
609 /**
610 * Check for the passed class declaration for the
611 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
612 *
613 * @param node the class declaration to check
614 * @return `true` if and only if a hint code is generated on the passed node
615 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
616 */
617 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
618 // ClassElement classElement = node.element;
619 // if (classElement == null) {
620 // return false;
621 // }
622 // MethodElement equalsOperatorMethodElement =
623 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
624 // if (equalsOperatorMethodElement != null) {
625 // PropertyAccessorElement hashCodeElement =
626 // classElement.getGetter(_HASHCODE_GETTER_NAME);
627 // if (hashCodeElement == null) {
628 // _errorReporter.reportErrorForNode(
629 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
630 // node.name,
631 // [classElement.displayName]);
632 // return true;
633 // }
634 // }
635 // return false;
636 // }
637
638 /**
639 * Check for the passed as expression for the [HintCode.UNNECESSARY_CAST] hint code.
640 *
641 * @param node the as expression to check
642 * @return `true` if and only if a hint code is generated on the passed node
643 * See [HintCode.UNNECESSARY_CAST].
644 */
645 bool _checkForUnnecessaryCast(AsExpression node) {
646 // TODO(jwren) After dartbug.com/13732, revisit this, we should be able to
647 // remove the (x is! TypeParameterType) checks.
648 AstNode parent = node.parent;
649 if (parent is ConditionalExpression &&
650 (node == parent.thenExpression || node == parent.elseExpression)) {
651 Expression thenExpression = parent.thenExpression;
652 DartType thenType;
653 if (thenExpression is AsExpression) {
654 thenType = thenExpression.expression.staticType;
655 } else {
656 thenType = thenExpression.staticType;
657 }
658 Expression elseExpression = parent.elseExpression;
659 DartType elseType;
660 if (elseExpression is AsExpression) {
661 elseType = elseExpression.expression.staticType;
662 } else {
663 elseType = elseExpression.staticType;
664 }
665 if (thenType != null &&
666 elseType != null &&
667 !thenType.isDynamic &&
668 !elseType.isDynamic &&
669 !thenType.isMoreSpecificThan(elseType) &&
670 !elseType.isMoreSpecificThan(thenType)) {
671 return false;
672 }
673 }
674 DartType lhsType = node.expression.staticType;
675 DartType rhsType = node.type.type;
676 if (lhsType != null &&
677 rhsType != null &&
678 !lhsType.isDynamic &&
679 !rhsType.isDynamic &&
680 lhsType.isMoreSpecificThan(rhsType)) {
681 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node);
682 return true;
683 }
684 return false;
685 }
686
687 /**
688 * Check for situations where the result of a method or function is used, when it returns 'void'.
689 *
690 * TODO(jwren) Many other situations of use could be covered. We currently cov er the cases var x =
691 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m (), f(m()), return
692 * m().
693 *
694 * @param node expression on the RHS of some assignment
695 * @return `true` if and only if a hint code is generated on the passed node
696 * See [HintCode.USE_OF_VOID_RESULT].
697 */
698 bool _checkForUseOfVoidResult(Expression expression) {
699 if (expression == null || expression is! MethodInvocation) {
700 return false;
701 }
702 MethodInvocation methodInvocation = expression as MethodInvocation;
703 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) {
704 SimpleIdentifier methodName = methodInvocation.methodName;
705 _errorReporter.reportErrorForNode(
706 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
707 return true;
708 }
709 return false;
710 }
711
712 /**
713 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the
714 * expression that is a parenthesized expression, but whose parent is not a pa renthesized
715 * expression.
716 *
717 * For example given the code `(((e)))`: `(e) -> (((e)))`.
718 *
719 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression
720 * @return the first parent or grand-parent that is a parenthesized expression , that does not have
721 * a parenthesized expression parent
722 */
723 static ParenthesizedExpression _wrapParenthesizedExpression(
724 ParenthesizedExpression parenthesizedExpression) {
725 if (parenthesizedExpression.parent is ParenthesizedExpression) {
726 return _wrapParenthesizedExpression(
727 parenthesizedExpression.parent as ParenthesizedExpression);
728 }
729 return parenthesizedExpression;
730 }
731 }
732
733 /**
734 * Instances of the class `ClassScope` implement the scope defined by a class.
735 */
736 class ClassScope extends EnclosedScope {
737 /**
738 * Initialize a newly created scope enclosed within another scope.
739 *
740 * @param enclosingScope the scope in which this scope is lexically enclosed
741 * @param typeElement the element representing the type represented by this sc ope
742 */
743 ClassScope(Scope enclosingScope, ClassElement typeElement)
744 : super(enclosingScope) {
745 if (typeElement == null) {
746 throw new IllegalArgumentException("class element cannot be null");
747 }
748 _defineMembers(typeElement);
749 }
750
751 @override
752 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
753 if (existing is PropertyAccessorElement && duplicate is MethodElement) {
754 if (existing.nameOffset < duplicate.nameOffset) {
755 return new AnalysisError(
756 duplicate.source,
757 duplicate.nameOffset,
758 duplicate.displayName.length,
759 CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME,
760 [existing.displayName]);
761 } else {
762 return new AnalysisError(
763 existing.source,
764 existing.nameOffset,
765 existing.displayName.length,
766 CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
767 [existing.displayName]);
768 }
769 }
770 return super.getErrorForDuplicate(existing, duplicate);
771 }
772
773 /**
774 * Define the instance members defined by the class.
775 *
776 * @param typeElement the element representing the type represented by this sc ope
777 */
778 void _defineMembers(ClassElement typeElement) {
779 for (PropertyAccessorElement accessor in typeElement.accessors) {
780 define(accessor);
781 }
782 for (MethodElement method in typeElement.methods) {
783 define(method);
784 }
785 }
786 }
787
788 /**
789 * A `CompilationUnitBuilder` builds an element model for a single compilation
790 * unit.
791 */
792 class CompilationUnitBuilder {
793 /**
794 * Build the compilation unit element for the given [source] based on the
795 * compilation [unit] associated with the source. Throw an AnalysisException
796 * if the element could not be built. [librarySource] is the source for the
797 * containing library.
798 */
799 CompilationUnitElementImpl buildCompilationUnit(
800 Source source, CompilationUnit unit, Source librarySource) {
801 return PerformanceStatistics.resolve.makeCurrentWhile(() {
802 if (unit == null) {
803 return null;
804 }
805 ElementHolder holder = new ElementHolder();
806 ElementBuilder builder = new ElementBuilder(holder);
807 unit.accept(builder);
808 CompilationUnitElementImpl element =
809 new CompilationUnitElementImpl(source.shortName);
810 element.accessors = holder.accessors;
811 element.enums = holder.enums;
812 element.functions = holder.functions;
813 element.source = source;
814 element.librarySource = librarySource;
815 element.typeAliases = holder.typeAliases;
816 element.types = holder.types;
817 element.topLevelVariables = holder.topLevelVariables;
818 unit.element = element;
819 holder.validate();
820 return element;
821 });
822 }
823 }
824
825 /**
826 * Instances of the class `ConstantVerifier` traverse an AST structure looking f or additional
827 * errors and warnings not covered by the parser and resolver. In particular, it looks for errors
828 * and warnings related to constant expressions.
829 */
830 class ConstantVerifier extends RecursiveAstVisitor<Object> {
831 /**
832 * The error reporter by which errors will be reported.
833 */
834 final ErrorReporter _errorReporter;
835
836 /**
837 * The type provider used to access the known types.
838 */
839 final TypeProvider _typeProvider;
840
841 /**
842 * The set of variables declared using '-D' on the command line.
843 */
844 final DeclaredVariables declaredVariables;
845
846 /**
847 * The type representing the type 'bool'.
848 */
849 InterfaceType _boolType;
850
851 /**
852 * The type representing the type 'int'.
853 */
854 InterfaceType _intType;
855
856 /**
857 * The type representing the type 'num'.
858 */
859 InterfaceType _numType;
860
861 /**
862 * The type representing the type 'string'.
863 */
864 InterfaceType _stringType;
865
866 /**
867 * The current library that is being analyzed.
868 */
869 final LibraryElement _currentLibrary;
870
871 /**
872 * Initialize a newly created constant verifier.
873 *
874 * @param errorReporter the error reporter by which errors will be reported
875 */
876 ConstantVerifier(this._errorReporter, this._currentLibrary,
877 this._typeProvider, this.declaredVariables) {
878 this._boolType = _typeProvider.boolType;
879 this._intType = _typeProvider.intType;
880 this._numType = _typeProvider.numType;
881 this._stringType = _typeProvider.stringType;
882 }
883
884 @override
885 Object visitAnnotation(Annotation node) {
886 super.visitAnnotation(node);
887 // check annotation creation
888 Element element = node.element;
889 if (element is ConstructorElement) {
890 ConstructorElement constructorElement = element;
891 // should 'const' constructor
892 if (!constructorElement.isConst) {
893 _errorReporter.reportErrorForNode(
894 CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node);
895 return null;
896 }
897 // should have arguments
898 ArgumentList argumentList = node.arguments;
899 if (argumentList == null) {
900 _errorReporter.reportErrorForNode(
901 CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node);
902 return null;
903 }
904 // arguments should be constants
905 _validateConstantArguments(argumentList);
906 }
907 return null;
908 }
909
910 @override
911 Object visitConstructorDeclaration(ConstructorDeclaration node) {
912 if (node.constKeyword != null) {
913 _validateConstructorInitializers(node);
914 _validateFieldInitializers(node.parent as ClassDeclaration, node);
915 }
916 _validateDefaultValues(node.parameters);
917 return super.visitConstructorDeclaration(node);
918 }
919
920 @override
921 Object visitFunctionExpression(FunctionExpression node) {
922 super.visitFunctionExpression(node);
923 _validateDefaultValues(node.parameters);
924 return null;
925 }
926
927 @override
928 Object visitInstanceCreationExpression(InstanceCreationExpression node) {
929 if (node.isConst) {
930 // We need to evaluate the constant to see if any errors occur during its
931 // evaluation.
932 ConstructorElement constructor = node.staticElement;
933 if (constructor != null) {
934 ConstantEvaluationEngine evaluationEngine =
935 new ConstantEvaluationEngine(_typeProvider, declaredVariables);
936 ConstantVisitor constantVisitor =
937 new ConstantVisitor(evaluationEngine, _errorReporter);
938 evaluationEngine.evaluateConstructorCall(
939 node,
940 node.argumentList.arguments,
941 constructor,
942 constantVisitor,
943 _errorReporter);
944 }
945 }
946 _validateInstanceCreationArguments(node);
947 return super.visitInstanceCreationExpression(node);
948 }
949
950 @override
951 Object visitListLiteral(ListLiteral node) {
952 super.visitListLiteral(node);
953 if (node.constKeyword != null) {
954 DartObjectImpl result;
955 for (Expression element in node.elements) {
956 result =
957 _validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT);
958 if (result != null) {
959 _reportErrorIfFromDeferredLibrary(element,
960 CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRA RY);
961 }
962 }
963 }
964 return null;
965 }
966
967 @override
968 Object visitMapLiteral(MapLiteral node) {
969 super.visitMapLiteral(node);
970 bool isConst = node.constKeyword != null;
971 bool reportEqualKeys = true;
972 HashSet<DartObject> keys = new HashSet<DartObject>();
973 List<Expression> invalidKeys = new List<Expression>();
974 for (MapLiteralEntry entry in node.entries) {
975 Expression key = entry.key;
976 if (isConst) {
977 DartObjectImpl keyResult =
978 _validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY);
979 Expression valueExpression = entry.value;
980 DartObjectImpl valueResult = _validate(
981 valueExpression, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE);
982 if (valueResult != null) {
983 _reportErrorIfFromDeferredLibrary(valueExpression,
984 CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY) ;
985 }
986 if (keyResult != null) {
987 _reportErrorIfFromDeferredLibrary(key,
988 CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY);
989 if (keys.contains(keyResult)) {
990 invalidKeys.add(key);
991 } else {
992 keys.add(keyResult);
993 }
994 DartType type = keyResult.type;
995 if (_implementsEqualsWhenNotAllowed(type)) {
996 _errorReporter.reportErrorForNode(
997 CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQ UALS,
998 key,
999 [type.displayName]);
1000 }
1001 }
1002 } else {
1003 // Note: we throw the errors away because this isn't actually a const.
1004 AnalysisErrorListener errorListener =
1005 AnalysisErrorListener.NULL_LISTENER;
1006 ErrorReporter subErrorReporter =
1007 new ErrorReporter(errorListener, _errorReporter.source);
1008 DartObjectImpl result = key.accept(new ConstantVisitor(
1009 new ConstantEvaluationEngine(_typeProvider, declaredVariables),
1010 subErrorReporter));
1011 if (result != null) {
1012 if (keys.contains(result)) {
1013 invalidKeys.add(key);
1014 } else {
1015 keys.add(result);
1016 }
1017 } else {
1018 reportEqualKeys = false;
1019 }
1020 }
1021 }
1022 if (reportEqualKeys) {
1023 for (Expression key in invalidKeys) {
1024 _errorReporter.reportErrorForNode(
1025 StaticWarningCode.EQUAL_KEYS_IN_MAP, key);
1026 }
1027 }
1028 return null;
1029 }
1030
1031 @override
1032 Object visitMethodDeclaration(MethodDeclaration node) {
1033 super.visitMethodDeclaration(node);
1034 _validateDefaultValues(node.parameters);
1035 return null;
1036 }
1037
1038 @override
1039 Object visitSwitchStatement(SwitchStatement node) {
1040 // TODO(paulberry): to minimize error messages, it would be nice to
1041 // compare all types with the most popular type rather than the first
1042 // type.
1043 NodeList<SwitchMember> switchMembers = node.members;
1044 bool foundError = false;
1045 DartType firstType = null;
1046 for (SwitchMember switchMember in switchMembers) {
1047 if (switchMember is SwitchCase) {
1048 SwitchCase switchCase = switchMember;
1049 Expression expression = switchCase.expression;
1050 DartObjectImpl caseResult = _validate(
1051 expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION);
1052 if (caseResult != null) {
1053 _reportErrorIfFromDeferredLibrary(expression,
1054 CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LI BRARY);
1055 DartObject value = caseResult;
1056 if (firstType == null) {
1057 firstType = value.type;
1058 } else {
1059 DartType nType = value.type;
1060 if (firstType != nType) {
1061 _errorReporter.reportErrorForNode(
1062 CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES,
1063 expression,
1064 [expression.toSource(), firstType.displayName]);
1065 foundError = true;
1066 }
1067 }
1068 }
1069 }
1070 }
1071 if (!foundError) {
1072 _checkForCaseExpressionTypeImplementsEquals(node, firstType);
1073 }
1074 return super.visitSwitchStatement(node);
1075 }
1076
1077 @override
1078 Object visitVariableDeclaration(VariableDeclaration node) {
1079 super.visitVariableDeclaration(node);
1080 Expression initializer = node.initializer;
1081 if (initializer != null && (node.isConst || node.isFinal)) {
1082 VariableElementImpl element = node.element as VariableElementImpl;
1083 EvaluationResultImpl result = element.evaluationResult;
1084 if (result == null) {
1085 // Variables marked "const" should have had their values computed by
1086 // ConstantValueComputer. Other variables will only have had their
1087 // values computed if the value was needed (e.g. final variables in a
1088 // class containing const constructors).
1089 assert(!node.isConst);
1090 return null;
1091 }
1092 _reportErrors(result.errors,
1093 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
1094 _reportErrorIfFromDeferredLibrary(initializer,
1095 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DE FERRED_LIBRARY);
1096 }
1097 return null;
1098 }
1099
1100 /**
1101 * This verifies that the passed switch statement does not have a case express ion with the
1102 * operator '==' overridden.
1103 *
1104 * @param node the switch statement to evaluate
1105 * @param type the common type of all 'case' expressions
1106 * @return `true` if and only if an error code is generated on the passed node
1107 * See [CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS].
1108 */
1109 bool _checkForCaseExpressionTypeImplementsEquals(
1110 SwitchStatement node, DartType type) {
1111 if (!_implementsEqualsWhenNotAllowed(type)) {
1112 return false;
1113 }
1114 // report error
1115 _errorReporter.reportErrorForToken(
1116 CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
1117 node.switchKeyword,
1118 [type.displayName]);
1119 return true;
1120 }
1121
1122 /**
1123 * @return `true` if given [Type] implements operator <i>==</i>, and it is not
1124 * <i>int</i> or <i>String</i>.
1125 */
1126 bool _implementsEqualsWhenNotAllowed(DartType type) {
1127 // ignore int or String
1128 if (type == null || type == _intType || type == _typeProvider.stringType) {
1129 return false;
1130 } else if (type == _typeProvider.doubleType) {
1131 return true;
1132 }
1133 // prepare ClassElement
1134 Element element = type.element;
1135 if (element is! ClassElement) {
1136 return false;
1137 }
1138 ClassElement classElement = element as ClassElement;
1139 // lookup for ==
1140 MethodElement method =
1141 classElement.lookUpConcreteMethod("==", _currentLibrary);
1142 if (method == null || method.enclosingElement.type.isObject) {
1143 return false;
1144 }
1145 // there is == that we don't like
1146 return true;
1147 }
1148
1149 /**
1150 * Given some computed [Expression], this method generates the passed [ErrorCo de] on
1151 * the node if its' value consists of information from a deferred library.
1152 *
1153 * @param expression the expression to be tested for a deferred library refere nce
1154 * @param errorCode the error code to be used if the expression is or consists of a reference to a
1155 * deferred library
1156 */
1157 void _reportErrorIfFromDeferredLibrary(
1158 Expression expression, ErrorCode errorCode) {
1159 DeferredLibraryReferenceDetector referenceDetector =
1160 new DeferredLibraryReferenceDetector();
1161 expression.accept(referenceDetector);
1162 if (referenceDetector.result) {
1163 _errorReporter.reportErrorForNode(errorCode, expression);
1164 }
1165 }
1166
1167 /**
1168 * Report any errors in the given list. Except for special cases, use the give n error code rather
1169 * than the one reported in the error.
1170 *
1171 * @param errors the errors that need to be reported
1172 * @param errorCode the error code to be used
1173 */
1174 void _reportErrors(List<AnalysisError> errors, ErrorCode errorCode) {
1175 for (AnalysisError data in errors) {
1176 ErrorCode dataErrorCode = data.errorCode;
1177 if (identical(dataErrorCode,
1178 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) ||
1179 identical(
1180 dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) ||
1181 identical(dataErrorCode,
1182 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) ||
1183 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) ||
1184 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) ||
1185 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) ||
1186 identical(dataErrorCode,
1187 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) ||
1188 identical(dataErrorCode,
1189 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMA TCH) ||
1190 identical(dataErrorCode,
1191 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMA TCH) ||
1192 identical(dataErrorCode,
1193 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH)) {
1194 _errorReporter.reportError(data);
1195 } else if (errorCode != null) {
1196 _errorReporter.reportError(new AnalysisError(
1197 data.source, data.offset, data.length, errorCode));
1198 }
1199 }
1200 }
1201
1202 /**
1203 * Validate that the given expression is a compile time constant. Return the v alue of the compile
1204 * time constant, or `null` if the expression is not a compile time constant.
1205 *
1206 * @param expression the expression to be validated
1207 * @param errorCode the error code to be used if the expression is not a compi le time constant
1208 * @return the value of the compile time constant
1209 */
1210 DartObjectImpl _validate(Expression expression, ErrorCode errorCode) {
1211 RecordingErrorListener errorListener = new RecordingErrorListener();
1212 ErrorReporter subErrorReporter =
1213 new ErrorReporter(errorListener, _errorReporter.source);
1214 DartObjectImpl result = expression.accept(new ConstantVisitor(
1215 new ConstantEvaluationEngine(_typeProvider, declaredVariables),
1216 subErrorReporter));
1217 _reportErrors(errorListener.errors, errorCode);
1218 return result;
1219 }
1220
1221 /**
1222 * Validate that if the passed arguments are constant expressions.
1223 *
1224 * @param argumentList the argument list to evaluate
1225 */
1226 void _validateConstantArguments(ArgumentList argumentList) {
1227 for (Expression argument in argumentList.arguments) {
1228 if (argument is NamedExpression) {
1229 argument = (argument as NamedExpression).expression;
1230 }
1231 _validate(
1232 argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
1233 }
1234 }
1235
1236 /**
1237 * Validates that the expressions of the given initializers (of a constant con structor) are all
1238 * compile time constants.
1239 *
1240 * @param constructor the constant constructor declaration to validate
1241 */
1242 void _validateConstructorInitializers(ConstructorDeclaration constructor) {
1243 List<ParameterElement> parameterElements =
1244 constructor.parameters.parameterElements;
1245 NodeList<ConstructorInitializer> initializers = constructor.initializers;
1246 for (ConstructorInitializer initializer in initializers) {
1247 if (initializer is ConstructorFieldInitializer) {
1248 ConstructorFieldInitializer fieldInitializer = initializer;
1249 _validateInitializerExpression(
1250 parameterElements, fieldInitializer.expression);
1251 }
1252 if (initializer is RedirectingConstructorInvocation) {
1253 RedirectingConstructorInvocation invocation = initializer;
1254 _validateInitializerInvocationArguments(
1255 parameterElements, invocation.argumentList);
1256 }
1257 if (initializer is SuperConstructorInvocation) {
1258 SuperConstructorInvocation invocation = initializer;
1259 _validateInitializerInvocationArguments(
1260 parameterElements, invocation.argumentList);
1261 }
1262 }
1263 }
1264
1265 /**
1266 * Validate that the default value associated with each of the parameters in t he given list is a
1267 * compile time constant.
1268 *
1269 * @param parameters the list of parameters to be validated
1270 */
1271 void _validateDefaultValues(FormalParameterList parameters) {
1272 if (parameters == null) {
1273 return;
1274 }
1275 for (FormalParameter parameter in parameters.parameters) {
1276 if (parameter is DefaultFormalParameter) {
1277 DefaultFormalParameter defaultParameter = parameter;
1278 Expression defaultValue = defaultParameter.defaultValue;
1279 DartObjectImpl result;
1280 if (defaultValue == null) {
1281 result =
1282 new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE);
1283 } else {
1284 result = _validate(
1285 defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE);
1286 if (result != null) {
1287 _reportErrorIfFromDeferredLibrary(defaultValue,
1288 CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LI BRARY);
1289 }
1290 }
1291 VariableElementImpl element = parameter.element as VariableElementImpl;
1292 element.evaluationResult = new EvaluationResultImpl(result);
1293 }
1294 }
1295 }
1296
1297 /**
1298 * Validates that the expressions of any field initializers in the class decla ration are all
1299 * compile time constants. Since this is only required if the class has a cons tant constructor,
1300 * the error is reported at the constructor site.
1301 *
1302 * @param classDeclaration the class which should be validated
1303 * @param errorSite the site at which errors should be reported.
1304 */
1305 void _validateFieldInitializers(
1306 ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) {
1307 NodeList<ClassMember> members = classDeclaration.members;
1308 for (ClassMember member in members) {
1309 if (member is FieldDeclaration) {
1310 FieldDeclaration fieldDeclaration = member;
1311 if (!fieldDeclaration.isStatic) {
1312 for (VariableDeclaration variableDeclaration
1313 in fieldDeclaration.fields.variables) {
1314 Expression initializer = variableDeclaration.initializer;
1315 if (initializer != null) {
1316 // Ignore any errors produced during validation--if the constant
1317 // can't be eavluated we'll just report a single error.
1318 AnalysisErrorListener errorListener =
1319 AnalysisErrorListener.NULL_LISTENER;
1320 ErrorReporter subErrorReporter =
1321 new ErrorReporter(errorListener, _errorReporter.source);
1322 DartObjectImpl result = initializer.accept(new ConstantVisitor(
1323 new ConstantEvaluationEngine(
1324 _typeProvider, declaredVariables),
1325 subErrorReporter));
1326 if (result == null) {
1327 _errorReporter.reportErrorForNode(
1328 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZE D_BY_NON_CONST,
1329 errorSite,
1330 [variableDeclaration.name.name]);
1331 }
1332 }
1333 }
1334 }
1335 }
1336 }
1337 }
1338
1339 /**
1340 * Validates that the given expression is a compile time constant.
1341 *
1342 * @param parameterElements the elements of parameters of constant constructor , they are
1343 * considered as a valid potentially constant expressions
1344 * @param expression the expression to validate
1345 */
1346 void _validateInitializerExpression(
1347 List<ParameterElement> parameterElements, Expression expression) {
1348 RecordingErrorListener errorListener = new RecordingErrorListener();
1349 ErrorReporter subErrorReporter =
1350 new ErrorReporter(errorListener, _errorReporter.source);
1351 DartObjectImpl result = expression.accept(
1352 new _ConstantVerifier_validateInitializerExpression(_typeProvider,
1353 subErrorReporter, this, parameterElements, declaredVariables));
1354 _reportErrors(errorListener.errors,
1355 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
1356 if (result != null) {
1357 _reportErrorIfFromDeferredLibrary(expression,
1358 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_L IBRARY);
1359 }
1360 }
1361
1362 /**
1363 * Validates that all of the arguments of a constructor initializer are compil e time constants.
1364 *
1365 * @param parameterElements the elements of parameters of constant constructor , they are
1366 * considered as a valid potentially constant expressions
1367 * @param argumentList the argument list to validate
1368 */
1369 void _validateInitializerInvocationArguments(
1370 List<ParameterElement> parameterElements, ArgumentList argumentList) {
1371 if (argumentList == null) {
1372 return;
1373 }
1374 for (Expression argument in argumentList.arguments) {
1375 _validateInitializerExpression(parameterElements, argument);
1376 }
1377 }
1378
1379 /**
1380 * Validate that if the passed instance creation is 'const' then all its argum ents are constant
1381 * expressions.
1382 *
1383 * @param node the instance creation evaluate
1384 */
1385 void _validateInstanceCreationArguments(InstanceCreationExpression node) {
1386 if (!node.isConst) {
1387 return;
1388 }
1389 ArgumentList argumentList = node.argumentList;
1390 if (argumentList == null) {
1391 return;
1392 }
1393 _validateConstantArguments(argumentList);
1394 }
1395 }
1396
1397 /**
1398 * Instances of the class `Dart2JSVerifier` traverse an AST structure looking fo r hints for
1399 * code that will be compiled to JS, such as [HintCode.IS_DOUBLE].
1400 */
1401 class Dart2JSVerifier extends RecursiveAstVisitor<Object> {
1402 /**
1403 * The name of the `double` type.
1404 */
1405 static String _DOUBLE_TYPE_NAME = "double";
1406
1407 /**
1408 * The error reporter by which errors will be reported.
1409 */
1410 final ErrorReporter _errorReporter;
1411
1412 /**
1413 * Create a new instance of the [Dart2JSVerifier].
1414 *
1415 * @param errorReporter the error reporter
1416 */
1417 Dart2JSVerifier(this._errorReporter);
1418
1419 @override
1420 Object visitIsExpression(IsExpression node) {
1421 _checkForIsDoubleHints(node);
1422 return super.visitIsExpression(node);
1423 }
1424
1425 /**
1426 * Check for instances of `x is double`, `x is int`, `x is! double` and
1427 * `x is! int`.
1428 *
1429 * @param node the is expression to check
1430 * @return `true` if and only if a hint code is generated on the passed node
1431 * See [HintCode.IS_DOUBLE],
1432 * [HintCode.IS_INT],
1433 * [HintCode.IS_NOT_DOUBLE], and
1434 * [HintCode.IS_NOT_INT].
1435 */
1436 bool _checkForIsDoubleHints(IsExpression node) {
1437 TypeName typeName = node.type;
1438 DartType type = typeName.type;
1439 if (type != null && type.element != null) {
1440 Element element = type.element;
1441 String typeNameStr = element.name;
1442 LibraryElement libraryElement = element.library;
1443 // if (typeNameStr.equals(INT_TYPE_NAME) && libraryElement != null
1444 // && libraryElement.isDartCore()) {
1445 // if (node.getNotOperator() == null) {
1446 // errorReporter.reportError(HintCode.IS_INT, node);
1447 // } else {
1448 // errorReporter.reportError(HintCode.IS_NOT_INT, node);
1449 // }
1450 // return true;
1451 // } else
1452 if (typeNameStr == _DOUBLE_TYPE_NAME &&
1453 libraryElement != null &&
1454 libraryElement.isDartCore) {
1455 if (node.notOperator == null) {
1456 _errorReporter.reportErrorForNode(HintCode.IS_DOUBLE, node);
1457 } else {
1458 _errorReporter.reportErrorForNode(HintCode.IS_NOT_DOUBLE, node);
1459 }
1460 return true;
1461 }
1462 }
1463 return false;
1464 }
1465 }
1466
1467 /**
1468 * Instances of the class `DeadCodeVerifier` traverse an AST structure looking f or cases of
1469 * [HintCode.DEAD_CODE].
1470 */
1471 class DeadCodeVerifier extends RecursiveAstVisitor<Object> {
1472 /**
1473 * The error reporter by which errors will be reported.
1474 */
1475 final ErrorReporter _errorReporter;
1476
1477 /**
1478 * Create a new instance of the [DeadCodeVerifier].
1479 *
1480 * @param errorReporter the error reporter
1481 */
1482 DeadCodeVerifier(this._errorReporter);
1483
1484 @override
1485 Object visitBinaryExpression(BinaryExpression node) {
1486 sc.Token operator = node.operator;
1487 bool isAmpAmp = operator.type == sc.TokenType.AMPERSAND_AMPERSAND;
1488 bool isBarBar = operator.type == sc.TokenType.BAR_BAR;
1489 if (isAmpAmp || isBarBar) {
1490 Expression lhsCondition = node.leftOperand;
1491 if (!_isDebugConstant(lhsCondition)) {
1492 EvaluationResultImpl lhsResult = _getConstantBooleanValue(lhsCondition);
1493 if (lhsResult != null) {
1494 if (lhsResult.value.isTrue && isBarBar) {
1495 // report error on else block: true || !e!
1496 _errorReporter.reportErrorForNode(
1497 HintCode.DEAD_CODE, node.rightOperand);
1498 // only visit the LHS:
1499 _safelyVisit(lhsCondition);
1500 return null;
1501 } else if (lhsResult.value.isFalse && isAmpAmp) {
1502 // report error on if block: false && !e!
1503 _errorReporter.reportErrorForNode(
1504 HintCode.DEAD_CODE, node.rightOperand);
1505 // only visit the LHS:
1506 _safelyVisit(lhsCondition);
1507 return null;
1508 }
1509 }
1510 }
1511 // How do we want to handle the RHS? It isn't dead code, but "pointless"
1512 // or "obscure"...
1513 // Expression rhsCondition = node.getRightOperand();
1514 // ValidResult rhsResult = getConstantBooleanValue(rhsCondition);
1515 // if (rhsResult != null) {
1516 // if (rhsResult == ValidResult.RESULT_TRUE && isBarBar) {
1517 // // report error on else block: !e! || true
1518 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand());
1519 // // only visit the RHS:
1520 // safelyVisit(rhsCondition);
1521 // return null;
1522 // } else if (rhsResult == ValidResult.RESULT_FALSE && isAmpAmp) {
1523 // // report error on if block: !e! && false
1524 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand());
1525 // // only visit the RHS:
1526 // safelyVisit(rhsCondition);
1527 // return null;
1528 // }
1529 // }
1530 }
1531 return super.visitBinaryExpression(node);
1532 }
1533
1534 /**
1535 * For each [Block], this method reports and error on all statements between t he end of the
1536 * block and the first return statement (assuming there it is not at the end o f the block.)
1537 *
1538 * @param node the block to evaluate
1539 */
1540 @override
1541 Object visitBlock(Block node) {
1542 NodeList<Statement> statements = node.statements;
1543 _checkForDeadStatementsInNodeList(statements);
1544 return null;
1545 }
1546
1547 @override
1548 Object visitConditionalExpression(ConditionalExpression node) {
1549 Expression conditionExpression = node.condition;
1550 _safelyVisit(conditionExpression);
1551 if (!_isDebugConstant(conditionExpression)) {
1552 EvaluationResultImpl result =
1553 _getConstantBooleanValue(conditionExpression);
1554 if (result != null) {
1555 if (result.value.isTrue) {
1556 // report error on else block: true ? 1 : !2!
1557 _errorReporter.reportErrorForNode(
1558 HintCode.DEAD_CODE, node.elseExpression);
1559 _safelyVisit(node.thenExpression);
1560 return null;
1561 } else {
1562 // report error on if block: false ? !1! : 2
1563 _errorReporter.reportErrorForNode(
1564 HintCode.DEAD_CODE, node.thenExpression);
1565 _safelyVisit(node.elseExpression);
1566 return null;
1567 }
1568 }
1569 }
1570 return super.visitConditionalExpression(node);
1571 }
1572
1573 @override
1574 Object visitIfStatement(IfStatement node) {
1575 Expression conditionExpression = node.condition;
1576 _safelyVisit(conditionExpression);
1577 if (!_isDebugConstant(conditionExpression)) {
1578 EvaluationResultImpl result =
1579 _getConstantBooleanValue(conditionExpression);
1580 if (result != null) {
1581 if (result.value.isTrue) {
1582 // report error on else block: if(true) {} else {!}
1583 Statement elseStatement = node.elseStatement;
1584 if (elseStatement != null) {
1585 _errorReporter.reportErrorForNode(
1586 HintCode.DEAD_CODE, elseStatement);
1587 _safelyVisit(node.thenStatement);
1588 return null;
1589 }
1590 } else {
1591 // report error on if block: if (false) {!} else {}
1592 _errorReporter.reportErrorForNode(
1593 HintCode.DEAD_CODE, node.thenStatement);
1594 _safelyVisit(node.elseStatement);
1595 return null;
1596 }
1597 }
1598 }
1599 return super.visitIfStatement(node);
1600 }
1601
1602 @override
1603 Object visitSwitchCase(SwitchCase node) {
1604 _checkForDeadStatementsInNodeList(node.statements);
1605 return super.visitSwitchCase(node);
1606 }
1607
1608 @override
1609 Object visitSwitchDefault(SwitchDefault node) {
1610 _checkForDeadStatementsInNodeList(node.statements);
1611 return super.visitSwitchDefault(node);
1612 }
1613
1614 @override
1615 Object visitTryStatement(TryStatement node) {
1616 _safelyVisit(node.body);
1617 _safelyVisit(node.finallyBlock);
1618 NodeList<CatchClause> catchClauses = node.catchClauses;
1619 int numOfCatchClauses = catchClauses.length;
1620 List<DartType> visitedTypes = new List<DartType>();
1621 for (int i = 0; i < numOfCatchClauses; i++) {
1622 CatchClause catchClause = catchClauses[i];
1623 if (catchClause.onKeyword != null) {
1624 // on-catch clause found, verify that the exception type is not a
1625 // subtype of a previous on-catch exception type
1626 TypeName typeName = catchClause.exceptionType;
1627 if (typeName != null && typeName.type != null) {
1628 DartType currentType = typeName.type;
1629 if (currentType.isObject) {
1630 // Found catch clause clause that has Object as an exception type,
1631 // this is equivalent to having a catch clause that doesn't have an
1632 // exception type, visit the block, but generate an error on any
1633 // following catch clauses (and don't visit them).
1634 _safelyVisit(catchClause);
1635 if (i + 1 != numOfCatchClauses) {
1636 // this catch clause is not the last in the try statement
1637 CatchClause nextCatchClause = catchClauses[i + 1];
1638 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1639 int offset = nextCatchClause.offset;
1640 int length = lastCatchClause.end - offset;
1641 _errorReporter.reportErrorForOffset(
1642 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length);
1643 return null;
1644 }
1645 }
1646 for (DartType type in visitedTypes) {
1647 if (currentType.isSubtypeOf(type)) {
1648 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1649 int offset = catchClause.offset;
1650 int length = lastCatchClause.end - offset;
1651 _errorReporter.reportErrorForOffset(
1652 HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
1653 offset,
1654 length,
1655 [currentType.displayName, type.displayName]);
1656 return null;
1657 }
1658 }
1659 visitedTypes.add(currentType);
1660 }
1661 _safelyVisit(catchClause);
1662 } else {
1663 // Found catch clause clause that doesn't have an exception type,
1664 // visit the block, but generate an error on any following catch clauses
1665 // (and don't visit them).
1666 _safelyVisit(catchClause);
1667 if (i + 1 != numOfCatchClauses) {
1668 // this catch clause is not the last in the try statement
1669 CatchClause nextCatchClause = catchClauses[i + 1];
1670 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1671 int offset = nextCatchClause.offset;
1672 int length = lastCatchClause.end - offset;
1673 _errorReporter.reportErrorForOffset(
1674 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length);
1675 return null;
1676 }
1677 }
1678 }
1679 return null;
1680 }
1681
1682 @override
1683 Object visitWhileStatement(WhileStatement node) {
1684 Expression conditionExpression = node.condition;
1685 _safelyVisit(conditionExpression);
1686 if (!_isDebugConstant(conditionExpression)) {
1687 EvaluationResultImpl result =
1688 _getConstantBooleanValue(conditionExpression);
1689 if (result != null) {
1690 if (result.value.isFalse) {
1691 // report error on if block: while (false) {!}
1692 _errorReporter.reportErrorForNode(HintCode.DEAD_CODE, node.body);
1693 return null;
1694 }
1695 }
1696 }
1697 _safelyVisit(node.body);
1698 return null;
1699 }
1700
1701 /**
1702 * Given some [NodeList] of [Statement]s, from either a [Block] or
1703 * [SwitchMember], this loops through the list in reverse order searching for statements
1704 * after a return, unlabeled break or unlabeled continue statement to mark the m as dead code.
1705 *
1706 * @param statements some ordered list of statements in a [Block] or [SwitchMe mber]
1707 */
1708 void _checkForDeadStatementsInNodeList(NodeList<Statement> statements) {
1709 int size = statements.length;
1710 for (int i = 0; i < size; i++) {
1711 Statement currentStatement = statements[i];
1712 _safelyVisit(currentStatement);
1713 bool returnOrBreakingStatement = currentStatement is ReturnStatement ||
1714 (currentStatement is BreakStatement &&
1715 currentStatement.label == null) ||
1716 (currentStatement is ContinueStatement &&
1717 currentStatement.label == null);
1718 if (returnOrBreakingStatement && i != size - 1) {
1719 Statement nextStatement = statements[i + 1];
1720 Statement lastStatement = statements[size - 1];
1721 int offset = nextStatement.offset;
1722 int length = lastStatement.end - offset;
1723 _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length);
1724 return;
1725 }
1726 }
1727 }
1728
1729 /**
1730 * Given some [Expression], this method returns [ValidResult.RESULT_TRUE] if i t is
1731 * `true`, [ValidResult.RESULT_FALSE] if it is `false`, or `null` if the
1732 * expression is not a constant boolean value.
1733 *
1734 * @param expression the expression to evaluate
1735 * @return [ValidResult.RESULT_TRUE] if it is `true`, [ValidResult.RESULT_FALS E]
1736 * if it is `false`, or `null` if the expression is not a constant boo lean
1737 * value
1738 */
1739 EvaluationResultImpl _getConstantBooleanValue(Expression expression) {
1740 if (expression is BooleanLiteral) {
1741 if (expression.value) {
1742 return new EvaluationResultImpl(
1743 new DartObjectImpl(null, BoolState.from(true)));
1744 } else {
1745 return new EvaluationResultImpl(
1746 new DartObjectImpl(null, BoolState.from(false)));
1747 }
1748 }
1749 // Don't consider situations where we could evaluate to a constant boolean
1750 // expression with the ConstantVisitor
1751 // else {
1752 // EvaluationResultImpl result = expression.accept(new ConstantVisitor());
1753 // if (result == ValidResult.RESULT_TRUE) {
1754 // return ValidResult.RESULT_TRUE;
1755 // } else if (result == ValidResult.RESULT_FALSE) {
1756 // return ValidResult.RESULT_FALSE;
1757 // }
1758 // return null;
1759 // }
1760 return null;
1761 }
1762
1763 /**
1764 * Return `true` if and only if the passed expression is resolved to a constan t variable.
1765 *
1766 * @param expression some conditional expression
1767 * @return `true` if and only if the passed expression is resolved to a consta nt variable
1768 */
1769 bool _isDebugConstant(Expression expression) {
1770 Element element = null;
1771 if (expression is Identifier) {
1772 Identifier identifier = expression;
1773 element = identifier.staticElement;
1774 } else if (expression is PropertyAccess) {
1775 PropertyAccess propertyAccess = expression;
1776 element = propertyAccess.propertyName.staticElement;
1777 }
1778 if (element is PropertyAccessorElement) {
1779 PropertyInducingElement variable = element.variable;
1780 return variable != null && variable.isConst;
1781 }
1782 return false;
1783 }
1784
1785 /**
1786 * If the given node is not `null`, visit this instance of the dead code verif ier.
1787 *
1788 * @param node the node to be visited
1789 */
1790 void _safelyVisit(AstNode node) {
1791 if (node != null) {
1792 node.accept(this);
1793 }
1794 }
1795 }
1796
1797 /**
1798 * Instances of the class `DeclarationResolver` are used to resolve declarations in an AST
1799 * structure to already built elements.
1800 */
1801 class DeclarationResolver extends RecursiveAstVisitor<Object> {
1802 /**
1803 * The compilation unit containing the AST nodes being visited.
1804 */
1805 CompilationUnitElement _enclosingUnit;
1806
1807 /**
1808 * The function type alias containing the AST nodes being visited, or `null` i f we are not
1809 * in the scope of a function type alias.
1810 */
1811 FunctionTypeAliasElement _enclosingAlias;
1812
1813 /**
1814 * The class containing the AST nodes being visited, or `null` if we are not i n the scope of
1815 * a class.
1816 */
1817 ClassElement _enclosingClass;
1818
1819 /**
1820 * The method or function containing the AST nodes being visited, or `null` if we are not in
1821 * the scope of a method or function.
1822 */
1823 ExecutableElement _enclosingExecutable;
1824
1825 /**
1826 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the
1827 * scope of a parameter.
1828 */
1829 ParameterElement _enclosingParameter;
1830
1831 /**
1832 * Resolve the declarations within the given compilation unit to the elements rooted at the given
1833 * element.
1834 *
1835 * @param unit the compilation unit to be resolved
1836 * @param element the root of the element model used to resolve the AST nodes
1837 */
1838 void resolve(CompilationUnit unit, CompilationUnitElement element) {
1839 _enclosingUnit = element;
1840 unit.element = element;
1841 unit.accept(this);
1842 }
1843
1844 @override
1845 Object visitCatchClause(CatchClause node) {
1846 SimpleIdentifier exceptionParameter = node.exceptionParameter;
1847 if (exceptionParameter != null) {
1848 List<LocalVariableElement> localVariables =
1849 _enclosingExecutable.localVariables;
1850 _findIdentifier(localVariables, exceptionParameter);
1851 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
1852 if (stackTraceParameter != null) {
1853 _findIdentifier(localVariables, stackTraceParameter);
1854 }
1855 }
1856 return super.visitCatchClause(node);
1857 }
1858
1859 @override
1860 Object visitClassDeclaration(ClassDeclaration node) {
1861 ClassElement outerClass = _enclosingClass;
1862 try {
1863 SimpleIdentifier className = node.name;
1864 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
1865 return super.visitClassDeclaration(node);
1866 } finally {
1867 _enclosingClass = outerClass;
1868 }
1869 }
1870
1871 @override
1872 Object visitClassTypeAlias(ClassTypeAlias node) {
1873 ClassElement outerClass = _enclosingClass;
1874 try {
1875 SimpleIdentifier className = node.name;
1876 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
1877 return super.visitClassTypeAlias(node);
1878 } finally {
1879 _enclosingClass = outerClass;
1880 }
1881 }
1882
1883 @override
1884 Object visitConstructorDeclaration(ConstructorDeclaration node) {
1885 ExecutableElement outerExecutable = _enclosingExecutable;
1886 try {
1887 SimpleIdentifier constructorName = node.name;
1888 if (constructorName == null) {
1889 _enclosingExecutable = _enclosingClass.unnamedConstructor;
1890 } else {
1891 _enclosingExecutable =
1892 _enclosingClass.getNamedConstructor(constructorName.name);
1893 constructorName.staticElement = _enclosingExecutable;
1894 }
1895 node.element = _enclosingExecutable as ConstructorElement;
1896 return super.visitConstructorDeclaration(node);
1897 } finally {
1898 _enclosingExecutable = outerExecutable;
1899 }
1900 }
1901
1902 @override
1903 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
1904 SimpleIdentifier variableName = node.identifier;
1905 _findIdentifier(_enclosingExecutable.localVariables, variableName);
1906 return super.visitDeclaredIdentifier(node);
1907 }
1908
1909 @override
1910 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
1911 SimpleIdentifier parameterName = node.parameter.identifier;
1912 ParameterElement element = _getElementForParameter(node, parameterName);
1913 Expression defaultValue = node.defaultValue;
1914 if (defaultValue != null) {
1915 ExecutableElement outerExecutable = _enclosingExecutable;
1916 try {
1917 if (element == null) {
1918 // TODO(brianwilkerson) Report this internal error.
1919 } else {
1920 _enclosingExecutable = element.initializer;
1921 }
1922 defaultValue.accept(this);
1923 } finally {
1924 _enclosingExecutable = outerExecutable;
1925 }
1926 }
1927 ParameterElement outerParameter = _enclosingParameter;
1928 try {
1929 _enclosingParameter = element;
1930 return super.visitDefaultFormalParameter(node);
1931 } finally {
1932 _enclosingParameter = outerParameter;
1933 }
1934 }
1935
1936 @override
1937 Object visitEnumDeclaration(EnumDeclaration node) {
1938 ClassElement enclosingEnum =
1939 _findIdentifier(_enclosingUnit.enums, node.name);
1940 List<FieldElement> constants = enclosingEnum.fields;
1941 for (EnumConstantDeclaration constant in node.constants) {
1942 _findIdentifier(constants, constant.name);
1943 }
1944 return super.visitEnumDeclaration(node);
1945 }
1946
1947 @override
1948 Object visitExportDirective(ExportDirective node) {
1949 String uri = _getStringValue(node.uri);
1950 if (uri != null) {
1951 LibraryElement library = _enclosingUnit.library;
1952 ExportElement exportElement = _findExport(
1953 library.exports,
1954 _enclosingUnit.context.sourceFactory
1955 .resolveUri(_enclosingUnit.source, uri));
1956 node.element = exportElement;
1957 }
1958 return super.visitExportDirective(node);
1959 }
1960
1961 @override
1962 Object visitFieldFormalParameter(FieldFormalParameter node) {
1963 if (node.parent is! DefaultFormalParameter) {
1964 SimpleIdentifier parameterName = node.identifier;
1965 ParameterElement element = _getElementForParameter(node, parameterName);
1966 ParameterElement outerParameter = _enclosingParameter;
1967 try {
1968 _enclosingParameter = element;
1969 return super.visitFieldFormalParameter(node);
1970 } finally {
1971 _enclosingParameter = outerParameter;
1972 }
1973 } else {
1974 return super.visitFieldFormalParameter(node);
1975 }
1976 }
1977
1978 @override
1979 Object visitFunctionDeclaration(FunctionDeclaration node) {
1980 ExecutableElement outerExecutable = _enclosingExecutable;
1981 try {
1982 SimpleIdentifier functionName = node.name;
1983 sc.Token property = node.propertyKeyword;
1984 if (property == null) {
1985 if (_enclosingExecutable != null) {
1986 _enclosingExecutable =
1987 _findIdentifier(_enclosingExecutable.functions, functionName);
1988 } else {
1989 _enclosingExecutable =
1990 _findIdentifier(_enclosingUnit.functions, functionName);
1991 }
1992 } else {
1993 PropertyAccessorElement accessor =
1994 _findIdentifier(_enclosingUnit.accessors, functionName);
1995 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
1996 accessor = accessor.variable.setter;
1997 functionName.staticElement = accessor;
1998 }
1999 _enclosingExecutable = accessor;
2000 }
2001 node.functionExpression.element = _enclosingExecutable;
2002 return super.visitFunctionDeclaration(node);
2003 } finally {
2004 _enclosingExecutable = outerExecutable;
2005 }
2006 }
2007
2008 @override
2009 Object visitFunctionExpression(FunctionExpression node) {
2010 if (node.parent is! FunctionDeclaration) {
2011 FunctionElement element =
2012 _findAtOffset(_enclosingExecutable.functions, node.beginToken.offset);
2013 node.element = element;
2014 }
2015 ExecutableElement outerExecutable = _enclosingExecutable;
2016 try {
2017 _enclosingExecutable = node.element;
2018 return super.visitFunctionExpression(node);
2019 } finally {
2020 _enclosingExecutable = outerExecutable;
2021 }
2022 }
2023
2024 @override
2025 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
2026 FunctionTypeAliasElement outerAlias = _enclosingAlias;
2027 try {
2028 SimpleIdentifier aliasName = node.name;
2029 _enclosingAlias =
2030 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName);
2031 return super.visitFunctionTypeAlias(node);
2032 } finally {
2033 _enclosingAlias = outerAlias;
2034 }
2035 }
2036
2037 @override
2038 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
2039 if (node.parent is! DefaultFormalParameter) {
2040 SimpleIdentifier parameterName = node.identifier;
2041 ParameterElement element = _getElementForParameter(node, parameterName);
2042 ParameterElement outerParameter = _enclosingParameter;
2043 try {
2044 _enclosingParameter = element;
2045 return super.visitFunctionTypedFormalParameter(node);
2046 } finally {
2047 _enclosingParameter = outerParameter;
2048 }
2049 } else {
2050 return super.visitFunctionTypedFormalParameter(node);
2051 }
2052 }
2053
2054 @override
2055 Object visitImportDirective(ImportDirective node) {
2056 String uri = _getStringValue(node.uri);
2057 if (uri != null) {
2058 LibraryElement library = _enclosingUnit.library;
2059 ImportElement importElement = _findImport(
2060 library.imports,
2061 _enclosingUnit.context.sourceFactory
2062 .resolveUri(_enclosingUnit.source, uri),
2063 node.prefix);
2064 node.element = importElement;
2065 }
2066 return super.visitImportDirective(node);
2067 }
2068
2069 @override
2070 Object visitLabeledStatement(LabeledStatement node) {
2071 for (Label label in node.labels) {
2072 SimpleIdentifier labelName = label.label;
2073 _findIdentifier(_enclosingExecutable.labels, labelName);
2074 }
2075 return super.visitLabeledStatement(node);
2076 }
2077
2078 @override
2079 Object visitLibraryDirective(LibraryDirective node) {
2080 node.element = _enclosingUnit.library;
2081 return super.visitLibraryDirective(node);
2082 }
2083
2084 @override
2085 Object visitMethodDeclaration(MethodDeclaration node) {
2086 ExecutableElement outerExecutable = _enclosingExecutable;
2087 try {
2088 sc.Token property = node.propertyKeyword;
2089 SimpleIdentifier methodName = node.name;
2090 String nameOfMethod = methodName.name;
2091 if (property == null) {
2092 _enclosingExecutable = _findWithNameAndOffset(
2093 _enclosingClass.methods, nameOfMethod, methodName.offset);
2094 methodName.staticElement = _enclosingExecutable;
2095 } else {
2096 PropertyAccessorElement accessor =
2097 _findIdentifier(_enclosingClass.accessors, methodName);
2098 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) {
2099 accessor = accessor.variable.setter;
2100 methodName.staticElement = accessor;
2101 }
2102 _enclosingExecutable = accessor;
2103 }
2104 return super.visitMethodDeclaration(node);
2105 } finally {
2106 _enclosingExecutable = outerExecutable;
2107 }
2108 }
2109
2110 @override
2111 Object visitPartDirective(PartDirective node) {
2112 String uri = _getStringValue(node.uri);
2113 if (uri != null) {
2114 Source partSource = _enclosingUnit.context.sourceFactory
2115 .resolveUri(_enclosingUnit.source, uri);
2116 node.element = _findPart(_enclosingUnit.library.parts, partSource);
2117 }
2118 return super.visitPartDirective(node);
2119 }
2120
2121 @override
2122 Object visitPartOfDirective(PartOfDirective node) {
2123 node.element = _enclosingUnit.library;
2124 return super.visitPartOfDirective(node);
2125 }
2126
2127 @override
2128 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
2129 if (node.parent is! DefaultFormalParameter) {
2130 SimpleIdentifier parameterName = node.identifier;
2131 ParameterElement element = _getElementForParameter(node, parameterName);
2132 ParameterElement outerParameter = _enclosingParameter;
2133 try {
2134 _enclosingParameter = element;
2135 return super.visitSimpleFormalParameter(node);
2136 } finally {
2137 _enclosingParameter = outerParameter;
2138 }
2139 } else {}
2140 return super.visitSimpleFormalParameter(node);
2141 }
2142
2143 @override
2144 Object visitSwitchCase(SwitchCase node) {
2145 for (Label label in node.labels) {
2146 SimpleIdentifier labelName = label.label;
2147 _findIdentifier(_enclosingExecutable.labels, labelName);
2148 }
2149 return super.visitSwitchCase(node);
2150 }
2151
2152 @override
2153 Object visitSwitchDefault(SwitchDefault node) {
2154 for (Label label in node.labels) {
2155 SimpleIdentifier labelName = label.label;
2156 _findIdentifier(_enclosingExecutable.labels, labelName);
2157 }
2158 return super.visitSwitchDefault(node);
2159 }
2160
2161 @override
2162 Object visitTypeParameter(TypeParameter node) {
2163 SimpleIdentifier parameterName = node.name;
2164 if (_enclosingClass != null) {
2165 _findIdentifier(_enclosingClass.typeParameters, parameterName);
2166 } else if (_enclosingAlias != null) {
2167 _findIdentifier(_enclosingAlias.typeParameters, parameterName);
2168 }
2169 return super.visitTypeParameter(node);
2170 }
2171
2172 @override
2173 Object visitVariableDeclaration(VariableDeclaration node) {
2174 VariableElement element = null;
2175 SimpleIdentifier variableName = node.name;
2176 if (_enclosingExecutable != null) {
2177 element =
2178 _findIdentifier(_enclosingExecutable.localVariables, variableName);
2179 }
2180 if (element == null && _enclosingClass != null) {
2181 element = _findIdentifier(_enclosingClass.fields, variableName);
2182 }
2183 if (element == null && _enclosingUnit != null) {
2184 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName);
2185 }
2186 Expression initializer = node.initializer;
2187 if (initializer != null) {
2188 ExecutableElement outerExecutable = _enclosingExecutable;
2189 try {
2190 if (element == null) {
2191 // TODO(brianwilkerson) Report this internal error.
2192 } else {
2193 _enclosingExecutable = element.initializer;
2194 }
2195 return super.visitVariableDeclaration(node);
2196 } finally {
2197 _enclosingExecutable = outerExecutable;
2198 }
2199 }
2200 return super.visitVariableDeclaration(node);
2201 }
2202
2203 /**
2204 * Return the element in the given array of elements that was created for the declaration at the
2205 * given offset. This method should only be used when there is no name
2206 *
2207 * @param elements the elements of the appropriate kind that exist in the curr ent context
2208 * @param offset the offset of the name of the element to be returned
2209 * @return the element at the given offset
2210 */
2211 Element _findAtOffset(List<Element> elements, int offset) =>
2212 _findWithNameAndOffset(elements, "", offset);
2213
2214 /**
2215 * Return the export element from the given array whose library has the given source, or
2216 * `null` if there is no such export.
2217 *
2218 * @param exports the export elements being searched
2219 * @param source the source of the library associated with the export element to being searched
2220 * for
2221 * @return the export element whose library has the given source
2222 */
2223 ExportElement _findExport(List<ExportElement> exports, Source source) {
2224 for (ExportElement export in exports) {
2225 if (export.exportedLibrary.source == source) {
2226 return export;
2227 }
2228 }
2229 return null;
2230 }
2231
2232 /**
2233 * Return the element in the given array of elements that was created for the declaration with the
2234 * given name.
2235 *
2236 * @param elements the elements of the appropriate kind that exist in the curr ent context
2237 * @param identifier the name node in the declaration of the element to be ret urned
2238 * @return the element created for the declaration with the given name
2239 */
2240 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier) {
2241 Element element =
2242 _findWithNameAndOffset(elements, identifier.name, identifier.offset);
2243 identifier.staticElement = element;
2244 return element;
2245 }
2246
2247 /**
2248 * Return the import element from the given array whose library has the given source and that has
2249 * the given prefix, or `null` if there is no such import.
2250 *
2251 * @param imports the import elements being searched
2252 * @param source the source of the library associated with the import element to being searched
2253 * for
2254 * @param prefix the prefix with which the library was imported
2255 * @return the import element whose library has the given source and prefix
2256 */
2257 ImportElement _findImport(
2258 List<ImportElement> imports, Source source, SimpleIdentifier prefix) {
2259 for (ImportElement element in imports) {
2260 if (element.importedLibrary.source == source) {
2261 PrefixElement prefixElement = element.prefix;
2262 if (prefix == null) {
2263 if (prefixElement == null) {
2264 return element;
2265 }
2266 } else {
2267 if (prefixElement != null &&
2268 prefix.name == prefixElement.displayName) {
2269 return element;
2270 }
2271 }
2272 }
2273 }
2274 return null;
2275 }
2276
2277 /**
2278 * Return the element for the part with the given source, or `null` if there i s no element
2279 * for the given source.
2280 *
2281 * @param parts the elements for the parts
2282 * @param partSource the source for the part whose element is to be returned
2283 * @return the element for the part with the given source
2284 */
2285 CompilationUnitElement _findPart(
2286 List<CompilationUnitElement> parts, Source partSource) {
2287 for (CompilationUnitElement part in parts) {
2288 if (part.source == partSource) {
2289 return part;
2290 }
2291 }
2292 return null;
2293 }
2294
2295 /**
2296 * Return the element in the given array of elements that was created for the declaration with the
2297 * given name at the given offset.
2298 *
2299 * @param elements the elements of the appropriate kind that exist in the curr ent context
2300 * @param name the name of the element to be returned
2301 * @param offset the offset of the name of the element to be returned
2302 * @return the element with the given name and offset
2303 */
2304 Element _findWithNameAndOffset(
2305 List<Element> elements, String name, int offset) {
2306 for (Element element in elements) {
2307 if (element.nameOffset == offset && element.displayName == name) {
2308 return element;
2309 }
2310 }
2311 return null;
2312 }
2313
2314 /**
2315 * Search the most closely enclosing list of parameters for a parameter with t he given name.
2316 *
2317 * @param node the node defining the parameter with the given name
2318 * @param parameterName the name of the parameter being searched for
2319 * @return the element representing the parameter with that name
2320 */
2321 ParameterElement _getElementForParameter(
2322 FormalParameter node, SimpleIdentifier parameterName) {
2323 List<ParameterElement> parameters = null;
2324 if (_enclosingParameter != null) {
2325 parameters = _enclosingParameter.parameters;
2326 }
2327 if (parameters == null && _enclosingExecutable != null) {
2328 parameters = _enclosingExecutable.parameters;
2329 }
2330 if (parameters == null && _enclosingAlias != null) {
2331 parameters = _enclosingAlias.parameters;
2332 }
2333 ParameterElement element =
2334 parameters == null ? null : _findIdentifier(parameters, parameterName);
2335 if (element == null) {
2336 StringBuffer buffer = new StringBuffer();
2337 buffer.writeln("Invalid state found in the Analysis Engine:");
2338 buffer.writeln(
2339 "DeclarationResolver.getElementForParameter() is visiting a parameter that does not appear to be in a method or function.");
2340 buffer.writeln("Ancestors:");
2341 AstNode parent = node.parent;
2342 while (parent != null) {
2343 buffer.writeln(parent.runtimeType.toString());
2344 buffer.writeln("---------");
2345 parent = parent.parent;
2346 }
2347 AnalysisEngine.instance.logger.logError(buffer.toString(),
2348 new CaughtException(new AnalysisException(), null));
2349 }
2350 return element;
2351 }
2352
2353 /**
2354 * Return the value of the given string literal, or `null` if the string is no t a constant
2355 * string without any string interpolation.
2356 *
2357 * @param literal the string literal whose value is to be returned
2358 * @return the value of the given string literal
2359 */
2360 String _getStringValue(StringLiteral literal) {
2361 if (literal is StringInterpolation) {
2362 return null;
2363 }
2364 return literal.stringValue;
2365 }
2366 }
2367
2368 /**
2369 * Instances of the class `ElementBuilder` traverse an AST structure and build t he element
2370 * model representing the AST structure.
2371 */
2372 class ElementBuilder extends RecursiveAstVisitor<Object> {
2373 /**
2374 * The element holder associated with the element that is currently being buil t.
2375 */
2376 ElementHolder _currentHolder;
2377
2378 /**
2379 * A flag indicating whether a variable declaration is in the context of a fie ld declaration.
2380 */
2381 bool _inFieldContext = false;
2382
2383 /**
2384 * A flag indicating whether a variable declaration is within the body of a me thod or function.
2385 */
2386 bool _inFunction = false;
2387
2388 /**
2389 * A flag indicating whether the class currently being visited can be used as a mixin.
2390 */
2391 bool _isValidMixin = false;
2392
2393 /**
2394 * A collection holding the function types defined in a class that need to hav e their type
2395 * arguments set to the types of the type parameters for the class, or `null` if we are not
2396 * currently processing nodes within a class.
2397 */
2398 List<FunctionTypeImpl> _functionTypesToFix = null;
2399
2400 /**
2401 * A table mapping field names to field elements for the fields defined in the current class, or
2402 * `null` if we are not in the scope of a class.
2403 */
2404 HashMap<String, FieldElement> _fieldMap;
2405
2406 /**
2407 * Initialize a newly created element builder to build the elements for a comp ilation unit.
2408 *
2409 * @param initialHolder the element holder associated with the compilation uni t being built
2410 */
2411 ElementBuilder(ElementHolder initialHolder) {
2412 _currentHolder = initialHolder;
2413 }
2414
2415 @override
2416 Object visitBlock(Block node) {
2417 bool wasInField = _inFieldContext;
2418 _inFieldContext = false;
2419 try {
2420 node.visitChildren(this);
2421 } finally {
2422 _inFieldContext = wasInField;
2423 }
2424 return null;
2425 }
2426
2427 @override
2428 Object visitCatchClause(CatchClause node) {
2429 SimpleIdentifier exceptionParameter = node.exceptionParameter;
2430 if (exceptionParameter != null) {
2431 // exception
2432 LocalVariableElementImpl exception =
2433 new LocalVariableElementImpl.forNode(exceptionParameter);
2434 if (node.exceptionType == null) {
2435 exception.hasImplicitType = true;
2436 }
2437 _currentHolder.addLocalVariable(exception);
2438 exceptionParameter.staticElement = exception;
2439 // stack trace
2440 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
2441 if (stackTraceParameter != null) {
2442 LocalVariableElementImpl stackTrace =
2443 new LocalVariableElementImpl.forNode(stackTraceParameter);
2444 _currentHolder.addLocalVariable(stackTrace);
2445 stackTraceParameter.staticElement = stackTrace;
2446 }
2447 }
2448 return super.visitCatchClause(node);
2449 }
2450
2451 @override
2452 Object visitClassDeclaration(ClassDeclaration node) {
2453 ElementHolder holder = new ElementHolder();
2454 _isValidMixin = true;
2455 _functionTypesToFix = new List<FunctionTypeImpl>();
2456 //
2457 // Process field declarations before constructors and methods so that field
2458 // formal parameters can be correctly resolved to their fields.
2459 //
2460 ElementHolder previousHolder = _currentHolder;
2461 _currentHolder = holder;
2462 try {
2463 List<ClassMember> nonFields = new List<ClassMember>();
2464 node.visitChildren(
2465 new _ElementBuilder_visitClassDeclaration(this, nonFields));
2466 _buildFieldMap(holder.fieldsWithoutFlushing);
2467 int count = nonFields.length;
2468 for (int i = 0; i < count; i++) {
2469 nonFields[i].accept(this);
2470 }
2471 } finally {
2472 _currentHolder = previousHolder;
2473 }
2474 SimpleIdentifier className = node.name;
2475 ClassElementImpl element = new ClassElementImpl.forNode(className);
2476 List<TypeParameterElement> typeParameters = holder.typeParameters;
2477 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
2478 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
2479 interfaceType.typeArguments = typeArguments;
2480 element.type = interfaceType;
2481 List<ConstructorElement> constructors = holder.constructors;
2482 if (constructors.length == 0) {
2483 //
2484 // Create the default constructor.
2485 //
2486 constructors = _createDefaultConstructors(interfaceType);
2487 }
2488 element.abstract = node.isAbstract;
2489 element.accessors = holder.accessors;
2490 element.constructors = constructors;
2491 element.fields = holder.fields;
2492 element.methods = holder.methods;
2493 element.typeParameters = typeParameters;
2494 element.validMixin = _isValidMixin;
2495 int functionTypeCount = _functionTypesToFix.length;
2496 for (int i = 0; i < functionTypeCount; i++) {
2497 _functionTypesToFix[i].typeArguments = typeArguments;
2498 }
2499 _functionTypesToFix = null;
2500 _currentHolder.addType(element);
2501 className.staticElement = element;
2502 _fieldMap = null;
2503 holder.validate();
2504 return null;
2505 }
2506
2507 /**
2508 * Implementation of this method should be synchronized with
2509 * [visitClassDeclaration].
2510 */
2511 void visitClassDeclarationIncrementally(ClassDeclaration node) {
2512 //
2513 // Process field declarations before constructors and methods so that field
2514 // formal parameters can be correctly resolved to their fields.
2515 //
2516 ClassElement classElement = node.element;
2517 _buildFieldMap(classElement.fields);
2518 }
2519
2520 @override
2521 Object visitClassTypeAlias(ClassTypeAlias node) {
2522 ElementHolder holder = new ElementHolder();
2523 _functionTypesToFix = new List<FunctionTypeImpl>();
2524 _visitChildren(holder, node);
2525 SimpleIdentifier className = node.name;
2526 ClassElementImpl element = new ClassElementImpl.forNode(className);
2527 element.abstract = node.abstractKeyword != null;
2528 element.mixinApplication = true;
2529 List<TypeParameterElement> typeParameters = holder.typeParameters;
2530 element.typeParameters = typeParameters;
2531 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
2532 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
2533 interfaceType.typeArguments = typeArguments;
2534 element.type = interfaceType;
2535 // set default constructor
2536 for (FunctionTypeImpl functionType in _functionTypesToFix) {
2537 functionType.typeArguments = typeArguments;
2538 }
2539 _functionTypesToFix = null;
2540 _currentHolder.addType(element);
2541 className.staticElement = element;
2542 holder.validate();
2543 return null;
2544 }
2545
2546 @override
2547 Object visitConstructorDeclaration(ConstructorDeclaration node) {
2548 _isValidMixin = false;
2549 ElementHolder holder = new ElementHolder();
2550 bool wasInFunction = _inFunction;
2551 _inFunction = true;
2552 try {
2553 _visitChildren(holder, node);
2554 } finally {
2555 _inFunction = wasInFunction;
2556 }
2557 FunctionBody body = node.body;
2558 SimpleIdentifier constructorName = node.name;
2559 ConstructorElementImpl element =
2560 new ConstructorElementImpl.forNode(constructorName);
2561 if (node.externalKeyword != null) {
2562 element.external = true;
2563 }
2564 if (node.factoryKeyword != null) {
2565 element.factory = true;
2566 }
2567 element.functions = holder.functions;
2568 element.labels = holder.labels;
2569 element.localVariables = holder.localVariables;
2570 element.parameters = holder.parameters;
2571 element.const2 = node.constKeyword != null;
2572 if (body.isAsynchronous) {
2573 element.asynchronous = true;
2574 }
2575 if (body.isGenerator) {
2576 element.generator = true;
2577 }
2578 _currentHolder.addConstructor(element);
2579 node.element = element;
2580 if (constructorName == null) {
2581 Identifier returnType = node.returnType;
2582 if (returnType != null) {
2583 element.nameOffset = returnType.offset;
2584 element.nameEnd = returnType.end;
2585 }
2586 } else {
2587 constructorName.staticElement = element;
2588 element.periodOffset = node.period.offset;
2589 element.nameEnd = constructorName.end;
2590 }
2591 holder.validate();
2592 return null;
2593 }
2594
2595 @override
2596 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
2597 SimpleIdentifier variableName = node.identifier;
2598 LocalVariableElementImpl element =
2599 new LocalVariableElementImpl.forNode(variableName);
2600 ForEachStatement statement = node.parent as ForEachStatement;
2601 int declarationEnd = node.offset + node.length;
2602 int statementEnd = statement.offset + statement.length;
2603 element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1);
2604 element.const3 = node.isConst;
2605 element.final2 = node.isFinal;
2606 if (node.type == null) {
2607 element.hasImplicitType = true;
2608 }
2609 _currentHolder.addLocalVariable(element);
2610 variableName.staticElement = element;
2611 return super.visitDeclaredIdentifier(node);
2612 }
2613
2614 @override
2615 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
2616 ElementHolder holder = new ElementHolder();
2617 NormalFormalParameter normalParameter = node.parameter;
2618 SimpleIdentifier parameterName = normalParameter.identifier;
2619 ParameterElementImpl parameter;
2620 if (normalParameter is FieldFormalParameter) {
2621 parameter = new DefaultFieldFormalParameterElementImpl(parameterName);
2622 FieldElement field =
2623 _fieldMap == null ? null : _fieldMap[parameterName.name];
2624 if (field != null) {
2625 (parameter as DefaultFieldFormalParameterElementImpl).field = field;
2626 }
2627 } else {
2628 parameter = new DefaultParameterElementImpl(parameterName);
2629 }
2630 parameter.const3 = node.isConst;
2631 parameter.final2 = node.isFinal;
2632 parameter.parameterKind = node.kind;
2633 // set initializer, default value range
2634 Expression defaultValue = node.defaultValue;
2635 if (defaultValue != null) {
2636 _visit(holder, defaultValue);
2637 FunctionElementImpl initializer =
2638 new FunctionElementImpl.forOffset(defaultValue.beginToken.offset);
2639 initializer.functions = holder.functions;
2640 initializer.labels = holder.labels;
2641 initializer.localVariables = holder.localVariables;
2642 initializer.parameters = holder.parameters;
2643 initializer.synthetic = true;
2644 parameter.initializer = initializer;
2645 parameter.defaultValueCode = defaultValue.toSource();
2646 }
2647 // visible range
2648 _setParameterVisibleRange(node, parameter);
2649 if (normalParameter is SimpleFormalParameter &&
2650 normalParameter.type == null) {
2651 parameter.hasImplicitType = true;
2652 }
2653 _currentHolder.addParameter(parameter);
2654 parameterName.staticElement = parameter;
2655 normalParameter.accept(this);
2656 holder.validate();
2657 return null;
2658 }
2659
2660 @override
2661 Object visitEnumDeclaration(EnumDeclaration node) {
2662 SimpleIdentifier enumName = node.name;
2663 ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
2664 enumElement.enum2 = true;
2665 InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
2666 enumElement.type = enumType;
2667 // The equivalent code for enums in the spec shows a single constructor,
2668 // but that constructor is not callable (since it is a compile-time error
2669 // to subclass, mix-in, implement, or explicitly instantiate an enum). So
2670 // we represent this as having no constructors.
2671 enumElement.constructors = ConstructorElement.EMPTY_LIST;
2672 _currentHolder.addEnum(enumElement);
2673 enumName.staticElement = enumElement;
2674 return super.visitEnumDeclaration(node);
2675 }
2676
2677 @override
2678 Object visitFieldDeclaration(FieldDeclaration node) {
2679 bool wasInField = _inFieldContext;
2680 _inFieldContext = true;
2681 try {
2682 node.visitChildren(this);
2683 } finally {
2684 _inFieldContext = wasInField;
2685 }
2686 return null;
2687 }
2688
2689 @override
2690 Object visitFieldFormalParameter(FieldFormalParameter node) {
2691 if (node.parent is! DefaultFormalParameter) {
2692 SimpleIdentifier parameterName = node.identifier;
2693 FieldElement field =
2694 _fieldMap == null ? null : _fieldMap[parameterName.name];
2695 FieldFormalParameterElementImpl parameter =
2696 new FieldFormalParameterElementImpl(parameterName);
2697 parameter.const3 = node.isConst;
2698 parameter.final2 = node.isFinal;
2699 parameter.parameterKind = node.kind;
2700 if (field != null) {
2701 parameter.field = field;
2702 }
2703 _currentHolder.addParameter(parameter);
2704 parameterName.staticElement = parameter;
2705 }
2706 //
2707 // The children of this parameter include any parameters defined on the type
2708 // of this parameter.
2709 //
2710 ElementHolder holder = new ElementHolder();
2711 _visitChildren(holder, node);
2712 ParameterElementImpl element = node.element;
2713 element.parameters = holder.parameters;
2714 element.typeParameters = holder.typeParameters;
2715 holder.validate();
2716 return null;
2717 }
2718
2719 @override
2720 Object visitFunctionDeclaration(FunctionDeclaration node) {
2721 FunctionExpression expression = node.functionExpression;
2722 if (expression != null) {
2723 ElementHolder holder = new ElementHolder();
2724 bool wasInFunction = _inFunction;
2725 _inFunction = true;
2726 try {
2727 _visitChildren(holder, node);
2728 } finally {
2729 _inFunction = wasInFunction;
2730 }
2731 FunctionBody body = expression.body;
2732 sc.Token property = node.propertyKeyword;
2733 if (property == null || _inFunction) {
2734 SimpleIdentifier functionName = node.name;
2735 FunctionElementImpl element =
2736 new FunctionElementImpl.forNode(functionName);
2737 if (node.externalKeyword != null) {
2738 element.external = true;
2739 }
2740 element.functions = holder.functions;
2741 element.labels = holder.labels;
2742 element.localVariables = holder.localVariables;
2743 element.parameters = holder.parameters;
2744 element.typeParameters = holder.typeParameters;
2745 if (body.isAsynchronous) {
2746 element.asynchronous = true;
2747 }
2748 if (body.isGenerator) {
2749 element.generator = true;
2750 }
2751 if (_inFunction) {
2752 Block enclosingBlock = node.getAncestor((node) => node is Block);
2753 if (enclosingBlock != null) {
2754 int functionEnd = node.offset + node.length;
2755 int blockEnd = enclosingBlock.offset + enclosingBlock.length;
2756 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
2757 }
2758 }
2759 if (node.returnType == null) {
2760 element.hasImplicitReturnType = true;
2761 }
2762 _currentHolder.addFunction(element);
2763 expression.element = element;
2764 functionName.staticElement = element;
2765 } else {
2766 SimpleIdentifier propertyNameNode = node.name;
2767 if (propertyNameNode == null) {
2768 // TODO(brianwilkerson) Report this internal error.
2769 return null;
2770 }
2771 String propertyName = propertyNameNode.name;
2772 TopLevelVariableElementImpl variable = _currentHolder
2773 .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl;
2774 if (variable == null) {
2775 variable = new TopLevelVariableElementImpl(node.name.name, -1);
2776 variable.final2 = true;
2777 variable.synthetic = true;
2778 _currentHolder.addTopLevelVariable(variable);
2779 }
2780 if (node.isGetter) {
2781 PropertyAccessorElementImpl getter =
2782 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2783 if (node.externalKeyword != null) {
2784 getter.external = true;
2785 }
2786 getter.functions = holder.functions;
2787 getter.labels = holder.labels;
2788 getter.localVariables = holder.localVariables;
2789 if (body.isAsynchronous) {
2790 getter.asynchronous = true;
2791 }
2792 if (body.isGenerator) {
2793 getter.generator = true;
2794 }
2795 getter.variable = variable;
2796 getter.getter = true;
2797 getter.static = true;
2798 variable.getter = getter;
2799 if (node.returnType == null) {
2800 getter.hasImplicitReturnType = true;
2801 }
2802 _currentHolder.addAccessor(getter);
2803 expression.element = getter;
2804 propertyNameNode.staticElement = getter;
2805 } else {
2806 PropertyAccessorElementImpl setter =
2807 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2808 if (node.externalKeyword != null) {
2809 setter.external = true;
2810 }
2811 setter.functions = holder.functions;
2812 setter.labels = holder.labels;
2813 setter.localVariables = holder.localVariables;
2814 setter.parameters = holder.parameters;
2815 if (body.isAsynchronous) {
2816 setter.asynchronous = true;
2817 }
2818 if (body.isGenerator) {
2819 setter.generator = true;
2820 }
2821 setter.variable = variable;
2822 setter.setter = true;
2823 setter.static = true;
2824 variable.setter = setter;
2825 variable.final2 = false;
2826 _currentHolder.addAccessor(setter);
2827 expression.element = setter;
2828 propertyNameNode.staticElement = setter;
2829 }
2830 }
2831 holder.validate();
2832 }
2833 return null;
2834 }
2835
2836 @override
2837 Object visitFunctionExpression(FunctionExpression node) {
2838 if (node.parent is FunctionDeclaration) {
2839 // visitFunctionDeclaration has already created the element for the
2840 // declaration. We just need to visit children.
2841 return super.visitFunctionExpression(node);
2842 }
2843 ElementHolder holder = new ElementHolder();
2844 bool wasInFunction = _inFunction;
2845 _inFunction = true;
2846 try {
2847 _visitChildren(holder, node);
2848 } finally {
2849 _inFunction = wasInFunction;
2850 }
2851 FunctionBody body = node.body;
2852 FunctionElementImpl element =
2853 new FunctionElementImpl.forOffset(node.beginToken.offset);
2854 element.functions = holder.functions;
2855 element.labels = holder.labels;
2856 element.localVariables = holder.localVariables;
2857 element.parameters = holder.parameters;
2858 element.typeParameters = holder.typeParameters;
2859 if (body.isAsynchronous) {
2860 element.asynchronous = true;
2861 }
2862 if (body.isGenerator) {
2863 element.generator = true;
2864 }
2865 if (_inFunction) {
2866 Block enclosingBlock = node.getAncestor((node) => node is Block);
2867 if (enclosingBlock != null) {
2868 int functionEnd = node.offset + node.length;
2869 int blockEnd = enclosingBlock.offset + enclosingBlock.length;
2870 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
2871 }
2872 }
2873 FunctionTypeImpl type = new FunctionTypeImpl(element);
2874 if (_functionTypesToFix != null) {
2875 _functionTypesToFix.add(type);
2876 }
2877 element.type = type;
2878 element.hasImplicitReturnType = true;
2879 _currentHolder.addFunction(element);
2880 node.element = element;
2881 holder.validate();
2882 return null;
2883 }
2884
2885 @override
2886 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
2887 ElementHolder holder = new ElementHolder();
2888 _visitChildren(holder, node);
2889 SimpleIdentifier aliasName = node.name;
2890 List<ParameterElement> parameters = holder.parameters;
2891 List<TypeParameterElement> typeParameters = holder.typeParameters;
2892 FunctionTypeAliasElementImpl element =
2893 new FunctionTypeAliasElementImpl.forNode(aliasName);
2894 element.parameters = parameters;
2895 element.typeParameters = typeParameters;
2896 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element);
2897 type.typeArguments = _createTypeParameterTypes(typeParameters);
2898 element.type = type;
2899 _currentHolder.addTypeAlias(element);
2900 aliasName.staticElement = element;
2901 holder.validate();
2902 return null;
2903 }
2904
2905 @override
2906 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
2907 if (node.parent is! DefaultFormalParameter) {
2908 SimpleIdentifier parameterName = node.identifier;
2909 ParameterElementImpl parameter =
2910 new ParameterElementImpl.forNode(parameterName);
2911 parameter.parameterKind = node.kind;
2912 _setParameterVisibleRange(node, parameter);
2913 _currentHolder.addParameter(parameter);
2914 parameterName.staticElement = parameter;
2915 }
2916 //
2917 // The children of this parameter include any parameters defined on the type
2918 //of this parameter.
2919 //
2920 ElementHolder holder = new ElementHolder();
2921 _visitChildren(holder, node);
2922 ParameterElementImpl element = node.element;
2923 element.parameters = holder.parameters;
2924 element.typeParameters = holder.typeParameters;
2925 holder.validate();
2926 return null;
2927 }
2928
2929 @override
2930 Object visitLabeledStatement(LabeledStatement node) {
2931 bool onSwitchStatement = node.statement is SwitchStatement;
2932 for (Label label in node.labels) {
2933 SimpleIdentifier labelName = label.label;
2934 LabelElementImpl element =
2935 new LabelElementImpl(labelName, onSwitchStatement, false);
2936 _currentHolder.addLabel(element);
2937 labelName.staticElement = element;
2938 }
2939 return super.visitLabeledStatement(node);
2940 }
2941
2942 @override
2943 Object visitMethodDeclaration(MethodDeclaration node) {
2944 try {
2945 ElementHolder holder = new ElementHolder();
2946 bool wasInFunction = _inFunction;
2947 _inFunction = true;
2948 try {
2949 _visitChildren(holder, node);
2950 } finally {
2951 _inFunction = wasInFunction;
2952 }
2953 bool isStatic = node.isStatic;
2954 sc.Token property = node.propertyKeyword;
2955 FunctionBody body = node.body;
2956 if (property == null) {
2957 SimpleIdentifier methodName = node.name;
2958 String nameOfMethod = methodName.name;
2959 if (nameOfMethod == sc.TokenType.MINUS.lexeme &&
2960 node.parameters.parameters.length == 0) {
2961 nameOfMethod = "unary-";
2962 }
2963 MethodElementImpl element =
2964 new MethodElementImpl(nameOfMethod, methodName.offset);
2965 element.abstract = node.isAbstract;
2966 if (node.externalKeyword != null) {
2967 element.external = true;
2968 }
2969 element.functions = holder.functions;
2970 element.labels = holder.labels;
2971 element.localVariables = holder.localVariables;
2972 element.parameters = holder.parameters;
2973 element.static = isStatic;
2974 element.typeParameters = holder.typeParameters;
2975 if (body.isAsynchronous) {
2976 element.asynchronous = true;
2977 }
2978 if (body.isGenerator) {
2979 element.generator = true;
2980 }
2981 if (node.returnType == null) {
2982 element.hasImplicitReturnType = true;
2983 }
2984 _currentHolder.addMethod(element);
2985 methodName.staticElement = element;
2986 } else {
2987 SimpleIdentifier propertyNameNode = node.name;
2988 String propertyName = propertyNameNode.name;
2989 FieldElementImpl field =
2990 _currentHolder.getField(propertyName) as FieldElementImpl;
2991 if (field == null) {
2992 field = new FieldElementImpl(node.name.name, -1);
2993 field.final2 = true;
2994 field.static = isStatic;
2995 field.synthetic = true;
2996 _currentHolder.addField(field);
2997 }
2998 if (node.isGetter) {
2999 PropertyAccessorElementImpl getter =
3000 new PropertyAccessorElementImpl.forNode(propertyNameNode);
3001 if (node.externalKeyword != null) {
3002 getter.external = true;
3003 }
3004 getter.functions = holder.functions;
3005 getter.labels = holder.labels;
3006 getter.localVariables = holder.localVariables;
3007 if (body.isAsynchronous) {
3008 getter.asynchronous = true;
3009 }
3010 if (body.isGenerator) {
3011 getter.generator = true;
3012 }
3013 getter.variable = field;
3014 getter.abstract = node.isAbstract;
3015 getter.getter = true;
3016 getter.static = isStatic;
3017 field.getter = getter;
3018 if (node.returnType == null) {
3019 getter.hasImplicitReturnType = true;
3020 }
3021 _currentHolder.addAccessor(getter);
3022 propertyNameNode.staticElement = getter;
3023 } else {
3024 PropertyAccessorElementImpl setter =
3025 new PropertyAccessorElementImpl.forNode(propertyNameNode);
3026 if (node.externalKeyword != null) {
3027 setter.external = true;
3028 }
3029 setter.functions = holder.functions;
3030 setter.labels = holder.labels;
3031 setter.localVariables = holder.localVariables;
3032 setter.parameters = holder.parameters;
3033 if (body.isAsynchronous) {
3034 setter.asynchronous = true;
3035 }
3036 if (body.isGenerator) {
3037 setter.generator = true;
3038 }
3039 setter.variable = field;
3040 setter.abstract = node.isAbstract;
3041 setter.setter = true;
3042 setter.static = isStatic;
3043 field.setter = setter;
3044 field.final2 = false;
3045 _currentHolder.addAccessor(setter);
3046 propertyNameNode.staticElement = setter;
3047 }
3048 }
3049 holder.validate();
3050 } catch (exception, stackTrace) {
3051 if (node.name.staticElement == null) {
3052 ClassDeclaration classNode =
3053 node.getAncestor((node) => node is ClassDeclaration);
3054 StringBuffer buffer = new StringBuffer();
3055 buffer.write("The element for the method ");
3056 buffer.write(node.name);
3057 buffer.write(" in ");
3058 buffer.write(classNode.name);
3059 buffer.write(" was not set while trying to build the element model.");
3060 AnalysisEngine.instance.logger.logError(
3061 buffer.toString(), new CaughtException(exception, stackTrace));
3062 } else {
3063 String message =
3064 "Exception caught in ElementBuilder.visitMethodDeclaration()";
3065 AnalysisEngine.instance.logger
3066 .logError(message, new CaughtException(exception, stackTrace));
3067 }
3068 } finally {
3069 if (node.name.staticElement == null) {
3070 ClassDeclaration classNode =
3071 node.getAncestor((node) => node is ClassDeclaration);
3072 StringBuffer buffer = new StringBuffer();
3073 buffer.write("The element for the method ");
3074 buffer.write(node.name);
3075 buffer.write(" in ");
3076 buffer.write(classNode.name);
3077 buffer.write(" was not set while trying to resolve types.");
3078 AnalysisEngine.instance.logger.logError(
3079 buffer.toString(),
3080 new CaughtException(
3081 new AnalysisException(buffer.toString()), null));
3082 }
3083 }
3084 return null;
3085 }
3086
3087 @override
3088 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
3089 if (node.parent is! DefaultFormalParameter) {
3090 SimpleIdentifier parameterName = node.identifier;
3091 ParameterElementImpl parameter =
3092 new ParameterElementImpl.forNode(parameterName);
3093 parameter.const3 = node.isConst;
3094 parameter.final2 = node.isFinal;
3095 parameter.parameterKind = node.kind;
3096 _setParameterVisibleRange(node, parameter);
3097 if (node.type == null) {
3098 parameter.hasImplicitType = true;
3099 }
3100 _currentHolder.addParameter(parameter);
3101 parameterName.staticElement = parameter;
3102 }
3103 return super.visitSimpleFormalParameter(node);
3104 }
3105
3106 @override
3107 Object visitSuperExpression(SuperExpression node) {
3108 _isValidMixin = false;
3109 return super.visitSuperExpression(node);
3110 }
3111
3112 @override
3113 Object visitSwitchCase(SwitchCase node) {
3114 for (Label label in node.labels) {
3115 SimpleIdentifier labelName = label.label;
3116 LabelElementImpl element = new LabelElementImpl(labelName, false, true);
3117 _currentHolder.addLabel(element);
3118 labelName.staticElement = element;
3119 }
3120 return super.visitSwitchCase(node);
3121 }
3122
3123 @override
3124 Object visitSwitchDefault(SwitchDefault node) {
3125 for (Label label in node.labels) {
3126 SimpleIdentifier labelName = label.label;
3127 LabelElementImpl element = new LabelElementImpl(labelName, false, true);
3128 _currentHolder.addLabel(element);
3129 labelName.staticElement = element;
3130 }
3131 return super.visitSwitchDefault(node);
3132 }
3133
3134 @override
3135 Object visitTypeParameter(TypeParameter node) {
3136 SimpleIdentifier parameterName = node.name;
3137 TypeParameterElementImpl typeParameter =
3138 new TypeParameterElementImpl.forNode(parameterName);
3139 TypeParameterTypeImpl typeParameterType =
3140 new TypeParameterTypeImpl(typeParameter);
3141 typeParameter.type = typeParameterType;
3142 _currentHolder.addTypeParameter(typeParameter);
3143 parameterName.staticElement = typeParameter;
3144 return super.visitTypeParameter(node);
3145 }
3146
3147 @override
3148 Object visitVariableDeclaration(VariableDeclaration node) {
3149 bool isConst = node.isConst;
3150 bool isFinal = node.isFinal;
3151 bool hasInitializer = node.initializer != null;
3152 VariableElementImpl element;
3153 if (_inFieldContext) {
3154 SimpleIdentifier fieldName = node.name;
3155 FieldElementImpl field;
3156 if ((isConst || isFinal) && hasInitializer) {
3157 field = new ConstFieldElementImpl.forNode(fieldName);
3158 } else {
3159 field = new FieldElementImpl.forNode(fieldName);
3160 }
3161 element = field;
3162 if ((node.parent as VariableDeclarationList).type == null) {
3163 field.hasImplicitType = true;
3164 }
3165 _currentHolder.addField(field);
3166 fieldName.staticElement = field;
3167 } else if (_inFunction) {
3168 SimpleIdentifier variableName = node.name;
3169 LocalVariableElementImpl variable;
3170 if (isConst && hasInitializer) {
3171 variable = new ConstLocalVariableElementImpl.forNode(variableName);
3172 } else {
3173 variable = new LocalVariableElementImpl.forNode(variableName);
3174 }
3175 element = variable;
3176 Block enclosingBlock = node.getAncestor((node) => node is Block);
3177 // TODO(brianwilkerson) This isn't right for variables declared in a for
3178 // loop.
3179 variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
3180 if ((node.parent as VariableDeclarationList).type == null) {
3181 variable.hasImplicitType = true;
3182 }
3183 _currentHolder.addLocalVariable(variable);
3184 variableName.staticElement = element;
3185 } else {
3186 SimpleIdentifier variableName = node.name;
3187 TopLevelVariableElementImpl variable;
3188 if (isConst && hasInitializer) {
3189 variable = new ConstTopLevelVariableElementImpl(variableName);
3190 } else {
3191 variable = new TopLevelVariableElementImpl.forNode(variableName);
3192 }
3193 element = variable;
3194 if ((node.parent as VariableDeclarationList).type == null) {
3195 variable.hasImplicitType = true;
3196 }
3197 _currentHolder.addTopLevelVariable(variable);
3198 variableName.staticElement = element;
3199 }
3200 element.const3 = isConst;
3201 element.final2 = isFinal;
3202 if (hasInitializer) {
3203 ElementHolder holder = new ElementHolder();
3204 bool wasInFieldContext = _inFieldContext;
3205 _inFieldContext = false;
3206 try {
3207 _visit(holder, node.initializer);
3208 } finally {
3209 _inFieldContext = wasInFieldContext;
3210 }
3211 FunctionElementImpl initializer =
3212 new FunctionElementImpl.forOffset(node.initializer.beginToken.offset);
3213 initializer.functions = holder.functions;
3214 initializer.labels = holder.labels;
3215 initializer.localVariables = holder.localVariables;
3216 initializer.synthetic = true;
3217 element.initializer = initializer;
3218 holder.validate();
3219 }
3220 if (element is PropertyInducingElementImpl) {
3221 if (_inFieldContext) {
3222 (element as FieldElementImpl).static =
3223 (node.parent.parent as FieldDeclaration).isStatic;
3224 }
3225 PropertyAccessorElementImpl getter =
3226 new PropertyAccessorElementImpl.forVariable(element);
3227 getter.getter = true;
3228 if (element.hasImplicitType) {
3229 getter.hasImplicitReturnType = true;
3230 }
3231 _currentHolder.addAccessor(getter);
3232 element.getter = getter;
3233 if (!isConst && !isFinal) {
3234 PropertyAccessorElementImpl setter =
3235 new PropertyAccessorElementImpl.forVariable(element);
3236 setter.setter = true;
3237 ParameterElementImpl parameter =
3238 new ParameterElementImpl("_${element.name}", element.nameOffset);
3239 parameter.synthetic = true;
3240 parameter.parameterKind = ParameterKind.REQUIRED;
3241 setter.parameters = <ParameterElement>[parameter];
3242 _currentHolder.addAccessor(setter);
3243 element.setter = setter;
3244 }
3245 }
3246 return null;
3247 }
3248
3249 /**
3250 * Build the table mapping field names to field elements for the fields define d in the current
3251 * class.
3252 *
3253 * @param fields the field elements defined in the current class
3254 */
3255 void _buildFieldMap(List<FieldElement> fields) {
3256 _fieldMap = new HashMap<String, FieldElement>();
3257 int count = fields.length;
3258 for (int i = 0; i < count; i++) {
3259 FieldElement field = fields[i];
3260 _fieldMap[field.name] = field;
3261 }
3262 }
3263
3264 /**
3265 * Creates the [ConstructorElement]s array with the single default constructor element.
3266 *
3267 * @param interfaceType the interface type for which to create a default const ructor
3268 * @return the [ConstructorElement]s array with the single default constructor element
3269 */
3270 List<ConstructorElement> _createDefaultConstructors(
3271 InterfaceTypeImpl interfaceType) {
3272 ConstructorElementImpl constructor =
3273 new ConstructorElementImpl.forNode(null);
3274 constructor.synthetic = true;
3275 constructor.returnType = interfaceType;
3276 FunctionTypeImpl type = new FunctionTypeImpl(constructor);
3277 _functionTypesToFix.add(type);
3278 constructor.type = type;
3279 return <ConstructorElement>[constructor];
3280 }
3281
3282 /**
3283 * Create the types associated with the given type parameters, setting the typ e of each type
3284 * parameter, and return an array of types corresponding to the given paramete rs.
3285 *
3286 * @param typeParameters the type parameters for which types are to be created
3287 * @return an array of types corresponding to the given parameters
3288 */
3289 List<DartType> _createTypeParameterTypes(
3290 List<TypeParameterElement> typeParameters) {
3291 int typeParameterCount = typeParameters.length;
3292 List<DartType> typeArguments = new List<DartType>(typeParameterCount);
3293 for (int i = 0; i < typeParameterCount; i++) {
3294 TypeParameterElementImpl typeParameter =
3295 typeParameters[i] as TypeParameterElementImpl;
3296 TypeParameterTypeImpl typeParameterType =
3297 new TypeParameterTypeImpl(typeParameter);
3298 typeParameter.type = typeParameterType;
3299 typeArguments[i] = typeParameterType;
3300 }
3301 return typeArguments;
3302 }
3303
3304 /**
3305 * Return the body of the function that contains the given parameter, or `null ` if no
3306 * function body could be found.
3307 *
3308 * @param node the parameter contained in the function whose body is to be ret urned
3309 * @return the body of the function that contains the given parameter
3310 */
3311 FunctionBody _getFunctionBody(FormalParameter node) {
3312 AstNode parent = node.parent;
3313 while (parent != null) {
3314 if (parent is ConstructorDeclaration) {
3315 return parent.body;
3316 } else if (parent is FunctionExpression) {
3317 return parent.body;
3318 } else if (parent is MethodDeclaration) {
3319 return parent.body;
3320 }
3321 parent = parent.parent;
3322 }
3323 return null;
3324 }
3325
3326 /**
3327 * Sets the visible source range for formal parameter.
3328 */
3329 void _setParameterVisibleRange(
3330 FormalParameter node, ParameterElementImpl element) {
3331 FunctionBody body = _getFunctionBody(node);
3332 if (body != null) {
3333 element.setVisibleRange(body.offset, body.length);
3334 }
3335 }
3336
3337 /**
3338 * Make the given holder be the current holder while visiting the given node.
3339 *
3340 * @param holder the holder that will gather elements that are built while vis iting the children
3341 * @param node the node to be visited
3342 */
3343 void _visit(ElementHolder holder, AstNode node) {
3344 if (node != null) {
3345 ElementHolder previousHolder = _currentHolder;
3346 _currentHolder = holder;
3347 try {
3348 node.accept(this);
3349 } finally {
3350 _currentHolder = previousHolder;
3351 }
3352 }
3353 }
3354
3355 /**
3356 * Make the given holder be the current holder while visiting the children of the given node.
3357 *
3358 * @param holder the holder that will gather elements that are built while vis iting the children
3359 * @param node the node whose children are to be visited
3360 */
3361 void _visitChildren(ElementHolder holder, AstNode node) {
3362 if (node != null) {
3363 ElementHolder previousHolder = _currentHolder;
3364 _currentHolder = holder;
3365 try {
3366 node.visitChildren(this);
3367 } finally {
3368 _currentHolder = previousHolder;
3369 }
3370 }
3371 }
3372 }
3373
3374 /**
3375 * Instances of the class `ElementHolder` hold on to elements created while trav ersing an AST
3376 * structure so that they can be accessed when creating their enclosing element.
3377 */
3378 class ElementHolder {
3379 List<PropertyAccessorElement> _accessors;
3380
3381 List<ConstructorElement> _constructors;
3382
3383 List<ClassElement> _enums;
3384
3385 List<FieldElement> _fields;
3386
3387 List<FunctionElement> _functions;
3388
3389 List<LabelElement> _labels;
3390
3391 List<LocalVariableElement> _localVariables;
3392
3393 List<MethodElement> _methods;
3394
3395 List<ParameterElement> _parameters;
3396
3397 List<TopLevelVariableElement> _topLevelVariables;
3398
3399 List<ClassElement> _types;
3400
3401 List<FunctionTypeAliasElement> _typeAliases;
3402
3403 List<TypeParameterElement> _typeParameters;
3404
3405 List<PropertyAccessorElement> get accessors {
3406 if (_accessors == null) {
3407 return PropertyAccessorElement.EMPTY_LIST;
3408 }
3409 List<PropertyAccessorElement> result = _accessors;
3410 _accessors = null;
3411 return result;
3412 }
3413
3414 List<ConstructorElement> get constructors {
3415 if (_constructors == null) {
3416 return ConstructorElement.EMPTY_LIST;
3417 }
3418 List<ConstructorElement> result = _constructors;
3419 _constructors = null;
3420 return result;
3421 }
3422
3423 List<ClassElement> get enums {
3424 if (_enums == null) {
3425 return ClassElement.EMPTY_LIST;
3426 }
3427 List<ClassElement> result = _enums;
3428 _enums = null;
3429 return result;
3430 }
3431
3432 List<FieldElement> get fields {
3433 if (_fields == null) {
3434 return FieldElement.EMPTY_LIST;
3435 }
3436 List<FieldElement> result = _fields;
3437 _fields = null;
3438 return result;
3439 }
3440
3441 List<FieldElement> get fieldsWithoutFlushing {
3442 if (_fields == null) {
3443 return FieldElement.EMPTY_LIST;
3444 }
3445 List<FieldElement> result = _fields;
3446 return result;
3447 }
3448
3449 List<FunctionElement> get functions {
3450 if (_functions == null) {
3451 return FunctionElement.EMPTY_LIST;
3452 }
3453 List<FunctionElement> result = _functions;
3454 _functions = null;
3455 return result;
3456 }
3457
3458 List<LabelElement> get labels {
3459 if (_labels == null) {
3460 return LabelElement.EMPTY_LIST;
3461 }
3462 List<LabelElement> result = _labels;
3463 _labels = null;
3464 return result;
3465 }
3466
3467 List<LocalVariableElement> get localVariables {
3468 if (_localVariables == null) {
3469 return LocalVariableElement.EMPTY_LIST;
3470 }
3471 List<LocalVariableElement> result = _localVariables;
3472 _localVariables = null;
3473 return result;
3474 }
3475
3476 List<MethodElement> get methods {
3477 if (_methods == null) {
3478 return MethodElement.EMPTY_LIST;
3479 }
3480 List<MethodElement> result = _methods;
3481 _methods = null;
3482 return result;
3483 }
3484
3485 List<ParameterElement> get parameters {
3486 if (_parameters == null) {
3487 return ParameterElement.EMPTY_LIST;
3488 }
3489 List<ParameterElement> result = _parameters;
3490 _parameters = null;
3491 return result;
3492 }
3493
3494 List<TopLevelVariableElement> get topLevelVariables {
3495 if (_topLevelVariables == null) {
3496 return TopLevelVariableElement.EMPTY_LIST;
3497 }
3498 List<TopLevelVariableElement> result = _topLevelVariables;
3499 _topLevelVariables = null;
3500 return result;
3501 }
3502
3503 List<FunctionTypeAliasElement> get typeAliases {
3504 if (_typeAliases == null) {
3505 return FunctionTypeAliasElement.EMPTY_LIST;
3506 }
3507 List<FunctionTypeAliasElement> result = _typeAliases;
3508 _typeAliases = null;
3509 return result;
3510 }
3511
3512 List<TypeParameterElement> get typeParameters {
3513 if (_typeParameters == null) {
3514 return TypeParameterElement.EMPTY_LIST;
3515 }
3516 List<TypeParameterElement> result = _typeParameters;
3517 _typeParameters = null;
3518 return result;
3519 }
3520
3521 List<ClassElement> get types {
3522 if (_types == null) {
3523 return ClassElement.EMPTY_LIST;
3524 }
3525 List<ClassElement> result = _types;
3526 _types = null;
3527 return result;
3528 }
3529
3530 void addAccessor(PropertyAccessorElement element) {
3531 if (_accessors == null) {
3532 _accessors = new List<PropertyAccessorElement>();
3533 }
3534 _accessors.add(element);
3535 }
3536
3537 void addConstructor(ConstructorElement element) {
3538 if (_constructors == null) {
3539 _constructors = new List<ConstructorElement>();
3540 }
3541 _constructors.add(element);
3542 }
3543
3544 void addEnum(ClassElement element) {
3545 if (_enums == null) {
3546 _enums = new List<ClassElement>();
3547 }
3548 _enums.add(element);
3549 }
3550
3551 void addField(FieldElement element) {
3552 if (_fields == null) {
3553 _fields = new List<FieldElement>();
3554 }
3555 _fields.add(element);
3556 }
3557
3558 void addFunction(FunctionElement element) {
3559 if (_functions == null) {
3560 _functions = new List<FunctionElement>();
3561 }
3562 _functions.add(element);
3563 }
3564
3565 void addLabel(LabelElement element) {
3566 if (_labels == null) {
3567 _labels = new List<LabelElement>();
3568 }
3569 _labels.add(element);
3570 }
3571
3572 void addLocalVariable(LocalVariableElement element) {
3573 if (_localVariables == null) {
3574 _localVariables = new List<LocalVariableElement>();
3575 }
3576 _localVariables.add(element);
3577 }
3578
3579 void addMethod(MethodElement element) {
3580 if (_methods == null) {
3581 _methods = new List<MethodElement>();
3582 }
3583 _methods.add(element);
3584 }
3585
3586 void addParameter(ParameterElement element) {
3587 if (_parameters == null) {
3588 _parameters = new List<ParameterElement>();
3589 }
3590 _parameters.add(element);
3591 }
3592
3593 void addTopLevelVariable(TopLevelVariableElement element) {
3594 if (_topLevelVariables == null) {
3595 _topLevelVariables = new List<TopLevelVariableElement>();
3596 }
3597 _topLevelVariables.add(element);
3598 }
3599
3600 void addType(ClassElement element) {
3601 if (_types == null) {
3602 _types = new List<ClassElement>();
3603 }
3604 _types.add(element);
3605 }
3606
3607 void addTypeAlias(FunctionTypeAliasElement element) {
3608 if (_typeAliases == null) {
3609 _typeAliases = new List<FunctionTypeAliasElement>();
3610 }
3611 _typeAliases.add(element);
3612 }
3613
3614 void addTypeParameter(TypeParameterElement element) {
3615 if (_typeParameters == null) {
3616 _typeParameters = new List<TypeParameterElement>();
3617 }
3618 _typeParameters.add(element);
3619 }
3620
3621 FieldElement getField(String fieldName) {
3622 if (_fields == null) {
3623 return null;
3624 }
3625 for (FieldElement field in _fields) {
3626 if (field.name == fieldName) {
3627 return field;
3628 }
3629 }
3630 return null;
3631 }
3632
3633 TopLevelVariableElement getTopLevelVariable(String variableName) {
3634 if (_topLevelVariables == null) {
3635 return null;
3636 }
3637 for (TopLevelVariableElement variable in _topLevelVariables) {
3638 if (variable.name == variableName) {
3639 return variable;
3640 }
3641 }
3642 return null;
3643 }
3644
3645 void validate() {
3646 StringBuffer buffer = new StringBuffer();
3647 if (_accessors != null) {
3648 buffer.write(_accessors.length);
3649 buffer.write(" accessors");
3650 }
3651 if (_constructors != null) {
3652 if (buffer.length > 0) {
3653 buffer.write("; ");
3654 }
3655 buffer.write(_constructors.length);
3656 buffer.write(" constructors");
3657 }
3658 if (_fields != null) {
3659 if (buffer.length > 0) {
3660 buffer.write("; ");
3661 }
3662 buffer.write(_fields.length);
3663 buffer.write(" fields");
3664 }
3665 if (_functions != null) {
3666 if (buffer.length > 0) {
3667 buffer.write("; ");
3668 }
3669 buffer.write(_functions.length);
3670 buffer.write(" functions");
3671 }
3672 if (_labels != null) {
3673 if (buffer.length > 0) {
3674 buffer.write("; ");
3675 }
3676 buffer.write(_labels.length);
3677 buffer.write(" labels");
3678 }
3679 if (_localVariables != null) {
3680 if (buffer.length > 0) {
3681 buffer.write("; ");
3682 }
3683 buffer.write(_localVariables.length);
3684 buffer.write(" local variables");
3685 }
3686 if (_methods != null) {
3687 if (buffer.length > 0) {
3688 buffer.write("; ");
3689 }
3690 buffer.write(_methods.length);
3691 buffer.write(" methods");
3692 }
3693 if (_parameters != null) {
3694 if (buffer.length > 0) {
3695 buffer.write("; ");
3696 }
3697 buffer.write(_parameters.length);
3698 buffer.write(" parameters");
3699 }
3700 if (_topLevelVariables != null) {
3701 if (buffer.length > 0) {
3702 buffer.write("; ");
3703 }
3704 buffer.write(_topLevelVariables.length);
3705 buffer.write(" top-level variables");
3706 }
3707 if (_types != null) {
3708 if (buffer.length > 0) {
3709 buffer.write("; ");
3710 }
3711 buffer.write(_types.length);
3712 buffer.write(" types");
3713 }
3714 if (_typeAliases != null) {
3715 if (buffer.length > 0) {
3716 buffer.write("; ");
3717 }
3718 buffer.write(_typeAliases.length);
3719 buffer.write(" type aliases");
3720 }
3721 if (_typeParameters != null) {
3722 if (buffer.length > 0) {
3723 buffer.write("; ");
3724 }
3725 buffer.write(_typeParameters.length);
3726 buffer.write(" type parameters");
3727 }
3728 if (buffer.length > 0) {
3729 AnalysisEngine.instance.logger
3730 .logError("Failed to capture elements: $buffer");
3731 }
3732 }
3733 }
3734
3735 /**
3736 * Instances of the class `EnclosedScope` implement a scope that is lexically en closed in
3737 * another scope.
3738 */
3739 class EnclosedScope extends Scope {
3740 /**
3741 * The scope in which this scope is lexically enclosed.
3742 */
3743 final Scope enclosingScope;
3744
3745 /**
3746 * A table mapping names that will be defined in this scope, but right now are not initialized.
3747 * According to the scoping rules these names are hidden, even if they were de fined in an outer
3748 * scope.
3749 */
3750 HashMap<String, Element> _hiddenElements = new HashMap<String, Element>();
3751
3752 /**
3753 * A flag indicating whether there are any names defined in this scope.
3754 */
3755 bool _hasHiddenName = false;
3756
3757 /**
3758 * Initialize a newly created scope enclosed within another scope.
3759 *
3760 * @param enclosingScope the scope in which this scope is lexically enclosed
3761 */
3762 EnclosedScope(this.enclosingScope);
3763
3764 @override
3765 AnalysisErrorListener get errorListener => enclosingScope.errorListener;
3766
3767 /**
3768 * Record that given element is declared in this scope, but hasn't been initia lized yet, so it is
3769 * error to use. If there is already an element with the given name defined in an outer scope,
3770 * then it will become unavailable.
3771 *
3772 * @param element the element declared, but not initialized in this scope
3773 */
3774 void hide(Element element) {
3775 if (element != null) {
3776 String name = element.name;
3777 if (name != null && !name.isEmpty) {
3778 _hiddenElements[name] = element;
3779 _hasHiddenName = true;
3780 }
3781 }
3782 }
3783
3784 @override
3785 Element internalLookup(
3786 Identifier identifier, String name, LibraryElement referencingLibrary) {
3787 Element element = localLookup(name, referencingLibrary);
3788 if (element != null) {
3789 return element;
3790 }
3791 // May be there is a hidden Element.
3792 if (_hasHiddenName) {
3793 Element hiddenElement = _hiddenElements[name];
3794 if (hiddenElement != null) {
3795 errorListener.onError(new AnalysisError(
3796 getSource(identifier),
3797 identifier.offset,
3798 identifier.length,
3799 CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, []));
3800 return hiddenElement;
3801 }
3802 }
3803 // Check enclosing scope.
3804 return enclosingScope.internalLookup(identifier, name, referencingLibrary);
3805 }
3806 }
3807
3808 /**
3809 * Instances of the class `EnumMemberBuilder` build the members in enum declarat ions.
3810 */
3811 class EnumMemberBuilder extends RecursiveAstVisitor<Object> {
3812 /**
3813 * The type provider used to access the types needed to build an element model for enum
3814 * declarations.
3815 */
3816 final TypeProvider _typeProvider;
3817
3818 /**
3819 * Initialize a newly created enum member builder.
3820 *
3821 * @param typeProvider the type provider used to access the types needed to bu ild an element model
3822 * for enum declarations
3823 */
3824 EnumMemberBuilder(this._typeProvider);
3825
3826 @override
3827 Object visitEnumDeclaration(EnumDeclaration node) {
3828 //
3829 // Finish building the enum.
3830 //
3831 ClassElementImpl enumElement = node.name.staticElement as ClassElementImpl;
3832 InterfaceType enumType = enumElement.type;
3833 enumElement.supertype = _typeProvider.objectType;
3834 //
3835 // Populate the fields.
3836 //
3837 List<FieldElement> fields = new List<FieldElement>();
3838 List<PropertyAccessorElement> getters = new List<PropertyAccessorElement>();
3839 InterfaceType intType = _typeProvider.intType;
3840 String indexFieldName = "index";
3841 FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1);
3842 indexField.final2 = true;
3843 indexField.synthetic = true;
3844 indexField.type = intType;
3845 fields.add(indexField);
3846 getters.add(_createGetter(indexField));
3847 ConstFieldElementImpl valuesField = new ConstFieldElementImpl("values", -1);
3848 valuesField.static = true;
3849 valuesField.const3 = true;
3850 valuesField.synthetic = true;
3851 valuesField.type = _typeProvider.listType.substitute4(<DartType>[enumType]);
3852 fields.add(valuesField);
3853 getters.add(_createGetter(valuesField));
3854 //
3855 // Build the enum constants.
3856 //
3857 NodeList<EnumConstantDeclaration> constants = node.constants;
3858 List<DartObjectImpl> constantValues = new List<DartObjectImpl>();
3859 int constantCount = constants.length;
3860 for (int i = 0; i < constantCount; i++) {
3861 SimpleIdentifier constantName = constants[i].name;
3862 FieldElementImpl constantField =
3863 new ConstFieldElementImpl.forNode(constantName);
3864 constantField.static = true;
3865 constantField.const3 = true;
3866 constantField.type = enumType;
3867 //
3868 // Create a value for the constant.
3869 //
3870 HashMap<String, DartObjectImpl> fieldMap =
3871 new HashMap<String, DartObjectImpl>();
3872 fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i));
3873 DartObjectImpl value =
3874 new DartObjectImpl(enumType, new GenericState(fieldMap));
3875 constantValues.add(value);
3876 constantField.evaluationResult = new EvaluationResultImpl(value);
3877 fields.add(constantField);
3878 getters.add(_createGetter(constantField));
3879 constantName.staticElement = constantField;
3880 }
3881 //
3882 // Build the value of the 'values' field.
3883 //
3884 valuesField.evaluationResult = new EvaluationResultImpl(
3885 new DartObjectImpl(valuesField.type, new ListState(constantValues)));
3886 //
3887 // Finish building the enum.
3888 //
3889 enumElement.fields = fields;
3890 enumElement.accessors = getters;
3891 // Client code isn't allowed to invoke the constructor, so we do not model
3892 // it.
3893 return super.visitEnumDeclaration(node);
3894 }
3895
3896 /**
3897 * Create a getter that corresponds to the given field.
3898 *
3899 * @param field the field for which a getter is to be created
3900 * @return the getter that was created
3901 */
3902 PropertyAccessorElement _createGetter(FieldElementImpl field) {
3903 PropertyAccessorElementImpl getter =
3904 new PropertyAccessorElementImpl.forVariable(field);
3905 getter.getter = true;
3906 getter.returnType = field.type;
3907 getter.type = new FunctionTypeImpl(getter);
3908 field.getter = getter;
3909 return getter;
3910 }
3911 }
3912
3913 /**
3914 * Instances of the class `ExitDetector` determine whether the visited AST node is guaranteed
3915 * to terminate by executing a `return` statement, `throw` expression, `rethrow`
3916 * expression, or simple infinite loop such as `while(true)`.
3917 */
3918 class ExitDetector extends GeneralizingAstVisitor<bool> {
3919 /**
3920 * Set to `true` when a `break` is encountered, and reset to `false` when a
3921 * `do`, `while`, `for` or `switch` block is entered.
3922 */
3923 bool _enclosingBlockContainsBreak = false;
3924
3925 @override
3926 bool visitArgumentList(ArgumentList node) =>
3927 _visitExpressions(node.arguments);
3928
3929 @override
3930 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression);
3931
3932 @override
3933 bool visitAssertStatement(AssertStatement node) => _nodeExits(node.condition);
3934
3935 @override
3936 bool visitAssignmentExpression(AssignmentExpression node) =>
3937 _nodeExits(node.leftHandSide) || _nodeExits(node.rightHandSide);
3938
3939 @override
3940 bool visitAwaitExpression(AwaitExpression node) =>
3941 _nodeExits(node.expression);
3942
3943 @override
3944 bool visitBinaryExpression(BinaryExpression node) {
3945 Expression lhsExpression = node.leftOperand;
3946 sc.TokenType operatorType = node.operator.type;
3947 // If the operator is || and the left hand side is false literal, don't
3948 // consider the RHS of the binary expression.
3949 // TODO(jwren) Do we want to take constant expressions into account,
3950 // evaluate if(false) {} differently than if(<condition>), when <condition>
3951 // evaluates to a constant false value?
3952 if (operatorType == sc.TokenType.BAR_BAR) {
3953 if (lhsExpression is BooleanLiteral) {
3954 BooleanLiteral booleanLiteral = lhsExpression;
3955 if (!booleanLiteral.value) {
3956 return false;
3957 }
3958 }
3959 }
3960 // If the operator is && and the left hand side is true literal, don't
3961 // consider the RHS of the binary expression.
3962 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) {
3963 if (lhsExpression is BooleanLiteral) {
3964 BooleanLiteral booleanLiteral = lhsExpression;
3965 if (booleanLiteral.value) {
3966 return false;
3967 }
3968 }
3969 }
3970 Expression rhsExpression = node.rightOperand;
3971 return _nodeExits(lhsExpression) || _nodeExits(rhsExpression);
3972 }
3973
3974 @override
3975 bool visitBlock(Block node) => _visitStatements(node.statements);
3976
3977 @override
3978 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block);
3979
3980 @override
3981 bool visitBreakStatement(BreakStatement node) {
3982 _enclosingBlockContainsBreak = true;
3983 return false;
3984 }
3985
3986 @override
3987 bool visitCascadeExpression(CascadeExpression node) =>
3988 _nodeExits(node.target) || _visitExpressions(node.cascadeSections);
3989
3990 @override
3991 bool visitConditionalExpression(ConditionalExpression node) {
3992 Expression conditionExpression = node.condition;
3993 Expression thenStatement = node.thenExpression;
3994 Expression elseStatement = node.elseExpression;
3995 // TODO(jwren) Do we want to take constant expressions into account,
3996 // evaluate if(false) {} differently than if(<condition>), when <condition>
3997 // evaluates to a constant false value?
3998 if (_nodeExits(conditionExpression)) {
3999 return true;
4000 }
4001 if (thenStatement == null || elseStatement == null) {
4002 return false;
4003 }
4004 return thenStatement.accept(this) && elseStatement.accept(this);
4005 }
4006
4007 @override
4008 bool visitContinueStatement(ContinueStatement node) => false;
4009
4010 @override
4011 bool visitDoStatement(DoStatement node) {
4012 bool outerBreakValue = _enclosingBlockContainsBreak;
4013 _enclosingBlockContainsBreak = false;
4014 try {
4015 Expression conditionExpression = node.condition;
4016 if (_nodeExits(conditionExpression)) {
4017 return true;
4018 }
4019 // TODO(jwren) Do we want to take all constant expressions into account?
4020 if (conditionExpression is BooleanLiteral) {
4021 BooleanLiteral booleanLiteral = conditionExpression;
4022 // If do {} while (true), and the body doesn't return or the body
4023 // doesn't have a break, then return true.
4024 bool blockReturns = _nodeExits(node.body);
4025 if (booleanLiteral.value &&
4026 (blockReturns || !_enclosingBlockContainsBreak)) {
4027 return true;
4028 }
4029 }
4030 return false;
4031 } finally {
4032 _enclosingBlockContainsBreak = outerBreakValue;
4033 }
4034 }
4035
4036 @override
4037 bool visitEmptyStatement(EmptyStatement node) => false;
4038
4039 @override
4040 bool visitExpressionStatement(ExpressionStatement node) =>
4041 _nodeExits(node.expression);
4042
4043 @override
4044 bool visitForEachStatement(ForEachStatement node) {
4045 bool outerBreakValue = _enclosingBlockContainsBreak;
4046 _enclosingBlockContainsBreak = false;
4047 try {
4048 return _nodeExits(node.iterable);
4049 } finally {
4050 _enclosingBlockContainsBreak = outerBreakValue;
4051 }
4052 }
4053
4054 @override
4055 bool visitForStatement(ForStatement node) {
4056 bool outerBreakValue = _enclosingBlockContainsBreak;
4057 _enclosingBlockContainsBreak = false;
4058 try {
4059 if (node.variables != null &&
4060 _visitVariableDeclarations(node.variables.variables)) {
4061 return true;
4062 }
4063 if (node.initialization != null && _nodeExits(node.initialization)) {
4064 return true;
4065 }
4066 Expression conditionExpression = node.condition;
4067 if (conditionExpression != null && _nodeExits(conditionExpression)) {
4068 return true;
4069 }
4070 if (_visitExpressions(node.updaters)) {
4071 return true;
4072 }
4073 // TODO(jwren) Do we want to take all constant expressions into account?
4074 // If for(; true; ) (or for(;;)), and the body doesn't return or the body
4075 // doesn't have a break, then return true.
4076 bool implicitOrExplictTrue = conditionExpression == null ||
4077 (conditionExpression is BooleanLiteral && conditionExpression.value);
4078 if (implicitOrExplictTrue) {
4079 bool blockReturns = _nodeExits(node.body);
4080 if (blockReturns || !_enclosingBlockContainsBreak) {
4081 return true;
4082 }
4083 }
4084 return false;
4085 } finally {
4086 _enclosingBlockContainsBreak = outerBreakValue;
4087 }
4088 }
4089
4090 @override
4091 bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) =>
4092 false;
4093
4094 @override
4095 bool visitFunctionExpression(FunctionExpression node) => false;
4096
4097 @override
4098 bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
4099 if (_nodeExits(node.function)) {
4100 return true;
4101 }
4102 return node.argumentList.accept(this);
4103 }
4104
4105 @override
4106 bool visitIdentifier(Identifier node) => false;
4107
4108 @override
4109 bool visitIfStatement(IfStatement node) {
4110 Expression conditionExpression = node.condition;
4111 Statement thenStatement = node.thenStatement;
4112 Statement elseStatement = node.elseStatement;
4113 if (_nodeExits(conditionExpression)) {
4114 return true;
4115 }
4116 // TODO(jwren) Do we want to take all constant expressions into account?
4117 if (conditionExpression is BooleanLiteral) {
4118 BooleanLiteral booleanLiteral = conditionExpression;
4119 if (booleanLiteral.value) {
4120 // if(true) ...
4121 return _nodeExits(thenStatement);
4122 } else if (elseStatement != null) {
4123 // if (false) ...
4124 return _nodeExits(elseStatement);
4125 }
4126 }
4127 if (thenStatement == null || elseStatement == null) {
4128 return false;
4129 }
4130 return _nodeExits(thenStatement) && _nodeExits(elseStatement);
4131 }
4132
4133 @override
4134 bool visitIndexExpression(IndexExpression node) {
4135 Expression target = node.realTarget;
4136 if (_nodeExits(target)) {
4137 return true;
4138 }
4139 if (_nodeExits(node.index)) {
4140 return true;
4141 }
4142 return false;
4143 }
4144
4145 @override
4146 bool visitInstanceCreationExpression(InstanceCreationExpression node) =>
4147 _nodeExits(node.argumentList);
4148
4149 @override
4150 bool visitIsExpression(IsExpression node) => node.expression.accept(this);
4151
4152 @override
4153 bool visitLabel(Label node) => false;
4154
4155 @override
4156 bool visitLabeledStatement(LabeledStatement node) =>
4157 node.statement.accept(this);
4158
4159 @override
4160 bool visitLiteral(Literal node) => false;
4161
4162 @override
4163 bool visitMethodInvocation(MethodInvocation node) {
4164 Expression target = node.realTarget;
4165 if (target != null && target.accept(this)) {
4166 return true;
4167 }
4168 return _nodeExits(node.argumentList);
4169 }
4170
4171 @override
4172 bool visitNamedExpression(NamedExpression node) =>
4173 node.expression.accept(this);
4174
4175 @override
4176 bool visitParenthesizedExpression(ParenthesizedExpression node) =>
4177 node.expression.accept(this);
4178
4179 @override
4180 bool visitPostfixExpression(PostfixExpression node) => false;
4181
4182 @override
4183 bool visitPrefixExpression(PrefixExpression node) => false;
4184
4185 @override
4186 bool visitPropertyAccess(PropertyAccess node) {
4187 Expression target = node.realTarget;
4188 if (target != null && target.accept(this)) {
4189 return true;
4190 }
4191 return false;
4192 }
4193
4194 @override
4195 bool visitRethrowExpression(RethrowExpression node) => true;
4196
4197 @override
4198 bool visitReturnStatement(ReturnStatement node) => true;
4199
4200 @override
4201 bool visitSuperExpression(SuperExpression node) => false;
4202
4203 @override
4204 bool visitSwitchCase(SwitchCase node) => _visitStatements(node.statements);
4205
4206 @override
4207 bool visitSwitchDefault(SwitchDefault node) =>
4208 _visitStatements(node.statements);
4209
4210 @override
4211 bool visitSwitchStatement(SwitchStatement node) {
4212 bool outerBreakValue = _enclosingBlockContainsBreak;
4213 _enclosingBlockContainsBreak = false;
4214 try {
4215 bool hasDefault = false;
4216 List<SwitchMember> members = node.members;
4217 for (int i = 0; i < members.length; i++) {
4218 SwitchMember switchMember = members[i];
4219 if (switchMember is SwitchDefault) {
4220 hasDefault = true;
4221 // If this is the last member and there are no statements, return
4222 // false
4223 if (switchMember.statements.isEmpty && i + 1 == members.length) {
4224 return false;
4225 }
4226 }
4227 // For switch members with no statements, don't visit the children,
4228 // otherwise, return false if no return is found in the children
4229 // statements.
4230 if (!switchMember.statements.isEmpty && !switchMember.accept(this)) {
4231 return false;
4232 }
4233 }
4234 // All of the members exit, determine whether there are possible cases
4235 // that are not caught by the members.
4236 DartType type = node.expression == null ? null : node.expression.bestType;
4237 if (type is InterfaceType) {
4238 ClassElement element = type.element;
4239 if (element != null && element.isEnum) {
4240 // If some of the enum values are not covered, then a warning will
4241 // have already been generated, so there's no point in generating a
4242 // hint.
4243 return true;
4244 }
4245 }
4246 return hasDefault;
4247 } finally {
4248 _enclosingBlockContainsBreak = outerBreakValue;
4249 }
4250 }
4251
4252 @override
4253 bool visitThisExpression(ThisExpression node) => false;
4254
4255 @override
4256 bool visitThrowExpression(ThrowExpression node) => true;
4257
4258 @override
4259 bool visitTryStatement(TryStatement node) {
4260 if (_nodeExits(node.body)) {
4261 return true;
4262 }
4263 Block finallyBlock = node.finallyBlock;
4264 if (_nodeExits(finallyBlock)) {
4265 return true;
4266 }
4267 return false;
4268 }
4269
4270 @override
4271 bool visitTypeName(TypeName node) => false;
4272
4273 @override
4274 bool visitVariableDeclaration(VariableDeclaration node) {
4275 Expression initializer = node.initializer;
4276 if (initializer != null) {
4277 return initializer.accept(this);
4278 }
4279 return false;
4280 }
4281
4282 @override
4283 bool visitVariableDeclarationList(VariableDeclarationList node) =>
4284 _visitVariableDeclarations(node.variables);
4285
4286 @override
4287 bool visitVariableDeclarationStatement(VariableDeclarationStatement node) {
4288 NodeList<VariableDeclaration> variables = node.variables.variables;
4289 for (int i = 0; i < variables.length; i++) {
4290 if (variables[i].accept(this)) {
4291 return true;
4292 }
4293 }
4294 return false;
4295 }
4296
4297 @override
4298 bool visitWhileStatement(WhileStatement node) {
4299 bool outerBreakValue = _enclosingBlockContainsBreak;
4300 _enclosingBlockContainsBreak = false;
4301 try {
4302 Expression conditionExpression = node.condition;
4303 if (conditionExpression.accept(this)) {
4304 return true;
4305 }
4306 // TODO(jwren) Do we want to take all constant expressions into account?
4307 if (conditionExpression is BooleanLiteral) {
4308 BooleanLiteral booleanLiteral = conditionExpression;
4309 // If while(true), and the body doesn't return or the body doesn't have
4310 // a break, then return true.
4311 bool blockReturns = node.body.accept(this);
4312 if (booleanLiteral.value &&
4313 (blockReturns || !_enclosingBlockContainsBreak)) {
4314 return true;
4315 }
4316 }
4317 return false;
4318 } finally {
4319 _enclosingBlockContainsBreak = outerBreakValue;
4320 }
4321 }
4322
4323 /**
4324 * Return `true` if the given node exits.
4325 *
4326 * @param node the node being tested
4327 * @return `true` if the given node exits
4328 */
4329 bool _nodeExits(AstNode node) {
4330 if (node == null) {
4331 return false;
4332 }
4333 return node.accept(this);
4334 }
4335
4336 bool _visitExpressions(NodeList<Expression> expressions) {
4337 for (int i = expressions.length - 1; i >= 0; i--) {
4338 if (expressions[i].accept(this)) {
4339 return true;
4340 }
4341 }
4342 return false;
4343 }
4344
4345 bool _visitStatements(NodeList<Statement> statements) {
4346 for (int i = statements.length - 1; i >= 0; i--) {
4347 if (statements[i].accept(this)) {
4348 return true;
4349 }
4350 }
4351 return false;
4352 }
4353
4354 bool _visitVariableDeclarations(
4355 NodeList<VariableDeclaration> variableDeclarations) {
4356 for (int i = variableDeclarations.length - 1; i >= 0; i--) {
4357 if (variableDeclarations[i].accept(this)) {
4358 return true;
4359 }
4360 }
4361 return false;
4362 }
4363
4364 /**
4365 * Return `true` if the given [node] exits.
4366 */
4367 static bool exits(AstNode node) {
4368 return new ExitDetector()._nodeExits(node);
4369 }
4370 }
4371
4372 /**
4373 * The scope defined by a function.
4374 */
4375 class FunctionScope extends EnclosedScope {
4376 /**
4377 * The element representing the function that defines this scope.
4378 */
4379 final ExecutableElement _functionElement;
4380
4381 /**
4382 * A flag indicating whether the parameters have already been defined, used to
4383 * prevent the parameters from being defined multiple times.
4384 */
4385 bool _parametersDefined = false;
4386
4387 /**
4388 * Initialize a newly created scope enclosed within the [enclosingScope] that
4389 * represents the given [_functionElement].
4390 */
4391 FunctionScope(Scope enclosingScope, this._functionElement)
4392 : super(new EnclosedScope(new EnclosedScope(enclosingScope))) {
4393 if (_functionElement == null) {
4394 throw new IllegalArgumentException("function element cannot be null");
4395 }
4396 _defineTypeParameters();
4397 }
4398
4399 /**
4400 * Define the parameters for the given function in the scope that encloses
4401 * this function.
4402 */
4403 void defineParameters() {
4404 if (_parametersDefined) {
4405 return;
4406 }
4407 _parametersDefined = true;
4408 Scope parameterScope = enclosingScope;
4409 for (ParameterElement parameter in _functionElement.parameters) {
4410 if (!parameter.isInitializingFormal) {
4411 parameterScope.define(parameter);
4412 }
4413 }
4414 }
4415
4416 /**
4417 * Define the type parameters for the function.
4418 */
4419 void _defineTypeParameters() {
4420 Scope typeParameterScope = enclosingScope.enclosingScope;
4421 for (TypeParameterElement typeParameter
4422 in _functionElement.typeParameters) {
4423 typeParameterScope.define(typeParameter);
4424 }
4425 }
4426 }
4427
4428 /**
4429 * The scope defined by a function type alias.
4430 */
4431 class FunctionTypeScope extends EnclosedScope {
4432 final FunctionTypeAliasElement _typeElement;
4433
4434 bool _parametersDefined = false;
4435
4436 /**
4437 * Initialize a newly created scope enclosed within the [enclosingScope] that
4438 * represents the given [_typeElement].
4439 */
4440 FunctionTypeScope(Scope enclosingScope, this._typeElement)
4441 : super(new EnclosedScope(enclosingScope)) {
4442 _defineTypeParameters();
4443 }
4444
4445 /**
4446 * Define the parameters for the function type alias.
4447 */
4448 void defineParameters() {
4449 if (_parametersDefined) {
4450 return;
4451 }
4452 _parametersDefined = true;
4453 for (ParameterElement parameter in _typeElement.parameters) {
4454 define(parameter);
4455 }
4456 }
4457
4458 /**
4459 * Define the type parameters for the function type alias.
4460 */
4461 void _defineTypeParameters() {
4462 Scope typeParameterScope = enclosingScope;
4463 for (TypeParameterElement typeParameter in _typeElement.typeParameters) {
4464 typeParameterScope.define(typeParameter);
4465 }
4466 }
4467 }
4468
4469 /**
4470 * A visitor that visits ASTs and fills [UsedImportedElements].
4471 */
4472 class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
4473 final LibraryElement library;
4474 final UsedImportedElements usedElements = new UsedImportedElements();
4475
4476 GatherUsedImportedElementsVisitor(this.library);
4477
4478 @override
4479 void visitExportDirective(ExportDirective node) {
4480 _visitMetadata(node.metadata);
4481 }
4482
4483 @override
4484 void visitImportDirective(ImportDirective node) {
4485 _visitMetadata(node.metadata);
4486 }
4487
4488 @override
4489 void visitLibraryDirective(LibraryDirective node) {
4490 _visitMetadata(node.metadata);
4491 }
4492
4493 @override
4494 void visitPrefixedIdentifier(PrefixedIdentifier node) {
4495 // If the prefixed identifier references some A.B, where A is a library
4496 // prefix, then we can lookup the associated ImportDirective in
4497 // prefixElementMap and remove it from the unusedImports list.
4498 SimpleIdentifier prefixIdentifier = node.prefix;
4499 Element element = prefixIdentifier.staticElement;
4500 if (element is PrefixElement) {
4501 usedElements.prefixes.add(element);
4502 return;
4503 }
4504 // Otherwise, pass the prefixed identifier element and name onto
4505 // visitIdentifier.
4506 _visitIdentifier(element, prefixIdentifier.name);
4507 }
4508
4509 @override
4510 void visitSimpleIdentifier(SimpleIdentifier node) {
4511 _visitIdentifier(node.staticElement, node.name);
4512 }
4513
4514 void _visitIdentifier(Element element, String name) {
4515 if (element == null) {
4516 return;
4517 }
4518 // If the element is multiply defined then call this method recursively for
4519 // each of the conflicting elements.
4520 if (element is MultiplyDefinedElement) {
4521 MultiplyDefinedElement multiplyDefinedElement = element;
4522 for (Element elt in multiplyDefinedElement.conflictingElements) {
4523 _visitIdentifier(elt, name);
4524 }
4525 return;
4526 } else if (element is PrefixElement) {
4527 usedElements.prefixes.add(element);
4528 return;
4529 } else if (element.enclosingElement is! CompilationUnitElement) {
4530 // Identifiers that aren't a prefix element and whose enclosing element
4531 // isn't a CompilationUnit are ignored- this covers the case the
4532 // identifier is a relative-reference, a reference to an identifier not
4533 // imported by this library.
4534 return;
4535 }
4536 // Ignore if an unknown library.
4537 LibraryElement containingLibrary = element.library;
4538 if (containingLibrary == null) {
4539 return;
4540 }
4541 // Ignore if a local element.
4542 if (library == containingLibrary) {
4543 return;
4544 }
4545 // Remember the element.
4546 usedElements.elements.add(element);
4547 }
4548
4549 /**
4550 * Given some [NodeList] of [Annotation]s, ensure that the identifiers are vis ited by
4551 * this visitor. Specifically, this covers the cases where AST nodes don't hav e their identifiers
4552 * visited by this visitor, but still need their annotations visited.
4553 *
4554 * @param annotations the list of annotations to visit
4555 */
4556 void _visitMetadata(NodeList<Annotation> annotations) {
4557 int count = annotations.length;
4558 for (int i = 0; i < count; i++) {
4559 annotations[i].accept(this);
4560 }
4561 }
4562 }
4563
4564 /**
4565 * An [AstVisitor] that fills [UsedLocalElements].
4566 */
4567 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor {
4568 final UsedLocalElements usedElements = new UsedLocalElements();
4569
4570 final LibraryElement _enclosingLibrary;
4571 ClassElement _enclosingClass;
4572 ExecutableElement _enclosingExec;
4573
4574 GatherUsedLocalElementsVisitor(this._enclosingLibrary);
4575
4576 @override
4577 visitCatchClause(CatchClause node) {
4578 SimpleIdentifier exceptionParameter = node.exceptionParameter;
4579 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
4580 if (exceptionParameter != null) {
4581 Element element = exceptionParameter.staticElement;
4582 usedElements.addCatchException(element);
4583 if (stackTraceParameter != null || node.onKeyword == null) {
4584 usedElements.addElement(element);
4585 }
4586 }
4587 if (stackTraceParameter != null) {
4588 Element element = stackTraceParameter.staticElement;
4589 usedElements.addCatchStackTrace(element);
4590 }
4591 super.visitCatchClause(node);
4592 }
4593
4594 @override
4595 visitClassDeclaration(ClassDeclaration node) {
4596 ClassElement enclosingClassOld = _enclosingClass;
4597 try {
4598 _enclosingClass = node.element;
4599 super.visitClassDeclaration(node);
4600 } finally {
4601 _enclosingClass = enclosingClassOld;
4602 }
4603 }
4604
4605 @override
4606 visitFunctionDeclaration(FunctionDeclaration node) {
4607 ExecutableElement enclosingExecOld = _enclosingExec;
4608 try {
4609 _enclosingExec = node.element;
4610 super.visitFunctionDeclaration(node);
4611 } finally {
4612 _enclosingExec = enclosingExecOld;
4613 }
4614 }
4615
4616 @override
4617 visitFunctionExpression(FunctionExpression node) {
4618 if (node.parent is! FunctionDeclaration) {
4619 usedElements.addElement(node.element);
4620 }
4621 super.visitFunctionExpression(node);
4622 }
4623
4624 @override
4625 visitMethodDeclaration(MethodDeclaration node) {
4626 ExecutableElement enclosingExecOld = _enclosingExec;
4627 try {
4628 _enclosingExec = node.element;
4629 super.visitMethodDeclaration(node);
4630 } finally {
4631 _enclosingExec = enclosingExecOld;
4632 }
4633 }
4634
4635 @override
4636 visitSimpleIdentifier(SimpleIdentifier node) {
4637 if (node.inDeclarationContext()) {
4638 return;
4639 }
4640 Element element = node.staticElement;
4641 bool isIdentifierRead = _isReadIdentifier(node);
4642 if (element is LocalVariableElement) {
4643 if (isIdentifierRead) {
4644 usedElements.addElement(element);
4645 }
4646 } else {
4647 _useIdentifierElement(node);
4648 if (element == null ||
4649 element.enclosingElement is ClassElement &&
4650 !identical(element, _enclosingExec)) {
4651 usedElements.members.add(node.name);
4652 if (isIdentifierRead) {
4653 usedElements.readMembers.add(node.name);
4654 }
4655 }
4656 }
4657 }
4658
4659 /**
4660 * Marks an [Element] of [node] as used in the library.
4661 */
4662 void _useIdentifierElement(Identifier node) {
4663 Element element = node.staticElement;
4664 if (element == null) {
4665 return;
4666 }
4667 // check if a local element
4668 if (!identical(element.library, _enclosingLibrary)) {
4669 return;
4670 }
4671 // ignore references to an element from itself
4672 if (identical(element, _enclosingClass)) {
4673 return;
4674 }
4675 if (identical(element, _enclosingExec)) {
4676 return;
4677 }
4678 // ignore places where the element is not actually used
4679 if (node.parent is TypeName) {
4680 if (element is ClassElement) {
4681 AstNode parent2 = node.parent.parent;
4682 if (parent2 is IsExpression) {
4683 return;
4684 }
4685 if (parent2 is VariableDeclarationList) {
4686 return;
4687 }
4688 }
4689 }
4690 // OK
4691 usedElements.addElement(element);
4692 }
4693
4694 static bool _isReadIdentifier(SimpleIdentifier node) {
4695 // not reading at all
4696 if (!node.inGetterContext()) {
4697 return false;
4698 }
4699 // check if useless reading
4700 AstNode parent = node.parent;
4701 if (parent.parent is ExpressionStatement &&
4702 (parent is PrefixExpression ||
4703 parent is PostfixExpression ||
4704 parent is AssignmentExpression && parent.leftHandSide == node)) {
4705 // v++;
4706 // ++v;
4707 // v += 2;
4708 return false;
4709 }
4710 // OK
4711 return true;
4712 }
4713 }
4714
4715 /**
4716 * Instances of the class `HintGenerator` traverse a library's worth of dart cod e at a time to
4717 * generate hints over the set of sources.
4718 *
4719 * See [HintCode].
4720 */
4721 class HintGenerator {
4722 final List<CompilationUnit> _compilationUnits;
4723
4724 final InternalAnalysisContext _context;
4725
4726 final AnalysisErrorListener _errorListener;
4727
4728 LibraryElement _library;
4729
4730 GatherUsedImportedElementsVisitor _usedImportedElementsVisitor;
4731
4732 bool _enableDart2JSHints = false;
4733
4734 /**
4735 * The inheritance manager used to find overridden methods.
4736 */
4737 InheritanceManager _manager;
4738
4739 GatherUsedLocalElementsVisitor _usedLocalElementsVisitor;
4740
4741 HintGenerator(this._compilationUnits, this._context, this._errorListener) {
4742 _library = _compilationUnits[0].element.library;
4743 _usedImportedElementsVisitor =
4744 new GatherUsedImportedElementsVisitor(_library);
4745 _enableDart2JSHints = _context.analysisOptions.dart2jsHint;
4746 _manager = new InheritanceManager(_compilationUnits[0].element.library);
4747 _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library);
4748 }
4749
4750 void generateForLibrary() {
4751 PerformanceStatistics.hints.makeCurrentWhile(() {
4752 for (CompilationUnit unit in _compilationUnits) {
4753 CompilationUnitElement element = unit.element;
4754 if (element != null) {
4755 _generateForCompilationUnit(unit, element.source);
4756 }
4757 }
4758 CompilationUnit definingUnit = _compilationUnits[0];
4759 ErrorReporter definingUnitErrorReporter =
4760 new ErrorReporter(_errorListener, definingUnit.element.source);
4761 {
4762 ImportsVerifier importsVerifier = new ImportsVerifier();
4763 importsVerifier.addImports(definingUnit);
4764 importsVerifier
4765 .removeUsedElements(_usedImportedElementsVisitor.usedElements);
4766 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter);
4767 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter);
4768 }
4769 _library.accept(new UnusedLocalElementsVerifier(
4770 _errorListener, _usedLocalElementsVisitor.usedElements));
4771 });
4772 }
4773
4774 void _generateForCompilationUnit(CompilationUnit unit, Source source) {
4775 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source);
4776 unit.accept(_usedImportedElementsVisitor);
4777 // dead code analysis
4778 unit.accept(new DeadCodeVerifier(errorReporter));
4779 unit.accept(_usedLocalElementsVisitor);
4780 // dart2js analysis
4781 if (_enableDart2JSHints) {
4782 unit.accept(new Dart2JSVerifier(errorReporter));
4783 }
4784 // Dart best practices
4785 unit.accept(
4786 new BestPracticesVerifier(errorReporter, _context.typeProvider));
4787 unit.accept(new OverrideVerifier(errorReporter, _manager));
4788 // Find to-do comments
4789 new ToDoFinder(errorReporter).findIn(unit);
4790 // pub analysis
4791 // TODO(danrubel/jwren) Commented out until bugs in the pub verifier are
4792 // fixed
4793 // unit.accept(new PubVerifier(context, errorReporter));
4794 }
4795 }
4796
4797 /**
4798 * Instances of the class {@code HtmlTagInfo} record information about the tags used in an HTML
4799 * file.
4800 */
4801 class HtmlTagInfo {
4802 /**
4803 * An array containing all of the tags used in the HTML file.
4804 */
4805 List<String> allTags;
4806
4807 /**
4808 * A table mapping the id's defined in the HTML file to an array containing th e names of tags with
4809 * that identifier.
4810 */
4811 HashMap<String, String> idToTagMap;
4812
4813 /**
4814 * A table mapping the classes defined in the HTML file to an array containing the names of tags
4815 * with that class.
4816 */
4817 HashMap<String, List<String>> classToTagsMap;
4818
4819 /**
4820 * Initialize a newly created information holder to hold the given information about the tags in
4821 * an HTML file.
4822 *
4823 * @param allTags an array containing all of the tags used in the HTML file
4824 * @param idToTagMap a table mapping the id's defined in the HTML file to an a rray containing the
4825 * names of tags with that identifier
4826 * @param classToTagsMap a table mapping the classes defined in the HTML file to an array
4827 * containing the names of tags with that class
4828 */
4829 HtmlTagInfo(this.allTags, this.idToTagMap, this.classToTagsMap);
4830
4831 /**
4832 * Return an array containing the tags that have the given class, or {@code nu ll} if there are no
4833 * such tags.
4834 *
4835 * @return an array containing the tags that have the given class
4836 */
4837 List<String> getTagsWithClass(String identifier) {
4838 return classToTagsMap[identifier];
4839 }
4840
4841 /**
4842 * Return the tag that has the given identifier, or {@code null} if there is n o such tag (the
4843 * identifier is not defined).
4844 *
4845 * @return the tag that has the given identifier
4846 */
4847 String getTagWithId(String identifier) {
4848 return idToTagMap[identifier];
4849 }
4850 }
4851
4852 /**
4853 * Instances of the class {@code HtmlTagInfoBuilder} gather information about th e tags used in one
4854 * or more HTML structures.
4855 */
4856 class HtmlTagInfoBuilder implements ht.XmlVisitor {
4857 /**
4858 * The name of the 'id' attribute.
4859 */
4860 static final String ID_ATTRIBUTE = "id";
4861
4862 /**
4863 * The name of the 'class' attribute.
4864 */
4865 static final String ID_CLASS = "class";
4866
4867 /**
4868 * A set containing all of the tag names used in the HTML.
4869 */
4870 HashSet<String> tagSet = new HashSet<String>();
4871
4872 /**
4873 * A table mapping the id's that are defined to the tag name with that id.
4874 */
4875 HashMap<String, String> idMap = new HashMap<String, String>();
4876
4877 /**
4878 * A table mapping the classes that are defined to a set of the tag names with that class.
4879 */
4880 HashMap<String, HashSet<String>> classMap =
4881 new HashMap<String, HashSet<String>>();
4882
4883 /**
4884 * Initialize a newly created HTML tag info builder.
4885 */
4886 HtmlTagInfoBuilder();
4887
4888 /**
4889 * Create a tag information holder holding all of the information gathered abo ut the tags in the
4890 * HTML structures that were visited.
4891 *
4892 * @return the information gathered about the tags in the visited HTML structu res
4893 */
4894 HtmlTagInfo getTagInfo() {
4895 List<String> allTags = tagSet.toList();
4896 HashMap<String, List<String>> classToTagsMap =
4897 new HashMap<String, List<String>>();
4898 classMap.forEach((String key, Set<String> tags) {
4899 classToTagsMap[key] = tags.toList();
4900 });
4901 return new HtmlTagInfo(allTags, idMap, classToTagsMap);
4902 }
4903
4904 @override
4905 visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
4906 visitXmlTagNode(node);
4907 }
4908
4909 @override
4910 visitHtmlUnit(ht.HtmlUnit node) {
4911 node.visitChildren(this);
4912 }
4913
4914 @override
4915 visitXmlAttributeNode(ht.XmlAttributeNode node) {}
4916
4917 @override
4918 visitXmlTagNode(ht.XmlTagNode node) {
4919 node.visitChildren(this);
4920 String tagName = node.tag;
4921 tagSet.add(tagName);
4922 for (ht.XmlAttributeNode attribute in node.attributes) {
4923 String attributeName = attribute.name;
4924 if (attributeName == ID_ATTRIBUTE) {
4925 String attributeValue = attribute.text;
4926 if (attributeValue != null) {
4927 String tag = idMap[attributeValue];
4928 if (tag == null) {
4929 idMap[attributeValue] = tagName;
4930 } else {
4931 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken);
4932 }
4933 }
4934 } else if (attributeName == ID_CLASS) {
4935 String attributeValue = attribute.text;
4936 if (attributeValue != null) {
4937 HashSet<String> tagList = classMap[attributeValue];
4938 if (tagList == null) {
4939 tagList = new HashSet<String>();
4940 classMap[attributeValue] = tagList;
4941 } else {
4942 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken);
4943 }
4944 tagList.add(tagName);
4945 }
4946 }
4947 }
4948 }
4949
4950 // /**
4951 // * Report an error with the given error code at the given location. Use the given arguments to
4952 // * compose the error message.
4953 // *
4954 // * @param errorCode the error code of the error to be reported
4955 // * @param offset the offset of the first character to be highlighted
4956 // * @param length the number of characters to be highlighted
4957 // * @param arguments the arguments used to compose the error message
4958 // */
4959 // private void reportError(ErrorCode errorCode, Token token, Object... argumen ts) {
4960 // errorListener.onError(new AnalysisError(
4961 // htmlElement.getSource(),
4962 // token.getOffset(),
4963 // token.getLength(),
4964 // errorCode,
4965 // arguments));
4966 // }
4967 //
4968 // /**
4969 // * Report an error with the given error code at the given location. Use the given arguments to
4970 // * compose the error message.
4971 // *
4972 // * @param errorCode the error code of the error to be reported
4973 // * @param offset the offset of the first character to be highlighted
4974 // * @param length the number of characters to be highlighted
4975 // * @param arguments the arguments used to compose the error message
4976 // */
4977 // private void reportError(ErrorCode errorCode, int offset, int length, Object ... arguments) {
4978 // errorListener.onError(new AnalysisError(
4979 // htmlElement.getSource(),
4980 // offset,
4981 // length,
4982 // errorCode,
4983 // arguments));
4984 // }
4985 }
4986
4987 /**
4988 * Instances of the class `HtmlUnitBuilder` build an element model for a single HTML unit.
4989 */
4990 class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
4991 static String _SRC = "src";
4992
4993 /**
4994 * The analysis context in which the element model will be built.
4995 */
4996 final InternalAnalysisContext _context;
4997
4998 /**
4999 * The error listener to which errors will be reported.
5000 */
5001 RecordingErrorListener _errorListener;
5002
5003 /**
5004 * The HTML element being built.
5005 */
5006 HtmlElementImpl _htmlElement;
5007
5008 /**
5009 * The elements in the path from the HTML unit to the current tag node.
5010 */
5011 List<ht.XmlTagNode> _parentNodes;
5012
5013 /**
5014 * The script elements being built.
5015 */
5016 List<HtmlScriptElement> _scripts;
5017
5018 /**
5019 * A set of the libraries that were resolved while resolving the HTML unit.
5020 */
5021 Set<Library> _resolvedLibraries = new HashSet<Library>();
5022
5023 /**
5024 * Initialize a newly created HTML unit builder.
5025 *
5026 * @param context the analysis context in which the element model will be buil t
5027 */
5028 HtmlUnitBuilder(this._context) {
5029 this._errorListener = new RecordingErrorListener();
5030 }
5031
5032 /**
5033 * Return the listener to which analysis errors will be reported.
5034 *
5035 * @return the listener to which analysis errors will be reported
5036 */
5037 RecordingErrorListener get errorListener => _errorListener;
5038
5039 /**
5040 * Return an array containing information about all of the libraries that were resolved.
5041 *
5042 * @return an array containing the libraries that were resolved
5043 */
5044 Set<Library> get resolvedLibraries => _resolvedLibraries;
5045
5046 /**
5047 * Build the HTML element for the given source.
5048 *
5049 * @param source the source describing the compilation unit
5050 * @param unit the AST structure representing the HTML
5051 * @throws AnalysisException if the analysis could not be performed
5052 */
5053 HtmlElementImpl buildHtmlElement(Source source, ht.HtmlUnit unit) {
5054 HtmlElementImpl result = new HtmlElementImpl(_context, source.shortName);
5055 result.source = source;
5056 _htmlElement = result;
5057 unit.accept(this);
5058 _htmlElement = null;
5059 unit.element = result;
5060 return result;
5061 }
5062
5063 @override
5064 Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
5065 if (_parentNodes.contains(node)) {
5066 return _reportCircularity(node);
5067 }
5068 _parentNodes.add(node);
5069 try {
5070 Source htmlSource = _htmlElement.source;
5071 ht.XmlAttributeNode scriptAttribute = _getScriptSourcePath(node);
5072 String scriptSourcePath =
5073 scriptAttribute == null ? null : scriptAttribute.text;
5074 if (node.attributeEnd.type == ht.TokenType.GT &&
5075 scriptSourcePath == null) {
5076 EmbeddedHtmlScriptElementImpl script =
5077 new EmbeddedHtmlScriptElementImpl(node);
5078 try {
5079 LibraryResolver resolver = new LibraryResolver(_context);
5080 LibraryElementImpl library =
5081 resolver.resolveEmbeddedLibrary(htmlSource, node.script, true);
5082 script.scriptLibrary = library;
5083 _resolvedLibraries.addAll(resolver.resolvedLibraries);
5084 _errorListener.addAll(resolver.errorListener);
5085 } on AnalysisException catch (exception, stackTrace) {
5086 //TODO (danrubel): Handle or forward the exception
5087 AnalysisEngine.instance.logger.logError(
5088 "Could not resolve script tag",
5089 new CaughtException(exception, stackTrace));
5090 }
5091 node.scriptElement = script;
5092 _scripts.add(script);
5093 } else {
5094 ExternalHtmlScriptElementImpl script =
5095 new ExternalHtmlScriptElementImpl(node);
5096 if (scriptSourcePath != null) {
5097 try {
5098 scriptSourcePath = Uri.encodeFull(scriptSourcePath);
5099 // Force an exception to be thrown if the URI is invalid so that we
5100 // can report the problem.
5101 parseUriWithException(scriptSourcePath);
5102 Source scriptSource =
5103 _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
5104 script.scriptSource = scriptSource;
5105 if (!_context.exists(scriptSource)) {
5106 _reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST,
5107 scriptAttribute, [scriptSourcePath]);
5108 }
5109 } on URISyntaxException {
5110 _reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute,
5111 [scriptSourcePath]);
5112 }
5113 }
5114 node.scriptElement = script;
5115 _scripts.add(script);
5116 }
5117 } finally {
5118 _parentNodes.remove(node);
5119 }
5120 return null;
5121 }
5122
5123 @override
5124 Object visitHtmlUnit(ht.HtmlUnit node) {
5125 _parentNodes = new List<ht.XmlTagNode>();
5126 _scripts = new List<HtmlScriptElement>();
5127 try {
5128 node.visitChildren(this);
5129 _htmlElement.scripts = new List.from(_scripts);
5130 } finally {
5131 _scripts = null;
5132 _parentNodes = null;
5133 }
5134 return null;
5135 }
5136
5137 @override
5138 Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
5139
5140 @override
5141 Object visitXmlTagNode(ht.XmlTagNode node) {
5142 if (_parentNodes.contains(node)) {
5143 return _reportCircularity(node);
5144 }
5145 _parentNodes.add(node);
5146 try {
5147 node.visitChildren(this);
5148 } finally {
5149 _parentNodes.remove(node);
5150 }
5151 return null;
5152 }
5153
5154 /**
5155 * Return the first source attribute for the given tag node, or `null` if it d oes not exist.
5156 *
5157 * @param node the node containing attributes
5158 * @return the source attribute contained in the given tag
5159 */
5160 ht.XmlAttributeNode _getScriptSourcePath(ht.XmlTagNode node) {
5161 for (ht.XmlAttributeNode attribute in node.attributes) {
5162 if (attribute.name == _SRC) {
5163 return attribute;
5164 }
5165 }
5166 return null;
5167 }
5168
5169 Object _reportCircularity(ht.XmlTagNode node) {
5170 //
5171 // This should not be possible, but we have an error report that suggests
5172 // that it happened at least once. This code will guard against infinite
5173 // recursion and might help us identify the cause of the issue.
5174 //
5175 StringBuffer buffer = new StringBuffer();
5176 buffer.write("Found circularity in XML nodes: ");
5177 bool first = true;
5178 for (ht.XmlTagNode pathNode in _parentNodes) {
5179 if (first) {
5180 first = false;
5181 } else {
5182 buffer.write(", ");
5183 }
5184 String tagName = pathNode.tag;
5185 if (identical(pathNode, node)) {
5186 buffer.write("*");
5187 buffer.write(tagName);
5188 buffer.write("*");
5189 } else {
5190 buffer.write(tagName);
5191 }
5192 }
5193 AnalysisEngine.instance.logger.logError(buffer.toString());
5194 return null;
5195 }
5196
5197 /**
5198 * Report an error with the given error code at the given location. Use the gi ven arguments to
5199 * compose the error message.
5200 *
5201 * @param errorCode the error code of the error to be reported
5202 * @param offset the offset of the first character to be highlighted
5203 * @param length the number of characters to be highlighted
5204 * @param arguments the arguments used to compose the error message
5205 */
5206 void _reportErrorForOffset(
5207 ErrorCode errorCode, int offset, int length, List<Object> arguments) {
5208 _errorListener.onError(new AnalysisError(
5209 _htmlElement.source, offset, length, errorCode, arguments));
5210 }
5211
5212 /**
5213 * Report an error with the given error code at the location of the value of t he given attribute.
5214 * Use the given arguments to compose the error message.
5215 *
5216 * @param errorCode the error code of the error to be reported
5217 * @param offset the offset of the first character to be highlighted
5218 * @param length the number of characters to be highlighted
5219 * @param arguments the arguments used to compose the error message
5220 */
5221 void _reportValueError(ErrorCode errorCode, ht.XmlAttributeNode attribute,
5222 List<Object> arguments) {
5223 int offset = attribute.valueToken.offset + 1;
5224 int length = attribute.valueToken.length - 2;
5225 _reportErrorForOffset(errorCode, offset, length, arguments);
5226 }
5227 }
5228
5229 /**
5230 * Instances of the class `ImplicitLabelScope` represent the scope statements
5231 * that can be the target of unlabeled break and continue statements.
5232 */
5233 class ImplicitLabelScope {
5234 /**
5235 * The implicit label scope associated with the top level of a function.
5236 */
5237 static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null);
5238
5239 /**
5240 * The implicit label scope enclosing this implicit label scope.
5241 */
5242 final ImplicitLabelScope outerScope;
5243
5244 /**
5245 * The statement that acts as a target for break and/or continue statements
5246 * at this scoping level.
5247 */
5248 final Statement statement;
5249
5250 /**
5251 * Private constructor.
5252 */
5253 const ImplicitLabelScope._(this.outerScope, this.statement);
5254
5255 /**
5256 * Get the statement which should be the target of an unlabeled `break` or
5257 * `continue` statement, or `null` if there is no appropriate target.
5258 */
5259 Statement getTarget(bool isContinue) {
5260 if (outerScope == null) {
5261 // This scope represents the toplevel of a function body, so it doesn't
5262 // match either break or continue.
5263 return null;
5264 }
5265 if (isContinue && statement is SwitchStatement) {
5266 return outerScope.getTarget(isContinue);
5267 }
5268 return statement;
5269 }
5270
5271 /**
5272 * Initialize a newly created scope to represent a switch statement or loop
5273 * nested within the current scope. [statement] is the statement associated
5274 * with the newly created scope.
5275 */
5276 ImplicitLabelScope nest(Statement statement) =>
5277 new ImplicitLabelScope._(this, statement);
5278 }
5279
5280 /**
5281 * Instances of the class `ImportsVerifier` visit all of the referenced librarie s in the
5282 * source code verifying that all of the imports are used, otherwise a
5283 * [HintCode.UNUSED_IMPORT] is generated with
5284 * [generateUnusedImportHints].
5285 *
5286 * While this class does not yet have support for an "Organize Imports" action, this logic built up
5287 * in this class could be used for such an action in the future.
5288 */
5289 class ImportsVerifier /*extends RecursiveAstVisitor<Object>*/ {
5290 /**
5291 * A list of [ImportDirective]s that the current library imports, as identifie rs are visited
5292 * by this visitor and an import has been identified as being used by the libr ary, the
5293 * [ImportDirective] is removed from this list. After all the sources in the l ibrary have
5294 * been evaluated, this list represents the set of unused imports.
5295 *
5296 * See [ImportsVerifier.generateUnusedImportErrors].
5297 */
5298 final List<ImportDirective> _unusedImports = <ImportDirective>[];
5299
5300 /**
5301 * After the list of [unusedImports] has been computed, this list is a proper subset of the
5302 * unused imports that are listed more than once.
5303 */
5304 final List<ImportDirective> _duplicateImports = <ImportDirective>[];
5305
5306 /**
5307 * This is a map between the set of [LibraryElement]s that the current library imports, and
5308 * a list of [ImportDirective]s that imports the library. In cases where the c urrent library
5309 * imports a library with a single directive (such as `import lib1.dart;`), th e library
5310 * element will map to a list of one [ImportDirective], which will then be rem oved from the
5311 * [unusedImports] list. In cases where the current library imports a library with multiple
5312 * directives (such as `import lib1.dart; import lib1.dart show C;`), the
5313 * [LibraryElement] will be mapped to a list of the import directives, and the namespace
5314 * will need to be used to compute the correct [ImportDirective] being used, s ee
5315 * [namespaceMap].
5316 */
5317 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap =
5318 new HashMap<LibraryElement, List<ImportDirective>>();
5319
5320 /**
5321 * In cases where there is more than one import directive per library element, this mapping is
5322 * used to determine which of the multiple import directives are used by gener ating a
5323 * [Namespace] for each of the imports to do lookups in the same way that they are done from
5324 * the [ElementResolver].
5325 */
5326 final HashMap<ImportDirective, Namespace> _namespaceMap =
5327 new HashMap<ImportDirective, Namespace>();
5328
5329 /**
5330 * This is a map between prefix elements and the import directives from which they are derived. In
5331 * cases where a type is referenced via a prefix element, the import directive can be marked as
5332 * used (removed from the unusedImports) by looking at the resolved `lib` in ` lib.X`,
5333 * instead of looking at which library the `lib.X` resolves.
5334 *
5335 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl ement],
5336 * it is possible to have an unreported unused import in situations where two imports use the same
5337 * prefix and at least one import directive is used.
5338 */
5339 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap =
5340 new HashMap<PrefixElement, List<ImportDirective>>();
5341
5342 void addImports(CompilationUnit node) {
5343 for (Directive directive in node.directives) {
5344 if (directive is ImportDirective) {
5345 ImportDirective importDirective = directive;
5346 LibraryElement libraryElement = importDirective.uriElement;
5347 if (libraryElement != null) {
5348 _unusedImports.add(importDirective);
5349 //
5350 // Initialize prefixElementMap
5351 //
5352 if (importDirective.asKeyword != null) {
5353 SimpleIdentifier prefixIdentifier = importDirective.prefix;
5354 if (prefixIdentifier != null) {
5355 Element element = prefixIdentifier.staticElement;
5356 if (element is PrefixElement) {
5357 PrefixElement prefixElementKey = element;
5358 List<ImportDirective> list =
5359 _prefixElementMap[prefixElementKey];
5360 if (list == null) {
5361 list = new List<ImportDirective>();
5362 _prefixElementMap[prefixElementKey] = list;
5363 }
5364 list.add(importDirective);
5365 }
5366 // TODO (jwren) Can the element ever not be a PrefixElement?
5367 }
5368 }
5369 //
5370 // Initialize libraryMap: libraryElement -> importDirective
5371 //
5372 _putIntoLibraryMap(libraryElement, importDirective);
5373 //
5374 // For this new addition to the libraryMap, also recursively add any
5375 // exports from the libraryElement.
5376 //
5377 _addAdditionalLibrariesForExports(
5378 libraryElement, importDirective, new List<LibraryElement>());
5379 }
5380 }
5381 }
5382 if (_unusedImports.length > 1) {
5383 // order the list of unusedImports to find duplicates in faster than
5384 // O(n^2) time
5385 List<ImportDirective> importDirectiveArray =
5386 new List<ImportDirective>.from(_unusedImports);
5387 importDirectiveArray.sort(ImportDirective.COMPARATOR);
5388 ImportDirective currentDirective = importDirectiveArray[0];
5389 for (int i = 1; i < importDirectiveArray.length; i++) {
5390 ImportDirective nextDirective = importDirectiveArray[i];
5391 if (ImportDirective.COMPARATOR(currentDirective, nextDirective) == 0) {
5392 // Add either the currentDirective or nextDirective depending on which
5393 // comes second, this guarantees that the first of the duplicates
5394 // won't be highlighted.
5395 if (currentDirective.offset < nextDirective.offset) {
5396 _duplicateImports.add(nextDirective);
5397 } else {
5398 _duplicateImports.add(currentDirective);
5399 }
5400 }
5401 currentDirective = nextDirective;
5402 }
5403 }
5404 }
5405
5406 /**
5407 * Any time after the defining compilation unit has been visited by this visit or, this method can
5408 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp ort directives
5409 * in the [duplicateImports] list.
5410 *
5411 * @param errorReporter the error reporter to report the set of [HintCode.DUPL ICATE_IMPORT]
5412 * hints to
5413 */
5414 void generateDuplicateImportHints(ErrorReporter errorReporter) {
5415 for (ImportDirective duplicateImport in _duplicateImports) {
5416 errorReporter.reportErrorForNode(
5417 HintCode.DUPLICATE_IMPORT, duplicateImport.uri);
5418 }
5419 }
5420
5421 /**
5422 * After all of the compilation units have been visited by this visitor, this method can be called
5423 * to report an [HintCode.UNUSED_IMPORT] hint for each of the import directive s in the
5424 * [unusedImports] list.
5425 *
5426 * @param errorReporter the error reporter to report the set of [HintCode.UNUS ED_IMPORT]
5427 * hints to
5428 */
5429 void generateUnusedImportHints(ErrorReporter errorReporter) {
5430 for (ImportDirective unusedImport in _unusedImports) {
5431 // Check that the import isn't dart:core
5432 ImportElement importElement = unusedImport.element;
5433 if (importElement != null) {
5434 LibraryElement libraryElement = importElement.importedLibrary;
5435 if (libraryElement != null && libraryElement.isDartCore) {
5436 continue;
5437 }
5438 }
5439 errorReporter.reportErrorForNode(
5440 HintCode.UNUSED_IMPORT, unusedImport.uri);
5441 }
5442 }
5443
5444 /**
5445 * Remove elements from [_unusedImports] using the given [usedElements].
5446 */
5447 void removeUsedElements(UsedImportedElements usedElements) {
5448 // Stop if all the imports are known to be used.
5449 if (_unusedImports.isEmpty) {
5450 return;
5451 }
5452 // Process import prefixes.
5453 for (PrefixElement prefix in usedElements.prefixes) {
5454 List<ImportDirective> importDirectives = _prefixElementMap[prefix];
5455 if (importDirectives != null) {
5456 for (ImportDirective importDirective in importDirectives) {
5457 _unusedImports.remove(importDirective);
5458 }
5459 }
5460 }
5461 // Process top-level elements.
5462 for (Element element in usedElements.elements) {
5463 // Stop if all the imports are known to be used.
5464 if (_unusedImports.isEmpty) {
5465 return;
5466 }
5467 // Prepare import directives for this library.
5468 LibraryElement library = element.library;
5469 List<ImportDirective> importsLibrary = _libraryMap[library];
5470 if (importsLibrary == null) {
5471 continue;
5472 }
5473 // If there is only one import directive for this library, then it must be
5474 // the directive that this element is imported with, remove it from the
5475 // unusedImports list.
5476 if (importsLibrary.length == 1) {
5477 ImportDirective usedImportDirective = importsLibrary[0];
5478 _unusedImports.remove(usedImportDirective);
5479 continue;
5480 }
5481 // Otherwise, find import directives using namespaces.
5482 String name = element.displayName;
5483 for (ImportDirective importDirective in importsLibrary) {
5484 Namespace namespace = _computeNamespace(importDirective);
5485 if (namespace != null && namespace.get(name) != null) {
5486 _unusedImports.remove(importDirective);
5487 }
5488 }
5489 }
5490 }
5491
5492 /**
5493 * Recursively add any exported library elements into the [libraryMap].
5494 */
5495 void _addAdditionalLibrariesForExports(LibraryElement library,
5496 ImportDirective importDirective, List<LibraryElement> exportPath) {
5497 if (exportPath.contains(library)) {
5498 return;
5499 }
5500 exportPath.add(library);
5501 for (LibraryElement exportedLibraryElt in library.exportedLibraries) {
5502 _putIntoLibraryMap(exportedLibraryElt, importDirective);
5503 _addAdditionalLibrariesForExports(
5504 exportedLibraryElt, importDirective, exportPath);
5505 }
5506 }
5507
5508 /**
5509 * Lookup and return the [Namespace] from the [namespaceMap], if the map does not
5510 * have the computed namespace, compute it and cache it in the map. If the imp ort directive is not
5511 * resolved or is not resolvable, `null` is returned.
5512 *
5513 * @param importDirective the import directive used to compute the returned na mespace
5514 * @return the computed or looked up [Namespace]
5515 */
5516 Namespace _computeNamespace(ImportDirective importDirective) {
5517 Namespace namespace = _namespaceMap[importDirective];
5518 if (namespace == null) {
5519 // If the namespace isn't in the namespaceMap, then compute and put it in
5520 // the map.
5521 ImportElement importElement = importDirective.element;
5522 if (importElement != null) {
5523 NamespaceBuilder builder = new NamespaceBuilder();
5524 namespace = builder.createImportNamespaceForDirective(importElement);
5525 _namespaceMap[importDirective] = namespace;
5526 }
5527 }
5528 return namespace;
5529 }
5530
5531 /**
5532 * The [libraryMap] is a mapping between a library elements and a list of impo rt
5533 * directives, but when adding these mappings into the [libraryMap], this meth od can be
5534 * used to simply add the mapping between the library element an an import dir ective without
5535 * needing to check to see if a list needs to be created.
5536 */
5537 void _putIntoLibraryMap(
5538 LibraryElement libraryElement, ImportDirective importDirective) {
5539 List<ImportDirective> importList = _libraryMap[libraryElement];
5540 if (importList == null) {
5541 importList = new List<ImportDirective>();
5542 _libraryMap[libraryElement] = importList;
5543 }
5544 importList.add(importDirective);
5545 }
5546 }
5547
5548 /**
5549 * Instances of the class `InheritanceManager` manage the knowledge of where cla ss members
5550 * (methods, getters & setters) are inherited from.
5551 */
5552 class InheritanceManager {
5553 /**
5554 * The [LibraryElement] that is managed by this manager.
5555 */
5556 LibraryElement _library;
5557
5558 /**
5559 * This is a mapping between each [ClassElement] and a map between the [String ] member
5560 * names and the associated [ExecutableElement] in the mixin and superclass ch ain.
5561 */
5562 HashMap<ClassElement, MemberMap> _classLookup;
5563
5564 /**
5565 * This is a mapping between each [ClassElement] and a map between the [String ] member
5566 * names and the associated [ExecutableElement] in the interface set.
5567 */
5568 HashMap<ClassElement, MemberMap> _interfaceLookup;
5569
5570 /**
5571 * A map between each visited [ClassElement] and the set of [AnalysisError]s f ound on
5572 * the class element.
5573 */
5574 HashMap<ClassElement, HashSet<AnalysisError>> _errorsInClassElement =
5575 new HashMap<ClassElement, HashSet<AnalysisError>>();
5576
5577 /**
5578 * Initialize a newly created inheritance manager.
5579 *
5580 * @param library the library element context that the inheritance mappings ar e being generated
5581 */
5582 InheritanceManager(LibraryElement library) {
5583 this._library = library;
5584 _classLookup = new HashMap<ClassElement, MemberMap>();
5585 _interfaceLookup = new HashMap<ClassElement, MemberMap>();
5586 }
5587
5588 /**
5589 * Set the new library element context.
5590 *
5591 * @param library the new library element
5592 */
5593 void set libraryElement(LibraryElement library) {
5594 this._library = library;
5595 }
5596
5597 /**
5598 * Return the set of [AnalysisError]s found on the passed [ClassElement], or
5599 * `null` if there are none.
5600 *
5601 * @param classElt the class element to query
5602 * @return the set of [AnalysisError]s found on the passed [ClassElement], or
5603 * `null` if there are none
5604 */
5605 HashSet<AnalysisError> getErrors(ClassElement classElt) =>
5606 _errorsInClassElement[classElt];
5607
5608 /**
5609 * Get and return a mapping between the set of all string names of the members inherited from the
5610 * passed [ClassElement] superclass hierarchy, and the associated [ExecutableE lement].
5611 *
5612 * @param classElt the class element to query
5613 * @return a mapping between the set of all members inherited from the passed [ClassElement]
5614 * superclass hierarchy, and the associated [ExecutableElement]
5615 */
5616 MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) =>
5617 _computeClassChainLookupMap(classElt, new HashSet<ClassElement>());
5618
5619 /**
5620 * Get and return a mapping between the set of all string names of the members inherited from the
5621 * passed [ClassElement] interface hierarchy, and the associated [ExecutableEl ement].
5622 *
5623 * @param classElt the class element to query
5624 * @return a mapping between the set of all string names of the members inheri ted from the passed
5625 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement].
5626 */
5627 MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) =>
5628 _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>());
5629
5630 /**
5631 * Given some [ClassElement] and some member name, this returns the
5632 * [ExecutableElement] that the class inherits from the mixins,
5633 * superclasses or interfaces, that has the member name, if no member is inher ited `null` is
5634 * returned.
5635 *
5636 * @param classElt the class element to query
5637 * @param memberName the name of the executable element to find and return
5638 * @return the inherited executable element with the member name, or `null` if no such
5639 * member exists
5640 */
5641 ExecutableElement lookupInheritance(
5642 ClassElement classElt, String memberName) {
5643 if (memberName == null || memberName.isEmpty) {
5644 return null;
5645 }
5646 ExecutableElement executable = _computeClassChainLookupMap(
5647 classElt, new HashSet<ClassElement>()).get(memberName);
5648 if (executable == null) {
5649 return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>())
5650 .get(memberName);
5651 }
5652 return executable;
5653 }
5654
5655 /**
5656 * Given some [ClassElement] and some member name, this returns the
5657 * [ExecutableElement] that the class either declares itself, or
5658 * inherits, that has the member name, if no member is inherited `null` is ret urned.
5659 *
5660 * @param classElt the class element to query
5661 * @param memberName the name of the executable element to find and return
5662 * @return the inherited executable element with the member name, or `null` if no such
5663 * member exists
5664 */
5665 ExecutableElement lookupMember(ClassElement classElt, String memberName) {
5666 ExecutableElement element = _lookupMemberInClass(classElt, memberName);
5667 if (element != null) {
5668 return element;
5669 }
5670 return lookupInheritance(classElt, memberName);
5671 }
5672
5673 /**
5674 * Given some [InterfaceType] and some member name, this returns the
5675 * [FunctionType] of the [ExecutableElement] that the
5676 * class either declares itself, or inherits, that has the member name, if no member is inherited
5677 * `null` is returned. The returned [FunctionType] has all type
5678 * parameters substituted with corresponding type arguments from the given [In terfaceType].
5679 *
5680 * @param interfaceType the interface type to query
5681 * @param memberName the name of the executable element to find and return
5682 * @return the member's function type, or `null` if no such member exists
5683 */
5684 FunctionType lookupMemberType(
5685 InterfaceType interfaceType, String memberName) {
5686 ExecutableElement iteratorMember =
5687 lookupMember(interfaceType.element, memberName);
5688 if (iteratorMember == null) {
5689 return null;
5690 }
5691 return substituteTypeArgumentsInMemberFromInheritance(
5692 iteratorMember.type, memberName, interfaceType);
5693 }
5694
5695 /**
5696 * Determine the set of methods which is overridden by the given class member. If no member is
5697 * inherited, an empty list is returned. If one of the inherited members is a
5698 * [MultiplyInheritedExecutableElement], then it is expanded into its constitu ent inherited
5699 * elements.
5700 *
5701 * @param classElt the class to query
5702 * @param memberName the name of the class member to query
5703 * @return a list of overridden methods
5704 */
5705 List<ExecutableElement> lookupOverrides(
5706 ClassElement classElt, String memberName) {
5707 List<ExecutableElement> result = new List<ExecutableElement>();
5708 if (memberName == null || memberName.isEmpty) {
5709 return result;
5710 }
5711 List<MemberMap> interfaceMaps =
5712 _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>());
5713 if (interfaceMaps != null) {
5714 for (MemberMap interfaceMap in interfaceMaps) {
5715 ExecutableElement overriddenElement = interfaceMap.get(memberName);
5716 if (overriddenElement != null) {
5717 if (overriddenElement is MultiplyInheritedExecutableElement) {
5718 MultiplyInheritedExecutableElement multiplyInheritedElement =
5719 overriddenElement;
5720 for (ExecutableElement element
5721 in multiplyInheritedElement.inheritedElements) {
5722 result.add(element);
5723 }
5724 } else {
5725 result.add(overriddenElement);
5726 }
5727 }
5728 }
5729 }
5730 return result;
5731 }
5732
5733 /**
5734 * This method takes some inherited [FunctionType], and resolves all the param eterized types
5735 * in the function type, dependent on the class in which it is being overridde n.
5736 *
5737 * @param baseFunctionType the function type that is being overridden
5738 * @param memberName the name of the member, this is used to lookup the inheri tance path of the
5739 * override
5740 * @param definingType the type that is overriding the member
5741 * @return the passed function type with any parameterized types substituted
5742 */
5743 FunctionType substituteTypeArgumentsInMemberFromInheritance(
5744 FunctionType baseFunctionType,
5745 String memberName,
5746 InterfaceType definingType) {
5747 // if the baseFunctionType is null, or does not have any parameters,
5748 // return it.
5749 if (baseFunctionType == null ||
5750 baseFunctionType.typeArguments.length == 0) {
5751 return baseFunctionType;
5752 }
5753 // First, generate the path from the defining type to the overridden member
5754 Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
5755 _computeInheritancePath(inheritancePath, definingType, memberName);
5756 if (inheritancePath == null || inheritancePath.isEmpty) {
5757 // TODO(jwren) log analysis engine error
5758 return baseFunctionType;
5759 }
5760 FunctionType functionTypeToReturn = baseFunctionType;
5761 // loop backward through the list substituting as we go:
5762 while (!inheritancePath.isEmpty) {
5763 InterfaceType lastType = inheritancePath.removeLast();
5764 List<DartType> parameterTypes = lastType.element.type.typeArguments;
5765 List<DartType> argumentTypes = lastType.typeArguments;
5766 functionTypeToReturn =
5767 functionTypeToReturn.substitute2(argumentTypes, parameterTypes);
5768 }
5769 return functionTypeToReturn;
5770 }
5771
5772 /**
5773 * Compute and return a mapping between the set of all string names of the mem bers inherited from
5774 * the passed [ClassElement] superclass hierarchy, and the associated
5775 * [ExecutableElement].
5776 *
5777 * @param classElt the class element to query
5778 * @param visitedClasses a set of visited classes passed back into this method when it calls
5779 * itself recursively
5780 * @return a mapping between the set of all string names of the members inheri ted from the passed
5781 * [ClassElement] superclass hierarchy, and the associated [Executable Element]
5782 */
5783 MemberMap _computeClassChainLookupMap(
5784 ClassElement classElt, HashSet<ClassElement> visitedClasses) {
5785 MemberMap resultMap = _classLookup[classElt];
5786 if (resultMap != null) {
5787 return resultMap;
5788 } else {
5789 resultMap = new MemberMap();
5790 }
5791 ClassElement superclassElt = null;
5792 InterfaceType supertype = classElt.supertype;
5793 if (supertype != null) {
5794 superclassElt = supertype.element;
5795 } else {
5796 // classElt is Object
5797 _classLookup[classElt] = resultMap;
5798 return resultMap;
5799 }
5800 if (superclassElt != null) {
5801 if (!visitedClasses.contains(superclassElt)) {
5802 visitedClasses.add(superclassElt);
5803 try {
5804 resultMap = new MemberMap.from(
5805 _computeClassChainLookupMap(superclassElt, visitedClasses));
5806 //
5807 // Substitute the super types down the hierarchy.
5808 //
5809 _substituteTypeParametersDownHierarchy(supertype, resultMap);
5810 //
5811 // Include the members from the superclass in the resultMap.
5812 //
5813 _recordMapWithClassMembers(resultMap, supertype, false);
5814 } finally {
5815 visitedClasses.remove(superclassElt);
5816 }
5817 } else {
5818 // This case happens only when the superclass was previously visited and
5819 // not in the lookup, meaning this is meant to shorten the compute for
5820 // recursive cases.
5821 _classLookup[superclassElt] = resultMap;
5822 return resultMap;
5823 }
5824 }
5825 //
5826 // Include the members from the mixins in the resultMap. If there are
5827 // multiple mixins, visit them in the order listed so that methods in later
5828 // mixins will overwrite identically-named methods in earlier mixins.
5829 //
5830 List<InterfaceType> mixins = classElt.mixins;
5831 for (InterfaceType mixin in mixins) {
5832 ClassElement mixinElement = mixin.element;
5833 if (mixinElement != null) {
5834 if (!visitedClasses.contains(mixinElement)) {
5835 visitedClasses.add(mixinElement);
5836 try {
5837 MemberMap map = new MemberMap.from(
5838 _computeClassChainLookupMap(mixinElement, visitedClasses));
5839 //
5840 // Substitute the super types down the hierarchy.
5841 //
5842 _substituteTypeParametersDownHierarchy(mixin, map);
5843 //
5844 // Include the members from the superclass in the resultMap.
5845 //
5846 _recordMapWithClassMembers(map, mixin, false);
5847 //
5848 // Add the members from map into result map.
5849 //
5850 for (int j = 0; j < map.size; j++) {
5851 String key = map.getKey(j);
5852 ExecutableElement value = map.getValue(j);
5853 if (key != null) {
5854 ClassElement definingClass = value
5855 .getAncestor((Element element) => element is ClassElement);
5856 if (!definingClass.type.isObject) {
5857 ExecutableElement existingValue = resultMap.get(key);
5858 if (existingValue == null ||
5859 (existingValue != null && !_isAbstract(value))) {
5860 resultMap.put(key, value);
5861 }
5862 }
5863 }
5864 }
5865 } finally {
5866 visitedClasses.remove(mixinElement);
5867 }
5868 } else {
5869 // This case happens only when the superclass was previously visited
5870 // and not in the lookup, meaning this is meant to shorten the compute
5871 // for recursive cases.
5872 _classLookup[mixinElement] = resultMap;
5873 return resultMap;
5874 }
5875 }
5876 }
5877 _classLookup[classElt] = resultMap;
5878 return resultMap;
5879 }
5880
5881 /**
5882 * Compute and return the inheritance path given the context of a type and a m ember that is
5883 * overridden in the inheritance path (for which the type is in the path).
5884 *
5885 * @param chain the inheritance path that is built up as this method calls its elf recursively,
5886 * when this method is called an empty [LinkedList] should be provide d
5887 * @param currentType the current type in the inheritance path
5888 * @param memberName the name of the member that is being looked up the inheri tance path
5889 */
5890 void _computeInheritancePath(Queue<InterfaceType> chain,
5891 InterfaceType currentType, String memberName) {
5892 // TODO (jwren) create a public version of this method which doesn't require
5893 // the initial chain to be provided, then provided tests for this
5894 // functionality in InheritanceManagerTest
5895 chain.add(currentType);
5896 ClassElement classElt = currentType.element;
5897 InterfaceType supertype = classElt.supertype;
5898 // Base case- reached Object
5899 if (supertype == null) {
5900 // Looked up the chain all the way to Object, return null.
5901 // This should never happen.
5902 return;
5903 }
5904 // If we are done, return the chain
5905 // We are not done if this is the first recursive call on this method.
5906 if (chain.length != 1) {
5907 // We are done however if the member is in this classElt
5908 if (_lookupMemberInClass(classElt, memberName) != null) {
5909 return;
5910 }
5911 }
5912 // Mixins- note that mixins call lookupMemberInClass, not lookupMember
5913 List<InterfaceType> mixins = classElt.mixins;
5914 for (int i = mixins.length - 1; i >= 0; i--) {
5915 ClassElement mixinElement = mixins[i].element;
5916 if (mixinElement != null) {
5917 ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName);
5918 if (elt != null) {
5919 // this is equivalent (but faster than) calling this method
5920 // recursively
5921 // (return computeInheritancePath(chain, mixins[i], memberName);)
5922 chain.add(mixins[i]);
5923 return;
5924 }
5925 }
5926 }
5927 // Superclass
5928 ClassElement superclassElt = supertype.element;
5929 if (lookupMember(superclassElt, memberName) != null) {
5930 _computeInheritancePath(chain, supertype, memberName);
5931 return;
5932 }
5933 // Interfaces
5934 List<InterfaceType> interfaces = classElt.interfaces;
5935 for (InterfaceType interfaceType in interfaces) {
5936 ClassElement interfaceElement = interfaceType.element;
5937 if (interfaceElement != null &&
5938 lookupMember(interfaceElement, memberName) != null) {
5939 _computeInheritancePath(chain, interfaceType, memberName);
5940 return;
5941 }
5942 }
5943 }
5944
5945 /**
5946 * Compute and return a mapping between the set of all string names of the mem bers inherited from
5947 * the passed [ClassElement] interface hierarchy, and the associated
5948 * [ExecutableElement].
5949 *
5950 * @param classElt the class element to query
5951 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
5952 * itself recursively
5953 * @return a mapping between the set of all string names of the members inheri ted from the passed
5954 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement]
5955 */
5956 MemberMap _computeInterfaceLookupMap(
5957 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
5958 MemberMap resultMap = _interfaceLookup[classElt];
5959 if (resultMap != null) {
5960 return resultMap;
5961 }
5962 List<MemberMap> lookupMaps =
5963 _gatherInterfaceLookupMaps(classElt, visitedInterfaces);
5964 if (lookupMaps == null) {
5965 resultMap = new MemberMap();
5966 } else {
5967 HashMap<String, List<ExecutableElement>> unionMap =
5968 _unionInterfaceLookupMaps(lookupMaps);
5969 resultMap = _resolveInheritanceLookup(classElt, unionMap);
5970 }
5971 _interfaceLookup[classElt] = resultMap;
5972 return resultMap;
5973 }
5974
5975 /**
5976 * Collect a list of interface lookup maps whose elements correspond to all of the classes
5977 * directly above [classElt] in the class hierarchy (the direct superclass if any, all
5978 * mixins, and all direct superinterfaces). Each item in the list is the inter face lookup map
5979 * returned by [computeInterfaceLookupMap] for the corresponding super, except with type
5980 * parameters appropriately substituted.
5981 *
5982 * @param classElt the class element to query
5983 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
5984 * itself recursively
5985 * @return `null` if there was a problem (such as a loop in the class hierarch y) or if there
5986 * are no classes above this one in the class hierarchy. Otherwise, a list of interface
5987 * lookup maps.
5988 */
5989 List<MemberMap> _gatherInterfaceLookupMaps(
5990 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
5991 InterfaceType supertype = classElt.supertype;
5992 ClassElement superclassElement =
5993 supertype != null ? supertype.element : null;
5994 List<InterfaceType> mixins = classElt.mixins;
5995 List<InterfaceType> interfaces = classElt.interfaces;
5996 // Recursively collect the list of mappings from all of the interface types
5997 List<MemberMap> lookupMaps = new List<MemberMap>();
5998 //
5999 // Superclass element
6000 //
6001 if (superclassElement != null) {
6002 if (!visitedInterfaces.contains(superclassElement)) {
6003 try {
6004 visitedInterfaces.add(superclassElement);
6005 //
6006 // Recursively compute the map for the super type.
6007 //
6008 MemberMap map =
6009 _computeInterfaceLookupMap(superclassElement, visitedInterfaces);
6010 map = new MemberMap.from(map);
6011 //
6012 // Substitute the super type down the hierarchy.
6013 //
6014 _substituteTypeParametersDownHierarchy(supertype, map);
6015 //
6016 // Add any members from the super type into the map as well.
6017 //
6018 _recordMapWithClassMembers(map, supertype, true);
6019 lookupMaps.add(map);
6020 } finally {
6021 visitedInterfaces.remove(superclassElement);
6022 }
6023 } else {
6024 return null;
6025 }
6026 }
6027 //
6028 // Mixin elements
6029 //
6030 for (int i = mixins.length - 1; i >= 0; i--) {
6031 InterfaceType mixinType = mixins[i];
6032 ClassElement mixinElement = mixinType.element;
6033 if (mixinElement != null) {
6034 if (!visitedInterfaces.contains(mixinElement)) {
6035 try {
6036 visitedInterfaces.add(mixinElement);
6037 //
6038 // Recursively compute the map for the mixin.
6039 //
6040 MemberMap map =
6041 _computeInterfaceLookupMap(mixinElement, visitedInterfaces);
6042 map = new MemberMap.from(map);
6043 //
6044 // Substitute the mixin type down the hierarchy.
6045 //
6046 _substituteTypeParametersDownHierarchy(mixinType, map);
6047 //
6048 // Add any members from the mixin type into the map as well.
6049 //
6050 _recordMapWithClassMembers(map, mixinType, true);
6051 lookupMaps.add(map);
6052 } finally {
6053 visitedInterfaces.remove(mixinElement);
6054 }
6055 } else {
6056 return null;
6057 }
6058 }
6059 }
6060 //
6061 // Interface elements
6062 //
6063 for (InterfaceType interfaceType in interfaces) {
6064 ClassElement interfaceElement = interfaceType.element;
6065 if (interfaceElement != null) {
6066 if (!visitedInterfaces.contains(interfaceElement)) {
6067 try {
6068 visitedInterfaces.add(interfaceElement);
6069 //
6070 // Recursively compute the map for the interfaces.
6071 //
6072 MemberMap map =
6073 _computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
6074 map = new MemberMap.from(map);
6075 //
6076 // Substitute the supertypes down the hierarchy
6077 //
6078 _substituteTypeParametersDownHierarchy(interfaceType, map);
6079 //
6080 // And add any members from the interface into the map as well.
6081 //
6082 _recordMapWithClassMembers(map, interfaceType, true);
6083 lookupMaps.add(map);
6084 } finally {
6085 visitedInterfaces.remove(interfaceElement);
6086 }
6087 } else {
6088 return null;
6089 }
6090 }
6091 }
6092 if (lookupMaps.length == 0) {
6093 return null;
6094 }
6095 return lookupMaps;
6096 }
6097
6098 /**
6099 * Given some [ClassElement], this method finds and returns the [ExecutableEle ment] of
6100 * the passed name in the class element. Static members, members in super type s and members not
6101 * accessible from the current library are not considered.
6102 *
6103 * @param classElt the class element to query
6104 * @param memberName the name of the member to lookup in the class
6105 * @return the found [ExecutableElement], or `null` if no such member was foun d
6106 */
6107 ExecutableElement _lookupMemberInClass(
6108 ClassElement classElt, String memberName) {
6109 List<MethodElement> methods = classElt.methods;
6110 for (MethodElement method in methods) {
6111 if (memberName == method.name &&
6112 method.isAccessibleIn(_library) &&
6113 !method.isStatic) {
6114 return method;
6115 }
6116 }
6117 List<PropertyAccessorElement> accessors = classElt.accessors;
6118 for (PropertyAccessorElement accessor in accessors) {
6119 if (memberName == accessor.name &&
6120 accessor.isAccessibleIn(_library) &&
6121 !accessor.isStatic) {
6122 return accessor;
6123 }
6124 }
6125 return null;
6126 }
6127
6128 /**
6129 * Record the passed map with the set of all members (methods, getters and set ters) in the type
6130 * into the passed map.
6131 *
6132 * @param map some non-`null` map to put the methods and accessors from the pa ssed
6133 * [ClassElement] into
6134 * @param type the type that will be recorded into the passed map
6135 * @param doIncludeAbstract `true` if abstract members will be put into the ma p
6136 */
6137 void _recordMapWithClassMembers(
6138 MemberMap map, InterfaceType type, bool doIncludeAbstract) {
6139 List<MethodElement> methods = type.methods;
6140 for (MethodElement method in methods) {
6141 if (method.isAccessibleIn(_library) &&
6142 !method.isStatic &&
6143 (doIncludeAbstract || !method.isAbstract)) {
6144 map.put(method.name, method);
6145 }
6146 }
6147 List<PropertyAccessorElement> accessors = type.accessors;
6148 for (PropertyAccessorElement accessor in accessors) {
6149 if (accessor.isAccessibleIn(_library) &&
6150 !accessor.isStatic &&
6151 (doIncludeAbstract || !accessor.isAbstract)) {
6152 map.put(accessor.name, accessor);
6153 }
6154 }
6155 }
6156
6157 /**
6158 * This method is used to report errors on when they are found computing inher itance information.
6159 * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where thes e generated
6160 * error codes are reported back into the analysis engine.
6161 *
6162 * @param classElt the location of the source for which the exception occurred
6163 * @param offset the offset of the location of the error
6164 * @param length the length of the location of the error
6165 * @param errorCode the error code to be associated with this error
6166 * @param arguments the arguments used to build the error message
6167 */
6168 void _reportError(ClassElement classElt, int offset, int length,
6169 ErrorCode errorCode, List<Object> arguments) {
6170 HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt];
6171 if (errorSet == null) {
6172 errorSet = new HashSet<AnalysisError>();
6173 _errorsInClassElement[classElt] = errorSet;
6174 }
6175 errorSet.add(new AnalysisError(
6176 classElt.source, offset, length, errorCode, arguments));
6177 }
6178
6179 /**
6180 * Given the set of methods defined by classes above [classElt] in the class h ierarchy,
6181 * apply the appropriate inheritance rules to determine those methods inherite d by or overridden
6182 * by [classElt]. Also report static warnings
6183 * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and
6184 * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if ap propriate.
6185 *
6186 * @param classElt the class element to query.
6187 * @param unionMap a mapping from method name to the set of unique (in terms o f signature) methods
6188 * defined in superclasses of [classElt].
6189 * @return the inheritance lookup map for [classElt].
6190 */
6191 MemberMap _resolveInheritanceLookup(ClassElement classElt,
6192 HashMap<String, List<ExecutableElement>> unionMap) {
6193 MemberMap resultMap = new MemberMap();
6194 unionMap.forEach((String key, List<ExecutableElement> list) {
6195 int numOfEltsWithMatchingNames = list.length;
6196 if (numOfEltsWithMatchingNames == 1) {
6197 //
6198 // Example: class A inherits only 1 method named 'm'.
6199 // Since it is the only such method, it is inherited.
6200 // Another example: class A inherits 2 methods named 'm' from 2
6201 // different interfaces, but they both have the same signature, so it is
6202 // the method inherited.
6203 //
6204 resultMap.put(key, list[0]);
6205 } else {
6206 //
6207 // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
6208 //
6209 bool allMethods = true;
6210 bool allSetters = true;
6211 bool allGetters = true;
6212 for (ExecutableElement executableElement in list) {
6213 if (executableElement is PropertyAccessorElement) {
6214 allMethods = false;
6215 if (executableElement.isSetter) {
6216 allGetters = false;
6217 } else {
6218 allSetters = false;
6219 }
6220 } else {
6221 allGetters = false;
6222 allSetters = false;
6223 }
6224 }
6225 //
6226 // If there isn't a mixture of methods with getters, then continue,
6227 // otherwise create a warning.
6228 //
6229 if (allMethods || allGetters || allSetters) {
6230 //
6231 // Compute the element whose type is the subtype of all of the other
6232 // types.
6233 //
6234 List<ExecutableElement> elements = new List.from(list);
6235 List<FunctionType> executableElementTypes =
6236 new List<FunctionType>(numOfEltsWithMatchingNames);
6237 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
6238 executableElementTypes[i] = elements[i].type;
6239 }
6240 List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
6241 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
6242 FunctionType subtype = executableElementTypes[i];
6243 if (subtype == null) {
6244 continue;
6245 }
6246 bool subtypeOfAllTypes = true;
6247 for (int j = 0;
6248 j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
6249 j++) {
6250 if (i != j) {
6251 if (!subtype.isSubtypeOf(executableElementTypes[j])) {
6252 subtypeOfAllTypes = false;
6253 break;
6254 }
6255 }
6256 }
6257 if (subtypeOfAllTypes) {
6258 subtypesOfAllOtherTypesIndexes.add(i);
6259 }
6260 }
6261 //
6262 // The following is split into three cases determined by the number of
6263 // elements in subtypesOfAllOtherTypes
6264 //
6265 if (subtypesOfAllOtherTypesIndexes.length == 1) {
6266 //
6267 // Example: class A inherited only 2 method named 'm'.
6268 // One has the function type '() -> dynamic' and one has the
6269 // function type '([int]) -> dynamic'. Since the second method is a
6270 // subtype of all the others, it is the inherited method.
6271 // Tests: InheritanceManagerTest.
6272 // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
6273 //
6274 resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]);
6275 } else {
6276 if (subtypesOfAllOtherTypesIndexes.isEmpty) {
6277 //
6278 // Determine if the current class has a method or accessor with
6279 // the member name, if it does then then this class does not
6280 // "inherit" from any of the supertypes. See issue 16134.
6281 //
6282 bool classHasMember = false;
6283 if (allMethods) {
6284 classHasMember = classElt.getMethod(key) != null;
6285 } else {
6286 List<PropertyAccessorElement> accessors = classElt.accessors;
6287 for (int i = 0; i < accessors.length; i++) {
6288 if (accessors[i].name == key) {
6289 classHasMember = true;
6290 }
6291 }
6292 }
6293 //
6294 // Example: class A inherited only 2 method named 'm'.
6295 // One has the function type '() -> int' and one has the function
6296 // type '() -> String'. Since neither is a subtype of the other,
6297 // we create a warning, and have this class inherit nothing.
6298 //
6299 if (!classHasMember) {
6300 String firstTwoFuntionTypesStr =
6301 "${executableElementTypes[0]}, ${executableElementTypes[1]}" ;
6302 _reportError(
6303 classElt,
6304 classElt.nameOffset,
6305 classElt.displayName.length,
6306 StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE,
6307 [key, firstTwoFuntionTypesStr]);
6308 }
6309 } else {
6310 //
6311 // Example: class A inherits 2 methods named 'm'.
6312 // One has the function type '(int) -> dynamic' and one has the
6313 // function type '(num) -> dynamic'. Since they are both a subtype
6314 // of the other, a synthetic function '(dynamic) -> dynamic' is
6315 // inherited.
6316 // Tests: test_getMapOfMembersInheritedFromInterfaces_
6317 // union_multipleSubtypes_*
6318 //
6319 List<ExecutableElement> elementArrayToMerge = new List<
6320 ExecutableElement>(subtypesOfAllOtherTypesIndexes.length);
6321 for (int i = 0; i < elementArrayToMerge.length; i++) {
6322 elementArrayToMerge[i] =
6323 elements[subtypesOfAllOtherTypesIndexes[i]];
6324 }
6325 ExecutableElement mergedExecutableElement =
6326 _computeMergedExecutableElement(elementArrayToMerge);
6327 resultMap.put(key, mergedExecutableElement);
6328 }
6329 }
6330 } else {
6331 _reportError(
6332 classElt,
6333 classElt.nameOffset,
6334 classElt.displayName.length,
6335 StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHO D,
6336 [key]);
6337 }
6338 }
6339 });
6340 return resultMap;
6341 }
6342
6343 /**
6344 * Loop through all of the members in some [MemberMap], performing type parame ter
6345 * substitutions using a passed supertype.
6346 *
6347 * @param superType the supertype to substitute into the members of the [Membe rMap]
6348 * @param map the MemberMap to perform the substitutions on
6349 */
6350 void _substituteTypeParametersDownHierarchy(
6351 InterfaceType superType, MemberMap map) {
6352 for (int i = 0; i < map.size; i++) {
6353 ExecutableElement executableElement = map.getValue(i);
6354 if (executableElement is MethodMember) {
6355 executableElement =
6356 MethodMember.from(executableElement as MethodMember, superType);
6357 map.setValue(i, executableElement);
6358 } else if (executableElement is PropertyAccessorMember) {
6359 executableElement = PropertyAccessorMember.from(
6360 executableElement as PropertyAccessorMember, superType);
6361 map.setValue(i, executableElement);
6362 }
6363 }
6364 }
6365
6366 /**
6367 * Union all of the [lookupMaps] together into a single map, grouping the Exec utableElements
6368 * into a list where none of the elements are equal where equality is determin ed by having equal
6369 * function types. (We also take note too of the kind of the element: ()->int and () -> int may
6370 * not be equal if one is a getter and the other is a method.)
6371 *
6372 * @param lookupMaps the maps to be unioned together.
6373 * @return the resulting union map.
6374 */
6375 HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps(
6376 List<MemberMap> lookupMaps) {
6377 HashMap<String, List<ExecutableElement>> unionMap =
6378 new HashMap<String, List<ExecutableElement>>();
6379 for (MemberMap lookupMap in lookupMaps) {
6380 int lookupMapSize = lookupMap.size;
6381 for (int i = 0; i < lookupMapSize; i++) {
6382 // Get the string key, if null, break.
6383 String key = lookupMap.getKey(i);
6384 if (key == null) {
6385 break;
6386 }
6387 // Get the list value out of the unionMap
6388 List<ExecutableElement> list = unionMap[key];
6389 // If we haven't created such a map for this key yet, do create it and
6390 // put the list entry into the unionMap.
6391 if (list == null) {
6392 list = new List<ExecutableElement>();
6393 unionMap[key] = list;
6394 }
6395 // Fetch the entry out of this lookupMap
6396 ExecutableElement newExecutableElementEntry = lookupMap.getValue(i);
6397 if (list.isEmpty) {
6398 // If the list is empty, just the new value
6399 list.add(newExecutableElementEntry);
6400 } else {
6401 // Otherwise, only add the newExecutableElementEntry if it isn't
6402 // already in the list, this covers situation where a class inherits
6403 // two methods (or two getters) that are identical.
6404 bool alreadyInList = false;
6405 bool isMethod1 = newExecutableElementEntry is MethodElement;
6406 for (ExecutableElement executableElementInList in list) {
6407 bool isMethod2 = executableElementInList is MethodElement;
6408 if (isMethod1 == isMethod2 &&
6409 executableElementInList.type ==
6410 newExecutableElementEntry.type) {
6411 alreadyInList = true;
6412 break;
6413 }
6414 }
6415 if (!alreadyInList) {
6416 list.add(newExecutableElementEntry);
6417 }
6418 }
6419 }
6420 }
6421 return unionMap;
6422 }
6423
6424 /**
6425 * Given some array of [ExecutableElement]s, this method creates a synthetic e lement as
6426 * described in 8.1.1:
6427 *
6428 * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional pa rameters of a
6429 * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote t he number of
6430 * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denot e the set of all
6431 * named parameters of the <i>m<sub>1</sub>, &hellip;, m<sub>k</sub></i>. Then let
6432 * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i>
6433 * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <= i <= k.</i>
6434 * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameter s of type
6435 * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, name d parameters
6436 * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
6437 *
6438 */
6439 static ExecutableElement _computeMergedExecutableElement(
6440 List<ExecutableElement> elementArrayToMerge) {
6441 int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
6442 int r = _getNumOfRequiredParameters(elementArrayToMerge[0]);
6443 Set<String> namedParametersList = new HashSet<String>();
6444 for (int i = 1; i < elementArrayToMerge.length; i++) {
6445 ExecutableElement element = elementArrayToMerge[i];
6446 int numOfPositionalParams = _getNumOfPositionalParameters(element);
6447 if (h < numOfPositionalParams) {
6448 h = numOfPositionalParams;
6449 }
6450 int numOfRequiredParams = _getNumOfRequiredParameters(element);
6451 if (r > numOfRequiredParams) {
6452 r = numOfRequiredParams;
6453 }
6454 namedParametersList.addAll(_getNamedParameterNames(element));
6455 }
6456 return _createSyntheticExecutableElement(
6457 elementArrayToMerge,
6458 elementArrayToMerge[0].displayName,
6459 r,
6460 h - r,
6461 new List.from(namedParametersList));
6462 }
6463
6464 /**
6465 * Used by [computeMergedExecutableElement] to actually create the
6466 * synthetic element.
6467 *
6468 * @param elementArrayToMerge the array used to create the synthetic element
6469 * @param name the name of the method, getter or setter
6470 * @param numOfRequiredParameters the number of required parameters
6471 * @param numOfPositionalParameters the number of positional parameters
6472 * @param namedParameters the list of [String]s that are the named parameters
6473 * @return the created synthetic element
6474 */
6475 static ExecutableElement _createSyntheticExecutableElement(
6476 List<ExecutableElement> elementArrayToMerge,
6477 String name,
6478 int numOfRequiredParameters,
6479 int numOfPositionalParameters,
6480 List<String> namedParameters) {
6481 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
6482 SimpleIdentifier nameIdentifier = new SimpleIdentifier(
6483 new sc.StringToken(sc.TokenType.IDENTIFIER, name, 0));
6484 ExecutableElementImpl executable;
6485 if (elementArrayToMerge[0] is MethodElement) {
6486 MultiplyInheritedMethodElementImpl unionedMethod =
6487 new MultiplyInheritedMethodElementImpl(nameIdentifier);
6488 unionedMethod.inheritedElements = elementArrayToMerge;
6489 executable = unionedMethod;
6490 } else {
6491 MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor =
6492 new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
6493 unionedPropertyAccessor.getter =
6494 (elementArrayToMerge[0] as PropertyAccessorElement).isGetter;
6495 unionedPropertyAccessor.setter =
6496 (elementArrayToMerge[0] as PropertyAccessorElement).isSetter;
6497 unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
6498 executable = unionedPropertyAccessor;
6499 }
6500 int numOfParameters = numOfRequiredParameters +
6501 numOfPositionalParameters +
6502 namedParameters.length;
6503 List<ParameterElement> parameters =
6504 new List<ParameterElement>(numOfParameters);
6505 int i = 0;
6506 for (int j = 0; j < numOfRequiredParameters; j++, i++) {
6507 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
6508 parameter.type = dynamicType;
6509 parameter.parameterKind = ParameterKind.REQUIRED;
6510 parameters[i] = parameter;
6511 }
6512 for (int k = 0; k < numOfPositionalParameters; k++, i++) {
6513 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
6514 parameter.type = dynamicType;
6515 parameter.parameterKind = ParameterKind.POSITIONAL;
6516 parameters[i] = parameter;
6517 }
6518 for (int m = 0; m < namedParameters.length; m++, i++) {
6519 ParameterElementImpl parameter =
6520 new ParameterElementImpl(namedParameters[m], 0);
6521 parameter.type = dynamicType;
6522 parameter.parameterKind = ParameterKind.NAMED;
6523 parameters[i] = parameter;
6524 }
6525 executable.returnType = dynamicType;
6526 executable.parameters = parameters;
6527 FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
6528 executable.type = methodType;
6529 return executable;
6530 }
6531
6532 /**
6533 * Given some [ExecutableElement], return the list of named parameters.
6534 */
6535 static List<String> _getNamedParameterNames(
6536 ExecutableElement executableElement) {
6537 List<String> namedParameterNames = new List<String>();
6538 List<ParameterElement> parameters = executableElement.parameters;
6539 for (int i = 0; i < parameters.length; i++) {
6540 ParameterElement parameterElement = parameters[i];
6541 if (parameterElement.parameterKind == ParameterKind.NAMED) {
6542 namedParameterNames.add(parameterElement.name);
6543 }
6544 }
6545 return namedParameterNames;
6546 }
6547
6548 /**
6549 * Given some [ExecutableElement] return the number of parameters of the speci fied kind.
6550 */
6551 static int _getNumOfParameters(
6552 ExecutableElement executableElement, ParameterKind parameterKind) {
6553 int parameterCount = 0;
6554 List<ParameterElement> parameters = executableElement.parameters;
6555 for (int i = 0; i < parameters.length; i++) {
6556 ParameterElement parameterElement = parameters[i];
6557 if (parameterElement.parameterKind == parameterKind) {
6558 parameterCount++;
6559 }
6560 }
6561 return parameterCount;
6562 }
6563
6564 /**
6565 * Given some [ExecutableElement] return the number of positional parameters.
6566 *
6567 * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSI TIONAL].
6568 */
6569 static int _getNumOfPositionalParameters(
6570 ExecutableElement executableElement) =>
6571 _getNumOfParameters(executableElement, ParameterKind.REQUIRED) +
6572 _getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
6573
6574 /**
6575 * Given some [ExecutableElement] return the number of required parameters.
6576 */
6577 static int _getNumOfRequiredParameters(ExecutableElement executableElement) =>
6578 _getNumOfParameters(executableElement, ParameterKind.REQUIRED);
6579
6580 /**
6581 * Given some [ExecutableElement] returns `true` if it is an abstract member o f a
6582 * class.
6583 *
6584 * @param executableElement some [ExecutableElement] to evaluate
6585 * @return `true` if the given element is an abstract member of a class
6586 */
6587 static bool _isAbstract(ExecutableElement executableElement) {
6588 if (executableElement is MethodElement) {
6589 return executableElement.isAbstract;
6590 } else if (executableElement is PropertyAccessorElement) {
6591 return executableElement.isAbstract;
6592 }
6593 return false;
6594 }
6595 }
6596
6597 /**
6598 * This enum holds one of four states of a field initialization state through a constructor
6599 * signature, not initialized, initialized in the field declaration, initialized in the field
6600 * formal, and finally, initialized in the initializers list.
6601 */
6602 class INIT_STATE extends Enum<INIT_STATE> {
6603 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0);
6604
6605 static const INIT_STATE INIT_IN_DECLARATION =
6606 const INIT_STATE('INIT_IN_DECLARATION', 1);
6607
6608 static const INIT_STATE INIT_IN_FIELD_FORMAL =
6609 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2);
6610
6611 static const INIT_STATE INIT_IN_INITIALIZERS =
6612 const INIT_STATE('INIT_IN_INITIALIZERS', 3);
6613
6614 static const List<INIT_STATE> values = const [
6615 NOT_INIT,
6616 INIT_IN_DECLARATION,
6617 INIT_IN_FIELD_FORMAL,
6618 INIT_IN_INITIALIZERS
6619 ];
6620
6621 const INIT_STATE(String name, int ordinal) : super(name, ordinal);
6622 }
6623
6624 /**
6625 * Instances of the class `LabelScope` represent a scope in which a single label is defined.
6626 */
6627 class LabelScope {
6628 /**
6629 * The label scope enclosing this label scope.
6630 */
6631 final LabelScope _outerScope;
6632
6633 /**
6634 * The label defined in this scope.
6635 */
6636 final String _label;
6637
6638 /**
6639 * The element to which the label resolves.
6640 */
6641 final LabelElement element;
6642
6643 /**
6644 * The AST node to which the label resolves.
6645 */
6646 final AstNode node;
6647
6648 /**
6649 * Initialize a newly created scope to represent the label [_label].
6650 * [_outerScope] is the scope enclosing the new label scope. [node] is the
6651 * AST node the label resolves to. [element] is the element the label
6652 * resolves to.
6653 */
6654 LabelScope(this._outerScope, this._label, this.node, this.element);
6655
6656 /**
6657 * Return the LabelScope which defines [targetLabel], or `null` if it is not
6658 * defined in this scope.
6659 */
6660 LabelScope lookup(String targetLabel) {
6661 if (_label == targetLabel) {
6662 return this;
6663 } else if (_outerScope != null) {
6664 return _outerScope.lookup(targetLabel);
6665 } else {
6666 return null;
6667 }
6668 }
6669 }
6670
6671 /**
6672 * Instances of the class `Library` represent the data about a single library du ring the
6673 * resolution of some (possibly different) library. They are not intended to be used except during
6674 * the resolution process.
6675 */
6676 class Library {
6677 /**
6678 * An empty list that can be used to initialize lists of libraries.
6679 */
6680 static const List<Library> _EMPTY_ARRAY = const <Library>[];
6681
6682 /**
6683 * The prefix of a URI using the dart-ext scheme to reference a native code li brary.
6684 */
6685 static String _DART_EXT_SCHEME = "dart-ext:";
6686
6687 /**
6688 * The analysis context in which this library is being analyzed.
6689 */
6690 final InternalAnalysisContext _analysisContext;
6691
6692 /**
6693 * The inheritance manager which is used for this member lookups in this libra ry.
6694 */
6695 InheritanceManager _inheritanceManager;
6696
6697 /**
6698 * The listener to which analysis errors will be reported.
6699 */
6700 final AnalysisErrorListener errorListener;
6701
6702 /**
6703 * The source specifying the defining compilation unit of this library.
6704 */
6705 final Source librarySource;
6706
6707 /**
6708 * The library element representing this library.
6709 */
6710 LibraryElementImpl _libraryElement;
6711
6712 /**
6713 * A list containing all of the libraries that are imported into this library.
6714 */
6715 List<Library> _importedLibraries = _EMPTY_ARRAY;
6716
6717 /**
6718 * A table mapping URI-based directive to the actual URI value.
6719 */
6720 HashMap<UriBasedDirective, String> _directiveUris =
6721 new HashMap<UriBasedDirective, String>();
6722
6723 /**
6724 * A flag indicating whether this library explicitly imports core.
6725 */
6726 bool explicitlyImportsCore = false;
6727
6728 /**
6729 * A list containing all of the libraries that are exported from this library.
6730 */
6731 List<Library> _exportedLibraries = _EMPTY_ARRAY;
6732
6733 /**
6734 * A table mapping the sources for the compilation units in this library to th eir corresponding
6735 * AST structures.
6736 */
6737 HashMap<Source, CompilationUnit> _astMap =
6738 new HashMap<Source, CompilationUnit>();
6739
6740 /**
6741 * The library scope used when resolving elements within this library's compil ation units.
6742 */
6743 LibraryScope _libraryScope;
6744
6745 /**
6746 * Initialize a newly created data holder that can maintain the data associate d with a library.
6747 *
6748 * @param analysisContext the analysis context in which this library is being analyzed
6749 * @param errorListener the listener to which analysis errors will be reported
6750 * @param librarySource the source specifying the defining compilation unit of this library
6751 */
6752 Library(this._analysisContext, this.errorListener, this.librarySource) {
6753 this._libraryElement =
6754 _analysisContext.getLibraryElement(librarySource) as LibraryElementImpl;
6755 }
6756
6757 /**
6758 * Return an array of the [CompilationUnit]s that make up the library. The fir st unit is
6759 * always the defining unit.
6760 *
6761 * @return an array of the [CompilationUnit]s that make up the library. The fi rst unit is
6762 * always the defining unit
6763 */
6764 List<CompilationUnit> get compilationUnits {
6765 List<CompilationUnit> unitArrayList = new List<CompilationUnit>();
6766 unitArrayList.add(definingCompilationUnit);
6767 for (Source source in _astMap.keys.toSet()) {
6768 if (librarySource != source) {
6769 unitArrayList.add(getAST(source));
6770 }
6771 }
6772 return unitArrayList;
6773 }
6774
6775 /**
6776 * Return a collection containing the sources for the compilation units in thi s library, including
6777 * the defining compilation unit.
6778 *
6779 * @return the sources for the compilation units in this library
6780 */
6781 Set<Source> get compilationUnitSources => _astMap.keys.toSet();
6782
6783 /**
6784 * Return the AST structure associated with the defining compilation unit for this library.
6785 *
6786 * @return the AST structure associated with the defining compilation unit for this library
6787 * @throws AnalysisException if an AST structure could not be created for the defining compilation
6788 * unit
6789 */
6790 CompilationUnit get definingCompilationUnit => getAST(librarySource);
6791
6792 /**
6793 * Set the libraries that are exported by this library to be those in the give n array.
6794 *
6795 * @param exportedLibraries the libraries that are exported by this library
6796 */
6797 void set exportedLibraries(List<Library> exportedLibraries) {
6798 this._exportedLibraries = exportedLibraries;
6799 }
6800
6801 /**
6802 * Return an array containing the libraries that are exported from this librar y.
6803 *
6804 * @return an array containing the libraries that are exported from this libra ry
6805 */
6806 List<Library> get exports => _exportedLibraries;
6807
6808 /**
6809 * Set the libraries that are imported into this library to be those in the gi ven array.
6810 *
6811 * @param importedLibraries the libraries that are imported into this library
6812 */
6813 void set importedLibraries(List<Library> importedLibraries) {
6814 this._importedLibraries = importedLibraries;
6815 }
6816
6817 /**
6818 * Return an array containing the libraries that are imported into this librar y.
6819 *
6820 * @return an array containing the libraries that are imported into this libra ry
6821 */
6822 List<Library> get imports => _importedLibraries;
6823
6824 /**
6825 * Return an array containing the libraries that are either imported or export ed from this
6826 * library.
6827 *
6828 * @return the libraries that are either imported or exported from this librar y
6829 */
6830 List<Library> get importsAndExports {
6831 HashSet<Library> libraries = new HashSet<Library>();
6832 for (Library library in _importedLibraries) {
6833 libraries.add(library);
6834 }
6835 for (Library library in _exportedLibraries) {
6836 libraries.add(library);
6837 }
6838 return new List.from(libraries);
6839 }
6840
6841 /**
6842 * Return the inheritance manager for this library.
6843 *
6844 * @return the inheritance manager for this library
6845 */
6846 InheritanceManager get inheritanceManager {
6847 if (_inheritanceManager == null) {
6848 return _inheritanceManager = new InheritanceManager(_libraryElement);
6849 }
6850 return _inheritanceManager;
6851 }
6852
6853 /**
6854 * Return the library element representing this library, creating it if necess ary.
6855 *
6856 * @return the library element representing this library
6857 */
6858 LibraryElementImpl get libraryElement {
6859 if (_libraryElement == null) {
6860 try {
6861 _libraryElement = _analysisContext.computeLibraryElement(librarySource)
6862 as LibraryElementImpl;
6863 } on AnalysisException catch (exception, stackTrace) {
6864 AnalysisEngine.instance.logger.logError(
6865 "Could not compute library element for ${librarySource.fullName}",
6866 new CaughtException(exception, stackTrace));
6867 }
6868 }
6869 return _libraryElement;
6870 }
6871
6872 /**
6873 * Set the library element representing this library to the given library elem ent.
6874 *
6875 * @param libraryElement the library element representing this library
6876 */
6877 void set libraryElement(LibraryElementImpl libraryElement) {
6878 this._libraryElement = libraryElement;
6879 if (_inheritanceManager != null) {
6880 _inheritanceManager.libraryElement = libraryElement;
6881 }
6882 }
6883
6884 /**
6885 * Return the library scope used when resolving elements within this library's compilation units.
6886 *
6887 * @return the library scope used when resolving elements within this library' s compilation units
6888 */
6889 LibraryScope get libraryScope {
6890 if (_libraryScope == null) {
6891 _libraryScope = new LibraryScope(_libraryElement, errorListener);
6892 }
6893 return _libraryScope;
6894 }
6895
6896 /**
6897 * Return the AST structure associated with the given source.
6898 *
6899 * @param source the source representing the compilation unit whose AST is to be returned
6900 * @return the AST structure associated with the given source
6901 * @throws AnalysisException if an AST structure could not be created for the compilation unit
6902 */
6903 CompilationUnit getAST(Source source) {
6904 CompilationUnit unit = _astMap[source];
6905 if (unit == null) {
6906 unit = _analysisContext.computeResolvableCompilationUnit(source);
6907 _astMap[source] = unit;
6908 }
6909 return unit;
6910 }
6911
6912 /**
6913 * Return the result of resolving the URI of the given URI-based directive aga inst the URI of the
6914 * library, or `null` if the URI is not valid. If the URI is not valid, report the error.
6915 *
6916 * @param directive the directive which URI should be resolved
6917 * @return the result of resolving the URI against the URI of the library
6918 */
6919 Source getSource(UriBasedDirective directive) {
6920 StringLiteral uriLiteral = directive.uri;
6921 if (uriLiteral is StringInterpolation) {
6922 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
6923 uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION));
6924 return null;
6925 }
6926 String uriContent = uriLiteral.stringValue.trim();
6927 _directiveUris[directive] = uriContent;
6928 uriContent = Uri.encodeFull(uriContent);
6929 if (directive is ImportDirective &&
6930 uriContent.startsWith(_DART_EXT_SCHEME)) {
6931 _libraryElement.hasExtUri = true;
6932 return null;
6933 }
6934 try {
6935 parseUriWithException(uriContent);
6936 Source source =
6937 _analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
6938 if (!_analysisContext.exists(source)) {
6939 errorListener.onError(new AnalysisError(
6940 librarySource,
6941 uriLiteral.offset,
6942 uriLiteral.length,
6943 CompileTimeErrorCode.URI_DOES_NOT_EXIST,
6944 [uriContent]));
6945 }
6946 return source;
6947 } on URISyntaxException {
6948 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
6949 uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent]));
6950 }
6951 return null;
6952 }
6953
6954 /**
6955 * Returns the URI value of the given directive.
6956 */
6957 String getUri(UriBasedDirective directive) => _directiveUris[directive];
6958
6959 /**
6960 * Set the AST structure associated with the defining compilation unit for thi s library to the
6961 * given AST structure.
6962 *
6963 * @param unit the AST structure associated with the defining compilation unit for this library
6964 */
6965 void setDefiningCompilationUnit(CompilationUnit unit) {
6966 _astMap[librarySource] = unit;
6967 }
6968
6969 @override
6970 String toString() => librarySource.shortName;
6971 }
6972
6973 /**
6974 * Instances of the class `LibraryElementBuilder` build an element model for a s ingle library.
6975 */
6976 class LibraryElementBuilder {
6977 /**
6978 * The analysis context in which the element model will be built.
6979 */
6980 final InternalAnalysisContext _analysisContext;
6981
6982 /**
6983 * The listener to which errors will be reported.
6984 */
6985 final AnalysisErrorListener _errorListener;
6986
6987 /**
6988 * Initialize a newly created library element builder.
6989 *
6990 * @param analysisContext the analysis context in which the element model will be built
6991 * @param errorListener the listener to which errors will be reported
6992 */
6993 LibraryElementBuilder(this._analysisContext, this._errorListener);
6994
6995 /**
6996 * Build the library element for the given library.
6997 *
6998 * @param library the library for which an element model is to be built
6999 * @return the library element that was built
7000 * @throws AnalysisException if the analysis could not be performed
7001 */
7002 LibraryElementImpl buildLibrary(Library library) {
7003 CompilationUnitBuilder builder = new CompilationUnitBuilder();
7004 Source librarySource = library.librarySource;
7005 CompilationUnit definingCompilationUnit = library.definingCompilationUnit;
7006 CompilationUnitElementImpl definingCompilationUnitElement = builder
7007 .buildCompilationUnit(
7008 librarySource, definingCompilationUnit, librarySource);
7009 NodeList<Directive> directives = definingCompilationUnit.directives;
7010 LibraryIdentifier libraryNameNode = null;
7011 bool hasPartDirective = false;
7012 FunctionElement entryPoint =
7013 _findEntryPoint(definingCompilationUnitElement);
7014 List<Directive> directivesToResolve = new List<Directive>();
7015 List<CompilationUnitElementImpl> sourcedCompilationUnits =
7016 new List<CompilationUnitElementImpl>();
7017 for (Directive directive in directives) {
7018 //
7019 // We do not build the elements representing the import and export
7020 // directives at this point. That is not done until we get to
7021 // LibraryResolver.buildDirectiveModels() because we need the
7022 // LibraryElements for the referenced libraries, which might not exist at
7023 // this point (due to the possibility of circular references).
7024 //
7025 if (directive is LibraryDirective) {
7026 if (libraryNameNode == null) {
7027 libraryNameNode = directive.name;
7028 directivesToResolve.add(directive);
7029 }
7030 } else if (directive is PartDirective) {
7031 PartDirective partDirective = directive;
7032 StringLiteral partUri = partDirective.uri;
7033 Source partSource = partDirective.source;
7034 if (_analysisContext.exists(partSource)) {
7035 hasPartDirective = true;
7036 CompilationUnit partUnit = library.getAST(partSource);
7037 CompilationUnitElementImpl part =
7038 builder.buildCompilationUnit(partSource, partUnit, librarySource);
7039 part.uriOffset = partUri.offset;
7040 part.uriEnd = partUri.end;
7041 part.uri = partDirective.uriContent;
7042 //
7043 // Validate that the part contains a part-of directive with the same
7044 // name as the library.
7045 //
7046 String partLibraryName =
7047 _getPartLibraryName(partSource, partUnit, directivesToResolve);
7048 if (partLibraryName == null) {
7049 _errorListener.onError(new AnalysisError(
7050 librarySource,
7051 partUri.offset,
7052 partUri.length,
7053 CompileTimeErrorCode.PART_OF_NON_PART,
7054 [partUri.toSource()]));
7055 } else if (libraryNameNode == null) {
7056 // TODO(brianwilkerson) Collect the names declared by the part.
7057 // If they are all the same then we can use that name as the
7058 // inferred name of the library and present it in a quick-fix.
7059 // partLibraryNames.add(partLibraryName);
7060 } else if (libraryNameNode.name != partLibraryName) {
7061 _errorListener.onError(new AnalysisError(
7062 librarySource,
7063 partUri.offset,
7064 partUri.length,
7065 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
7066 [libraryNameNode.name, partLibraryName]));
7067 }
7068 if (entryPoint == null) {
7069 entryPoint = _findEntryPoint(part);
7070 }
7071 directive.element = part;
7072 sourcedCompilationUnits.add(part);
7073 }
7074 }
7075 }
7076 if (hasPartDirective && libraryNameNode == null) {
7077 _errorListener.onError(new AnalysisError(librarySource, 0, 0,
7078 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
7079 }
7080 //
7081 // Create and populate the library element.
7082 //
7083 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
7084 _analysisContext.getContextFor(librarySource), libraryNameNode);
7085 libraryElement.definingCompilationUnit = definingCompilationUnitElement;
7086 if (entryPoint != null) {
7087 libraryElement.entryPoint = entryPoint;
7088 }
7089 int sourcedUnitCount = sourcedCompilationUnits.length;
7090 libraryElement.parts = sourcedCompilationUnits;
7091 for (Directive directive in directivesToResolve) {
7092 directive.element = libraryElement;
7093 }
7094 library.libraryElement = libraryElement;
7095 if (sourcedUnitCount > 0) {
7096 _patchTopLevelAccessors(libraryElement);
7097 }
7098 return libraryElement;
7099 }
7100
7101 /**
7102 * Build the library element for the given library. The resulting element is
7103 * stored in the [ResolvableLibrary] structure.
7104 *
7105 * @param library the library for which an element model is to be built
7106 * @throws AnalysisException if the analysis could not be performed
7107 */
7108 void buildLibrary2(ResolvableLibrary library) {
7109 CompilationUnitBuilder builder = new CompilationUnitBuilder();
7110 Source librarySource = library.librarySource;
7111 CompilationUnit definingCompilationUnit = library.definingCompilationUnit;
7112 CompilationUnitElementImpl definingCompilationUnitElement = builder
7113 .buildCompilationUnit(
7114 librarySource, definingCompilationUnit, librarySource);
7115 NodeList<Directive> directives = definingCompilationUnit.directives;
7116 LibraryIdentifier libraryNameNode = null;
7117 bool hasPartDirective = false;
7118 FunctionElement entryPoint =
7119 _findEntryPoint(definingCompilationUnitElement);
7120 List<Directive> directivesToResolve = new List<Directive>();
7121 List<CompilationUnitElementImpl> sourcedCompilationUnits =
7122 new List<CompilationUnitElementImpl>();
7123 for (Directive directive in directives) {
7124 //
7125 // We do not build the elements representing the import and export
7126 // directives at this point. That is not done until we get to
7127 // LibraryResolver.buildDirectiveModels() because we need the
7128 // LibraryElements for the referenced libraries, which might not exist at
7129 // this point (due to the possibility of circular references).
7130 //
7131 if (directive is LibraryDirective) {
7132 if (libraryNameNode == null) {
7133 libraryNameNode = directive.name;
7134 directivesToResolve.add(directive);
7135 }
7136 } else if (directive is PartDirective) {
7137 PartDirective partDirective = directive;
7138 StringLiteral partUri = partDirective.uri;
7139 Source partSource = partDirective.source;
7140 if (_analysisContext.exists(partSource)) {
7141 hasPartDirective = true;
7142 CompilationUnit partUnit = library.getAST(partSource);
7143 if (partUnit != null) {
7144 CompilationUnitElementImpl part = builder.buildCompilationUnit(
7145 partSource, partUnit, librarySource);
7146 part.uriOffset = partUri.offset;
7147 part.uriEnd = partUri.end;
7148 part.uri = partDirective.uriContent;
7149 //
7150 // Validate that the part contains a part-of directive with the same
7151 // name as the library.
7152 //
7153 String partLibraryName =
7154 _getPartLibraryName(partSource, partUnit, directivesToResolve);
7155 if (partLibraryName == null) {
7156 _errorListener.onError(new AnalysisError(
7157 librarySource,
7158 partUri.offset,
7159 partUri.length,
7160 CompileTimeErrorCode.PART_OF_NON_PART,
7161 [partUri.toSource()]));
7162 } else if (libraryNameNode == null) {
7163 // TODO(brianwilkerson) Collect the names declared by the part.
7164 // If they are all the same then we can use that name as the
7165 // inferred name of the library and present it in a quick-fix.
7166 // partLibraryNames.add(partLibraryName);
7167 } else if (libraryNameNode.name != partLibraryName) {
7168 _errorListener.onError(new AnalysisError(
7169 librarySource,
7170 partUri.offset,
7171 partUri.length,
7172 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
7173 [libraryNameNode.name, partLibraryName]));
7174 }
7175 if (entryPoint == null) {
7176 entryPoint = _findEntryPoint(part);
7177 }
7178 directive.element = part;
7179 sourcedCompilationUnits.add(part);
7180 }
7181 }
7182 }
7183 }
7184 if (hasPartDirective && libraryNameNode == null) {
7185 _errorListener.onError(new AnalysisError(librarySource, 0, 0,
7186 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
7187 }
7188 //
7189 // Create and populate the library element.
7190 //
7191 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
7192 _analysisContext.getContextFor(librarySource), libraryNameNode);
7193 libraryElement.definingCompilationUnit = definingCompilationUnitElement;
7194 if (entryPoint != null) {
7195 libraryElement.entryPoint = entryPoint;
7196 }
7197 int sourcedUnitCount = sourcedCompilationUnits.length;
7198 libraryElement.parts = sourcedCompilationUnits;
7199 for (Directive directive in directivesToResolve) {
7200 directive.element = libraryElement;
7201 }
7202 library.libraryElement = libraryElement;
7203 if (sourcedUnitCount > 0) {
7204 _patchTopLevelAccessors(libraryElement);
7205 }
7206 }
7207
7208 /**
7209 * Add all of the non-synthetic getters and setters defined in the given compi lation unit that
7210 * have no corresponding accessor to one of the given collections.
7211 *
7212 * @param getters the map to which getters are to be added
7213 * @param setters the list to which setters are to be added
7214 * @param unit the compilation unit defining the accessors that are potentiall y being added
7215 */
7216 void _collectAccessors(HashMap<String, PropertyAccessorElement> getters,
7217 List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
7218 for (PropertyAccessorElement accessor in unit.accessors) {
7219 if (accessor.isGetter) {
7220 if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
7221 getters[accessor.displayName] = accessor;
7222 }
7223 } else {
7224 if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
7225 setters.add(accessor);
7226 }
7227 }
7228 }
7229 }
7230
7231 /**
7232 * Search the top-level functions defined in the given compilation unit for th e entry point.
7233 *
7234 * @param element the compilation unit to be searched
7235 * @return the entry point that was found, or `null` if the compilation unit d oes not define
7236 * an entry point
7237 */
7238 FunctionElement _findEntryPoint(CompilationUnitElementImpl element) {
7239 for (FunctionElement function in element.functions) {
7240 if (function.isEntryPoint) {
7241 return function;
7242 }
7243 }
7244 return null;
7245 }
7246
7247 /**
7248 * Return the name of the library that the given part is declared to be a part of, or `null`
7249 * if the part does not contain a part-of directive.
7250 *
7251 * @param partSource the source representing the part
7252 * @param partUnit the AST structure of the part
7253 * @param directivesToResolve a list of directives that should be resolved to the library being
7254 * built
7255 * @return the name of the library that the given part is declared to be a par t of
7256 */
7257 String _getPartLibraryName(Source partSource, CompilationUnit partUnit,
7258 List<Directive> directivesToResolve) {
7259 for (Directive directive in partUnit.directives) {
7260 if (directive is PartOfDirective) {
7261 directivesToResolve.add(directive);
7262 LibraryIdentifier libraryName = directive.libraryName;
7263 if (libraryName != null) {
7264 return libraryName.name;
7265 }
7266 }
7267 }
7268 return null;
7269 }
7270
7271 /**
7272 * Look through all of the compilation units defined for the given library, lo oking for getters
7273 * and setters that are defined in different compilation units but that have t he same names. If
7274 * any are found, make sure that they have the same variable element.
7275 *
7276 * @param libraryElement the library defining the compilation units to be proc essed
7277 */
7278 void _patchTopLevelAccessors(LibraryElementImpl libraryElement) {
7279 HashMap<String, PropertyAccessorElement> getters =
7280 new HashMap<String, PropertyAccessorElement>();
7281 List<PropertyAccessorElement> setters = new List<PropertyAccessorElement>();
7282 _collectAccessors(getters, setters, libraryElement.definingCompilationUnit);
7283 for (CompilationUnitElement unit in libraryElement.parts) {
7284 _collectAccessors(getters, setters, unit);
7285 }
7286 for (PropertyAccessorElement setter in setters) {
7287 PropertyAccessorElement getter = getters[setter.displayName];
7288 if (getter != null) {
7289 PropertyInducingElementImpl variable =
7290 getter.variable as PropertyInducingElementImpl;
7291 variable.setter = setter;
7292 (setter as PropertyAccessorElementImpl).variable = variable;
7293 }
7294 }
7295 }
7296 }
7297
7298 /**
7299 * Instances of the class `LibraryImportScope` represent the scope containing al l of the names
7300 * available from imported libraries.
7301 */
7302 class LibraryImportScope extends Scope {
7303 /**
7304 * The element representing the library in which this scope is enclosed.
7305 */
7306 final LibraryElement _definingLibrary;
7307
7308 /**
7309 * The listener that is to be informed when an error is encountered.
7310 */
7311 final AnalysisErrorListener errorListener;
7312
7313 /**
7314 * A list of the namespaces representing the names that are available in this scope from imported
7315 * libraries.
7316 */
7317 List<Namespace> _importedNamespaces;
7318
7319 /**
7320 * Initialize a newly created scope representing the names imported into the g iven library.
7321 *
7322 * @param definingLibrary the element representing the library that imports th e names defined in
7323 * this scope
7324 * @param errorListener the listener that is to be informed when an error is e ncountered
7325 */
7326 LibraryImportScope(this._definingLibrary, this.errorListener) {
7327 _createImportedNamespaces();
7328 }
7329
7330 @override
7331 void define(Element element) {
7332 if (!Scope.isPrivateName(element.displayName)) {
7333 super.define(element);
7334 }
7335 }
7336
7337 @override
7338 Source getSource(AstNode node) {
7339 Source source = super.getSource(node);
7340 if (source == null) {
7341 source = _definingLibrary.definingCompilationUnit.source;
7342 }
7343 return source;
7344 }
7345
7346 @override
7347 Element internalLookup(
7348 Identifier identifier, String name, LibraryElement referencingLibrary) {
7349 Element foundElement = localLookup(name, referencingLibrary);
7350 if (foundElement != null) {
7351 return foundElement;
7352 }
7353 for (int i = 0; i < _importedNamespaces.length; i++) {
7354 Namespace nameSpace = _importedNamespaces[i];
7355 Element element = nameSpace.get(name);
7356 if (element != null) {
7357 if (foundElement == null) {
7358 foundElement = element;
7359 } else if (!identical(foundElement, element)) {
7360 foundElement = MultiplyDefinedElementImpl.fromElements(
7361 _definingLibrary.context, foundElement, element);
7362 }
7363 }
7364 }
7365 if (foundElement is MultiplyDefinedElementImpl) {
7366 foundElement = _removeSdkElements(
7367 identifier, name, foundElement as MultiplyDefinedElementImpl);
7368 }
7369 if (foundElement is MultiplyDefinedElementImpl) {
7370 String foundEltName = foundElement.displayName;
7371 List<Element> conflictingMembers = foundElement.conflictingElements;
7372 int count = conflictingMembers.length;
7373 List<String> libraryNames = new List<String>(count);
7374 for (int i = 0; i < count; i++) {
7375 libraryNames[i] = _getLibraryName(conflictingMembers[i]);
7376 }
7377 libraryNames.sort();
7378 errorListener.onError(new AnalysisError(
7379 getSource(identifier),
7380 identifier.offset,
7381 identifier.length,
7382 StaticWarningCode.AMBIGUOUS_IMPORT, [
7383 foundEltName,
7384 StringUtilities.printListOfQuotedNames(libraryNames)
7385 ]));
7386 return foundElement;
7387 }
7388 if (foundElement != null) {
7389 defineNameWithoutChecking(name, foundElement);
7390 }
7391 return foundElement;
7392 }
7393
7394 /**
7395 * Create all of the namespaces associated with the libraries imported into th is library. The
7396 * names are not added to this scope, but are stored for later reference.
7397 *
7398 * @param definingLibrary the element representing the library that imports th e libraries for
7399 * which namespaces will be created
7400 */
7401 void _createImportedNamespaces() {
7402 NamespaceBuilder builder = new NamespaceBuilder();
7403 List<ImportElement> imports = _definingLibrary.imports;
7404 int count = imports.length;
7405 _importedNamespaces = new List<Namespace>(count);
7406 for (int i = 0; i < count; i++) {
7407 _importedNamespaces[i] =
7408 builder.createImportNamespaceForDirective(imports[i]);
7409 }
7410 }
7411
7412 /**
7413 * Returns the name of the library that defines given element.
7414 *
7415 * @param element the element to get library name
7416 * @return the name of the library that defines given element
7417 */
7418 String _getLibraryName(Element element) {
7419 if (element == null) {
7420 return StringUtilities.EMPTY;
7421 }
7422 LibraryElement library = element.library;
7423 if (library == null) {
7424 return StringUtilities.EMPTY;
7425 }
7426 List<ImportElement> imports = _definingLibrary.imports;
7427 int count = imports.length;
7428 for (int i = 0; i < count; i++) {
7429 if (identical(imports[i].importedLibrary, library)) {
7430 return library.definingCompilationUnit.displayName;
7431 }
7432 }
7433 List<String> indirectSources = new List<String>();
7434 for (int i = 0; i < count; i++) {
7435 LibraryElement importedLibrary = imports[i].importedLibrary;
7436 if (importedLibrary != null) {
7437 for (LibraryElement exportedLibrary
7438 in importedLibrary.exportedLibraries) {
7439 if (identical(exportedLibrary, library)) {
7440 indirectSources
7441 .add(importedLibrary.definingCompilationUnit.displayName);
7442 }
7443 }
7444 }
7445 }
7446 int indirectCount = indirectSources.length;
7447 StringBuffer buffer = new StringBuffer();
7448 buffer.write(library.definingCompilationUnit.displayName);
7449 if (indirectCount > 0) {
7450 buffer.write(" (via ");
7451 if (indirectCount > 1) {
7452 indirectSources.sort();
7453 buffer.write(StringUtilities.printListOfQuotedNames(indirectSources));
7454 } else {
7455 buffer.write(indirectSources[0]);
7456 }
7457 buffer.write(")");
7458 }
7459 return buffer.toString();
7460 }
7461
7462 /**
7463 * Given a collection of elements (captured by the [foundElement]) that the
7464 * [identifier] (with the given [name]) resolved to, remove from the list all
7465 * of the names defined in the SDK and return the element(s) that remain.
7466 */
7467 Element _removeSdkElements(Identifier identifier, String name,
7468 MultiplyDefinedElementImpl foundElement) {
7469 List<Element> conflictingElements = foundElement.conflictingElements;
7470 List<Element> nonSdkElements = new List<Element>();
7471 Element sdkElement = null;
7472 for (Element member in conflictingElements) {
7473 if (member.library.isInSdk) {
7474 sdkElement = member;
7475 } else {
7476 nonSdkElements.add(member);
7477 }
7478 }
7479 if (sdkElement != null && nonSdkElements.length > 0) {
7480 String sdkLibName = _getLibraryName(sdkElement);
7481 String otherLibName = _getLibraryName(nonSdkElements[0]);
7482 errorListener.onError(new AnalysisError(
7483 getSource(identifier),
7484 identifier.offset,
7485 identifier.length,
7486 StaticWarningCode.CONFLICTING_DART_IMPORT,
7487 [name, sdkLibName, otherLibName]));
7488 }
7489 if (nonSdkElements.length == conflictingElements.length) {
7490 // None of the members were removed
7491 return foundElement;
7492 } else if (nonSdkElements.length == 1) {
7493 // All but one member was removed
7494 return nonSdkElements[0];
7495 } else if (nonSdkElements.length == 0) {
7496 // All members were removed
7497 AnalysisEngine.instance.logger
7498 .logInformation("Multiply defined SDK element: $foundElement");
7499 return foundElement;
7500 }
7501 return new MultiplyDefinedElementImpl(
7502 _definingLibrary.context, nonSdkElements);
7503 }
7504 }
7505
7506 /**
7507 * Instances of the class `LibraryResolver` are used to resolve one or more mutu ally dependent
7508 * libraries within a single context.
7509 */
7510 class LibraryResolver {
7511 /**
7512 * The analysis context in which the libraries are being analyzed.
7513 */
7514 final InternalAnalysisContext analysisContext;
7515
7516 /**
7517 * The listener to which analysis errors will be reported, this error listener is either
7518 * references [recordingErrorListener], or it unions the passed
7519 * [AnalysisErrorListener] with the [recordingErrorListener].
7520 */
7521 RecordingErrorListener _errorListener;
7522
7523 /**
7524 * A source object representing the core library (dart:core).
7525 */
7526 Source _coreLibrarySource;
7527
7528 /**
7529 * A Source object representing the async library (dart:async).
7530 */
7531 Source _asyncLibrarySource;
7532
7533 /**
7534 * The object representing the core library.
7535 */
7536 Library _coreLibrary;
7537
7538 /**
7539 * The object representing the async library.
7540 */
7541 Library _asyncLibrary;
7542
7543 /**
7544 * The object used to access the types from the core library.
7545 */
7546 TypeProvider _typeProvider;
7547
7548 /**
7549 * A table mapping library sources to the information being maintained for tho se libraries.
7550 */
7551 HashMap<Source, Library> _libraryMap = new HashMap<Source, Library>();
7552
7553 /**
7554 * A collection containing the libraries that are being resolved together.
7555 */
7556 Set<Library> _librariesInCycles;
7557
7558 /**
7559 * Initialize a newly created library resolver to resolve libraries within the given context.
7560 *
7561 * @param analysisContext the analysis context in which the library is being a nalyzed
7562 */
7563 LibraryResolver(this.analysisContext) {
7564 this._errorListener = new RecordingErrorListener();
7565 _coreLibrarySource =
7566 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE);
7567 _asyncLibrarySource =
7568 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC);
7569 }
7570
7571 /**
7572 * Return the listener to which analysis errors will be reported.
7573 *
7574 * @return the listener to which analysis errors will be reported
7575 */
7576 RecordingErrorListener get errorListener => _errorListener;
7577
7578 /**
7579 * Return an array containing information about all of the libraries that were resolved.
7580 *
7581 * @return an array containing the libraries that were resolved
7582 */
7583 Set<Library> get resolvedLibraries => _librariesInCycles;
7584
7585 /**
7586 * The object used to access the types from the core library.
7587 */
7588 TypeProvider get typeProvider => _typeProvider;
7589
7590 /**
7591 * Create an object to represent the information about the library defined by the compilation unit
7592 * with the given source.
7593 *
7594 * @param librarySource the source of the library's defining compilation unit
7595 * @return the library object that was created
7596 * @throws AnalysisException if the library source is not valid
7597 */
7598 Library createLibrary(Source librarySource) {
7599 Library library =
7600 new Library(analysisContext, _errorListener, librarySource);
7601 _libraryMap[librarySource] = library;
7602 return library;
7603 }
7604
7605 /**
7606 * Resolve the library specified by the given source in the given context. The library is assumed
7607 * to be embedded in the given source.
7608 *
7609 * @param librarySource the source specifying the defining compilation unit of the library to be
7610 * resolved
7611 * @param unit the compilation unit representing the embedded library
7612 * @param fullAnalysis `true` if a full analysis should be performed
7613 * @return the element representing the resolved library
7614 * @throws AnalysisException if the library could not be resolved for some rea son
7615 */
7616 LibraryElement resolveEmbeddedLibrary(
7617 Source librarySource, CompilationUnit unit, bool fullAnalysis) {
7618 //
7619 // Create the objects representing the library being resolved and the core
7620 // library.
7621 //
7622 Library targetLibrary = _createLibraryWithUnit(librarySource, unit);
7623 _coreLibrary = _libraryMap[_coreLibrarySource];
7624 if (_coreLibrary == null) {
7625 // This will only happen if the library being analyzed is the core
7626 // library.
7627 _coreLibrary = createLibrary(_coreLibrarySource);
7628 if (_coreLibrary == null) {
7629 LibraryResolver2.missingCoreLibrary(
7630 analysisContext, _coreLibrarySource);
7631 }
7632 }
7633 _asyncLibrary = _libraryMap[_asyncLibrarySource];
7634 if (_asyncLibrary == null) {
7635 // This will only happen if the library being analyzed is the async
7636 // library.
7637 _asyncLibrary = createLibrary(_asyncLibrarySource);
7638 if (_asyncLibrary == null) {
7639 LibraryResolver2.missingAsyncLibrary(
7640 analysisContext, _asyncLibrarySource);
7641 }
7642 }
7643 //
7644 // Compute the set of libraries that need to be resolved together.
7645 //
7646 _computeEmbeddedLibraryDependencies(targetLibrary, unit);
7647 _librariesInCycles = _computeLibrariesInCycles(targetLibrary);
7648 //
7649 // Build the element models representing the libraries being resolved.
7650 // This is done in three steps:
7651 //
7652 // 1. Build the basic element models without making any connections
7653 // between elements other than the basic parent/child relationships.
7654 // This includes building the elements representing the libraries.
7655 // 2. Build the elements for the import and export directives. This
7656 // requires that we have the elements built for the referenced
7657 // libraries, but because of the possibility of circular references
7658 // needs to happen after all of the library elements have been created.
7659 // 3. Build the rest of the type model by connecting superclasses, mixins,
7660 // and interfaces. This requires that we be able to compute the names
7661 // visible in the libraries being resolved, which in turn requires that
7662 // we have resolved the import directives.
7663 //
7664 _buildElementModels();
7665 LibraryElement coreElement = _coreLibrary.libraryElement;
7666 if (coreElement == null) {
7667 throw new AnalysisException("Could not resolve dart:core");
7668 }
7669 LibraryElement asyncElement = _asyncLibrary.libraryElement;
7670 if (asyncElement == null) {
7671 throw new AnalysisException("Could not resolve dart:async");
7672 }
7673 _buildDirectiveModels();
7674 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
7675 _buildTypeHierarchies();
7676 //
7677 // Perform resolution and type analysis.
7678 //
7679 // TODO(brianwilkerson) Decide whether we want to resolve all of the
7680 // libraries or whether we want to only resolve the target library.
7681 // The advantage to resolving everything is that we have already done part
7682 // of the work so we'll avoid duplicated effort. The disadvantage of
7683 // resolving everything is that we might do extra work that we don't
7684 // really care about. Another possibility is to add a parameter to this
7685 // method and punt the decision to the clients.
7686 //
7687 //if (analyzeAll) {
7688 resolveReferencesAndTypes();
7689 //} else {
7690 // resolveReferencesAndTypes(targetLibrary);
7691 //}
7692 _performConstantEvaluation();
7693 return targetLibrary.libraryElement;
7694 }
7695
7696 /**
7697 * Resolve the library specified by the given source in the given context.
7698 *
7699 * Note that because Dart allows circular imports between libraries, it is pos sible that more than
7700 * one library will need to be resolved. In such cases the error listener can receive errors from
7701 * multiple libraries.
7702 *
7703 * @param librarySource the source specifying the defining compilation unit of the library to be
7704 * resolved
7705 * @param fullAnalysis `true` if a full analysis should be performed
7706 * @return the element representing the resolved library
7707 * @throws AnalysisException if the library could not be resolved for some rea son
7708 */
7709 LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) {
7710 //
7711 // Create the object representing the library being resolved and compute
7712 // the dependency relationship. Note that all libraries depend implicitly
7713 // on core, and we inject an ersatz dependency on async, so once this is
7714 // done the core and async library elements will have been created.
7715 //
7716 Library targetLibrary = createLibrary(librarySource);
7717 _computeLibraryDependencies(targetLibrary);
7718 _coreLibrary = _libraryMap[_coreLibrarySource];
7719 _asyncLibrary = _libraryMap[_asyncLibrarySource];
7720 //
7721 // Compute the set of libraries that need to be resolved together.
7722 //
7723 _librariesInCycles = _computeLibrariesInCycles(targetLibrary);
7724 //
7725 // Build the element models representing the libraries being resolved.
7726 // This is done in three steps:
7727 //
7728 // 1. Build the basic element models without making any connections
7729 // between elements other than the basic parent/child relationships.
7730 // This includes building the elements representing the libraries, but
7731 // excludes members defined in enums.
7732 // 2. Build the elements for the import and export directives. This
7733 // requires that we have the elements built for the referenced
7734 // libraries, but because of the possibility of circular references
7735 // needs to happen after all of the library elements have been created.
7736 // 3. Build the members in enum declarations.
7737 // 4. Build the rest of the type model by connecting superclasses, mixins,
7738 // and interfaces. This requires that we be able to compute the names
7739 // visible in the libraries being resolved, which in turn requires that
7740 // we have resolved the import directives.
7741 //
7742 _buildElementModels();
7743 LibraryElement coreElement = _coreLibrary.libraryElement;
7744 if (coreElement == null) {
7745 throw new AnalysisException("Could not resolve dart:core");
7746 }
7747 LibraryElement asyncElement = _asyncLibrary.libraryElement;
7748 if (asyncElement == null) {
7749 throw new AnalysisException("Could not resolve dart:async");
7750 }
7751 _buildDirectiveModels();
7752 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
7753 _buildEnumMembers();
7754 _buildTypeHierarchies();
7755 //
7756 // Perform resolution and type analysis.
7757 //
7758 // TODO(brianwilkerson) Decide whether we want to resolve all of the
7759 // libraries or whether we want to only resolve the target library. The
7760 // advantage to resolving everything is that we have already done part of
7761 // the work so we'll avoid duplicated effort. The disadvantage of
7762 // resolving everything is that we might do extra work that we don't
7763 // really care about. Another possibility is to add a parameter to this
7764 // method and punt the decision to the clients.
7765 //
7766 //if (analyzeAll) {
7767 resolveReferencesAndTypes();
7768 //} else {
7769 // resolveReferencesAndTypes(targetLibrary);
7770 //}
7771 _performConstantEvaluation();
7772 return targetLibrary.libraryElement;
7773 }
7774
7775 /**
7776 * Resolve the identifiers and perform type analysis in the libraries in the c urrent cycle.
7777 *
7778 * @throws AnalysisException if any of the identifiers could not be resolved o r if any of the
7779 * libraries could not have their types analyzed
7780 */
7781 void resolveReferencesAndTypes() {
7782 for (Library library in _librariesInCycles) {
7783 _resolveReferencesAndTypesInLibrary(library);
7784 }
7785 }
7786
7787 /**
7788 * Add a dependency to the given map from the referencing library to the refer enced library.
7789 *
7790 * @param dependencyMap the map to which the dependency is to be added
7791 * @param referencingLibrary the library that references the referenced librar y
7792 * @param referencedLibrary the library referenced by the referencing library
7793 */
7794 void _addDependencyToMap(HashMap<Library, List<Library>> dependencyMap,
7795 Library referencingLibrary, Library referencedLibrary) {
7796 List<Library> dependentLibraries = dependencyMap[referencedLibrary];
7797 if (dependentLibraries == null) {
7798 dependentLibraries = new List<Library>();
7799 dependencyMap[referencedLibrary] = dependentLibraries;
7800 }
7801 dependentLibraries.add(referencingLibrary);
7802 }
7803
7804 /**
7805 * Given a library that is part of a cycle that includes the root library, add to the given set of
7806 * libraries all of the libraries reachable from the root library that are als o included in the
7807 * cycle.
7808 *
7809 * @param library the library to be added to the collection of libraries in cy cles
7810 * @param librariesInCycle a collection of the libraries that are in the cycle
7811 * @param dependencyMap a table mapping libraries to the collection of librari es from which those
7812 * libraries are referenced
7813 */
7814 void _addLibrariesInCycle(Library library, Set<Library> librariesInCycle,
7815 HashMap<Library, List<Library>> dependencyMap) {
7816 if (librariesInCycle.add(library)) {
7817 List<Library> dependentLibraries = dependencyMap[library];
7818 if (dependentLibraries != null) {
7819 for (Library dependentLibrary in dependentLibraries) {
7820 _addLibrariesInCycle(
7821 dependentLibrary, librariesInCycle, dependencyMap);
7822 }
7823 }
7824 }
7825 }
7826
7827 /**
7828 * Add the given library, and all libraries reachable from it that have not al ready been visited,
7829 * to the given dependency map.
7830 *
7831 * @param library the library currently being added to the dependency map
7832 * @param dependencyMap the dependency map being computed
7833 * @param visitedLibraries the libraries that have already been visited, used to prevent infinite
7834 * recursion
7835 */
7836 void _addToDependencyMap(
7837 Library library,
7838 HashMap<Library, List<Library>> dependencyMap,
7839 Set<Library> visitedLibraries) {
7840 if (visitedLibraries.add(library)) {
7841 bool asyncFound = false;
7842 for (Library referencedLibrary in library.importsAndExports) {
7843 _addDependencyToMap(dependencyMap, library, referencedLibrary);
7844 _addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries);
7845 if (identical(referencedLibrary, _asyncLibrary)) {
7846 asyncFound = true;
7847 }
7848 }
7849 if (!library.explicitlyImportsCore && !identical(library, _coreLibrary)) {
7850 _addDependencyToMap(dependencyMap, library, _coreLibrary);
7851 }
7852 if (!asyncFound && !identical(library, _asyncLibrary)) {
7853 _addDependencyToMap(dependencyMap, library, _asyncLibrary);
7854 _addToDependencyMap(_asyncLibrary, dependencyMap, visitedLibraries);
7855 }
7856 }
7857 }
7858
7859 /**
7860 * Build the element model representing the combinators declared by the given directive.
7861 *
7862 * @param directive the directive that declares the combinators
7863 * @return an array containing the import combinators that were built
7864 */
7865 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) {
7866 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>();
7867 for (Combinator combinator in directive.combinators) {
7868 if (combinator is HideCombinator) {
7869 HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
7870 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames);
7871 combinators.add(hide);
7872 } else {
7873 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
7874 show.offset = combinator.offset;
7875 show.end = combinator.end;
7876 show.shownNames =
7877 _getIdentifiers((combinator as ShowCombinator).shownNames);
7878 combinators.add(show);
7879 }
7880 }
7881 return combinators;
7882 }
7883
7884 /**
7885 * Every library now has a corresponding [LibraryElement], so it is now possib le to resolve
7886 * the import and export directives.
7887 *
7888 * @throws AnalysisException if the defining compilation unit for any of the l ibraries could not
7889 * be accessed
7890 */
7891 void _buildDirectiveModels() {
7892 for (Library library in _librariesInCycles) {
7893 HashMap<String, PrefixElementImpl> nameToPrefixMap =
7894 new HashMap<String, PrefixElementImpl>();
7895 List<ImportElement> imports = new List<ImportElement>();
7896 List<ExportElement> exports = new List<ExportElement>();
7897 for (Directive directive in library.definingCompilationUnit.directives) {
7898 if (directive is ImportDirective) {
7899 ImportDirective importDirective = directive;
7900 String uriContent = importDirective.uriContent;
7901 if (DartUriResolver.isDartExtUri(uriContent)) {
7902 library.libraryElement.hasExtUri = true;
7903 }
7904 Source importedSource = importDirective.source;
7905 if (importedSource != null) {
7906 // The imported source will be null if the URI in the import
7907 // directive was invalid.
7908 Library importedLibrary = _libraryMap[importedSource];
7909 if (importedLibrary != null) {
7910 ImportElementImpl importElement =
7911 new ImportElementImpl(directive.offset);
7912 StringLiteral uriLiteral = importDirective.uri;
7913 importElement.uriOffset = uriLiteral.offset;
7914 importElement.uriEnd = uriLiteral.end;
7915 importElement.uri = uriContent;
7916 importElement.deferred = importDirective.deferredKeyword != null;
7917 importElement.combinators = _buildCombinators(importDirective);
7918 LibraryElement importedLibraryElement =
7919 importedLibrary.libraryElement;
7920 if (importedLibraryElement != null) {
7921 importElement.importedLibrary = importedLibraryElement;
7922 }
7923 SimpleIdentifier prefixNode = directive.prefix;
7924 if (prefixNode != null) {
7925 importElement.prefixOffset = prefixNode.offset;
7926 String prefixName = prefixNode.name;
7927 PrefixElementImpl prefix = nameToPrefixMap[prefixName];
7928 if (prefix == null) {
7929 prefix = new PrefixElementImpl.forNode(prefixNode);
7930 nameToPrefixMap[prefixName] = prefix;
7931 }
7932 importElement.prefix = prefix;
7933 prefixNode.staticElement = prefix;
7934 }
7935 directive.element = importElement;
7936 imports.add(importElement);
7937 if (analysisContext.computeKindOf(importedSource) !=
7938 SourceKind.LIBRARY) {
7939 ErrorCode errorCode = (importElement.isDeferred
7940 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
7941 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
7942 _errorListener.onError(new AnalysisError(
7943 library.librarySource,
7944 uriLiteral.offset,
7945 uriLiteral.length,
7946 errorCode,
7947 [uriLiteral.toSource()]));
7948 }
7949 }
7950 }
7951 } else if (directive is ExportDirective) {
7952 ExportDirective exportDirective = directive;
7953 Source exportedSource = exportDirective.source;
7954 if (exportedSource != null) {
7955 // The exported source will be null if the URI in the export
7956 // directive was invalid.
7957 Library exportedLibrary = _libraryMap[exportedSource];
7958 if (exportedLibrary != null) {
7959 ExportElementImpl exportElement =
7960 new ExportElementImpl(directive.offset);
7961 StringLiteral uriLiteral = exportDirective.uri;
7962 exportElement.uriOffset = uriLiteral.offset;
7963 exportElement.uriEnd = uriLiteral.end;
7964 exportElement.uri = exportDirective.uriContent;
7965 exportElement.combinators = _buildCombinators(exportDirective);
7966 LibraryElement exportedLibraryElement =
7967 exportedLibrary.libraryElement;
7968 if (exportedLibraryElement != null) {
7969 exportElement.exportedLibrary = exportedLibraryElement;
7970 }
7971 directive.element = exportElement;
7972 exports.add(exportElement);
7973 if (analysisContext.computeKindOf(exportedSource) !=
7974 SourceKind.LIBRARY) {
7975 _errorListener.onError(new AnalysisError(
7976 library.librarySource,
7977 uriLiteral.offset,
7978 uriLiteral.length,
7979 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
7980 [uriLiteral.toSource()]));
7981 }
7982 }
7983 }
7984 }
7985 }
7986 Source librarySource = library.librarySource;
7987 if (!library.explicitlyImportsCore &&
7988 _coreLibrarySource != librarySource) {
7989 ImportElementImpl importElement = new ImportElementImpl(-1);
7990 importElement.importedLibrary = _coreLibrary.libraryElement;
7991 importElement.synthetic = true;
7992 imports.add(importElement);
7993 }
7994 LibraryElementImpl libraryElement = library.libraryElement;
7995 libraryElement.imports = imports;
7996 libraryElement.exports = exports;
7997 if (libraryElement.entryPoint == null) {
7998 Namespace namespace = new NamespaceBuilder()
7999 .createExportNamespaceForLibrary(libraryElement);
8000 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME);
8001 if (element is FunctionElement) {
8002 libraryElement.entryPoint = element;
8003 }
8004 }
8005 }
8006 }
8007
8008 /**
8009 * Build element models for all of the libraries in the current cycle.
8010 *
8011 * @throws AnalysisException if any of the element models cannot be built
8012 */
8013 void _buildElementModels() {
8014 for (Library library in _librariesInCycles) {
8015 LibraryElementBuilder builder =
8016 new LibraryElementBuilder(analysisContext, errorListener);
8017 LibraryElementImpl libraryElement = builder.buildLibrary(library);
8018 library.libraryElement = libraryElement;
8019 }
8020 }
8021
8022 /**
8023 * Build the members in enum declarations. This cannot be done while building the rest of the
8024 * element model because it depends on being able to access core types, which cannot happen until
8025 * the rest of the element model has been built (when resolving the core libra ry).
8026 *
8027 * @throws AnalysisException if any of the enum members could not be built
8028 */
8029 void _buildEnumMembers() {
8030 PerformanceStatistics.resolve.makeCurrentWhile(() {
8031 for (Library library in _librariesInCycles) {
8032 for (Source source in library.compilationUnitSources) {
8033 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider);
8034 library.getAST(source).accept(builder);
8035 }
8036 }
8037 });
8038 }
8039
8040 /**
8041 * Resolve the type hierarchy across all of the types declared in the librarie s in the current
8042 * cycle.
8043 *
8044 * @throws AnalysisException if any of the type hierarchies could not be resol ved
8045 */
8046 void _buildTypeHierarchies() {
8047 PerformanceStatistics.resolve.makeCurrentWhile(() {
8048 for (Library library in _librariesInCycles) {
8049 for (Source source in library.compilationUnitSources) {
8050 TypeResolverVisitorFactory typeResolverVisitorFactory =
8051 analysisContext.typeResolverVisitorFactory;
8052 TypeResolverVisitor visitor = (typeResolverVisitorFactory == null)
8053 ? new TypeResolverVisitor(library.libraryElement, source,
8054 _typeProvider, library.errorListener,
8055 nameScope: library.libraryScope)
8056 : typeResolverVisitorFactory(library, source, _typeProvider);
8057 library.getAST(source).accept(visitor);
8058 }
8059 }
8060 });
8061 }
8062
8063 /**
8064 * Compute a dependency map of libraries reachable from the given library. A d ependency map is a
8065 * table that maps individual libraries to a list of the libraries that either import or export
8066 * those libraries.
8067 *
8068 * This map is used to compute all of the libraries involved in a cycle that i nclude the root
8069 * library. Given that we only add libraries that are reachable from the root library, when we
8070 * work backward we are guaranteed to only get libraries in the cycle.
8071 *
8072 * @param library the library currently being added to the dependency map
8073 */
8074 HashMap<Library, List<Library>> _computeDependencyMap(Library library) {
8075 HashMap<Library, List<Library>> dependencyMap =
8076 new HashMap<Library, List<Library>>();
8077 _addToDependencyMap(library, dependencyMap, new HashSet<Library>());
8078 return dependencyMap;
8079 }
8080
8081 /**
8082 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8083 * class [Library] to represent them, and record the references in the library objects.
8084 *
8085 * @param library the library to be processed to find libraries that have not yet been traversed
8086 * @throws AnalysisException if some portion of the library graph could not be traversed
8087 */
8088 void _computeEmbeddedLibraryDependencies(
8089 Library library, CompilationUnit unit) {
8090 Source librarySource = library.librarySource;
8091 HashSet<Source> exportedSources = new HashSet<Source>();
8092 HashSet<Source> importedSources = new HashSet<Source>();
8093 for (Directive directive in unit.directives) {
8094 if (directive is ExportDirective) {
8095 Source exportSource = _resolveSource(librarySource, directive);
8096 if (exportSource != null) {
8097 exportedSources.add(exportSource);
8098 }
8099 } else if (directive is ImportDirective) {
8100 Source importSource = _resolveSource(librarySource, directive);
8101 if (importSource != null) {
8102 importedSources.add(importSource);
8103 }
8104 }
8105 }
8106 _computeLibraryDependenciesFromDirectives(library,
8107 new List.from(importedSources), new List.from(exportedSources));
8108 }
8109
8110 /**
8111 * Return a collection containing all of the libraries reachable from the give n library that are
8112 * contained in a cycle that includes the given library.
8113 *
8114 * @param library the library that must be included in any cycles whose member s are to be returned
8115 * @return all of the libraries referenced by the given library that have a ci rcular reference
8116 * back to the given library
8117 */
8118 Set<Library> _computeLibrariesInCycles(Library library) {
8119 HashMap<Library, List<Library>> dependencyMap =
8120 _computeDependencyMap(library);
8121 Set<Library> librariesInCycle = new HashSet<Library>();
8122 _addLibrariesInCycle(library, librariesInCycle, dependencyMap);
8123 return librariesInCycle;
8124 }
8125
8126 /**
8127 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8128 * class [Library] to represent them, and record the references in the library objects.
8129 *
8130 * @param library the library to be processed to find libraries that have not yet been traversed
8131 * @throws AnalysisException if some portion of the library graph could not be traversed
8132 */
8133 void _computeLibraryDependencies(Library library) {
8134 Source librarySource = library.librarySource;
8135 _computeLibraryDependenciesFromDirectives(
8136 library,
8137 analysisContext.computeImportedLibraries(librarySource),
8138 analysisContext.computeExportedLibraries(librarySource));
8139 }
8140
8141 /**
8142 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8143 * class [Library] to represent them, and record the references in the library objects.
8144 *
8145 * @param library the library to be processed to find libraries that have not yet been traversed
8146 * @param importedSources an array containing the sources that are imported in to the given library
8147 * @param exportedSources an array containing the sources that are exported fr om the given library
8148 * @throws AnalysisException if some portion of the library graph could not be traversed
8149 */
8150 void _computeLibraryDependenciesFromDirectives(Library library,
8151 List<Source> importedSources, List<Source> exportedSources) {
8152 List<Library> importedLibraries = new List<Library>();
8153 bool explicitlyImportsCore = false;
8154 bool importsAsync = false;
8155 for (Source importedSource in importedSources) {
8156 if (importedSource == _coreLibrarySource) {
8157 explicitlyImportsCore = true;
8158 }
8159 if (importedSource == _asyncLibrarySource) {
8160 importsAsync = true;
8161 }
8162 Library importedLibrary = _libraryMap[importedSource];
8163 if (importedLibrary == null) {
8164 importedLibrary = _createLibraryOrNull(importedSource);
8165 if (importedLibrary != null) {
8166 _computeLibraryDependencies(importedLibrary);
8167 }
8168 }
8169 if (importedLibrary != null) {
8170 importedLibraries.add(importedLibrary);
8171 }
8172 }
8173 library.importedLibraries = importedLibraries;
8174 List<Library> exportedLibraries = new List<Library>();
8175 for (Source exportedSource in exportedSources) {
8176 Library exportedLibrary = _libraryMap[exportedSource];
8177 if (exportedLibrary == null) {
8178 exportedLibrary = _createLibraryOrNull(exportedSource);
8179 if (exportedLibrary != null) {
8180 _computeLibraryDependencies(exportedLibrary);
8181 }
8182 }
8183 if (exportedLibrary != null) {
8184 exportedLibraries.add(exportedLibrary);
8185 }
8186 }
8187 library.exportedLibraries = exportedLibraries;
8188 library.explicitlyImportsCore = explicitlyImportsCore;
8189 if (!explicitlyImportsCore && _coreLibrarySource != library.librarySource) {
8190 Library importedLibrary = _libraryMap[_coreLibrarySource];
8191 if (importedLibrary == null) {
8192 importedLibrary = _createLibraryOrNull(_coreLibrarySource);
8193 if (importedLibrary != null) {
8194 _computeLibraryDependencies(importedLibrary);
8195 }
8196 }
8197 }
8198 if (!importsAsync && _asyncLibrarySource != library.librarySource) {
8199 Library importedLibrary = _libraryMap[_asyncLibrarySource];
8200 if (importedLibrary == null) {
8201 importedLibrary = _createLibraryOrNull(_asyncLibrarySource);
8202 if (importedLibrary != null) {
8203 _computeLibraryDependencies(importedLibrary);
8204 }
8205 }
8206 }
8207 }
8208
8209 /**
8210 * Create an object to represent the information about the library defined by the compilation unit
8211 * with the given source. Return the library object that was created, or `null ` if the
8212 * source is not valid.
8213 *
8214 * @param librarySource the source of the library's defining compilation unit
8215 * @return the library object that was created
8216 */
8217 Library _createLibraryOrNull(Source librarySource) {
8218 if (!analysisContext.exists(librarySource)) {
8219 return null;
8220 }
8221 Library library =
8222 new Library(analysisContext, _errorListener, librarySource);
8223 _libraryMap[librarySource] = library;
8224 return library;
8225 }
8226
8227 /**
8228 * Create an object to represent the information about the library defined by the compilation unit
8229 * with the given source.
8230 *
8231 * @param librarySource the source of the library's defining compilation unit
8232 * @param unit the compilation unit that defines the library
8233 * @return the library object that was created
8234 * @throws AnalysisException if the library source is not valid
8235 */
8236 Library _createLibraryWithUnit(Source librarySource, CompilationUnit unit) {
8237 Library library =
8238 new Library(analysisContext, _errorListener, librarySource);
8239 library.setDefiningCompilationUnit(unit);
8240 _libraryMap[librarySource] = library;
8241 return library;
8242 }
8243
8244 /**
8245 * Return an array containing the lexical identifiers associated with the node s in the given list.
8246 *
8247 * @param names the AST nodes representing the identifiers
8248 * @return the lexical identifiers associated with the nodes in the list
8249 */
8250 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) {
8251 int count = names.length;
8252 List<String> identifiers = new List<String>(count);
8253 for (int i = 0; i < count; i++) {
8254 identifiers[i] = names[i].name;
8255 }
8256 return identifiers;
8257 }
8258
8259 /**
8260 * Compute a value for all of the constants in the libraries being analyzed.
8261 */
8262 void _performConstantEvaluation() {
8263 PerformanceStatistics.resolve.makeCurrentWhile(() {
8264 ConstantValueComputer computer = new ConstantValueComputer(
8265 analysisContext, _typeProvider, analysisContext.declaredVariables);
8266 for (Library library in _librariesInCycles) {
8267 for (Source source in library.compilationUnitSources) {
8268 try {
8269 CompilationUnit unit = library.getAST(source);
8270 if (unit != null) {
8271 computer.add(unit, source, library.librarySource);
8272 }
8273 } on AnalysisException catch (exception, stackTrace) {
8274 AnalysisEngine.instance.logger.logError(
8275 "Internal Error: Could not access AST for ${source.fullName} dur ing constant evaluation",
8276 new CaughtException(exception, stackTrace));
8277 }
8278 }
8279 }
8280 computer.computeValues();
8281 // As a temporary workaround for issue 21572, run ConstantVerifier now.
8282 // TODO(paulberry): remove this workaround once issue 21572 is fixed.
8283 for (Library library in _librariesInCycles) {
8284 for (Source source in library.compilationUnitSources) {
8285 try {
8286 CompilationUnit unit = library.getAST(source);
8287 ErrorReporter errorReporter =
8288 new ErrorReporter(_errorListener, source);
8289 ConstantVerifier constantVerifier = new ConstantVerifier(
8290 errorReporter,
8291 library.libraryElement,
8292 _typeProvider,
8293 analysisContext.declaredVariables);
8294 unit.accept(constantVerifier);
8295 } on AnalysisException catch (exception, stackTrace) {
8296 AnalysisEngine.instance.logger.logError(
8297 "Internal Error: Could not access AST for ${source.fullName} "
8298 "during constant verification",
8299 new CaughtException(exception, stackTrace));
8300 }
8301 }
8302 }
8303 });
8304 }
8305
8306 /**
8307 * Resolve the identifiers and perform type analysis in the given library.
8308 *
8309 * @param library the library to be resolved
8310 * @throws AnalysisException if any of the identifiers could not be resolved o r if the types in
8311 * the library cannot be analyzed
8312 */
8313 void _resolveReferencesAndTypesInLibrary(Library library) {
8314 PerformanceStatistics.resolve.makeCurrentWhile(() {
8315 for (Source source in library.compilationUnitSources) {
8316 CompilationUnit ast = library.getAST(source);
8317 ast.accept(new VariableResolverVisitor(library.libraryElement, source,
8318 _typeProvider, library.errorListener,
8319 nameScope: library.libraryScope));
8320 ResolverVisitorFactory visitorFactory =
8321 analysisContext.resolverVisitorFactory;
8322 ResolverVisitor visitor = visitorFactory != null
8323 ? visitorFactory(library, source, _typeProvider)
8324 : new ResolverVisitor(library.libraryElement, source, _typeProvider,
8325 library.errorListener,
8326 nameScope: library.libraryScope,
8327 inheritanceManager: library.inheritanceManager);
8328 ast.accept(visitor);
8329 }
8330 });
8331 }
8332
8333 /**
8334 * Return the result of resolving the URI of the given URI-based directive aga inst the URI of the
8335 * given library, or `null` if the URI is not valid.
8336 *
8337 * @param librarySource the source representing the library containing the dir ective
8338 * @param directive the directive which URI should be resolved
8339 * @return the result of resolving the URI against the URI of the library
8340 */
8341 Source _resolveSource(Source librarySource, UriBasedDirective directive) {
8342 StringLiteral uriLiteral = directive.uri;
8343 if (uriLiteral is StringInterpolation) {
8344 return null;
8345 }
8346 String uriContent = uriLiteral.stringValue.trim();
8347 if (uriContent == null || uriContent.isEmpty) {
8348 return null;
8349 }
8350 uriContent = Uri.encodeFull(uriContent);
8351 return analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
8352 }
8353 }
8354
8355 /**
8356 * Instances of the class `LibraryResolver` are used to resolve one or more mutu ally dependent
8357 * libraries within a single context.
8358 */
8359 class LibraryResolver2 {
8360 /**
8361 * The analysis context in which the libraries are being analyzed.
8362 */
8363 final InternalAnalysisContext analysisContext;
8364
8365 /**
8366 * The listener to which analysis errors will be reported, this error listener is either
8367 * references [recordingErrorListener], or it unions the passed
8368 * [AnalysisErrorListener] with the [recordingErrorListener].
8369 */
8370 RecordingErrorListener _errorListener;
8371
8372 /**
8373 * A source object representing the core library (dart:core).
8374 */
8375 Source _coreLibrarySource;
8376
8377 /**
8378 * A source object representing the async library (dart:async).
8379 */
8380 Source _asyncLibrarySource;
8381
8382 /**
8383 * The object representing the core library.
8384 */
8385 ResolvableLibrary _coreLibrary;
8386
8387 /**
8388 * The object representing the async library.
8389 */
8390 ResolvableLibrary _asyncLibrary;
8391
8392 /**
8393 * The object used to access the types from the core library.
8394 */
8395 TypeProvider _typeProvider;
8396
8397 /**
8398 * A table mapping library sources to the information being maintained for tho se libraries.
8399 */
8400 HashMap<Source, ResolvableLibrary> _libraryMap =
8401 new HashMap<Source, ResolvableLibrary>();
8402
8403 /**
8404 * A collection containing the libraries that are being resolved together.
8405 */
8406 List<ResolvableLibrary> _librariesInCycle;
8407
8408 /**
8409 * Initialize a newly created library resolver to resolve libraries within the given context.
8410 *
8411 * @param analysisContext the analysis context in which the library is being a nalyzed
8412 */
8413 LibraryResolver2(this.analysisContext) {
8414 this._errorListener = new RecordingErrorListener();
8415 _coreLibrarySource =
8416 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE);
8417 _asyncLibrarySource =
8418 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC);
8419 }
8420
8421 /**
8422 * Return the listener to which analysis errors will be reported.
8423 *
8424 * @return the listener to which analysis errors will be reported
8425 */
8426 RecordingErrorListener get errorListener => _errorListener;
8427
8428 /**
8429 * Return an array containing information about all of the libraries that were resolved.
8430 *
8431 * @return an array containing the libraries that were resolved
8432 */
8433 List<ResolvableLibrary> get resolvedLibraries => _librariesInCycle;
8434
8435 /**
8436 * Resolve the library specified by the given source in the given context.
8437 *
8438 * Note that because Dart allows circular imports between libraries, it is pos sible that more than
8439 * one library will need to be resolved. In such cases the error listener can receive errors from
8440 * multiple libraries.
8441 *
8442 * @param librarySource the source specifying the defining compilation unit of the library to be
8443 * resolved
8444 * @param fullAnalysis `true` if a full analysis should be performed
8445 * @return the element representing the resolved library
8446 * @throws AnalysisException if the library could not be resolved for some rea son
8447 */
8448 LibraryElement resolveLibrary(
8449 Source librarySource, List<ResolvableLibrary> librariesInCycle) {
8450 //
8451 // Build the map of libraries that are known.
8452 //
8453 this._librariesInCycle = librariesInCycle;
8454 _libraryMap = _buildLibraryMap();
8455 ResolvableLibrary targetLibrary = _libraryMap[librarySource];
8456 _coreLibrary = _libraryMap[_coreLibrarySource];
8457 _asyncLibrary = _libraryMap[_asyncLibrarySource];
8458 //
8459 // Build the element models representing the libraries being resolved.
8460 // This is done in three steps:
8461 //
8462 // 1. Build the basic element models without making any connections
8463 // between elements other than the basic parent/child relationships.
8464 // This includes building the elements representing the libraries, but
8465 // excludes members defined in enums.
8466 // 2. Build the elements for the import and export directives. This
8467 // requires that we have the elements built for the referenced
8468 // libraries, but because of the possibility of circular references
8469 // needs to happen after all of the library elements have been created.
8470 // 3. Build the members in enum declarations.
8471 // 4. Build the rest of the type model by connecting superclasses, mixins,
8472 // and interfaces. This requires that we be able to compute the names
8473 // visible in the libraries being resolved, which in turn requires that
8474 // we have resolved the import directives.
8475 //
8476 _buildElementModels();
8477 LibraryElement coreElement = _coreLibrary.libraryElement;
8478 if (coreElement == null) {
8479 missingCoreLibrary(analysisContext, _coreLibrarySource);
8480 }
8481 LibraryElement asyncElement = _asyncLibrary.libraryElement;
8482 if (asyncElement == null) {
8483 missingAsyncLibrary(analysisContext, _asyncLibrarySource);
8484 }
8485 _buildDirectiveModels();
8486 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
8487 _buildEnumMembers();
8488 _buildTypeHierarchies();
8489 //
8490 // Perform resolution and type analysis.
8491 //
8492 // TODO(brianwilkerson) Decide whether we want to resolve all of the
8493 // libraries or whether we want to only resolve the target library. The
8494 // advantage to resolving everything is that we have already done part of
8495 // the work so we'll avoid duplicated effort. The disadvantage of
8496 // resolving everything is that we might do extra work that we don't
8497 // really care about. Another possibility is to add a parameter to this
8498 // method and punt the decision to the clients.
8499 //
8500 //if (analyzeAll) {
8501 _resolveReferencesAndTypes();
8502 //} else {
8503 // resolveReferencesAndTypes(targetLibrary);
8504 //}
8505 _performConstantEvaluation();
8506 return targetLibrary.libraryElement;
8507 }
8508
8509 /**
8510 * Build the element model representing the combinators declared by the given directive.
8511 *
8512 * @param directive the directive that declares the combinators
8513 * @return an array containing the import combinators that were built
8514 */
8515 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) {
8516 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>();
8517 for (Combinator combinator in directive.combinators) {
8518 if (combinator is HideCombinator) {
8519 HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
8520 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames);
8521 combinators.add(hide);
8522 } else {
8523 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
8524 show.offset = combinator.offset;
8525 show.end = combinator.end;
8526 show.shownNames =
8527 _getIdentifiers((combinator as ShowCombinator).shownNames);
8528 combinators.add(show);
8529 }
8530 }
8531 return combinators;
8532 }
8533
8534 /**
8535 * Every library now has a corresponding [LibraryElement], so it is now possib le to resolve
8536 * the import and export directives.
8537 *
8538 * @throws AnalysisException if the defining compilation unit for any of the l ibraries could not
8539 * be accessed
8540 */
8541 void _buildDirectiveModels() {
8542 for (ResolvableLibrary library in _librariesInCycle) {
8543 HashMap<String, PrefixElementImpl> nameToPrefixMap =
8544 new HashMap<String, PrefixElementImpl>();
8545 List<ImportElement> imports = new List<ImportElement>();
8546 List<ExportElement> exports = new List<ExportElement>();
8547 for (Directive directive in library.definingCompilationUnit.directives) {
8548 if (directive is ImportDirective) {
8549 ImportDirective importDirective = directive;
8550 String uriContent = importDirective.uriContent;
8551 if (DartUriResolver.isDartExtUri(uriContent)) {
8552 library.libraryElement.hasExtUri = true;
8553 }
8554 Source importedSource = importDirective.source;
8555 if (importedSource != null &&
8556 analysisContext.exists(importedSource)) {
8557 // The imported source will be null if the URI in the import
8558 // directive was invalid.
8559 ResolvableLibrary importedLibrary = _libraryMap[importedSource];
8560 if (importedLibrary != null) {
8561 ImportElementImpl importElement =
8562 new ImportElementImpl(directive.offset);
8563 StringLiteral uriLiteral = importDirective.uri;
8564 if (uriLiteral != null) {
8565 importElement.uriOffset = uriLiteral.offset;
8566 importElement.uriEnd = uriLiteral.end;
8567 }
8568 importElement.uri = uriContent;
8569 importElement.deferred = importDirective.deferredKeyword != null;
8570 importElement.combinators = _buildCombinators(importDirective);
8571 LibraryElement importedLibraryElement =
8572 importedLibrary.libraryElement;
8573 if (importedLibraryElement != null) {
8574 importElement.importedLibrary = importedLibraryElement;
8575 }
8576 SimpleIdentifier prefixNode = directive.prefix;
8577 if (prefixNode != null) {
8578 importElement.prefixOffset = prefixNode.offset;
8579 String prefixName = prefixNode.name;
8580 PrefixElementImpl prefix = nameToPrefixMap[prefixName];
8581 if (prefix == null) {
8582 prefix = new PrefixElementImpl.forNode(prefixNode);
8583 nameToPrefixMap[prefixName] = prefix;
8584 }
8585 importElement.prefix = prefix;
8586 prefixNode.staticElement = prefix;
8587 }
8588 directive.element = importElement;
8589 imports.add(importElement);
8590 if (analysisContext.computeKindOf(importedSource) !=
8591 SourceKind.LIBRARY) {
8592 ErrorCode errorCode = (importElement.isDeferred
8593 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
8594 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
8595 _errorListener.onError(new AnalysisError(
8596 library.librarySource,
8597 uriLiteral.offset,
8598 uriLiteral.length,
8599 errorCode,
8600 [uriLiteral.toSource()]));
8601 }
8602 }
8603 }
8604 } else if (directive is ExportDirective) {
8605 ExportDirective exportDirective = directive;
8606 Source exportedSource = exportDirective.source;
8607 if (exportedSource != null &&
8608 analysisContext.exists(exportedSource)) {
8609 // The exported source will be null if the URI in the export
8610 // directive was invalid.
8611 ResolvableLibrary exportedLibrary = _libraryMap[exportedSource];
8612 if (exportedLibrary != null) {
8613 ExportElementImpl exportElement =
8614 new ExportElementImpl(directive.offset);
8615 StringLiteral uriLiteral = exportDirective.uri;
8616 if (uriLiteral != null) {
8617 exportElement.uriOffset = uriLiteral.offset;
8618 exportElement.uriEnd = uriLiteral.end;
8619 }
8620 exportElement.uri = exportDirective.uriContent;
8621 exportElement.combinators = _buildCombinators(exportDirective);
8622 LibraryElement exportedLibraryElement =
8623 exportedLibrary.libraryElement;
8624 if (exportedLibraryElement != null) {
8625 exportElement.exportedLibrary = exportedLibraryElement;
8626 }
8627 directive.element = exportElement;
8628 exports.add(exportElement);
8629 if (analysisContext.computeKindOf(exportedSource) !=
8630 SourceKind.LIBRARY) {
8631 _errorListener.onError(new AnalysisError(
8632 library.librarySource,
8633 uriLiteral.offset,
8634 uriLiteral.length,
8635 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
8636 [uriLiteral.toSource()]));
8637 }
8638 }
8639 }
8640 }
8641 }
8642 Source librarySource = library.librarySource;
8643 if (!library.explicitlyImportsCore &&
8644 _coreLibrarySource != librarySource) {
8645 ImportElementImpl importElement = new ImportElementImpl(-1);
8646 importElement.importedLibrary = _coreLibrary.libraryElement;
8647 importElement.synthetic = true;
8648 imports.add(importElement);
8649 }
8650 LibraryElementImpl libraryElement = library.libraryElement;
8651 libraryElement.imports = imports;
8652 libraryElement.exports = exports;
8653 if (libraryElement.entryPoint == null) {
8654 Namespace namespace = new NamespaceBuilder()
8655 .createExportNamespaceForLibrary(libraryElement);
8656 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME);
8657 if (element is FunctionElement) {
8658 libraryElement.entryPoint = element;
8659 }
8660 }
8661 }
8662 }
8663
8664 /**
8665 * Build element models for all of the libraries in the current cycle.
8666 *
8667 * @throws AnalysisException if any of the element models cannot be built
8668 */
8669 void _buildElementModels() {
8670 for (ResolvableLibrary library in _librariesInCycle) {
8671 LibraryElementBuilder builder =
8672 new LibraryElementBuilder(analysisContext, errorListener);
8673 builder.buildLibrary2(library);
8674 }
8675 }
8676
8677 /**
8678 * Build the members in enum declarations. This cannot be done while building the rest of the
8679 * element model because it depends on being able to access core types, which cannot happen until
8680 * the rest of the element model has been built (when resolving the core libra ry).
8681 *
8682 * @throws AnalysisException if any of the enum members could not be built
8683 */
8684 void _buildEnumMembers() {
8685 PerformanceStatistics.resolve.makeCurrentWhile(() {
8686 for (ResolvableLibrary library in _librariesInCycle) {
8687 for (Source source in library.compilationUnitSources) {
8688 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider);
8689 library.getAST(source).accept(builder);
8690 }
8691 }
8692 });
8693 }
8694
8695 HashMap<Source, ResolvableLibrary> _buildLibraryMap() {
8696 HashMap<Source, ResolvableLibrary> libraryMap =
8697 new HashMap<Source, ResolvableLibrary>();
8698 int libraryCount = _librariesInCycle.length;
8699 for (int i = 0; i < libraryCount; i++) {
8700 ResolvableLibrary library = _librariesInCycle[i];
8701 library.errorListener = _errorListener;
8702 libraryMap[library.librarySource] = library;
8703 List<ResolvableLibrary> dependencies = library.importsAndExports;
8704 int dependencyCount = dependencies.length;
8705 for (int j = 0; j < dependencyCount; j++) {
8706 ResolvableLibrary dependency = dependencies[j];
8707 //dependency.setErrorListener(errorListener);
8708 libraryMap[dependency.librarySource] = dependency;
8709 }
8710 }
8711 return libraryMap;
8712 }
8713
8714 /**
8715 * Resolve the type hierarchy across all of the types declared in the librarie s in the current
8716 * cycle.
8717 *
8718 * @throws AnalysisException if any of the type hierarchies could not be resol ved
8719 */
8720 void _buildTypeHierarchies() {
8721 PerformanceStatistics.resolve.makeCurrentWhile(() {
8722 for (ResolvableLibrary library in _librariesInCycle) {
8723 for (ResolvableCompilationUnit unit
8724 in library.resolvableCompilationUnits) {
8725 Source source = unit.source;
8726 CompilationUnit ast = unit.compilationUnit;
8727 TypeResolverVisitor visitor = new TypeResolverVisitor(
8728 library.libraryElement,
8729 source,
8730 _typeProvider,
8731 library.libraryScope.errorListener,
8732 nameScope: library.libraryScope);
8733 ast.accept(visitor);
8734 }
8735 }
8736 });
8737 }
8738
8739 /**
8740 * Return an array containing the lexical identifiers associated with the node s in the given list.
8741 *
8742 * @param names the AST nodes representing the identifiers
8743 * @return the lexical identifiers associated with the nodes in the list
8744 */
8745 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) {
8746 int count = names.length;
8747 List<String> identifiers = new List<String>(count);
8748 for (int i = 0; i < count; i++) {
8749 identifiers[i] = names[i].name;
8750 }
8751 return identifiers;
8752 }
8753
8754 /**
8755 * Compute a value for all of the constants in the libraries being analyzed.
8756 */
8757 void _performConstantEvaluation() {
8758 PerformanceStatistics.resolve.makeCurrentWhile(() {
8759 ConstantValueComputer computer = new ConstantValueComputer(
8760 analysisContext, _typeProvider, analysisContext.declaredVariables);
8761 for (ResolvableLibrary library in _librariesInCycle) {
8762 for (ResolvableCompilationUnit unit
8763 in library.resolvableCompilationUnits) {
8764 CompilationUnit ast = unit.compilationUnit;
8765 if (ast != null) {
8766 computer.add(ast, unit.source, library.librarySource);
8767 }
8768 }
8769 }
8770 computer.computeValues();
8771 // As a temporary workaround for issue 21572, run ConstantVerifier now.
8772 // TODO(paulberry): remove this workaround once issue 21572 is fixed.
8773 for (ResolvableLibrary library in _librariesInCycle) {
8774 for (ResolvableCompilationUnit unit
8775 in library.resolvableCompilationUnits) {
8776 CompilationUnit ast = unit.compilationUnit;
8777 ErrorReporter errorReporter =
8778 new ErrorReporter(_errorListener, unit.source);
8779 ConstantVerifier constantVerifier = new ConstantVerifier(
8780 errorReporter,
8781 library.libraryElement,
8782 _typeProvider,
8783 analysisContext.declaredVariables);
8784 ast.accept(constantVerifier);
8785 }
8786 }
8787 });
8788 }
8789
8790 /**
8791 * Resolve the identifiers and perform type analysis in the libraries in the c urrent cycle.
8792 *
8793 * @throws AnalysisException if any of the identifiers could not be resolved o r if any of the
8794 * libraries could not have their types analyzed
8795 */
8796 void _resolveReferencesAndTypes() {
8797 for (ResolvableLibrary library in _librariesInCycle) {
8798 _resolveReferencesAndTypesInLibrary(library);
8799 }
8800 }
8801
8802 /**
8803 * Resolve the identifiers and perform type analysis in the given library.
8804 *
8805 * @param library the library to be resolved
8806 * @throws AnalysisException if any of the identifiers could not be resolved o r if the types in
8807 * the library cannot be analyzed
8808 */
8809 void _resolveReferencesAndTypesInLibrary(ResolvableLibrary library) {
8810 PerformanceStatistics.resolve.makeCurrentWhile(() {
8811 for (ResolvableCompilationUnit unit
8812 in library.resolvableCompilationUnits) {
8813 Source source = unit.source;
8814 CompilationUnit ast = unit.compilationUnit;
8815 ast.accept(new VariableResolverVisitor(library.libraryElement, source,
8816 _typeProvider, library.libraryScope.errorListener,
8817 nameScope: library.libraryScope));
8818 ResolverVisitor visitor = new ResolverVisitor(library.libraryElement,
8819 source, _typeProvider, library._libraryScope.errorListener,
8820 nameScope: library._libraryScope,
8821 inheritanceManager: library.inheritanceManager);
8822 ast.accept(visitor);
8823 }
8824 });
8825 }
8826
8827 /**
8828 * Report that the async library could not be resolved in the given
8829 * [analysisContext] and throw an exception. [asyncLibrarySource] is the sour ce
8830 * representing the async library.
8831 */
8832 static void missingAsyncLibrary(
8833 AnalysisContext analysisContext, Source asyncLibrarySource) {
8834 throw new AnalysisException("Could not resolve dart:async");
8835 }
8836
8837 /**
8838 * Report that the core library could not be resolved in the given analysis co ntext and throw an
8839 * exception.
8840 *
8841 * @param analysisContext the analysis context in which the failure occurred
8842 * @param coreLibrarySource the source representing the core library
8843 * @throws AnalysisException always
8844 */
8845 static void missingCoreLibrary(
8846 AnalysisContext analysisContext, Source coreLibrarySource) {
8847 throw new AnalysisException("Could not resolve dart:core");
8848 }
8849 }
8850
8851 /**
8852 * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
8853 */
8854 class LibraryResolver2_TypeAliasInfo {
8855 final ResolvableLibrary _library;
8856
8857 final Source _source;
8858
8859 final FunctionTypeAlias _typeAlias;
8860
8861 /**
8862 * Initialize a newly created information holder with the given information.
8863 *
8864 * @param library the library containing the type alias
8865 * @param source the source of the file containing the type alias
8866 * @param typeAlias the type alias being remembered
8867 */
8868 LibraryResolver2_TypeAliasInfo(this._library, this._source, this._typeAlias);
8869 }
8870
8871 /**
8872 * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
8873 */
8874 class LibraryResolver_TypeAliasInfo {
8875 final Library _library;
8876
8877 final Source _source;
8878
8879 final FunctionTypeAlias _typeAlias;
8880
8881 /**
8882 * Initialize a newly created information holder with the given information.
8883 *
8884 * @param library the library containing the type alias
8885 * @param source the source of the file containing the type alias
8886 * @param typeAlias the type alias being remembered
8887 */
8888 LibraryResolver_TypeAliasInfo(this._library, this._source, this._typeAlias);
8889 }
8890
8891 /**
8892 * Instances of the class `LibraryScope` implement a scope containing all of the names defined
8893 * in a given library.
8894 */
8895 class LibraryScope extends EnclosedScope {
8896 /**
8897 * Initialize a newly created scope representing the names defined in the give n library.
8898 *
8899 * @param definingLibrary the element representing the library represented by this scope
8900 * @param errorListener the listener that is to be informed when an error is e ncountered
8901 */
8902 LibraryScope(
8903 LibraryElement definingLibrary, AnalysisErrorListener errorListener)
8904 : super(new LibraryImportScope(definingLibrary, errorListener)) {
8905 _defineTopLevelNames(definingLibrary);
8906 }
8907
8908 @override
8909 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
8910 if (existing is PrefixElement) {
8911 // TODO(scheglov) consider providing actual 'nameOffset' from the
8912 // synthetic accessor
8913 int offset = duplicate.nameOffset;
8914 if (duplicate is PropertyAccessorElement) {
8915 PropertyAccessorElement accessor = duplicate;
8916 if (accessor.isSynthetic) {
8917 offset = accessor.variable.nameOffset;
8918 }
8919 }
8920 return new AnalysisError(
8921 duplicate.source,
8922 offset,
8923 duplicate.displayName.length,
8924 CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
8925 [existing.displayName]);
8926 }
8927 return super.getErrorForDuplicate(existing, duplicate);
8928 }
8929
8930 /**
8931 * Add to this scope all of the public top-level names that are defined in the given compilation
8932 * unit.
8933 *
8934 * @param compilationUnit the compilation unit defining the top-level names to be added to this
8935 * scope
8936 */
8937 void _defineLocalNames(CompilationUnitElement compilationUnit) {
8938 for (PropertyAccessorElement element in compilationUnit.accessors) {
8939 define(element);
8940 }
8941 for (ClassElement element in compilationUnit.enums) {
8942 define(element);
8943 }
8944 for (FunctionElement element in compilationUnit.functions) {
8945 define(element);
8946 }
8947 for (FunctionTypeAliasElement element
8948 in compilationUnit.functionTypeAliases) {
8949 define(element);
8950 }
8951 for (ClassElement element in compilationUnit.types) {
8952 define(element);
8953 }
8954 }
8955
8956 /**
8957 * Add to this scope all of the names that are explicitly defined in the given library.
8958 *
8959 * @param definingLibrary the element representing the library that defines th e names in this
8960 * scope
8961 */
8962 void _defineTopLevelNames(LibraryElement definingLibrary) {
8963 for (PrefixElement prefix in definingLibrary.prefixes) {
8964 define(prefix);
8965 }
8966 _defineLocalNames(definingLibrary.definingCompilationUnit);
8967 for (CompilationUnitElement compilationUnit in definingLibrary.parts) {
8968 _defineLocalNames(compilationUnit);
8969 }
8970 }
8971 }
8972
8973 /**
8974 * This class is used to replace uses of `HashMap<String, ExecutableElement>`
8975 * which are not as performant as this class.
8976 */
8977 class MemberMap {
8978 /**
8979 * The current size of this map.
8980 */
8981 int _size = 0;
8982
8983 /**
8984 * The array of keys.
8985 */
8986 List<String> _keys;
8987
8988 /**
8989 * The array of ExecutableElement values.
8990 */
8991 List<ExecutableElement> _values;
8992
8993 /**
8994 * Initialize a newly created member map to have the given [initialCapacity].
8995 * The map will grow if needed.
8996 */
8997 MemberMap([int initialCapacity = 10]) {
8998 _initArrays(initialCapacity);
8999 }
9000
9001 /**
9002 * This constructor takes an initial capacity of the map.
9003 *
9004 * @param initialCapacity the initial capacity
9005 */
9006 @deprecated // Use new MemberMap(initialCapacity)
9007 MemberMap.con1(int initialCapacity) {
9008 _initArrays(initialCapacity);
9009 }
9010
9011 /**
9012 * Copy constructor.
9013 */
9014 @deprecated // Use new MemberMap.from(memberMap)
9015 MemberMap.con2(MemberMap memberMap) {
9016 _initArrays(memberMap._size + 5);
9017 for (int i = 0; i < memberMap._size; i++) {
9018 _keys[i] = memberMap._keys[i];
9019 _values[i] = memberMap._values[i];
9020 }
9021 _size = memberMap._size;
9022 }
9023
9024 /**
9025 * Initialize a newly created member map to contain the same members as the
9026 * given [memberMap].
9027 */
9028 MemberMap.from(MemberMap memberMap) {
9029 _initArrays(memberMap._size + 5);
9030 for (int i = 0; i < memberMap._size; i++) {
9031 _keys[i] = memberMap._keys[i];
9032 _values[i] = memberMap._values[i];
9033 }
9034 _size = memberMap._size;
9035 }
9036
9037 /**
9038 * The size of the map.
9039 *
9040 * @return the size of the map.
9041 */
9042 int get size => _size;
9043
9044 /**
9045 * Given some key, return the ExecutableElement value from the map, if the key does not exist in
9046 * the map, `null` is returned.
9047 *
9048 * @param key some key to look up in the map
9049 * @return the associated ExecutableElement value from the map, if the key doe s not exist in the
9050 * map, `null` is returned
9051 */
9052 ExecutableElement get(String key) {
9053 for (int i = 0; i < _size; i++) {
9054 if (_keys[i] != null && _keys[i] == key) {
9055 return _values[i];
9056 }
9057 }
9058 return null;
9059 }
9060
9061 /**
9062 * Get and return the key at the specified location. If the key/value pair has been removed from
9063 * the set, then `null` is returned.
9064 *
9065 * @param i some non-zero value less than size
9066 * @return the key at the passed index
9067 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
9068 * zero or greater than or equal to the capacity of the arrays
9069 */
9070 String getKey(int i) => _keys[i];
9071
9072 /**
9073 * Get and return the ExecutableElement at the specified location. If the key/ value pair has been
9074 * removed from the set, then then `null` is returned.
9075 *
9076 * @param i some non-zero value less than size
9077 * @return the key at the passed index
9078 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
9079 * zero or greater than or equal to the capacity of the arrays
9080 */
9081 ExecutableElement getValue(int i) => _values[i];
9082
9083 /**
9084 * Given some key/value pair, store the pair in the map. If the key exists alr eady, then the new
9085 * value overrides the old value.
9086 *
9087 * @param key the key to store in the map
9088 * @param value the ExecutableElement value to store in the map
9089 */
9090 void put(String key, ExecutableElement value) {
9091 // If we already have a value with this key, override the value
9092 for (int i = 0; i < _size; i++) {
9093 if (_keys[i] != null && _keys[i] == key) {
9094 _values[i] = value;
9095 return;
9096 }
9097 }
9098 // If needed, double the size of our arrays and copy values over in both
9099 // arrays
9100 if (_size == _keys.length) {
9101 int newArrayLength = _size * 2;
9102 List<String> keys_new_array = new List<String>(newArrayLength);
9103 List<ExecutableElement> values_new_array =
9104 new List<ExecutableElement>(newArrayLength);
9105 for (int i = 0; i < _size; i++) {
9106 keys_new_array[i] = _keys[i];
9107 }
9108 for (int i = 0; i < _size; i++) {
9109 values_new_array[i] = _values[i];
9110 }
9111 _keys = keys_new_array;
9112 _values = values_new_array;
9113 }
9114 // Put new value at end of array
9115 _keys[_size] = key;
9116 _values[_size] = value;
9117 _size++;
9118 }
9119
9120 /**
9121 * Given some [String] key, this method replaces the associated key and value pair with
9122 * `null`. The size is not decremented with this call, instead it is expected that the users
9123 * check for `null`.
9124 *
9125 * @param key the key of the key/value pair to remove from the map
9126 */
9127 void remove(String key) {
9128 for (int i = 0; i < _size; i++) {
9129 if (_keys[i] == key) {
9130 _keys[i] = null;
9131 _values[i] = null;
9132 return;
9133 }
9134 }
9135 }
9136
9137 /**
9138 * Sets the ExecutableElement at the specified location.
9139 *
9140 * @param i some non-zero value less than size
9141 * @param value the ExecutableElement value to store in the map
9142 */
9143 void setValue(int i, ExecutableElement value) {
9144 _values[i] = value;
9145 }
9146
9147 /**
9148 * Initializes [keys] and [values].
9149 */
9150 void _initArrays(int initialCapacity) {
9151 _keys = new List<String>(initialCapacity);
9152 _values = new List<ExecutableElement>(initialCapacity);
9153 }
9154 }
9155
9156 /**
9157 * Instances of the class `Namespace` implement a mapping of identifiers to the elements
9158 * represented by those identifiers. Namespaces are the building blocks for scop es.
9159 */
9160 class Namespace {
9161 /**
9162 * An empty namespace.
9163 */
9164 static Namespace EMPTY = new Namespace(new HashMap<String, Element>());
9165
9166 /**
9167 * A table mapping names that are defined in this namespace to the element rep resenting the thing
9168 * declared with that name.
9169 */
9170 final HashMap<String, Element> _definedNames;
9171
9172 /**
9173 * Initialize a newly created namespace to have the given defined names.
9174 *
9175 * @param definedNames the mapping from names that are defined in this namespa ce to the
9176 * corresponding elements
9177 */
9178 Namespace(this._definedNames);
9179
9180 /**
9181 * Return a table containing the same mappings as those defined by this namesp ace.
9182 *
9183 * @return a table containing the same mappings as those defined by this names pace
9184 */
9185 Map<String, Element> get definedNames =>
9186 new HashMap<String, Element>.from(_definedNames);
9187
9188 /**
9189 * Return the element in this namespace that is available to the containing sc ope using the given
9190 * name.
9191 *
9192 * @param name the name used to reference the
9193 * @return the element represented by the given identifier
9194 */
9195 Element get(String name) => _definedNames[name];
9196 }
9197
9198 /**
9199 * Instances of the class `NamespaceBuilder` are used to build a `Namespace`. Na mespace
9200 * builders are thread-safe and re-usable.
9201 */
9202 class NamespaceBuilder {
9203 /**
9204 * Create a namespace representing the export namespace of the given [ExportEl ement].
9205 *
9206 * @param element the export element whose export namespace is to be created
9207 * @return the export namespace that was created
9208 */
9209 Namespace createExportNamespaceForDirective(ExportElement element) {
9210 LibraryElement exportedLibrary = element.exportedLibrary;
9211 if (exportedLibrary == null) {
9212 //
9213 // The exported library will be null if the URI does not reference a valid
9214 // library.
9215 //
9216 return Namespace.EMPTY;
9217 }
9218 HashMap<String, Element> definedNames =
9219 _createExportMapping(exportedLibrary, new HashSet<LibraryElement>());
9220 definedNames = _applyCombinators(definedNames, element.combinators);
9221 return new Namespace(definedNames);
9222 }
9223
9224 /**
9225 * Create a namespace representing the export namespace of the given library.
9226 *
9227 * @param library the library whose export namespace is to be created
9228 * @return the export namespace that was created
9229 */
9230 Namespace createExportNamespaceForLibrary(LibraryElement library) =>
9231 new Namespace(
9232 _createExportMapping(library, new HashSet<LibraryElement>()));
9233
9234 /**
9235 * Create a namespace representing the import namespace of the given library.
9236 *
9237 * @param library the library whose import namespace is to be created
9238 * @return the import namespace that was created
9239 */
9240 Namespace createImportNamespaceForDirective(ImportElement element) {
9241 LibraryElement importedLibrary = element.importedLibrary;
9242 if (importedLibrary == null) {
9243 //
9244 // The imported library will be null if the URI does not reference a valid
9245 // library.
9246 //
9247 return Namespace.EMPTY;
9248 }
9249 HashMap<String, Element> definedNames =
9250 _createExportMapping(importedLibrary, new HashSet<LibraryElement>());
9251 definedNames = _applyCombinators(definedNames, element.combinators);
9252 definedNames = _applyPrefix(definedNames, element.prefix);
9253 return new Namespace(definedNames);
9254 }
9255
9256 /**
9257 * Create a namespace representing the public namespace of the given library.
9258 *
9259 * @param library the library whose public namespace is to be created
9260 * @return the public namespace that was created
9261 */
9262 Namespace createPublicNamespaceForLibrary(LibraryElement library) {
9263 HashMap<String, Element> definedNames = new HashMap<String, Element>();
9264 _addPublicNames(definedNames, library.definingCompilationUnit);
9265 for (CompilationUnitElement compilationUnit in library.parts) {
9266 _addPublicNames(definedNames, compilationUnit);
9267 }
9268 return new Namespace(definedNames);
9269 }
9270
9271 /**
9272 * Add all of the names in the given namespace to the given mapping table.
9273 *
9274 * @param definedNames the mapping table to which the names in the given names pace are to be added
9275 * @param namespace the namespace containing the names to be added to this nam espace
9276 */
9277 void _addAllFromNamespace(
9278 Map<String, Element> definedNames, Namespace namespace) {
9279 if (namespace != null) {
9280 definedNames.addAll(namespace.definedNames);
9281 }
9282 }
9283
9284 /**
9285 * Add the given element to the given mapping table if it has a publicly visib le name.
9286 *
9287 * @param definedNames the mapping table to which the public name is to be add ed
9288 * @param element the element to be added
9289 */
9290 void _addIfPublic(Map<String, Element> definedNames, Element element) {
9291 String name = element.name;
9292 if (name != null && !Scope.isPrivateName(name)) {
9293 definedNames[name] = element;
9294 }
9295 }
9296
9297 /**
9298 * Add to the given mapping table all of the public top-level names that are d efined in the given
9299 * compilation unit.
9300 *
9301 * @param definedNames the mapping table to which the public names are to be a dded
9302 * @param compilationUnit the compilation unit defining the top-level names to be added to this
9303 * namespace
9304 */
9305 void _addPublicNames(Map<String, Element> definedNames,
9306 CompilationUnitElement compilationUnit) {
9307 for (PropertyAccessorElement element in compilationUnit.accessors) {
9308 _addIfPublic(definedNames, element);
9309 }
9310 for (ClassElement element in compilationUnit.enums) {
9311 _addIfPublic(definedNames, element);
9312 }
9313 for (FunctionElement element in compilationUnit.functions) {
9314 _addIfPublic(definedNames, element);
9315 }
9316 for (FunctionTypeAliasElement element
9317 in compilationUnit.functionTypeAliases) {
9318 _addIfPublic(definedNames, element);
9319 }
9320 for (ClassElement element in compilationUnit.types) {
9321 _addIfPublic(definedNames, element);
9322 }
9323 }
9324
9325 /**
9326 * Apply the given combinators to all of the names in the given mapping table.
9327 *
9328 * @param definedNames the mapping table to which the namespace operations are to be applied
9329 * @param combinators the combinators to be applied
9330 */
9331 HashMap<String, Element> _applyCombinators(
9332 HashMap<String, Element> definedNames,
9333 List<NamespaceCombinator> combinators) {
9334 for (NamespaceCombinator combinator in combinators) {
9335 if (combinator is HideElementCombinator) {
9336 _hide(definedNames, combinator.hiddenNames);
9337 } else if (combinator is ShowElementCombinator) {
9338 definedNames = _show(definedNames, combinator.shownNames);
9339 } else {
9340 // Internal error.
9341 AnalysisEngine.instance.logger
9342 .logError("Unknown type of combinator: ${combinator.runtimeType}");
9343 }
9344 }
9345 return definedNames;
9346 }
9347
9348 /**
9349 * Apply the given prefix to all of the names in the table of defined names.
9350 *
9351 * @param definedNames the names that were defined before this operation
9352 * @param prefixElement the element defining the prefix to be added to the nam es
9353 */
9354 HashMap<String, Element> _applyPrefix(
9355 HashMap<String, Element> definedNames, PrefixElement prefixElement) {
9356 if (prefixElement != null) {
9357 String prefix = prefixElement.name;
9358 HashMap<String, Element> newNames = new HashMap<String, Element>();
9359 definedNames.forEach((String name, Element element) {
9360 newNames["$prefix.$name"] = element;
9361 });
9362 return newNames;
9363 } else {
9364 return definedNames;
9365 }
9366 }
9367
9368 /**
9369 * Create a mapping table representing the export namespace of the given libra ry.
9370 *
9371 * @param library the library whose public namespace is to be created
9372 * @param visitedElements a set of libraries that do not need to be visited wh en processing the
9373 * export directives of the given library because all of the names de fined by them will
9374 * be added by another library
9375 * @return the mapping table that was created
9376 */
9377 HashMap<String, Element> _createExportMapping(
9378 LibraryElement library, HashSet<LibraryElement> visitedElements) {
9379 // Check if the export namespace has been already computed.
9380 {
9381 Namespace exportNamespace = library.exportNamespace;
9382 if (exportNamespace != null) {
9383 return exportNamespace.definedNames;
9384 }
9385 }
9386 // TODO(scheglov) Remove this after switching to the new task model.
9387 visitedElements.add(library);
9388 try {
9389 HashMap<String, Element> definedNames = new HashMap<String, Element>();
9390 for (ExportElement element in library.exports) {
9391 LibraryElement exportedLibrary = element.exportedLibrary;
9392 if (exportedLibrary != null &&
9393 !visitedElements.contains(exportedLibrary)) {
9394 //
9395 // The exported library will be null if the URI does not reference a
9396 // valid library.
9397 //
9398 HashMap<String, Element> exportedNames =
9399 _createExportMapping(exportedLibrary, visitedElements);
9400 exportedNames = _applyCombinators(exportedNames, element.combinators);
9401 definedNames.addAll(exportedNames);
9402 }
9403 }
9404 _addAllFromNamespace(
9405 definedNames,
9406 (library.context as InternalAnalysisContext)
9407 .getPublicNamespace(library));
9408 return definedNames;
9409 } finally {
9410 visitedElements.remove(library);
9411 }
9412 }
9413
9414 /**
9415 * Hide all of the given names by removing them from the given collection of d efined names.
9416 *
9417 * @param definedNames the names that were defined before this operation
9418 * @param hiddenNames the names to be hidden
9419 */
9420 void _hide(HashMap<String, Element> definedNames, List<String> hiddenNames) {
9421 for (String name in hiddenNames) {
9422 definedNames.remove(name);
9423 definedNames.remove("$name=");
9424 }
9425 }
9426
9427 /**
9428 * Show only the given names by removing all other names from the given collec tion of defined
9429 * names.
9430 *
9431 * @param definedNames the names that were defined before this operation
9432 * @param shownNames the names to be shown
9433 */
9434 HashMap<String, Element> _show(
9435 HashMap<String, Element> definedNames, List<String> shownNames) {
9436 HashMap<String, Element> newNames = new HashMap<String, Element>();
9437 for (String name in shownNames) {
9438 Element element = definedNames[name];
9439 if (element != null) {
9440 newNames[name] = element;
9441 }
9442 String setterName = "$name=";
9443 element = definedNames[setterName];
9444 if (element != null) {
9445 newNames[setterName] = element;
9446 }
9447 }
9448 return newNames;
9449 }
9450 }
9451
9452 /**
9453 * Instances of the class `OverrideVerifier` visit all of the declarations in a compilation
9454 * unit to verify that if they have an override annotation it is being used corr ectly.
9455 */
9456 class OverrideVerifier extends RecursiveAstVisitor<Object> {
9457 /**
9458 * The error reporter used to report errors.
9459 */
9460 final ErrorReporter _errorReporter;
9461
9462 /**
9463 * The inheritance manager used to find overridden methods.
9464 */
9465 final InheritanceManager _manager;
9466
9467 /**
9468 * Initialize a newly created verifier to look for inappropriate uses of the o verride annotation.
9469 *
9470 * @param errorReporter the error reporter used to report errors
9471 * @param manager the inheritance manager used to find overridden methods
9472 */
9473 OverrideVerifier(this._errorReporter, this._manager);
9474
9475 @override
9476 Object visitMethodDeclaration(MethodDeclaration node) {
9477 ExecutableElement element = node.element;
9478 if (_isOverride(element)) {
9479 if (_getOverriddenMember(element) == null) {
9480 if (element is MethodElement) {
9481 _errorReporter.reportErrorForNode(
9482 HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name);
9483 } else if (element is PropertyAccessorElement) {
9484 if (element.isGetter) {
9485 _errorReporter.reportErrorForNode(
9486 HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER, node.name);
9487 } else {
9488 _errorReporter.reportErrorForNode(
9489 HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER, node.name);
9490 }
9491 }
9492 }
9493 }
9494 return super.visitMethodDeclaration(node);
9495 }
9496
9497 /**
9498 * Return the member that overrides the given member.
9499 *
9500 * @param member the member that overrides the returned member
9501 * @return the member that overrides the given member
9502 */
9503 ExecutableElement _getOverriddenMember(ExecutableElement member) {
9504 LibraryElement library = member.library;
9505 if (library == null) {
9506 return null;
9507 }
9508 ClassElement classElement =
9509 member.getAncestor((element) => element is ClassElement);
9510 if (classElement == null) {
9511 return null;
9512 }
9513 return _manager.lookupInheritance(classElement, member.name);
9514 }
9515
9516 /**
9517 * Return `true` if the given element has an override annotation associated wi th it.
9518 *
9519 * @param element the element being tested
9520 * @return `true` if the element has an override annotation associated with it
9521 */
9522 bool _isOverride(Element element) => element != null && element.isOverride;
9523 }
9524
9525 /**
9526 * Instances of the class `PubVerifier` traverse an AST structure looking for de viations from
9527 * pub best practices.
9528 */
9529 class PubVerifier extends RecursiveAstVisitor<Object> {
9530 // static String _PUBSPEC_YAML = "pubspec.yaml";
9531
9532 /**
9533 * The analysis context containing the sources to be analyzed
9534 */
9535 final AnalysisContext _context;
9536
9537 /**
9538 * The error reporter by which errors will be reported.
9539 */
9540 final ErrorReporter _errorReporter;
9541
9542 PubVerifier(this._context, this._errorReporter);
9543
9544 @override
9545 Object visitImportDirective(ImportDirective directive) {
9546 return null;
9547 }
9548
9549 // /**
9550 // * This verifies that the passed file import directive is not contained in a source inside a
9551 // * package "lib" directory hierarchy referencing a source outside that packa ge "lib" directory
9552 // * hierarchy.
9553 // *
9554 // * @param uriLiteral the import URL (not `null`)
9555 // * @param path the file path being verified (not `null`)
9556 // * @return `true` if and only if an error code is generated on the passed no de
9557 // * See [PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE].
9558 // */
9559 // bool
9560 // _checkForFileImportInsideLibReferencesFileOutside(StringLiteral uriLiter al,
9561 // String path) {
9562 // Source source = _getSource(uriLiteral);
9563 // String fullName = _getSourceFullName(source);
9564 // if (fullName != null) {
9565 // int pathIndex = 0;
9566 // int fullNameIndex = fullName.length;
9567 // while (pathIndex < path.length &&
9568 // StringUtilities.startsWith3(path, pathIndex, 0x2E, 0x2E, 0x2F)) {
9569 // fullNameIndex = JavaString.lastIndexOf(fullName, '/', fullNameIndex);
9570 // if (fullNameIndex < 4) {
9571 // return false;
9572 // }
9573 // // Check for "/lib" at a specified place in the fullName
9574 // if (StringUtilities.startsWith4(
9575 // fullName,
9576 // fullNameIndex - 4,
9577 // 0x2F,
9578 // 0x6C,
9579 // 0x69,
9580 // 0x62)) {
9581 // String relativePubspecPath =
9582 // path.substring(0, pathIndex + 3) +
9583 // _PUBSPEC_YAML;
9584 // Source pubspecSource =
9585 // _context.sourceFactory.resolveUri(source, relativePubspecPath);
9586 // if (_context.exists(pubspecSource)) {
9587 // // Files inside the lib directory hierarchy should not reference
9588 // // files outside
9589 // _errorReporter.reportErrorForNode(
9590 // HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE,
9591 // uriLiteral);
9592 // }
9593 // return true;
9594 // }
9595 // pathIndex += 3;
9596 // }
9597 // }
9598 // return false;
9599 // }
9600
9601 // /**
9602 // * This verifies that the passed file import directive is not contained in a source outside a
9603 // * package "lib" directory hierarchy referencing a source inside that packag e "lib" directory
9604 // * hierarchy.
9605 // *
9606 // * @param uriLiteral the import URL (not `null`)
9607 // * @param path the file path being verified (not `null`)
9608 // * @return `true` if and only if an error code is generated on the passed no de
9609 // * See [PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE].
9610 // */
9611 // bool
9612 // _checkForFileImportOutsideLibReferencesFileInside(StringLiteral uriLiter al,
9613 // String path) {
9614 // if (StringUtilities.startsWith4(path, 0, 0x6C, 0x69, 0x62, 0x2F)) {
9615 // if (_checkForFileImportOutsideLibReferencesFileInsideAtIndex(
9616 // uriLiteral,
9617 // path,
9618 // 0)) {
9619 // return true;
9620 // }
9621 // }
9622 // int pathIndex =
9623 // StringUtilities.indexOf5(path, 0, 0x2F, 0x6C, 0x69, 0x62, 0x2F);
9624 // while (pathIndex != -1) {
9625 // if (_checkForFileImportOutsideLibReferencesFileInsideAtIndex(
9626 // uriLiteral,
9627 // path,
9628 // pathIndex + 1)) {
9629 // return true;
9630 // }
9631 // pathIndex =
9632 // StringUtilities.indexOf5(path, pathIndex + 4, 0x2F, 0x6C, 0x69, 0x62 , 0x2F);
9633 // }
9634 // return false;
9635 // }
9636
9637 // bool
9638 // _checkForFileImportOutsideLibReferencesFileInsideAtIndex(StringLiteral u riLiteral,
9639 // String path, int pathIndex) {
9640 // Source source = _getSource(uriLiteral);
9641 // String relativePubspecPath = path.substring(0, pathIndex) + _PUBSPEC_YAML;
9642 // Source pubspecSource =
9643 // _context.sourceFactory.resolveUri(source, relativePubspecPath);
9644 // if (!_context.exists(pubspecSource)) {
9645 // return false;
9646 // }
9647 // String fullName = _getSourceFullName(source);
9648 // if (fullName != null) {
9649 // if (StringUtilities.indexOf5(fullName, 0, 0x2F, 0x6C, 0x69, 0x62, 0x2F) <
9650 // 0) {
9651 // // Files outside the lib directory hierarchy should not reference file s
9652 // // inside ... use package: url instead
9653 // _errorReporter.reportErrorForNode(
9654 // HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE,
9655 // uriLiteral);
9656 // return true;
9657 // }
9658 // }
9659 // return false;
9660 // }
9661
9662 // /**
9663 // * This verifies that the passed package import directive does not contain " .."
9664 // *
9665 // * @param uriLiteral the import URL (not `null`)
9666 // * @param path the path to be validated (not `null`)
9667 // * @return `true` if and only if an error code is generated on the passed no de
9668 // * See [PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT].
9669 // */
9670 // bool _checkForPackageImportContainsDotDot(StringLiteral uriLiteral,
9671 // String path) {
9672 // if (StringUtilities.startsWith3(path, 0, 0x2E, 0x2E, 0x2F) ||
9673 // StringUtilities.indexOf4(path, 0, 0x2F, 0x2E, 0x2E, 0x2F) >= 0) {
9674 // // Package import should not to contain ".."
9675 // _errorReporter.reportErrorForNode(
9676 // HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT,
9677 // uriLiteral);
9678 // return true;
9679 // }
9680 // return false;
9681 // }
9682
9683 // /**
9684 // * Answer the source associated with the compilation unit containing the giv en AST node.
9685 // *
9686 // * @param node the node (not `null`)
9687 // * @return the source or `null` if it could not be determined
9688 // */
9689 // Source _getSource(AstNode node) {
9690 // Source source = null;
9691 // CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit) ;
9692 // if (unit != null) {
9693 // CompilationUnitElement element = unit.element;
9694 // if (element != null) {
9695 // source = element.source;
9696 // }
9697 // }
9698 // return source;
9699 // }
9700
9701 // /**
9702 // * Answer the full name of the given source. The returned value will have al l
9703 // * [File.separatorChar] replace by '/'.
9704 // *
9705 // * @param source the source
9706 // * @return the full name or `null` if it could not be determined
9707 // */
9708 // String _getSourceFullName(Source source) {
9709 // if (source != null) {
9710 // String fullName = source.fullName;
9711 // if (fullName != null) {
9712 // return fullName.replaceAll(r'\', '/');
9713 // }
9714 // }
9715 // return null;
9716 // }
9717 }
9718
9719 /**
9720 * Kind of the redirecting constructor.
9721 */
9722 class RedirectingConstructorKind extends Enum<RedirectingConstructorKind> {
9723 static const RedirectingConstructorKind CONST =
9724 const RedirectingConstructorKind('CONST', 0);
9725
9726 static const RedirectingConstructorKind NORMAL =
9727 const RedirectingConstructorKind('NORMAL', 1);
9728
9729 static const List<RedirectingConstructorKind> values = const [CONST, NORMAL];
9730
9731 const RedirectingConstructorKind(String name, int ordinal)
9732 : super(name, ordinal);
9733 }
9734
9735 /**
9736 * A `ResolvableLibrary` represents a single library during the resolution of
9737 * some (possibly different) library. They are not intended to be used except
9738 * during the resolution process.
9739 */
9740 class ResolvableLibrary {
9741 /**
9742 * An empty array that can be used to initialize lists of libraries.
9743 */
9744 static List<ResolvableLibrary> _EMPTY_ARRAY = new List<ResolvableLibrary>(0);
9745
9746 /**
9747 * The next artificial hash code.
9748 */
9749 static int _NEXT_HASH_CODE = 0;
9750
9751 /**
9752 * The artifitial hash code for this object.
9753 */
9754 final int _hashCode = _nextHashCode();
9755
9756 /**
9757 * The source specifying the defining compilation unit of this library.
9758 */
9759 final Source librarySource;
9760
9761 /**
9762 * A list containing all of the libraries that are imported into this library.
9763 */
9764 List<ResolvableLibrary> _importedLibraries = _EMPTY_ARRAY;
9765
9766 /**
9767 * A flag indicating whether this library explicitly imports core.
9768 */
9769 bool explicitlyImportsCore = false;
9770
9771 /**
9772 * An array containing all of the libraries that are exported from this librar y.
9773 */
9774 List<ResolvableLibrary> _exportedLibraries = _EMPTY_ARRAY;
9775
9776 /**
9777 * An array containing the compilation units that comprise this library. The
9778 * defining compilation unit is always first.
9779 */
9780 List<ResolvableCompilationUnit> _compilationUnits;
9781
9782 /**
9783 * The library element representing this library.
9784 */
9785 LibraryElementImpl _libraryElement;
9786
9787 /**
9788 * The listener to which analysis errors will be reported.
9789 */
9790 AnalysisErrorListener _errorListener;
9791
9792 /**
9793 * The inheritance manager which is used for member lookups in this library.
9794 */
9795 InheritanceManager _inheritanceManager;
9796
9797 /**
9798 * The library scope used when resolving elements within this library's compil ation units.
9799 */
9800 LibraryScope _libraryScope;
9801
9802 /**
9803 * Initialize a newly created data holder that can maintain the data associate d with a library.
9804 *
9805 * @param librarySource the source specifying the defining compilation unit of this library
9806 * @param errorListener the listener to which analysis errors will be reported
9807 */
9808 ResolvableLibrary(this.librarySource);
9809
9810 /**
9811 * Return an array of the [CompilationUnit]s that make up the library. The fir st unit is
9812 * always the defining unit.
9813 *
9814 * @return an array of the [CompilationUnit]s that make up the library. The fi rst unit is
9815 * always the defining unit
9816 */
9817 List<CompilationUnit> get compilationUnits {
9818 int count = _compilationUnits.length;
9819 List<CompilationUnit> units = new List<CompilationUnit>(count);
9820 for (int i = 0; i < count; i++) {
9821 units[i] = _compilationUnits[i].compilationUnit;
9822 }
9823 return units;
9824 }
9825
9826 /**
9827 * Return an array containing the sources for the compilation units in this li brary, including the
9828 * defining compilation unit.
9829 *
9830 * @return the sources for the compilation units in this library
9831 */
9832 List<Source> get compilationUnitSources {
9833 int count = _compilationUnits.length;
9834 List<Source> sources = new List<Source>(count);
9835 for (int i = 0; i < count; i++) {
9836 sources[i] = _compilationUnits[i].source;
9837 }
9838 return sources;
9839 }
9840
9841 /**
9842 * Return the AST structure associated with the defining compilation unit for this library.
9843 *
9844 * @return the AST structure associated with the defining compilation unit for this library
9845 * @throws AnalysisException if an AST structure could not be created for the defining compilation
9846 * unit
9847 */
9848 CompilationUnit get definingCompilationUnit =>
9849 _compilationUnits[0].compilationUnit;
9850
9851 /**
9852 * Set the listener to which analysis errors will be reported to be the given listener.
9853 *
9854 * @param errorListener the listener to which analysis errors will be reported
9855 */
9856 void set errorListener(AnalysisErrorListener errorListener) {
9857 this._errorListener = errorListener;
9858 }
9859
9860 /**
9861 * Set the libraries that are exported by this library to be those in the give n array.
9862 *
9863 * @param exportedLibraries the libraries that are exported by this library
9864 */
9865 void set exportedLibraries(List<ResolvableLibrary> exportedLibraries) {
9866 this._exportedLibraries = exportedLibraries;
9867 }
9868
9869 /**
9870 * Return an array containing the libraries that are exported from this librar y.
9871 *
9872 * @return an array containing the libraries that are exported from this libra ry
9873 */
9874 List<ResolvableLibrary> get exports => _exportedLibraries;
9875
9876 @override
9877 int get hashCode => _hashCode;
9878
9879 /**
9880 * Set the libraries that are imported into this library to be those in the gi ven array.
9881 *
9882 * @param importedLibraries the libraries that are imported into this library
9883 */
9884 void set importedLibraries(List<ResolvableLibrary> importedLibraries) {
9885 this._importedLibraries = importedLibraries;
9886 }
9887
9888 /**
9889 * Return an array containing the libraries that are imported into this librar y.
9890 *
9891 * @return an array containing the libraries that are imported into this libra ry
9892 */
9893 List<ResolvableLibrary> get imports => _importedLibraries;
9894
9895 /**
9896 * Return an array containing the libraries that are either imported or export ed from this
9897 * library.
9898 *
9899 * @return the libraries that are either imported or exported from this librar y
9900 */
9901 List<ResolvableLibrary> get importsAndExports {
9902 HashSet<ResolvableLibrary> libraries = new HashSet<ResolvableLibrary>();
9903 for (ResolvableLibrary library in _importedLibraries) {
9904 libraries.add(library);
9905 }
9906 for (ResolvableLibrary library in _exportedLibraries) {
9907 libraries.add(library);
9908 }
9909 return new List.from(libraries);
9910 }
9911
9912 /**
9913 * Return the inheritance manager for this library.
9914 *
9915 * @return the inheritance manager for this library
9916 */
9917 InheritanceManager get inheritanceManager {
9918 if (_inheritanceManager == null) {
9919 return _inheritanceManager = new InheritanceManager(_libraryElement);
9920 }
9921 return _inheritanceManager;
9922 }
9923
9924 /**
9925 * Return the library element representing this library, creating it if necess ary.
9926 *
9927 * @return the library element representing this library
9928 */
9929 LibraryElementImpl get libraryElement => _libraryElement;
9930
9931 /**
9932 * Set the library element representing this library to the given library elem ent.
9933 *
9934 * @param libraryElement the library element representing this library
9935 */
9936 void set libraryElement(LibraryElementImpl libraryElement) {
9937 this._libraryElement = libraryElement;
9938 if (_inheritanceManager != null) {
9939 _inheritanceManager.libraryElement = libraryElement;
9940 }
9941 }
9942
9943 /**
9944 * Return the library scope used when resolving elements within this library's compilation units.
9945 *
9946 * @return the library scope used when resolving elements within this library' s compilation units
9947 */
9948 LibraryScope get libraryScope {
9949 if (_libraryScope == null) {
9950 _libraryScope = new LibraryScope(_libraryElement, _errorListener);
9951 }
9952 return _libraryScope;
9953 }
9954
9955 /**
9956 * Return an array containing the compilation units that comprise this library . The defining
9957 * compilation unit is always first.
9958 *
9959 * @return the compilation units that comprise this library
9960 */
9961 List<ResolvableCompilationUnit> get resolvableCompilationUnits =>
9962 _compilationUnits;
9963
9964 /**
9965 * Set the compilation unit in this library to the given compilation units. Th e defining
9966 * compilation unit must be the first element of the array.
9967 *
9968 * @param units the compilation units in this library
9969 */
9970 void set resolvableCompilationUnits(List<ResolvableCompilationUnit> units) {
9971 _compilationUnits = units;
9972 }
9973
9974 /**
9975 * Return the AST structure associated with the given source, or `null` if the source does
9976 * not represent a compilation unit that is included in this library.
9977 *
9978 * @param source the source representing the compilation unit whose AST is to be returned
9979 * @return the AST structure associated with the given source
9980 * @throws AnalysisException if an AST structure could not be created for the compilation unit
9981 */
9982 CompilationUnit getAST(Source source) {
9983 int count = _compilationUnits.length;
9984 for (int i = 0; i < count; i++) {
9985 if (_compilationUnits[i].source == source) {
9986 return _compilationUnits[i].compilationUnit;
9987 }
9988 }
9989 return null;
9990 }
9991
9992 @override
9993 String toString() => librarySource.shortName;
9994
9995 static int _nextHashCode() {
9996 int next = (_NEXT_HASH_CODE + 1) & 0xFFFFFF;
9997 _NEXT_HASH_CODE = next;
9998 return next;
9999 }
10000 }
10001
10002 /**
10003 * The enumeration `ResolverErrorCode` defines the error codes used for errors
10004 * detected by the resolver. The convention for this class is for the name of
10005 * the error code to indicate the problem that caused the error to be generated
10006 * and for the error message to explain what is wrong and, when appropriate, how
10007 * the problem can be corrected.
10008 */
10009 class ResolverErrorCode extends ErrorCode {
10010 static const ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER =
10011 const ResolverErrorCode('BREAK_LABEL_ON_SWITCH_MEMBER',
10012 "Break label resolves to case or default statement");
10013
10014 static const ResolverErrorCode CONTINUE_LABEL_ON_SWITCH =
10015 const ResolverErrorCode('CONTINUE_LABEL_ON_SWITCH',
10016 "A continue label resolves to switch, must be loop or switch member");
10017
10018 static const ResolverErrorCode MISSING_LIBRARY_DIRECTIVE_WITH_PART =
10019 const ResolverErrorCode('MISSING_LIBRARY_DIRECTIVE_WITH_PART',
10020 "Libraries that have parts must have a library directive");
10021
10022 /**
10023 * Initialize a newly created error code to have the given [name]. The message
10024 * associated with the error will be created from the given [message]
10025 * template. The correction associated with the error will be created from the
10026 * given [correction] template.
10027 */
10028 const ResolverErrorCode(String name, String message, [String correction])
10029 : super(name, message, correction);
10030
10031 @override
10032 ErrorSeverity get errorSeverity => type.severity;
10033
10034 @override
10035 ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
10036 }
10037
10038 /**
10039 * Instances of the class `ResolverVisitor` are used to resolve the nodes within a single
10040 * compilation unit.
10041 */
10042 class ResolverVisitor extends ScopedVisitor {
10043 /**
10044 * The manager for the inheritance mappings.
10045 */
10046 InheritanceManager _inheritanceManager;
10047
10048 /**
10049 * The object used to resolve the element associated with the current node.
10050 */
10051 ElementResolver elementResolver;
10052
10053 /**
10054 * The object used to compute the type associated with the current node.
10055 */
10056 StaticTypeAnalyzer typeAnalyzer;
10057
10058 /**
10059 * The class element representing the class containing the current node,
10060 * or `null` if the current node is not contained in a class.
10061 */
10062 ClassElement enclosingClass = null;
10063
10064 /**
10065 * The class declaration representing the class containing the current node, o r `null` if
10066 * the current node is not contained in a class.
10067 */
10068 ClassDeclaration _enclosingClassDeclaration = null;
10069
10070 /**
10071 * The function type alias representing the function type containing the curre nt node, or
10072 * `null` if the current node is not contained in a function type alias.
10073 */
10074 FunctionTypeAlias _enclosingFunctionTypeAlias = null;
10075
10076 /**
10077 * The element representing the function containing the current node, or `null ` if the
10078 * current node is not contained in a function.
10079 */
10080 ExecutableElement _enclosingFunction = null;
10081
10082 /**
10083 * The [Comment] before a [FunctionDeclaration] or a [MethodDeclaration] that
10084 * cannot be resolved where we visited it, because it should be resolved in th e scope of the body.
10085 */
10086 Comment _commentBeforeFunction = null;
10087
10088 /**
10089 * The object keeping track of which elements have had their types overridden.
10090 */
10091 TypeOverrideManager _overrideManager = new TypeOverrideManager();
10092
10093 /**
10094 * The object keeping track of which elements have had their types promoted.
10095 */
10096 TypePromotionManager _promoteManager = new TypePromotionManager();
10097
10098 /**
10099 * A comment before a function should be resolved in the context of the
10100 * function. But when we incrementally resolve a comment, we don't want to
10101 * resolve the whole function.
10102 *
10103 * So, this flag is set to `true`, when just context of the function should
10104 * be built and the comment resolved.
10105 */
10106 bool resolveOnlyCommentInFunctionBody = false;
10107
10108 /**
10109 * Initialize a newly created visitor to resolve the nodes in an AST node.
10110 *
10111 * [definingLibrary] is the element for the library containing the node being
10112 * visited.
10113 * [source] is the source representing the compilation unit containing the
10114 * node being visited.
10115 * [typeProvider] the object used to access the types from the core library.
10116 * [errorListener] the error listener that will be informed of any errors
10117 * that are found during resolution.
10118 * [nameScope] is the scope used to resolve identifiers in the node that will
10119 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
10120 * created based on [definingLibrary] and [typeProvider].
10121 * [inheritanceManager] is used to perform inheritance lookups. If `null` or
10122 * unspecified, a new [InheritanceManager] will be created based on
10123 * [definingLibrary].
10124 * [typeAnalyzerFactory] is used to create the type analyzer. If `null` or
10125 * unspecified, a type analyzer of type [StaticTypeAnalyzer] will be created.
10126 */
10127 ResolverVisitor(LibraryElement definingLibrary, Source source,
10128 TypeProvider typeProvider, AnalysisErrorListener errorListener,
10129 {Scope nameScope,
10130 InheritanceManager inheritanceManager,
10131 StaticTypeAnalyzerFactory typeAnalyzerFactory})
10132 : super(definingLibrary, source, typeProvider, errorListener,
10133 nameScope: nameScope) {
10134 if (inheritanceManager == null) {
10135 this._inheritanceManager = new InheritanceManager(definingLibrary);
10136 } else {
10137 this._inheritanceManager = inheritanceManager;
10138 }
10139 this.elementResolver = new ElementResolver(this);
10140 if (typeAnalyzerFactory == null) {
10141 this.typeAnalyzer = new StaticTypeAnalyzer(this);
10142 } else {
10143 this.typeAnalyzer = typeAnalyzerFactory(this);
10144 }
10145 }
10146
10147 /**
10148 * Initialize a newly created visitor to resolve the nodes in a compilation un it.
10149 *
10150 * @param library the library containing the compilation unit being resolved
10151 * @param source the source representing the compilation unit being visited
10152 * @param typeProvider the object used to access the types from the core libra ry
10153 *
10154 * Deprecated. Please use unnamed constructor instead.
10155 */
10156 @deprecated
10157 ResolverVisitor.con1(
10158 Library library, Source source, TypeProvider typeProvider,
10159 {StaticTypeAnalyzerFactory typeAnalyzerFactory})
10160 : this(
10161 library.libraryElement, source, typeProvider, library.errorListener,
10162 nameScope: library.libraryScope,
10163 inheritanceManager: library.inheritanceManager,
10164 typeAnalyzerFactory: typeAnalyzerFactory);
10165
10166 /**
10167 * Return the element representing the function containing the current node, o r `null` if
10168 * the current node is not contained in a function.
10169 *
10170 * @return the element representing the function containing the current node
10171 */
10172 ExecutableElement get enclosingFunction => _enclosingFunction;
10173
10174 /**
10175 * Return the object keeping track of which elements have had their types over ridden.
10176 *
10177 * @return the object keeping track of which elements have had their types ove rridden
10178 */
10179 TypeOverrideManager get overrideManager => _overrideManager;
10180
10181 /**
10182 * Return the object keeping track of which elements have had their types prom oted.
10183 *
10184 * @return the object keeping track of which elements have had their types pro moted
10185 */
10186 TypePromotionManager get promoteManager => _promoteManager;
10187
10188 /**
10189 * Return the propagated element associated with the given expression whose ty pe can be
10190 * overridden, or `null` if there is no element whose type can be overridden.
10191 *
10192 * @param expression the expression with which the element is associated
10193 * @return the element associated with the given expression
10194 */
10195 VariableElement getOverridablePropagatedElement(Expression expression) {
10196 Element element = null;
10197 if (expression is SimpleIdentifier) {
10198 element = expression.propagatedElement;
10199 } else if (expression is PrefixedIdentifier) {
10200 element = expression.propagatedElement;
10201 } else if (expression is PropertyAccess) {
10202 element = expression.propertyName.propagatedElement;
10203 }
10204 if (element is VariableElement) {
10205 return element;
10206 }
10207 return null;
10208 }
10209
10210 /**
10211 * Return the static element associated with the given expression whose type c an be overridden, or
10212 * `null` if there is no element whose type can be overridden.
10213 *
10214 * @param expression the expression with which the element is associated
10215 * @return the element associated with the given expression
10216 */
10217 VariableElement getOverridableStaticElement(Expression expression) {
10218 Element element = null;
10219 if (expression is SimpleIdentifier) {
10220 element = expression.staticElement;
10221 } else if (expression is PrefixedIdentifier) {
10222 element = expression.staticElement;
10223 } else if (expression is PropertyAccess) {
10224 element = expression.propertyName.staticElement;
10225 }
10226 if (element is VariableElement) {
10227 return element;
10228 }
10229 return null;
10230 }
10231
10232 /**
10233 * Return the static element associated with the given expression whose type c an be promoted, or
10234 * `null` if there is no element whose type can be promoted.
10235 *
10236 * @param expression the expression with which the element is associated
10237 * @return the element associated with the given expression
10238 */
10239 VariableElement getPromotionStaticElement(Expression expression) {
10240 while (expression is ParenthesizedExpression) {
10241 expression = (expression as ParenthesizedExpression).expression;
10242 }
10243 if (expression is! SimpleIdentifier) {
10244 return null;
10245 }
10246 SimpleIdentifier identifier = expression as SimpleIdentifier;
10247 Element element = identifier.staticElement;
10248 if (element is! VariableElement) {
10249 return null;
10250 }
10251 ElementKind kind = element.kind;
10252 if (kind == ElementKind.LOCAL_VARIABLE) {
10253 return element as VariableElement;
10254 }
10255 if (kind == ElementKind.PARAMETER) {
10256 return element as VariableElement;
10257 }
10258 return null;
10259 }
10260
10261 /**
10262 * Prepares this [ResolverVisitor] to using it for incremental resolution.
10263 */
10264 void initForIncrementalResolution() {
10265 _overrideManager.enterScope();
10266 }
10267
10268 /**
10269 * If it is appropriate to do so, override the current type of the static and propagated elements
10270 * associated with the given expression with the given type. Generally speakin g, it is appropriate
10271 * if the given type is more specific than the current type.
10272 *
10273 * @param expression the expression used to access the static and propagated e lements whose types
10274 * might be overridden
10275 * @param potentialType the potential type of the elements
10276 * @param allowPrecisionLoss see @{code overrideVariable} docs
10277 */
10278 void overrideExpression(Expression expression, DartType potentialType,
10279 bool allowPrecisionLoss, bool setExpressionType) {
10280 VariableElement element = getOverridableStaticElement(expression);
10281 if (element != null) {
10282 DartType newBestType =
10283 overrideVariable(element, potentialType, allowPrecisionLoss);
10284 if (setExpressionType) {
10285 recordPropagatedTypeIfBetter(expression, newBestType);
10286 }
10287 }
10288 element = getOverridablePropagatedElement(expression);
10289 if (element != null) {
10290 overrideVariable(element, potentialType, allowPrecisionLoss);
10291 }
10292 }
10293
10294 /**
10295 * If it is appropriate to do so, override the current type of the given eleme nt with the given
10296 * type.
10297 *
10298 * @param element the element whose type might be overridden
10299 * @param potentialType the potential type of the element
10300 * @param allowPrecisionLoss true if `potentialType` is allowed to be less pre cise than the
10301 * current best type
10302 *
10303 * Return a new better [DartType], or `null` if [potentialType] is not better
10304 * than the current [element] type.
10305 */
10306 DartType overrideVariable(VariableElement element, DartType potentialType,
10307 bool allowPrecisionLoss) {
10308 if (potentialType == null || potentialType.isBottom) {
10309 return null;
10310 }
10311 DartType currentType = _overrideManager.getBestType(element);
10312
10313 if (potentialType == currentType) {
10314 return null;
10315 }
10316
10317 // If we aren't allowing precision loss then the third and fourth conditions
10318 // check that we aren't losing precision.
10319 //
10320 // Let [C] be the current type and [P] be the potential type. When we
10321 // aren't allowing precision loss -- which is the case for is-checks -- we
10322 // check that [! (C << P)] or [P << C]. The second check, that [P << C], is
10323 // analogous to part of the Dart Language Spec rule for type promotion under
10324 // is-checks (in the analogy [T] is [P] and [S] is [C]):
10325 //
10326 // An is-expression of the form [v is T] shows that [v] has type [T] iff
10327 // [T] is more specific than the type [S] of the expression [v] and both
10328 // [T != dynamic] and [S != dynamic].
10329 //
10330 // It also covers an important case that is not applicable in the spec:
10331 // for union types, we want an is-check to promote from an union type to
10332 // (a subtype of) any of its members.
10333 //
10334 // The first check, that [! (C << P)], covers the case where [P] and [C] are
10335 // unrelated types; This case is not addressed in the spec for static types.
10336 if (currentType == null ||
10337 allowPrecisionLoss ||
10338 !currentType.isMoreSpecificThan(potentialType) ||
10339 potentialType.isMoreSpecificThan(currentType)) {
10340 // TODO(scheglov) type propagation for instance/top-level fields
10341 // was disabled because it depends on the order or visiting.
10342 // If both field and its client are in the same unit, and we visit
10343 // the client before the field, then propagated type is not set yet.
10344 // if (element is PropertyInducingElement) {
10345 // PropertyInducingElement variable = element;
10346 // if (!variable.isConst && !variable.isFinal) {
10347 // return;
10348 // }
10349 // (variable as PropertyInducingElementImpl).propagatedType =
10350 // potentialType;
10351 // }
10352 _overrideManager.setType(element, potentialType);
10353 return potentialType;
10354 }
10355 return null;
10356 }
10357
10358 /**
10359 * A client is about to resolve a member in the given class declaration.
10360 */
10361 void prepareToResolveMembersInClass(ClassDeclaration node) {
10362 _enclosingClassDeclaration = node;
10363 enclosingClass = node.element;
10364 typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type;
10365 }
10366
10367 /**
10368 * If the given [type] is valid, strongly more specific than the
10369 * existing static type of the given [expression], record it as a propagated
10370 * type of the given [expression]. Otherwise, reset it to `null`.
10371 *
10372 * If [hasOldPropagatedType] is `true` then the existing propagated type
10373 * should also is checked.
10374 */
10375 void recordPropagatedTypeIfBetter(Expression expression, DartType type,
10376 [bool hasOldPropagatedType = false]) {
10377 // Ensure that propagated type invalid.
10378 if (type == null || type.isDynamic || type.isBottom) {
10379 if (!hasOldPropagatedType) {
10380 expression.propagatedType = null;
10381 }
10382 return;
10383 }
10384 // Ensure that propagated type is more specific than the static type.
10385 DartType staticType = expression.staticType;
10386 if (type == staticType || !type.isMoreSpecificThan(staticType)) {
10387 expression.propagatedType = null;
10388 return;
10389 }
10390 // Ensure that the new propagated type is more specific than the old one.
10391 if (hasOldPropagatedType) {
10392 DartType oldPropagatedType = expression.propagatedType;
10393 if (oldPropagatedType != null &&
10394 !type.isMoreSpecificThan(oldPropagatedType)) {
10395 return;
10396 }
10397 }
10398 // OK
10399 expression.propagatedType = type;
10400 }
10401
10402 @override
10403 Object visitAnnotation(Annotation node) {
10404 AstNode parent = node.parent;
10405 if (identical(parent, _enclosingClassDeclaration) ||
10406 identical(parent, _enclosingFunctionTypeAlias)) {
10407 return null;
10408 }
10409 return super.visitAnnotation(node);
10410 }
10411
10412 @override
10413 Object visitAsExpression(AsExpression node) {
10414 super.visitAsExpression(node);
10415 // Since an as-statement doesn't actually change the type, we don't
10416 // let it affect the propagated type when it would result in a loss
10417 // of precision.
10418 overrideExpression(node.expression, node.type.type, false, false);
10419 return null;
10420 }
10421
10422 @override
10423 Object visitAssertStatement(AssertStatement node) {
10424 super.visitAssertStatement(node);
10425 _propagateTrueState(node.condition);
10426 return null;
10427 }
10428
10429 @override
10430 Object visitBinaryExpression(BinaryExpression node) {
10431 sc.TokenType operatorType = node.operator.type;
10432 Expression leftOperand = node.leftOperand;
10433 Expression rightOperand = node.rightOperand;
10434 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) {
10435 safelyVisit(leftOperand);
10436 if (rightOperand != null) {
10437 _overrideManager.enterScope();
10438 try {
10439 _promoteManager.enterScope();
10440 try {
10441 _propagateTrueState(leftOperand);
10442 // Type promotion.
10443 _promoteTypes(leftOperand);
10444 _clearTypePromotionsIfPotentiallyMutatedIn(leftOperand);
10445 _clearTypePromotionsIfPotentiallyMutatedIn(rightOperand);
10446 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10447 rightOperand);
10448 // Visit right operand.
10449 rightOperand.accept(this);
10450 } finally {
10451 _promoteManager.exitScope();
10452 }
10453 } finally {
10454 _overrideManager.exitScope();
10455 }
10456 }
10457 } else if (operatorType == sc.TokenType.BAR_BAR) {
10458 safelyVisit(leftOperand);
10459 if (rightOperand != null) {
10460 _overrideManager.enterScope();
10461 try {
10462 _propagateFalseState(leftOperand);
10463 rightOperand.accept(this);
10464 } finally {
10465 _overrideManager.exitScope();
10466 }
10467 }
10468 } else {
10469 safelyVisit(leftOperand);
10470 safelyVisit(rightOperand);
10471 }
10472 node.accept(elementResolver);
10473 node.accept(typeAnalyzer);
10474 return null;
10475 }
10476
10477 @override
10478 Object visitBlockFunctionBody(BlockFunctionBody node) {
10479 safelyVisit(_commentBeforeFunction);
10480 _overrideManager.enterScope();
10481 try {
10482 super.visitBlockFunctionBody(node);
10483 } finally {
10484 _overrideManager.exitScope();
10485 }
10486 return null;
10487 }
10488
10489 @override
10490 Object visitBreakStatement(BreakStatement node) {
10491 //
10492 // We do not visit the label because it needs to be visited in the context
10493 // of the statement.
10494 //
10495 node.accept(elementResolver);
10496 node.accept(typeAnalyzer);
10497 return null;
10498 }
10499
10500 @override
10501 Object visitClassDeclaration(ClassDeclaration node) {
10502 //
10503 // Resolve the metadata in the library scope.
10504 //
10505 if (node.metadata != null) {
10506 node.metadata.accept(this);
10507 }
10508 _enclosingClassDeclaration = node;
10509 //
10510 // Continue the class resolution.
10511 //
10512 ClassElement outerType = enclosingClass;
10513 try {
10514 enclosingClass = node.element;
10515 typeAnalyzer.thisType =
10516 enclosingClass == null ? null : enclosingClass.type;
10517 super.visitClassDeclaration(node);
10518 node.accept(elementResolver);
10519 node.accept(typeAnalyzer);
10520 } finally {
10521 typeAnalyzer.thisType = outerType == null ? null : outerType.type;
10522 enclosingClass = outerType;
10523 _enclosingClassDeclaration = null;
10524 }
10525 return null;
10526 }
10527
10528 /**
10529 * Implementation of this method should be synchronized with
10530 * [visitClassDeclaration].
10531 */
10532 visitClassDeclarationIncrementally(ClassDeclaration node) {
10533 //
10534 // Resolve the metadata in the library scope.
10535 //
10536 if (node.metadata != null) {
10537 node.metadata.accept(this);
10538 }
10539 _enclosingClassDeclaration = node;
10540 //
10541 // Continue the class resolution.
10542 //
10543 enclosingClass = node.element;
10544 typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type;
10545 node.accept(elementResolver);
10546 node.accept(typeAnalyzer);
10547 }
10548
10549 @override
10550 Object visitComment(Comment node) {
10551 if (node.parent is FunctionDeclaration ||
10552 node.parent is ConstructorDeclaration ||
10553 node.parent is MethodDeclaration) {
10554 if (!identical(node, _commentBeforeFunction)) {
10555 _commentBeforeFunction = node;
10556 return null;
10557 }
10558 }
10559 super.visitComment(node);
10560 _commentBeforeFunction = null;
10561 return null;
10562 }
10563
10564 @override
10565 Object visitCommentReference(CommentReference node) {
10566 //
10567 // We do not visit the identifier because it needs to be visited in the
10568 // context of the reference.
10569 //
10570 node.accept(elementResolver);
10571 node.accept(typeAnalyzer);
10572 return null;
10573 }
10574
10575 @override
10576 Object visitCompilationUnit(CompilationUnit node) {
10577 //
10578 // TODO(brianwilkerson) The goal of the code below is to visit the
10579 // declarations in such an order that we can infer type information for
10580 // top-level variables before we visit references to them. This is better
10581 // than making no effort, but still doesn't completely satisfy that goal
10582 // (consider for example "final var a = b; final var b = 0;"; we'll infer a
10583 // type of 'int' for 'b', but not for 'a' because of the order of the
10584 // visits). Ideally we would create a dependency graph, but that would
10585 // require references to be resolved, which they are not.
10586 //
10587 _overrideManager.enterScope();
10588 try {
10589 NodeList<Directive> directives = node.directives;
10590 int directiveCount = directives.length;
10591 for (int i = 0; i < directiveCount; i++) {
10592 directives[i].accept(this);
10593 }
10594 NodeList<CompilationUnitMember> declarations = node.declarations;
10595 int declarationCount = declarations.length;
10596 for (int i = 0; i < declarationCount; i++) {
10597 CompilationUnitMember declaration = declarations[i];
10598 if (declaration is! ClassDeclaration) {
10599 declaration.accept(this);
10600 }
10601 }
10602 for (int i = 0; i < declarationCount; i++) {
10603 CompilationUnitMember declaration = declarations[i];
10604 if (declaration is ClassDeclaration) {
10605 declaration.accept(this);
10606 }
10607 }
10608 } finally {
10609 _overrideManager.exitScope();
10610 }
10611 node.accept(elementResolver);
10612 node.accept(typeAnalyzer);
10613 return null;
10614 }
10615
10616 @override
10617 Object visitConditionalExpression(ConditionalExpression node) {
10618 Expression condition = node.condition;
10619 safelyVisit(condition);
10620 Expression thenExpression = node.thenExpression;
10621 if (thenExpression != null) {
10622 _overrideManager.enterScope();
10623 try {
10624 _promoteManager.enterScope();
10625 try {
10626 _propagateTrueState(condition);
10627 // Type promotion.
10628 _promoteTypes(condition);
10629 _clearTypePromotionsIfPotentiallyMutatedIn(thenExpression);
10630 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10631 thenExpression);
10632 // Visit "then" expression.
10633 thenExpression.accept(this);
10634 } finally {
10635 _promoteManager.exitScope();
10636 }
10637 } finally {
10638 _overrideManager.exitScope();
10639 }
10640 }
10641 Expression elseExpression = node.elseExpression;
10642 if (elseExpression != null) {
10643 _overrideManager.enterScope();
10644 try {
10645 _propagateFalseState(condition);
10646 elseExpression.accept(this);
10647 } finally {
10648 _overrideManager.exitScope();
10649 }
10650 }
10651 node.accept(elementResolver);
10652 node.accept(typeAnalyzer);
10653 bool thenIsAbrupt = _isAbruptTerminationExpression(thenExpression);
10654 bool elseIsAbrupt = _isAbruptTerminationExpression(elseExpression);
10655 if (elseIsAbrupt && !thenIsAbrupt) {
10656 _propagateTrueState(condition);
10657 _propagateState(thenExpression);
10658 } else if (thenIsAbrupt && !elseIsAbrupt) {
10659 _propagateFalseState(condition);
10660 _propagateState(elseExpression);
10661 }
10662 return null;
10663 }
10664
10665 @override
10666 Object visitConstructorDeclaration(ConstructorDeclaration node) {
10667 ExecutableElement outerFunction = _enclosingFunction;
10668 try {
10669 _enclosingFunction = node.element;
10670 super.visitConstructorDeclaration(node);
10671 } finally {
10672 _enclosingFunction = outerFunction;
10673 }
10674 ConstructorElementImpl constructor = node.element;
10675 constructor.constantInitializers =
10676 new ConstantAstCloner().cloneNodeList(node.initializers);
10677 return null;
10678 }
10679
10680 @override
10681 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
10682 //
10683 // We visit the expression, but do not visit the field name because it needs
10684 // to be visited in the context of the constructor field initializer node.
10685 //
10686 safelyVisit(node.expression);
10687 node.accept(elementResolver);
10688 node.accept(typeAnalyzer);
10689 return null;
10690 }
10691
10692 @override
10693 Object visitConstructorName(ConstructorName node) {
10694 //
10695 // We do not visit either the type name, because it won't be visited anyway,
10696 // or the name, because it needs to be visited in the context of the
10697 // constructor name.
10698 //
10699 node.accept(elementResolver);
10700 node.accept(typeAnalyzer);
10701 return null;
10702 }
10703
10704 @override
10705 Object visitContinueStatement(ContinueStatement node) {
10706 //
10707 // We do not visit the label because it needs to be visited in the context
10708 // of the statement.
10709 //
10710 node.accept(elementResolver);
10711 node.accept(typeAnalyzer);
10712 return null;
10713 }
10714
10715 @override
10716 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
10717 super.visitDefaultFormalParameter(node);
10718 ParameterElement element = node.element;
10719 if (element.initializer != null && node.defaultValue != null) {
10720 (element.initializer as FunctionElementImpl).returnType =
10721 node.defaultValue.staticType;
10722 }
10723 FormalParameterList parent = node.parent;
10724 AstNode grandparent = parent.parent;
10725 if (grandparent is ConstructorDeclaration &&
10726 grandparent.constKeyword != null) {
10727 // For const constructors, we need to clone the ASTs for default formal
10728 // parameters, so that we can use them during constant evaluation.
10729 ParameterElement element = node.element;
10730 (element as ConstVariableElement).constantInitializer =
10731 new ConstantAstCloner().cloneNode(node.defaultValue);
10732 }
10733 return null;
10734 }
10735
10736 @override
10737 Object visitDoStatement(DoStatement node) {
10738 _overrideManager.enterScope();
10739 try {
10740 super.visitDoStatement(node);
10741 } finally {
10742 _overrideManager.exitScope();
10743 }
10744 // TODO(brianwilkerson) If the loop can only be exited because the condition
10745 // is false, then propagateFalseState(node.getCondition());
10746 return null;
10747 }
10748
10749 @override
10750 Object visitEmptyFunctionBody(EmptyFunctionBody node) {
10751 safelyVisit(_commentBeforeFunction);
10752 if (resolveOnlyCommentInFunctionBody) {
10753 return null;
10754 }
10755 return super.visitEmptyFunctionBody(node);
10756 }
10757
10758 @override
10759 Object visitEnumDeclaration(EnumDeclaration node) {
10760 //
10761 // Resolve the metadata in the library scope
10762 // and associate the annotations with the element.
10763 //
10764 if (node.metadata != null) {
10765 node.metadata.accept(this);
10766 ElementResolver.setMetadata(node.element, node);
10767 }
10768 //
10769 // Continue the enum resolution.
10770 //
10771 ClassElement outerType = enclosingClass;
10772 try {
10773 enclosingClass = node.element;
10774 typeAnalyzer.thisType =
10775 enclosingClass == null ? null : enclosingClass.type;
10776 super.visitEnumDeclaration(node);
10777 node.accept(elementResolver);
10778 node.accept(typeAnalyzer);
10779 } finally {
10780 typeAnalyzer.thisType = outerType == null ? null : outerType.type;
10781 enclosingClass = outerType;
10782 _enclosingClassDeclaration = null;
10783 }
10784 return null;
10785 }
10786
10787 @override
10788 Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
10789 safelyVisit(_commentBeforeFunction);
10790 if (resolveOnlyCommentInFunctionBody) {
10791 return null;
10792 }
10793 _overrideManager.enterScope();
10794 try {
10795 super.visitExpressionFunctionBody(node);
10796 } finally {
10797 _overrideManager.exitScope();
10798 }
10799 return null;
10800 }
10801
10802 @override
10803 Object visitFieldDeclaration(FieldDeclaration node) {
10804 _overrideManager.enterScope();
10805 try {
10806 super.visitFieldDeclaration(node);
10807 } finally {
10808 Map<VariableElement, DartType> overrides =
10809 _overrideManager.captureOverrides(node.fields);
10810 _overrideManager.exitScope();
10811 _overrideManager.applyOverrides(overrides);
10812 }
10813 return null;
10814 }
10815
10816 @override
10817 Object visitForEachStatement(ForEachStatement node) {
10818 _overrideManager.enterScope();
10819 try {
10820 super.visitForEachStatement(node);
10821 } finally {
10822 _overrideManager.exitScope();
10823 }
10824 return null;
10825 }
10826
10827 @override
10828 void visitForEachStatementInScope(ForEachStatement node) {
10829 //
10830 // We visit the iterator before the loop variable because the loop variable
10831 // cannot be in scope while visiting the iterator.
10832 //
10833 Expression iterable = node.iterable;
10834 safelyVisit(iterable);
10835 DeclaredIdentifier loopVariable = node.loopVariable;
10836 SimpleIdentifier identifier = node.identifier;
10837 safelyVisit(loopVariable);
10838 safelyVisit(identifier);
10839 Statement body = node.body;
10840 if (body != null) {
10841 _overrideManager.enterScope();
10842 try {
10843 if (loopVariable != null && iterable != null) {
10844 LocalVariableElement loopElement = loopVariable.element;
10845 if (loopElement != null) {
10846 DartType propagatedType = null;
10847 if (node.awaitKeyword == null) {
10848 propagatedType = _getIteratorElementType(iterable);
10849 } else {
10850 propagatedType = _getStreamElementType(iterable);
10851 }
10852 if (propagatedType != null) {
10853 overrideVariable(loopElement, propagatedType, true);
10854 _recordPropagatedType(loopVariable.identifier, propagatedType);
10855 }
10856 }
10857 } else if (identifier != null && iterable != null) {
10858 Element identifierElement = identifier.staticElement;
10859 if (identifierElement is VariableElement) {
10860 DartType iteratorElementType = _getIteratorElementType(iterable);
10861 overrideVariable(identifierElement, iteratorElementType, true);
10862 _recordPropagatedType(identifier, iteratorElementType);
10863 }
10864 }
10865 visitStatementInScope(body);
10866 } finally {
10867 _overrideManager.exitScope();
10868 }
10869 }
10870 node.accept(elementResolver);
10871 node.accept(typeAnalyzer);
10872 }
10873
10874 @override
10875 Object visitForStatement(ForStatement node) {
10876 _overrideManager.enterScope();
10877 try {
10878 super.visitForStatement(node);
10879 } finally {
10880 _overrideManager.exitScope();
10881 }
10882 return null;
10883 }
10884
10885 @override
10886 void visitForStatementInScope(ForStatement node) {
10887 safelyVisit(node.variables);
10888 safelyVisit(node.initialization);
10889 safelyVisit(node.condition);
10890 _overrideManager.enterScope();
10891 try {
10892 _propagateTrueState(node.condition);
10893 visitStatementInScope(node.body);
10894 node.updaters.accept(this);
10895 } finally {
10896 _overrideManager.exitScope();
10897 }
10898 // TODO(brianwilkerson) If the loop can only be exited because the condition
10899 // is false, then propagateFalseState(condition);
10900 }
10901
10902 @override
10903 Object visitFunctionDeclaration(FunctionDeclaration node) {
10904 ExecutableElement outerFunction = _enclosingFunction;
10905 try {
10906 SimpleIdentifier functionName = node.name;
10907 _enclosingFunction = functionName.staticElement as ExecutableElement;
10908 super.visitFunctionDeclaration(node);
10909 } finally {
10910 _enclosingFunction = outerFunction;
10911 }
10912 return null;
10913 }
10914
10915 @override
10916 Object visitFunctionExpression(FunctionExpression node) {
10917 ExecutableElement outerFunction = _enclosingFunction;
10918 try {
10919 _enclosingFunction = node.element;
10920 _overrideManager.enterScope();
10921 try {
10922 super.visitFunctionExpression(node);
10923 } finally {
10924 _overrideManager.exitScope();
10925 }
10926 } finally {
10927 _enclosingFunction = outerFunction;
10928 }
10929 return null;
10930 }
10931
10932 @override
10933 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
10934 safelyVisit(node.function);
10935 node.accept(elementResolver);
10936 _inferFunctionExpressionsParametersTypes(node.argumentList);
10937 safelyVisit(node.argumentList);
10938 node.accept(typeAnalyzer);
10939 return null;
10940 }
10941
10942 @override
10943 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
10944 // Resolve the metadata in the library scope.
10945 if (node.metadata != null) {
10946 node.metadata.accept(this);
10947 }
10948 FunctionTypeAlias outerAlias = _enclosingFunctionTypeAlias;
10949 _enclosingFunctionTypeAlias = node;
10950 try {
10951 super.visitFunctionTypeAlias(node);
10952 } finally {
10953 _enclosingFunctionTypeAlias = outerAlias;
10954 }
10955 return null;
10956 }
10957
10958 @override
10959 Object visitHideCombinator(HideCombinator node) => null;
10960
10961 @override
10962 Object visitIfStatement(IfStatement node) {
10963 Expression condition = node.condition;
10964 safelyVisit(condition);
10965 Map<VariableElement, DartType> thenOverrides =
10966 new HashMap<VariableElement, DartType>();
10967 Statement thenStatement = node.thenStatement;
10968 if (thenStatement != null) {
10969 _overrideManager.enterScope();
10970 try {
10971 _promoteManager.enterScope();
10972 try {
10973 _propagateTrueState(condition);
10974 // Type promotion.
10975 _promoteTypes(condition);
10976 _clearTypePromotionsIfPotentiallyMutatedIn(thenStatement);
10977 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10978 thenStatement);
10979 // Visit "then".
10980 visitStatementInScope(thenStatement);
10981 } finally {
10982 _promoteManager.exitScope();
10983 }
10984 } finally {
10985 thenOverrides = _overrideManager.captureLocalOverrides();
10986 _overrideManager.exitScope();
10987 }
10988 }
10989 Map<VariableElement, DartType> elseOverrides =
10990 new HashMap<VariableElement, DartType>();
10991 Statement elseStatement = node.elseStatement;
10992 if (elseStatement != null) {
10993 _overrideManager.enterScope();
10994 try {
10995 _propagateFalseState(condition);
10996 visitStatementInScope(elseStatement);
10997 } finally {
10998 elseOverrides = _overrideManager.captureLocalOverrides();
10999 _overrideManager.exitScope();
11000 }
11001 }
11002 node.accept(elementResolver);
11003 node.accept(typeAnalyzer);
11004 // Join overrides.
11005 bool thenIsAbrupt = _isAbruptTerminationStatement(thenStatement);
11006 bool elseIsAbrupt = _isAbruptTerminationStatement(elseStatement);
11007 if (elseIsAbrupt && !thenIsAbrupt) {
11008 _propagateTrueState(condition);
11009 _overrideManager.applyOverrides(thenOverrides);
11010 } else if (thenIsAbrupt && !elseIsAbrupt) {
11011 _propagateFalseState(condition);
11012 _overrideManager.applyOverrides(elseOverrides);
11013 } else if (!thenIsAbrupt && !elseIsAbrupt) {
11014 List<Map<VariableElement, DartType>> perBranchOverrides =
11015 new List<Map<VariableElement, DartType>>();
11016 perBranchOverrides.add(thenOverrides);
11017 perBranchOverrides.add(elseOverrides);
11018 _overrideManager.mergeOverrides(perBranchOverrides);
11019 }
11020 return null;
11021 }
11022
11023 @override
11024 Object visitLabel(Label node) => null;
11025
11026 @override
11027 Object visitLibraryIdentifier(LibraryIdentifier node) => null;
11028
11029 @override
11030 Object visitMethodDeclaration(MethodDeclaration node) {
11031 ExecutableElement outerFunction = _enclosingFunction;
11032 try {
11033 _enclosingFunction = node.element;
11034 super.visitMethodDeclaration(node);
11035 } finally {
11036 _enclosingFunction = outerFunction;
11037 }
11038 return null;
11039 }
11040
11041 @override
11042 Object visitMethodInvocation(MethodInvocation node) {
11043 //
11044 // We visit the target and argument list, but do not visit the method name
11045 // because it needs to be visited in the context of the invocation.
11046 //
11047 safelyVisit(node.target);
11048 node.accept(elementResolver);
11049 _inferFunctionExpressionsParametersTypes(node.argumentList);
11050 safelyVisit(node.argumentList);
11051 node.accept(typeAnalyzer);
11052 return null;
11053 }
11054
11055 @override
11056 Object visitNode(AstNode node) {
11057 node.visitChildren(this);
11058 node.accept(elementResolver);
11059 node.accept(typeAnalyzer);
11060 return null;
11061 }
11062
11063 @override
11064 Object visitPrefixedIdentifier(PrefixedIdentifier node) {
11065 //
11066 // We visit the prefix, but do not visit the identifier because it needs to
11067 // be visited in the context of the prefix.
11068 //
11069 safelyVisit(node.prefix);
11070 node.accept(elementResolver);
11071 node.accept(typeAnalyzer);
11072 return null;
11073 }
11074
11075 @override
11076 Object visitPropertyAccess(PropertyAccess node) {
11077 //
11078 // We visit the target, but do not visit the property name because it needs
11079 // to be visited in the context of the property access node.
11080 //
11081 safelyVisit(node.target);
11082 node.accept(elementResolver);
11083 node.accept(typeAnalyzer);
11084 return null;
11085 }
11086
11087 @override
11088 Object visitRedirectingConstructorInvocation(
11089 RedirectingConstructorInvocation node) {
11090 //
11091 // We visit the argument list, but do not visit the optional identifier
11092 // because it needs to be visited in the context of the constructor
11093 // invocation.
11094 //
11095 safelyVisit(node.argumentList);
11096 node.accept(elementResolver);
11097 node.accept(typeAnalyzer);
11098 return null;
11099 }
11100
11101 @override
11102 Object visitShowCombinator(ShowCombinator node) => null;
11103
11104 @override
11105 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
11106 //
11107 // We visit the argument list, but do not visit the optional identifier
11108 // because it needs to be visited in the context of the constructor
11109 // invocation.
11110 //
11111 safelyVisit(node.argumentList);
11112 node.accept(elementResolver);
11113 node.accept(typeAnalyzer);
11114 return null;
11115 }
11116
11117 @override
11118 Object visitSwitchCase(SwitchCase node) {
11119 _overrideManager.enterScope();
11120 try {
11121 super.visitSwitchCase(node);
11122 } finally {
11123 _overrideManager.exitScope();
11124 }
11125 return null;
11126 }
11127
11128 @override
11129 Object visitSwitchDefault(SwitchDefault node) {
11130 _overrideManager.enterScope();
11131 try {
11132 super.visitSwitchDefault(node);
11133 } finally {
11134 _overrideManager.exitScope();
11135 }
11136 return null;
11137 }
11138
11139 @override
11140 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
11141 _overrideManager.enterScope();
11142 try {
11143 super.visitTopLevelVariableDeclaration(node);
11144 } finally {
11145 Map<VariableElement, DartType> overrides =
11146 _overrideManager.captureOverrides(node.variables);
11147 _overrideManager.exitScope();
11148 _overrideManager.applyOverrides(overrides);
11149 }
11150 return null;
11151 }
11152
11153 @override
11154 Object visitTypeName(TypeName node) => null;
11155
11156 @override
11157 Object visitVariableDeclaration(VariableDeclaration node) {
11158 super.visitVariableDeclaration(node);
11159 VariableElement element = node.element;
11160 if (element.initializer != null && node.initializer != null) {
11161 (element.initializer as FunctionElementImpl).returnType =
11162 node.initializer.staticType;
11163 }
11164 // Note: in addition to cloning the initializers for const variables, we
11165 // have to clone the initializers for non-static final fields (because if
11166 // they occur in a class with a const constructor, they will be needed to
11167 // evaluate the const constructor).
11168 if ((element.isConst ||
11169 (element is FieldElement &&
11170 element.isFinal &&
11171 !element.isStatic)) &&
11172 node.initializer != null) {
11173 (element as ConstVariableElement).constantInitializer =
11174 new ConstantAstCloner().cloneNode(node.initializer);
11175 }
11176 return null;
11177 }
11178
11179 @override
11180 Object visitWhileStatement(WhileStatement node) {
11181 // Note: since we don't call the base class, we have to maintain
11182 // _implicitLabelScope ourselves.
11183 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
11184 try {
11185 _implicitLabelScope = _implicitLabelScope.nest(node);
11186 Expression condition = node.condition;
11187 safelyVisit(condition);
11188 Statement body = node.body;
11189 if (body != null) {
11190 _overrideManager.enterScope();
11191 try {
11192 _propagateTrueState(condition);
11193 visitStatementInScope(body);
11194 } finally {
11195 _overrideManager.exitScope();
11196 }
11197 }
11198 } finally {
11199 _implicitLabelScope = outerImplicitScope;
11200 }
11201 // TODO(brianwilkerson) If the loop can only be exited because the condition
11202 // is false, then propagateFalseState(condition);
11203 node.accept(elementResolver);
11204 node.accept(typeAnalyzer);
11205 return null;
11206 }
11207
11208 /**
11209 * Checks each promoted variable in the current scope for compliance with the following
11210 * specification statement:
11211 *
11212 * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> t hen the variable
11213 * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>.
11214 */
11215 void _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
11216 AstNode target) {
11217 for (Element element in _promoteManager.promotedElements) {
11218 if ((element as VariableElementImpl).isPotentiallyMutatedInScope) {
11219 if (_isVariableAccessedInClosure(element, target)) {
11220 _promoteManager.setType(element, null);
11221 }
11222 }
11223 }
11224 }
11225
11226 /**
11227 * Checks each promoted variable in the current scope for compliance with the following
11228 * specification statement:
11229 *
11230 * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a clo sure.
11231 */
11232 void _clearTypePromotionsIfPotentiallyMutatedIn(AstNode target) {
11233 for (Element element in _promoteManager.promotedElements) {
11234 if (_isVariablePotentiallyMutatedIn(element, target)) {
11235 _promoteManager.setType(element, null);
11236 }
11237 }
11238 }
11239
11240 /**
11241 * The given expression is the expression used to compute the iterator for a
11242 * for-each statement. Attempt to compute the type of objects that will be
11243 * assigned to the loop variable and return that type. Return `null` if the
11244 * type could not be determined. The [iteratorExpression] is the expression
11245 * that will return the Iterable being iterated over.
11246 */
11247 DartType _getIteratorElementType(Expression iteratorExpression) {
11248 DartType expressionType = iteratorExpression.bestType;
11249 if (expressionType is InterfaceType) {
11250 InterfaceType interfaceType = expressionType;
11251 FunctionType iteratorFunction =
11252 _inheritanceManager.lookupMemberType(interfaceType, "iterator");
11253 if (iteratorFunction == null) {
11254 // TODO(brianwilkerson) Should we report this error?
11255 return null;
11256 }
11257 DartType iteratorType = iteratorFunction.returnType;
11258 if (iteratorType is InterfaceType) {
11259 InterfaceType iteratorInterfaceType = iteratorType;
11260 FunctionType currentFunction = _inheritanceManager.lookupMemberType(
11261 iteratorInterfaceType, "current");
11262 if (currentFunction == null) {
11263 // TODO(brianwilkerson) Should we report this error?
11264 return null;
11265 }
11266 return currentFunction.returnType;
11267 }
11268 }
11269 return null;
11270 }
11271
11272 /**
11273 * The given expression is the expression used to compute the stream for an
11274 * asyncronous for-each statement. Attempt to compute the type of objects that
11275 * will be assigned to the loop variable and return that type. Return `null`
11276 * if the type could not be determined. The [streamExpression] is the
11277 * expression that will return the stream being iterated over.
11278 */
11279 DartType _getStreamElementType(Expression streamExpression) {
11280 DartType streamType = streamExpression.bestType;
11281 if (streamType is InterfaceType) {
11282 FunctionType listenFunction =
11283 _inheritanceManager.lookupMemberType(streamType, "listen");
11284 if (listenFunction == null) {
11285 return null;
11286 }
11287 List<ParameterElement> listenParameters = listenFunction.parameters;
11288 if (listenParameters == null || listenParameters.length < 1) {
11289 return null;
11290 }
11291 DartType onDataType = listenParameters[0].type;
11292 if (onDataType is FunctionType) {
11293 List<ParameterElement> onDataParameters = onDataType.parameters;
11294 if (onDataParameters == null || onDataParameters.length < 1) {
11295 return null;
11296 }
11297 DartType eventType = onDataParameters[0].type;
11298 // TODO(paulberry): checking that typeParameters.isNotEmpty is a
11299 // band-aid fix for dartbug.com/24191. Figure out what the correct
11300 // logic should be.
11301 if (streamType.typeParameters.isNotEmpty &&
11302 eventType.element == streamType.typeParameters[0]) {
11303 return streamType.typeArguments[0];
11304 }
11305 }
11306 }
11307 return null;
11308 }
11309
11310 /**
11311 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
11312 * required type is [FunctionType], then infer parameters types from [Function Type].
11313 */
11314 void _inferFunctionExpressionParametersTypes(
11315 Expression mayBeClosure, DartType mayByFunctionType) {
11316 // prepare closure
11317 if (mayBeClosure is! FunctionExpression) {
11318 return;
11319 }
11320 FunctionExpression closure = mayBeClosure as FunctionExpression;
11321 // prepare expected closure type
11322 if (mayByFunctionType is! FunctionType) {
11323 return;
11324 }
11325 FunctionType expectedClosureType = mayByFunctionType as FunctionType;
11326 // If the expectedClosureType is not more specific than the static type,
11327 // return.
11328 DartType staticClosureType =
11329 closure.element != null ? closure.element.type : null;
11330 if (staticClosureType != null &&
11331 !expectedClosureType.isMoreSpecificThan(staticClosureType)) {
11332 return;
11333 }
11334 // set propagated type for the closure
11335 closure.propagatedType = expectedClosureType;
11336 // set inferred types for parameters
11337 NodeList<FormalParameter> parameters = closure.parameters.parameters;
11338 List<ParameterElement> expectedParameters = expectedClosureType.parameters;
11339 for (int i = 0;
11340 i < parameters.length && i < expectedParameters.length;
11341 i++) {
11342 FormalParameter parameter = parameters[i];
11343 ParameterElement element = parameter.element;
11344 DartType currentType = _overrideManager.getBestType(element);
11345 // may be override the type
11346 DartType expectedType = expectedParameters[i].type;
11347 if (currentType == null || expectedType.isMoreSpecificThan(currentType)) {
11348 _overrideManager.setType(element, expectedType);
11349 }
11350 }
11351 }
11352
11353 /**
11354 * Try to infer types of parameters of the [FunctionExpression] arguments.
11355 */
11356 void _inferFunctionExpressionsParametersTypes(ArgumentList argumentList) {
11357 for (Expression argument in argumentList.arguments) {
11358 ParameterElement parameter = argument.propagatedParameterElement;
11359 if (parameter == null) {
11360 parameter = argument.staticParameterElement;
11361 }
11362 if (parameter != null) {
11363 _inferFunctionExpressionParametersTypes(argument, parameter.type);
11364 }
11365 }
11366 }
11367
11368 /**
11369 * Return `true` if the given expression terminates abruptly (that is, if any expression
11370 * following the given expression will not be reached).
11371 *
11372 * @param expression the expression being tested
11373 * @return `true` if the given expression terminates abruptly
11374 */
11375 bool _isAbruptTerminationExpression(Expression expression) {
11376 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we
11377 // would eventually turn this into a method on Expression that returns a
11378 // termination indication (normal, abrupt with no exception, abrupt with an
11379 // exception).
11380 while (expression is ParenthesizedExpression) {
11381 expression = (expression as ParenthesizedExpression).expression;
11382 }
11383 return expression is ThrowExpression || expression is RethrowExpression;
11384 }
11385
11386 /**
11387 * Return `true` if the given statement terminates abruptly (that is, if any s tatement
11388 * following the given statement will not be reached).
11389 *
11390 * @param statement the statement being tested
11391 * @return `true` if the given statement terminates abruptly
11392 */
11393 bool _isAbruptTerminationStatement(Statement statement) {
11394 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we
11395 // would eventually turn this into a method on Statement that returns a
11396 // termination indication (normal, abrupt with no exception, abrupt with an
11397 // exception).
11398 //
11399 // collinsn: it is unsound to assume that [break] and [continue] are
11400 // "abrupt". See: https://code.google.com/p/dart/issues/detail?id=19929#c4
11401 // (tests are included in TypePropagationTest.java).
11402 // In general, the difficulty is loopy control flow.
11403 //
11404 // In the presence of exceptions things become much more complicated, but
11405 // while we only use this to propagate at [if]-statement join points,
11406 // checking for [return] may work well enough in the common case.
11407 if (statement is ReturnStatement) {
11408 return true;
11409 } else if (statement is ExpressionStatement) {
11410 return _isAbruptTerminationExpression(statement.expression);
11411 } else if (statement is Block) {
11412 NodeList<Statement> statements = statement.statements;
11413 int size = statements.length;
11414 if (size == 0) {
11415 return false;
11416 }
11417
11418 // This last-statement-is-return heuristic is unsound for adversarial
11419 // code, but probably works well in the common case:
11420 //
11421 // var x = 123;
11422 // var c = true;
11423 // L: if (c) {
11424 // x = "hello";
11425 // c = false;
11426 // break L;
11427 // return;
11428 // }
11429 // print(x);
11430 //
11431 // Unsound to assume that [x = "hello";] never executed after the
11432 // if-statement. Of course, a dead-code analysis could point out that
11433 // [return] here is dead.
11434 return _isAbruptTerminationStatement(statements[size - 1]);
11435 }
11436 return false;
11437 }
11438
11439 /**
11440 * Return `true` if the given variable is accessed within a closure in the giv en
11441 * [AstNode] and also mutated somewhere in variable scope. This information is only
11442 * available for local variables (including parameters).
11443 *
11444 * @param variable the variable to check
11445 * @param target the [AstNode] to check within
11446 * @return `true` if this variable is potentially mutated somewhere in the giv en ASTNode
11447 */
11448 bool _isVariableAccessedInClosure(Element variable, AstNode target) {
11449 _ResolverVisitor_isVariableAccessedInClosure visitor =
11450 new _ResolverVisitor_isVariableAccessedInClosure(variable);
11451 target.accept(visitor);
11452 return visitor.result;
11453 }
11454
11455 /**
11456 * Return `true` if the given variable is potentially mutated somewhere in the given
11457 * [AstNode]. This information is only available for local variables (includin g parameters).
11458 *
11459 * @param variable the variable to check
11460 * @param target the [AstNode] to check within
11461 * @return `true` if this variable is potentially mutated somewhere in the giv en ASTNode
11462 */
11463 bool _isVariablePotentiallyMutatedIn(Element variable, AstNode target) {
11464 _ResolverVisitor_isVariablePotentiallyMutatedIn visitor =
11465 new _ResolverVisitor_isVariablePotentiallyMutatedIn(variable);
11466 target.accept(visitor);
11467 return visitor.result;
11468 }
11469
11470 /**
11471 * If it is appropriate to do so, promotes the current type of the static elem ent associated with
11472 * the given expression with the given type. Generally speaking, it is appropr iate if the given
11473 * type is more specific than the current type.
11474 *
11475 * @param expression the expression used to access the static element whose ty pes might be
11476 * promoted
11477 * @param potentialType the potential type of the elements
11478 */
11479 void _promote(Expression expression, DartType potentialType) {
11480 VariableElement element = getPromotionStaticElement(expression);
11481 if (element != null) {
11482 // may be mutated somewhere in closure
11483 if (element.isPotentiallyMutatedInClosure) {
11484 return;
11485 }
11486 // prepare current variable type
11487 DartType type = _promoteManager.getType(element);
11488 if (type == null) {
11489 type = expression.staticType;
11490 }
11491 // Declared type should not be "dynamic".
11492 if (type == null || type.isDynamic) {
11493 return;
11494 }
11495 // Promoted type should not be "dynamic".
11496 if (potentialType == null || potentialType.isDynamic) {
11497 return;
11498 }
11499 // Promoted type should be more specific than declared.
11500 if (!potentialType.isMoreSpecificThan(type)) {
11501 return;
11502 }
11503 // Do promote type of variable.
11504 _promoteManager.setType(element, potentialType);
11505 }
11506 }
11507
11508 /**
11509 * Promotes type information using given condition.
11510 */
11511 void _promoteTypes(Expression condition) {
11512 if (condition is BinaryExpression) {
11513 BinaryExpression binary = condition;
11514 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) {
11515 Expression left = binary.leftOperand;
11516 Expression right = binary.rightOperand;
11517 _promoteTypes(left);
11518 _promoteTypes(right);
11519 _clearTypePromotionsIfPotentiallyMutatedIn(right);
11520 }
11521 } else if (condition is IsExpression) {
11522 IsExpression is2 = condition;
11523 if (is2.notOperator == null) {
11524 _promote(is2.expression, is2.type.type);
11525 }
11526 } else if (condition is ParenthesizedExpression) {
11527 _promoteTypes(condition.expression);
11528 }
11529 }
11530
11531 /**
11532 * Propagate any type information that results from knowing that the given con dition will have
11533 * been evaluated to 'false'.
11534 *
11535 * @param condition the condition that will have evaluated to 'false'
11536 */
11537 void _propagateFalseState(Expression condition) {
11538 if (condition is BinaryExpression) {
11539 BinaryExpression binary = condition;
11540 if (binary.operator.type == sc.TokenType.BAR_BAR) {
11541 _propagateFalseState(binary.leftOperand);
11542 _propagateFalseState(binary.rightOperand);
11543 }
11544 } else if (condition is IsExpression) {
11545 IsExpression is2 = condition;
11546 if (is2.notOperator != null) {
11547 // Since an is-statement doesn't actually change the type, we don't
11548 // let it affect the propagated type when it would result in a loss
11549 // of precision.
11550 overrideExpression(is2.expression, is2.type.type, false, false);
11551 }
11552 } else if (condition is PrefixExpression) {
11553 PrefixExpression prefix = condition;
11554 if (prefix.operator.type == sc.TokenType.BANG) {
11555 _propagateTrueState(prefix.operand);
11556 }
11557 } else if (condition is ParenthesizedExpression) {
11558 _propagateFalseState(condition.expression);
11559 }
11560 }
11561
11562 /**
11563 * Propagate any type information that results from knowing that the given exp ression will have
11564 * been evaluated without altering the flow of execution.
11565 *
11566 * @param expression the expression that will have been evaluated
11567 */
11568 void _propagateState(Expression expression) {
11569 // TODO(brianwilkerson) Implement this.
11570 }
11571
11572 /**
11573 * Propagate any type information that results from knowing that the given con dition will have
11574 * been evaluated to 'true'.
11575 *
11576 * @param condition the condition that will have evaluated to 'true'
11577 */
11578 void _propagateTrueState(Expression condition) {
11579 if (condition is BinaryExpression) {
11580 BinaryExpression binary = condition;
11581 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) {
11582 _propagateTrueState(binary.leftOperand);
11583 _propagateTrueState(binary.rightOperand);
11584 }
11585 } else if (condition is IsExpression) {
11586 IsExpression is2 = condition;
11587 if (is2.notOperator == null) {
11588 // Since an is-statement doesn't actually change the type, we don't
11589 // let it affect the propagated type when it would result in a loss
11590 // of precision.
11591 overrideExpression(is2.expression, is2.type.type, false, false);
11592 }
11593 } else if (condition is PrefixExpression) {
11594 PrefixExpression prefix = condition;
11595 if (prefix.operator.type == sc.TokenType.BANG) {
11596 _propagateFalseState(prefix.operand);
11597 }
11598 } else if (condition is ParenthesizedExpression) {
11599 _propagateTrueState(condition.expression);
11600 }
11601 }
11602
11603 /**
11604 * Record that the propagated type of the given node is the given type.
11605 *
11606 * @param expression the node whose type is to be recorded
11607 * @param type the propagated type of the node
11608 */
11609 void _recordPropagatedType(Expression expression, DartType type) {
11610 if (type != null && !type.isDynamic) {
11611 expression.propagatedType = type;
11612 }
11613 }
11614 }
11615
11616 /**
11617 * The abstract class `Scope` defines the behavior common to name scopes used by the resolver
11618 * to determine which names are visible at any given point in the code.
11619 */
11620 abstract class Scope {
11621 /**
11622 * The prefix used to mark an identifier as being private to its library.
11623 */
11624 static int PRIVATE_NAME_PREFIX = 0x5F;
11625
11626 /**
11627 * The suffix added to the declared name of a setter when looking up the sette r. Used to
11628 * disambiguate between a getter and a setter that have the same name.
11629 */
11630 static String SETTER_SUFFIX = "=";
11631
11632 /**
11633 * The name used to look up the method used to implement the unary minus opera tor. Used to
11634 * disambiguate between the unary and binary operators.
11635 */
11636 static String UNARY_MINUS = "unary-";
11637
11638 /**
11639 * A table mapping names that are defined in this scope to the element represe nting the thing
11640 * declared with that name.
11641 */
11642 HashMap<String, Element> _definedNames = new HashMap<String, Element>();
11643
11644 /**
11645 * A flag indicating whether there are any names defined in this scope.
11646 */
11647 bool _hasName = false;
11648
11649 /**
11650 * Return the scope in which this scope is lexically enclosed.
11651 *
11652 * @return the scope in which this scope is lexically enclosed
11653 */
11654 Scope get enclosingScope => null;
11655
11656 /**
11657 * Return the listener that is to be informed when an error is encountered.
11658 *
11659 * @return the listener that is to be informed when an error is encountered
11660 */
11661 AnalysisErrorListener get errorListener;
11662
11663 /**
11664 * Add the given element to this scope. If there is already an element with th e given name defined
11665 * in this scope, then an error will be generated and the original element wil l continue to be
11666 * mapped to the name. If there is an element with the given name in an enclos ing scope, then a
11667 * warning will be generated but the given element will hide the inherited ele ment.
11668 *
11669 * @param element the element to be added to this scope
11670 */
11671 void define(Element element) {
11672 String name = _getName(element);
11673 if (name != null && !name.isEmpty) {
11674 if (_definedNames.containsKey(name)) {
11675 errorListener
11676 .onError(getErrorForDuplicate(_definedNames[name], element));
11677 } else {
11678 _definedNames[name] = element;
11679 _hasName = true;
11680 }
11681 }
11682 }
11683
11684 /**
11685 * Add the given element to this scope without checking for duplication or hid ing.
11686 *
11687 * @param name the name of the element to be added
11688 * @param element the element to be added to this scope
11689 */
11690 void defineNameWithoutChecking(String name, Element element) {
11691 _definedNames[name] = element;
11692 _hasName = true;
11693 }
11694
11695 /**
11696 * Add the given element to this scope without checking for duplication or hid ing.
11697 *
11698 * @param element the element to be added to this scope
11699 */
11700 void defineWithoutChecking(Element element) {
11701 _definedNames[_getName(element)] = element;
11702 _hasName = true;
11703 }
11704
11705 /**
11706 * Return the error code to be used when reporting that a name being defined l ocally conflicts
11707 * with another element of the same name in the local scope.
11708 *
11709 * @param existing the first element to be declared with the conflicting name
11710 * @param duplicate another element declared with the conflicting name
11711 * @return the error code used to report duplicate names within a scope
11712 */
11713 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
11714 // TODO(brianwilkerson) Customize the error message based on the types of
11715 // elements that share the same name.
11716 // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being
11717 // generated.
11718 Source source = duplicate.source;
11719 return new AnalysisError(
11720 source,
11721 duplicate.nameOffset,
11722 duplicate.displayName.length,
11723 CompileTimeErrorCode.DUPLICATE_DEFINITION,
11724 [existing.displayName]);
11725 }
11726
11727 /**
11728 * Return the source that contains the given identifier, or the source associa ted with this scope
11729 * if the source containing the identifier could not be determined.
11730 *
11731 * @param identifier the identifier whose source is to be returned
11732 * @return the source that contains the given identifier
11733 */
11734 Source getSource(AstNode node) {
11735 CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit);
11736 if (unit != null) {
11737 CompilationUnitElement unitElement = unit.element;
11738 if (unitElement != null) {
11739 return unitElement.source;
11740 }
11741 }
11742 return null;
11743 }
11744
11745 /**
11746 * Return the element with which the given name is associated, or `null` if th e name is not
11747 * defined within this scope.
11748 *
11749 * @param identifier the identifier node to lookup element for, used to report correct kind of a
11750 * problem and associate problem with
11751 * @param name the name associated with the element to be returned
11752 * @param referencingLibrary the library that contains the reference to the na me, used to
11753 * implement library-level privacy
11754 * @return the element with which the given name is associated
11755 */
11756 Element internalLookup(
11757 Identifier identifier, String name, LibraryElement referencingLibrary);
11758
11759 /**
11760 * Return the element with which the given name is associated, or `null` if th e name is not
11761 * defined within this scope. This method only returns elements that are direc tly defined within
11762 * this scope, not elements that are defined in an enclosing scope.
11763 *
11764 * @param name the name associated with the element to be returned
11765 * @param referencingLibrary the library that contains the reference to the na me, used to
11766 * implement library-level privacy
11767 * @return the element with which the given name is associated
11768 */
11769 Element localLookup(String name, LibraryElement referencingLibrary) {
11770 if (_hasName) {
11771 return _definedNames[name];
11772 }
11773 return null;
11774 }
11775
11776 /**
11777 * Return the element with which the given identifier is associated, or `null` if the name
11778 * is not defined within this scope.
11779 *
11780 * @param identifier the identifier associated with the element to be returned
11781 * @param referencingLibrary the library that contains the reference to the na me, used to
11782 * implement library-level privacy
11783 * @return the element with which the given identifier is associated
11784 */
11785 Element lookup(Identifier identifier, LibraryElement referencingLibrary) =>
11786 internalLookup(identifier, identifier.name, referencingLibrary);
11787
11788 /**
11789 * Return the name that will be used to look up the given element.
11790 *
11791 * @param element the element whose look-up name is to be returned
11792 * @return the name that will be used to look up the given element
11793 */
11794 String _getName(Element element) {
11795 if (element is MethodElement) {
11796 MethodElement method = element;
11797 if (method.name == "-" && method.parameters.length == 0) {
11798 return UNARY_MINUS;
11799 }
11800 }
11801 return element.name;
11802 }
11803
11804 /**
11805 * Return `true` if the given name is a library-private name.
11806 *
11807 * @param name the name being tested
11808 * @return `true` if the given name is a library-private name
11809 */
11810 static bool isPrivateName(String name) =>
11811 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX);
11812 }
11813
11814 /**
11815 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST structure is
11816 * being visited.
11817 */
11818 abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
11819 /**
11820 * The element for the library containing the compilation unit being visited.
11821 */
11822 final LibraryElement definingLibrary;
11823
11824 /**
11825 * The source representing the compilation unit being visited.
11826 */
11827 final Source source;
11828
11829 /**
11830 * The error listener that will be informed of any errors that are found durin g resolution.
11831 */
11832 final AnalysisErrorListener errorListener;
11833
11834 /**
11835 * The scope used to resolve identifiers.
11836 */
11837 Scope nameScope;
11838
11839 /**
11840 * The object used to access the types from the core library.
11841 */
11842 final TypeProvider typeProvider;
11843
11844 /**
11845 * The scope used to resolve unlabeled `break` and `continue` statements.
11846 */
11847 ImplicitLabelScope _implicitLabelScope = ImplicitLabelScope.ROOT;
11848
11849 /**
11850 * The scope used to resolve labels for `break` and `continue` statements, or
11851 * `null` if no labels have been defined in the current context.
11852 */
11853 LabelScope labelScope;
11854
11855 /**
11856 * The class containing the AST nodes being visited,
11857 * or `null` if we are not in the scope of a class.
11858 */
11859 ClassElement enclosingClass;
11860
11861 /**
11862 * Initialize a newly created visitor to resolve the nodes in a compilation
11863 * unit.
11864 *
11865 * [definingLibrary] is the element for the library containing the
11866 * compilation unit being visited.
11867 * [source] is the source representing the compilation unit being visited.
11868 * [typeProvider] is the object used to access the types from the core
11869 * library.
11870 * [errorListener] is the error listener that will be informed of any errors
11871 * that are found during resolution.
11872 * [nameScope] is the scope used to resolve identifiers in the node that will
11873 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
11874 * created based on [definingLibrary] and [typeProvider].
11875 */
11876 ScopedVisitor(
11877 this.definingLibrary, this.source, this.typeProvider, this.errorListener,
11878 {Scope nameScope}) {
11879 if (nameScope == null) {
11880 this.nameScope = new LibraryScope(definingLibrary, errorListener);
11881 } else {
11882 this.nameScope = nameScope;
11883 }
11884 }
11885
11886 /**
11887 * Return the implicit label scope in which the current node is being
11888 * resolved.
11889 */
11890 ImplicitLabelScope get implicitLabelScope => _implicitLabelScope;
11891
11892 /**
11893 * Replaces the current [Scope] with the enclosing [Scope].
11894 *
11895 * @return the enclosing [Scope].
11896 */
11897 Scope popNameScope() {
11898 nameScope = nameScope.enclosingScope;
11899 return nameScope;
11900 }
11901
11902 /**
11903 * Pushes a new [Scope] into the visitor.
11904 *
11905 * @return the new [Scope].
11906 */
11907 Scope pushNameScope() {
11908 Scope newScope = new EnclosedScope(nameScope);
11909 nameScope = newScope;
11910 return nameScope;
11911 }
11912
11913 /**
11914 * Report an error with the given error code and arguments.
11915 *
11916 * @param errorCode the error code of the error to be reported
11917 * @param node the node specifying the location of the error
11918 * @param arguments the arguments to the error, used to compose the error mess age
11919 */
11920 void reportErrorForNode(ErrorCode errorCode, AstNode node,
11921 [List<Object> arguments]) {
11922 errorListener.onError(new AnalysisError(
11923 source, node.offset, node.length, errorCode, arguments));
11924 }
11925
11926 /**
11927 * Report an error with the given error code and arguments.
11928 *
11929 * @param errorCode the error code of the error to be reported
11930 * @param offset the offset of the location of the error
11931 * @param length the length of the location of the error
11932 * @param arguments the arguments to the error, used to compose the error mess age
11933 */
11934 void reportErrorForOffset(ErrorCode errorCode, int offset, int length,
11935 [List<Object> arguments]) {
11936 errorListener.onError(
11937 new AnalysisError(source, offset, length, errorCode, arguments));
11938 }
11939
11940 /**
11941 * Report an error with the given error code and arguments.
11942 *
11943 * @param errorCode the error code of the error to be reported
11944 * @param token the token specifying the location of the error
11945 * @param arguments the arguments to the error, used to compose the error mess age
11946 */
11947 void reportErrorForToken(ErrorCode errorCode, sc.Token token,
11948 [List<Object> arguments]) {
11949 errorListener.onError(new AnalysisError(
11950 source, token.offset, token.length, errorCode, arguments));
11951 }
11952
11953 /**
11954 * Visit the given AST node if it is not null.
11955 *
11956 * @param node the node to be visited
11957 */
11958 void safelyVisit(AstNode node) {
11959 if (node != null) {
11960 node.accept(this);
11961 }
11962 }
11963
11964 @override
11965 Object visitBlock(Block node) {
11966 Scope outerScope = nameScope;
11967 try {
11968 EnclosedScope enclosedScope = new EnclosedScope(nameScope);
11969 _hideNamesDefinedInBlock(enclosedScope, node);
11970 nameScope = enclosedScope;
11971 super.visitBlock(node);
11972 } finally {
11973 nameScope = outerScope;
11974 }
11975 return null;
11976 }
11977
11978 @override
11979 Object visitBlockFunctionBody(BlockFunctionBody node) {
11980 ImplicitLabelScope implicitOuterScope = _implicitLabelScope;
11981 try {
11982 _implicitLabelScope = ImplicitLabelScope.ROOT;
11983 super.visitBlockFunctionBody(node);
11984 } finally {
11985 _implicitLabelScope = implicitOuterScope;
11986 }
11987 return null;
11988 }
11989
11990 @override
11991 Object visitCatchClause(CatchClause node) {
11992 SimpleIdentifier exception = node.exceptionParameter;
11993 if (exception != null) {
11994 Scope outerScope = nameScope;
11995 try {
11996 nameScope = new EnclosedScope(nameScope);
11997 nameScope.define(exception.staticElement);
11998 SimpleIdentifier stackTrace = node.stackTraceParameter;
11999 if (stackTrace != null) {
12000 nameScope.define(stackTrace.staticElement);
12001 }
12002 super.visitCatchClause(node);
12003 } finally {
12004 nameScope = outerScope;
12005 }
12006 } else {
12007 super.visitCatchClause(node);
12008 }
12009 return null;
12010 }
12011
12012 @override
12013 Object visitClassDeclaration(ClassDeclaration node) {
12014 ClassElement classElement = node.element;
12015 Scope outerScope = nameScope;
12016 try {
12017 if (classElement == null) {
12018 AnalysisEngine.instance.logger.logInformation(
12019 "Missing element for class declaration ${node.name.name} in ${defini ngLibrary.source.fullName}",
12020 new CaughtException(new AnalysisException(), null));
12021 super.visitClassDeclaration(node);
12022 } else {
12023 ClassElement outerClass = enclosingClass;
12024 try {
12025 enclosingClass = node.element;
12026 nameScope = new TypeParameterScope(nameScope, classElement);
12027 visitClassDeclarationInScope(node);
12028 nameScope = new ClassScope(nameScope, classElement);
12029 visitClassMembersInScope(node);
12030 } finally {
12031 enclosingClass = outerClass;
12032 }
12033 }
12034 } finally {
12035 nameScope = outerScope;
12036 }
12037 return null;
12038 }
12039
12040 void visitClassDeclarationInScope(ClassDeclaration node) {
12041 safelyVisit(node.name);
12042 safelyVisit(node.typeParameters);
12043 safelyVisit(node.extendsClause);
12044 safelyVisit(node.withClause);
12045 safelyVisit(node.implementsClause);
12046 safelyVisit(node.nativeClause);
12047 }
12048
12049 void visitClassMembersInScope(ClassDeclaration node) {
12050 safelyVisit(node.documentationComment);
12051 node.metadata.accept(this);
12052 node.members.accept(this);
12053 }
12054
12055 @override
12056 Object visitClassTypeAlias(ClassTypeAlias node) {
12057 Scope outerScope = nameScope;
12058 try {
12059 ClassElement element = node.element;
12060 nameScope =
12061 new ClassScope(new TypeParameterScope(nameScope, element), element);
12062 super.visitClassTypeAlias(node);
12063 } finally {
12064 nameScope = outerScope;
12065 }
12066 return null;
12067 }
12068
12069 @override
12070 Object visitConstructorDeclaration(ConstructorDeclaration node) {
12071 ConstructorElement constructorElement = node.element;
12072 Scope outerScope = nameScope;
12073 try {
12074 if (constructorElement == null) {
12075 StringBuffer buffer = new StringBuffer();
12076 buffer.write("Missing element for constructor ");
12077 buffer.write(node.returnType.name);
12078 if (node.name != null) {
12079 buffer.write(".");
12080 buffer.write(node.name.name);
12081 }
12082 buffer.write(" in ");
12083 buffer.write(definingLibrary.source.fullName);
12084 AnalysisEngine.instance.logger.logInformation(buffer.toString(),
12085 new CaughtException(new AnalysisException(), null));
12086 } else {
12087 nameScope = new FunctionScope(nameScope, constructorElement);
12088 }
12089 super.visitConstructorDeclaration(node);
12090 } finally {
12091 nameScope = outerScope;
12092 }
12093 return null;
12094 }
12095
12096 @override
12097 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
12098 VariableElement element = node.element;
12099 if (element != null) {
12100 nameScope.define(element);
12101 }
12102 super.visitDeclaredIdentifier(node);
12103 return null;
12104 }
12105
12106 @override
12107 Object visitDoStatement(DoStatement node) {
12108 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12109 try {
12110 _implicitLabelScope = _implicitLabelScope.nest(node);
12111 visitStatementInScope(node.body);
12112 safelyVisit(node.condition);
12113 } finally {
12114 _implicitLabelScope = outerImplicitScope;
12115 }
12116 return null;
12117 }
12118
12119 @override
12120 Object visitEnumDeclaration(EnumDeclaration node) {
12121 ClassElement classElement = node.element;
12122 Scope outerScope = nameScope;
12123 try {
12124 if (classElement == null) {
12125 AnalysisEngine.instance.logger.logInformation(
12126 "Missing element for enum declaration ${node.name.name} in ${definin gLibrary.source.fullName}",
12127 new CaughtException(new AnalysisException(), null));
12128 super.visitEnumDeclaration(node);
12129 } else {
12130 ClassElement outerClass = enclosingClass;
12131 try {
12132 enclosingClass = node.element;
12133 nameScope = new ClassScope(nameScope, classElement);
12134 visitEnumMembersInScope(node);
12135 } finally {
12136 enclosingClass = outerClass;
12137 }
12138 }
12139 } finally {
12140 nameScope = outerScope;
12141 }
12142 return null;
12143 }
12144
12145 void visitEnumMembersInScope(EnumDeclaration node) {
12146 safelyVisit(node.documentationComment);
12147 node.metadata.accept(this);
12148 node.constants.accept(this);
12149 }
12150
12151 @override
12152 Object visitForEachStatement(ForEachStatement node) {
12153 Scope outerNameScope = nameScope;
12154 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12155 try {
12156 nameScope = new EnclosedScope(nameScope);
12157 _implicitLabelScope = _implicitLabelScope.nest(node);
12158 visitForEachStatementInScope(node);
12159 } finally {
12160 nameScope = outerNameScope;
12161 _implicitLabelScope = outerImplicitScope;
12162 }
12163 return null;
12164 }
12165
12166 /**
12167 * Visit the given statement after it's scope has been created. This replaces the normal call to
12168 * the inherited visit method so that ResolverVisitor can intervene when type propagation is
12169 * enabled.
12170 *
12171 * @param node the statement to be visited
12172 */
12173 void visitForEachStatementInScope(ForEachStatement node) {
12174 //
12175 // We visit the iterator before the loop variable because the loop variable
12176 // cannot be in scope while visiting the iterator.
12177 //
12178 safelyVisit(node.identifier);
12179 safelyVisit(node.iterable);
12180 safelyVisit(node.loopVariable);
12181 visitStatementInScope(node.body);
12182 }
12183
12184 @override
12185 Object visitFormalParameterList(FormalParameterList node) {
12186 super.visitFormalParameterList(node);
12187 // We finished resolving function signature, now include formal parameters
12188 // scope. Note: we must not do this if the parent is a
12189 // FunctionTypedFormalParameter, because in that case we aren't finished
12190 // resolving the full function signature, just a part of it.
12191 if (nameScope is FunctionScope &&
12192 node.parent is! FunctionTypedFormalParameter) {
12193 (nameScope as FunctionScope).defineParameters();
12194 }
12195 if (nameScope is FunctionTypeScope) {
12196 (nameScope as FunctionTypeScope).defineParameters();
12197 }
12198 return null;
12199 }
12200
12201 @override
12202 Object visitForStatement(ForStatement node) {
12203 Scope outerNameScope = nameScope;
12204 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12205 try {
12206 nameScope = new EnclosedScope(nameScope);
12207 _implicitLabelScope = _implicitLabelScope.nest(node);
12208 visitForStatementInScope(node);
12209 } finally {
12210 nameScope = outerNameScope;
12211 _implicitLabelScope = outerImplicitScope;
12212 }
12213 return null;
12214 }
12215
12216 /**
12217 * Visit the given statement after it's scope has been created. This replaces the normal call to
12218 * the inherited visit method so that ResolverVisitor can intervene when type propagation is
12219 * enabled.
12220 *
12221 * @param node the statement to be visited
12222 */
12223 void visitForStatementInScope(ForStatement node) {
12224 safelyVisit(node.variables);
12225 safelyVisit(node.initialization);
12226 safelyVisit(node.condition);
12227 node.updaters.accept(this);
12228 visitStatementInScope(node.body);
12229 }
12230
12231 @override
12232 Object visitFunctionDeclaration(FunctionDeclaration node) {
12233 ExecutableElement functionElement = node.element;
12234 if (functionElement != null &&
12235 functionElement.enclosingElement is! CompilationUnitElement) {
12236 nameScope.define(functionElement);
12237 }
12238 Scope outerScope = nameScope;
12239 try {
12240 if (functionElement == null) {
12241 AnalysisEngine.instance.logger.logInformation(
12242 "Missing element for top-level function ${node.name.name} in ${defin ingLibrary.source.fullName}",
12243 new CaughtException(new AnalysisException(), null));
12244 } else {
12245 nameScope = new FunctionScope(nameScope, functionElement);
12246 }
12247 super.visitFunctionDeclaration(node);
12248 } finally {
12249 nameScope = outerScope;
12250 }
12251 return null;
12252 }
12253
12254 @override
12255 Object visitFunctionExpression(FunctionExpression node) {
12256 if (node.parent is FunctionDeclaration) {
12257 // We have already created a function scope and don't need to do so again.
12258 super.visitFunctionExpression(node);
12259 } else {
12260 Scope outerScope = nameScope;
12261 try {
12262 ExecutableElement functionElement = node.element;
12263 if (functionElement == null) {
12264 StringBuffer buffer = new StringBuffer();
12265 buffer.write("Missing element for function ");
12266 AstNode parent = node.parent;
12267 while (parent != null) {
12268 if (parent is Declaration) {
12269 Element parentElement = parent.element;
12270 buffer.write(parentElement == null
12271 ? "<unknown> "
12272 : "${parentElement.name} ");
12273 }
12274 parent = parent.parent;
12275 }
12276 buffer.write("in ");
12277 buffer.write(definingLibrary.source.fullName);
12278 AnalysisEngine.instance.logger.logInformation(buffer.toString(),
12279 new CaughtException(new AnalysisException(), null));
12280 } else {
12281 nameScope = new FunctionScope(nameScope, functionElement);
12282 }
12283 super.visitFunctionExpression(node);
12284 } finally {
12285 nameScope = outerScope;
12286 }
12287 }
12288 return null;
12289 }
12290
12291 @override
12292 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
12293 Scope outerScope = nameScope;
12294 try {
12295 nameScope = new FunctionTypeScope(nameScope, node.element);
12296 super.visitFunctionTypeAlias(node);
12297 } finally {
12298 nameScope = outerScope;
12299 }
12300 return null;
12301 }
12302
12303 @override
12304 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
12305 Scope outerScope = nameScope;
12306 try {
12307 ParameterElement parameterElement = node.element;
12308 if (parameterElement == null) {
12309 AnalysisEngine.instance.logger.logInformation(
12310 "Missing element for function typed formal parameter ${node.identifi er.name} in ${definingLibrary.source.fullName}",
12311 new CaughtException(new AnalysisException(), null));
12312 } else {
12313 nameScope = new EnclosedScope(nameScope);
12314 for (TypeParameterElement typeParameter
12315 in parameterElement.typeParameters) {
12316 nameScope.define(typeParameter);
12317 }
12318 }
12319 super.visitFunctionTypedFormalParameter(node);
12320 } finally {
12321 nameScope = outerScope;
12322 }
12323 return null;
12324 }
12325
12326 @override
12327 Object visitIfStatement(IfStatement node) {
12328 safelyVisit(node.condition);
12329 visitStatementInScope(node.thenStatement);
12330 visitStatementInScope(node.elseStatement);
12331 return null;
12332 }
12333
12334 @override
12335 Object visitLabeledStatement(LabeledStatement node) {
12336 LabelScope outerScope = _addScopesFor(node.labels, node.unlabeled);
12337 try {
12338 super.visitLabeledStatement(node);
12339 } finally {
12340 labelScope = outerScope;
12341 }
12342 return null;
12343 }
12344
12345 @override
12346 Object visitMethodDeclaration(MethodDeclaration node) {
12347 Scope outerScope = nameScope;
12348 try {
12349 ExecutableElement methodElement = node.element;
12350 if (methodElement == null) {
12351 AnalysisEngine.instance.logger.logInformation(
12352 "Missing element for method ${node.name.name} in ${definingLibrary.s ource.fullName}",
12353 new CaughtException(new AnalysisException(), null));
12354 } else {
12355 nameScope = new FunctionScope(nameScope, methodElement);
12356 }
12357 super.visitMethodDeclaration(node);
12358 } finally {
12359 nameScope = outerScope;
12360 }
12361 return null;
12362 }
12363
12364 /**
12365 * Visit the given statement after it's scope has been created. This is used b y ResolverVisitor to
12366 * correctly visit the 'then' and 'else' statements of an 'if' statement.
12367 *
12368 * @param node the statement to be visited
12369 */
12370 void visitStatementInScope(Statement node) {
12371 if (node is Block) {
12372 // Don't create a scope around a block because the block will create it's
12373 // own scope.
12374 visitBlock(node);
12375 } else if (node != null) {
12376 Scope outerNameScope = nameScope;
12377 try {
12378 nameScope = new EnclosedScope(nameScope);
12379 node.accept(this);
12380 } finally {
12381 nameScope = outerNameScope;
12382 }
12383 }
12384 }
12385
12386 @override
12387 Object visitSwitchCase(SwitchCase node) {
12388 node.expression.accept(this);
12389 Scope outerNameScope = nameScope;
12390 try {
12391 nameScope = new EnclosedScope(nameScope);
12392 node.statements.accept(this);
12393 } finally {
12394 nameScope = outerNameScope;
12395 }
12396 return null;
12397 }
12398
12399 @override
12400 Object visitSwitchDefault(SwitchDefault node) {
12401 Scope outerNameScope = nameScope;
12402 try {
12403 nameScope = new EnclosedScope(nameScope);
12404 node.statements.accept(this);
12405 } finally {
12406 nameScope = outerNameScope;
12407 }
12408 return null;
12409 }
12410
12411 @override
12412 Object visitSwitchStatement(SwitchStatement node) {
12413 LabelScope outerScope = labelScope;
12414 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12415 try {
12416 _implicitLabelScope = _implicitLabelScope.nest(node);
12417 for (SwitchMember member in node.members) {
12418 for (Label label in member.labels) {
12419 SimpleIdentifier labelName = label.label;
12420 LabelElement labelElement = labelName.staticElement as LabelElement;
12421 labelScope =
12422 new LabelScope(labelScope, labelName.name, member, labelElement);
12423 }
12424 }
12425 super.visitSwitchStatement(node);
12426 } finally {
12427 labelScope = outerScope;
12428 _implicitLabelScope = outerImplicitScope;
12429 }
12430 return null;
12431 }
12432
12433 @override
12434 Object visitVariableDeclaration(VariableDeclaration node) {
12435 super.visitVariableDeclaration(node);
12436 if (node.parent.parent is! TopLevelVariableDeclaration &&
12437 node.parent.parent is! FieldDeclaration) {
12438 VariableElement element = node.element;
12439 if (element != null) {
12440 nameScope.define(element);
12441 }
12442 }
12443 return null;
12444 }
12445
12446 @override
12447 Object visitWhileStatement(WhileStatement node) {
12448 safelyVisit(node.condition);
12449 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12450 try {
12451 _implicitLabelScope = _implicitLabelScope.nest(node);
12452 visitStatementInScope(node.body);
12453 } finally {
12454 _implicitLabelScope = outerImplicitScope;
12455 }
12456 return null;
12457 }
12458
12459 /**
12460 * Add scopes for each of the given labels.
12461 *
12462 * @param labels the labels for which new scopes are to be added
12463 * @return the scope that was in effect before the new scopes were added
12464 */
12465 LabelScope _addScopesFor(NodeList<Label> labels, AstNode node) {
12466 LabelScope outerScope = labelScope;
12467 for (Label label in labels) {
12468 SimpleIdentifier labelNameNode = label.label;
12469 String labelName = labelNameNode.name;
12470 LabelElement labelElement = labelNameNode.staticElement as LabelElement;
12471 labelScope = new LabelScope(labelScope, labelName, node, labelElement);
12472 }
12473 return outerScope;
12474 }
12475
12476 /**
12477 * Marks the local declarations of the given [Block] hidden in the enclosing s cope.
12478 * According to the scoping rules name is hidden if block defines it, but name is defined after
12479 * its declaration statement.
12480 */
12481 void _hideNamesDefinedInBlock(EnclosedScope scope, Block block) {
12482 NodeList<Statement> statements = block.statements;
12483 int statementCount = statements.length;
12484 for (int i = 0; i < statementCount; i++) {
12485 Statement statement = statements[i];
12486 if (statement is VariableDeclarationStatement) {
12487 VariableDeclarationStatement vds = statement;
12488 NodeList<VariableDeclaration> variables = vds.variables.variables;
12489 int variableCount = variables.length;
12490 for (int j = 0; j < variableCount; j++) {
12491 scope.hide(variables[j].element);
12492 }
12493 } else if (statement is FunctionDeclarationStatement) {
12494 FunctionDeclarationStatement fds = statement;
12495 scope.hide(fds.functionDeclaration.element);
12496 }
12497 }
12498 }
12499 }
12500
12501 /**
12502 * Instances of this class manage the knowledge of what the set of subtypes are for a given type.
12503 */
12504 class SubtypeManager {
12505 /**
12506 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype s of the
12507 * key.
12508 */
12509 HashMap<ClassElement, HashSet<ClassElement>> _subtypeMap =
12510 new HashMap<ClassElement, HashSet<ClassElement>>();
12511
12512 /**
12513 * The set of all [LibraryElement]s that have been visited by the manager. Thi s is used both
12514 * to prevent infinite loops in the recursive methods, and also as a marker fo r the scope of the
12515 * libraries visited by this manager.
12516 */
12517 HashSet<LibraryElement> _visitedLibraries = new HashSet<LibraryElement>();
12518
12519 /**
12520 * Given some [ClassElement], return the set of all subtypes, and subtypes of subtypes.
12521 *
12522 * @param classElement the class to recursively return the set of subtypes of
12523 */
12524 HashSet<ClassElement> computeAllSubtypes(ClassElement classElement) {
12525 // Ensure that we have generated the subtype map for the library
12526 _computeSubtypesInLibrary(classElement.library);
12527 // use the subtypeMap to compute the set of all subtypes and subtype's
12528 // subtypes
12529 HashSet<ClassElement> allSubtypes = new HashSet<ClassElement>();
12530 _safelyComputeAllSubtypes(
12531 classElement, new HashSet<ClassElement>(), allSubtypes);
12532 return allSubtypes;
12533 }
12534
12535 /**
12536 * Given some [LibraryElement], visit all of the types in the library, the pas sed library,
12537 * and any imported libraries, will be in the [visitedLibraries] set.
12538 *
12539 * @param libraryElement the library to visit, it it hasn't been visited alrea dy
12540 */
12541 void ensureLibraryVisited(LibraryElement libraryElement) {
12542 _computeSubtypesInLibrary(libraryElement);
12543 }
12544
12545 /**
12546 * Given some [ClassElement], this method adds all of the pairs combinations o f itself and
12547 * all of its supertypes to the [subtypeMap] map.
12548 *
12549 * @param classElement the class element
12550 */
12551 void _computeSubtypesInClass(ClassElement classElement) {
12552 InterfaceType supertypeType = classElement.supertype;
12553 if (supertypeType != null) {
12554 ClassElement supertypeElement = supertypeType.element;
12555 if (supertypeElement != null) {
12556 _putInSubtypeMap(supertypeElement, classElement);
12557 }
12558 }
12559 List<InterfaceType> interfaceTypes = classElement.interfaces;
12560 for (InterfaceType interfaceType in interfaceTypes) {
12561 ClassElement interfaceElement = interfaceType.element;
12562 if (interfaceElement != null) {
12563 _putInSubtypeMap(interfaceElement, classElement);
12564 }
12565 }
12566 List<InterfaceType> mixinTypes = classElement.mixins;
12567 for (InterfaceType mixinType in mixinTypes) {
12568 ClassElement mixinElement = mixinType.element;
12569 if (mixinElement != null) {
12570 _putInSubtypeMap(mixinElement, classElement);
12571 }
12572 }
12573 }
12574
12575 /**
12576 * Given some [CompilationUnitElement], this method calls
12577 * [computeAllSubtypes] on all of the [ClassElement]s in the
12578 * compilation unit.
12579 *
12580 * @param unitElement the compilation unit element
12581 */
12582 void _computeSubtypesInCompilationUnit(CompilationUnitElement unitElement) {
12583 List<ClassElement> classElements = unitElement.types;
12584 for (ClassElement classElement in classElements) {
12585 _computeSubtypesInClass(classElement);
12586 }
12587 }
12588
12589 /**
12590 * Given some [LibraryElement], this method calls
12591 * [computeAllSubtypes] on all of the [ClassElement]s in the
12592 * compilation unit, and itself for all imported and exported libraries. All v isited libraries are
12593 * added to the [visitedLibraries] set.
12594 *
12595 * @param libraryElement the library element
12596 */
12597 void _computeSubtypesInLibrary(LibraryElement libraryElement) {
12598 if (libraryElement == null || _visitedLibraries.contains(libraryElement)) {
12599 return;
12600 }
12601 _visitedLibraries.add(libraryElement);
12602 _computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit);
12603 List<CompilationUnitElement> parts = libraryElement.parts;
12604 for (CompilationUnitElement part in parts) {
12605 _computeSubtypesInCompilationUnit(part);
12606 }
12607 List<LibraryElement> imports = libraryElement.importedLibraries;
12608 for (LibraryElement importElt in imports) {
12609 _computeSubtypesInLibrary(importElt.library);
12610 }
12611 List<LibraryElement> exports = libraryElement.exportedLibraries;
12612 for (LibraryElement exportElt in exports) {
12613 _computeSubtypesInLibrary(exportElt.library);
12614 }
12615 }
12616
12617 /**
12618 * Add some key/ value pair into the [subtypeMap] map.
12619 *
12620 * @param supertypeElement the key for the [subtypeMap] map
12621 * @param subtypeElement the value for the [subtypeMap] map
12622 */
12623 void _putInSubtypeMap(
12624 ClassElement supertypeElement, ClassElement subtypeElement) {
12625 HashSet<ClassElement> subtypes = _subtypeMap[supertypeElement];
12626 if (subtypes == null) {
12627 subtypes = new HashSet<ClassElement>();
12628 _subtypeMap[supertypeElement] = subtypes;
12629 }
12630 subtypes.add(subtypeElement);
12631 }
12632
12633 /**
12634 * Given some [ClassElement] and a [HashSet<ClassElement>], this method recurs ively
12635 * adds all of the subtypes of the [ClassElement] to the passed array.
12636 *
12637 * @param classElement the type to compute the set of subtypes of
12638 * @param visitedClasses the set of class elements that this method has alread y recursively seen
12639 * @param allSubtypes the computed set of subtypes of the passed class element
12640 */
12641 void _safelyComputeAllSubtypes(ClassElement classElement,
12642 HashSet<ClassElement> visitedClasses, HashSet<ClassElement> allSubtypes) {
12643 if (!visitedClasses.add(classElement)) {
12644 // if this class has already been called on this class element
12645 return;
12646 }
12647 HashSet<ClassElement> subtypes = _subtypeMap[classElement];
12648 if (subtypes == null) {
12649 return;
12650 }
12651 for (ClassElement subtype in subtypes) {
12652 _safelyComputeAllSubtypes(subtype, visitedClasses, allSubtypes);
12653 }
12654 allSubtypes.addAll(subtypes);
12655 }
12656 }
12657
12658 /**
12659 * Instances of the class `ToDoFinder` find to-do comments in Dart code.
12660 */
12661 class ToDoFinder {
12662 /**
12663 * The error reporter by which to-do comments will be reported.
12664 */
12665 final ErrorReporter _errorReporter;
12666
12667 /**
12668 * Initialize a newly created to-do finder to report to-do comments to the giv en reporter.
12669 *
12670 * @param errorReporter the error reporter by which to-do comments will be rep orted
12671 */
12672 ToDoFinder(this._errorReporter);
12673
12674 /**
12675 * Search the comments in the given compilation unit for to-do comments and re port an error for
12676 * each.
12677 *
12678 * @param unit the compilation unit containing the to-do comments
12679 */
12680 void findIn(CompilationUnit unit) {
12681 _gatherTodoComments(unit.beginToken);
12682 }
12683
12684 /**
12685 * Search the comment tokens reachable from the given token and create errors for each to-do
12686 * comment.
12687 *
12688 * @param token the head of the list of tokens being searched
12689 */
12690 void _gatherTodoComments(sc.Token token) {
12691 while (token != null && token.type != sc.TokenType.EOF) {
12692 sc.Token commentToken = token.precedingComments;
12693 while (commentToken != null) {
12694 if (commentToken.type == sc.TokenType.SINGLE_LINE_COMMENT ||
12695 commentToken.type == sc.TokenType.MULTI_LINE_COMMENT) {
12696 _scrapeTodoComment(commentToken);
12697 }
12698 commentToken = commentToken.next;
12699 }
12700 token = token.next;
12701 }
12702 }
12703
12704 /**
12705 * Look for user defined tasks in comments and convert them into info level an alysis issues.
12706 *
12707 * @param commentToken the comment token to analyze
12708 */
12709 void _scrapeTodoComment(sc.Token commentToken) {
12710 JavaPatternMatcher matcher =
12711 new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme);
12712 if (matcher.find()) {
12713 int offset =
12714 commentToken.offset + matcher.start() + matcher.group(1).length;
12715 int length = matcher.group(2).length;
12716 _errorReporter.reportErrorForOffset(
12717 TodoCode.TODO, offset, length, [matcher.group(2)]);
12718 }
12719 }
12720 }
12721
12722 /**
12723 * Instances of the class `TypeOverrideManager` manage the ability to override t he type of an
12724 * element within a given context.
12725 */
12726 class TypeOverrideManager {
12727 /**
12728 * The current override scope, or `null` if no scope has been entered.
12729 */
12730 TypeOverrideManager_TypeOverrideScope currentScope;
12731
12732 /**
12733 * Apply a set of overrides that were previously captured.
12734 *
12735 * @param overrides the overrides to be applied
12736 */
12737 void applyOverrides(Map<VariableElement, DartType> overrides) {
12738 if (currentScope == null) {
12739 throw new IllegalStateException("Cannot apply overrides without a scope");
12740 }
12741 currentScope.applyOverrides(overrides);
12742 }
12743
12744 /**
12745 * Return a table mapping the elements whose type is overridden in the current scope to the
12746 * overriding type.
12747 *
12748 * @return the overrides in the current scope
12749 */
12750 Map<VariableElement, DartType> captureLocalOverrides() {
12751 if (currentScope == null) {
12752 throw new IllegalStateException(
12753 "Cannot capture local overrides without a scope");
12754 }
12755 return currentScope.captureLocalOverrides();
12756 }
12757
12758 /**
12759 * Return a map from the elements for the variables in the given list that hav e their types
12760 * overridden to the overriding type.
12761 *
12762 * @param variableList the list of variables whose overriding types are to be captured
12763 * @return a table mapping elements to their overriding types
12764 */
12765 Map<VariableElement, DartType> captureOverrides(
12766 VariableDeclarationList variableList) {
12767 if (currentScope == null) {
12768 throw new IllegalStateException(
12769 "Cannot capture overrides without a scope");
12770 }
12771 return currentScope.captureOverrides(variableList);
12772 }
12773
12774 /**
12775 * Enter a new override scope.
12776 */
12777 void enterScope() {
12778 currentScope = new TypeOverrideManager_TypeOverrideScope(currentScope);
12779 }
12780
12781 /**
12782 * Exit the current override scope.
12783 */
12784 void exitScope() {
12785 if (currentScope == null) {
12786 throw new IllegalStateException("No scope to exit");
12787 }
12788 currentScope = currentScope._outerScope;
12789 }
12790
12791 /**
12792 * Return the best type information available for the given element. If the ty pe of the element
12793 * has been overridden, then return the overriding type. Otherwise, return the static type.
12794 *
12795 * @param element the element for which type information is to be returned
12796 * @return the best type information available for the given element
12797 */
12798 DartType getBestType(VariableElement element) {
12799 DartType bestType = getType(element);
12800 return bestType == null ? element.type : bestType;
12801 }
12802
12803 /**
12804 * Return the overridden type of the given element, or `null` if the type of t he element has
12805 * not been overridden.
12806 *
12807 * @param element the element whose type might have been overridden
12808 * @return the overridden type of the given element
12809 */
12810 DartType getType(Element element) {
12811 if (currentScope == null) {
12812 return null;
12813 }
12814 return currentScope.getType(element);
12815 }
12816
12817 /**
12818 * Update overrides assuming [perBranchOverrides] is the collection of
12819 * per-branch overrides for *all* branches flowing into a join point.
12820 *
12821 * If a variable type in any of branches is not the same as its type before
12822 * the branching, then its propagated type is reset to `null`.
12823 */
12824 void mergeOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) {
12825 for (Map<VariableElement, DartType> branch in perBranchOverrides) {
12826 branch.forEach((VariableElement variable, DartType branchType) {
12827 DartType currentType = currentScope.getType(variable);
12828 if (currentType != branchType) {
12829 currentScope.resetType(variable);
12830 }
12831 });
12832 }
12833 }
12834
12835 /**
12836 * Set the overridden type of the given element to the given type
12837 *
12838 * @param element the element whose type might have been overridden
12839 * @param type the overridden type of the given element
12840 */
12841 void setType(VariableElement element, DartType type) {
12842 if (currentScope == null) {
12843 throw new IllegalStateException("Cannot override without a scope");
12844 }
12845 currentScope.setType(element, type);
12846 }
12847 }
12848
12849 /**
12850 * Instances of the class `TypeOverrideScope` represent a scope in which the typ es of
12851 * elements can be overridden.
12852 */
12853 class TypeOverrideManager_TypeOverrideScope {
12854 /**
12855 * The outer scope in which types might be overridden.
12856 */
12857 final TypeOverrideManager_TypeOverrideScope _outerScope;
12858
12859 /**
12860 * A table mapping elements to the overridden type of that element.
12861 */
12862 Map<VariableElement, DartType> _overridenTypes =
12863 new HashMap<VariableElement, DartType>();
12864
12865 /**
12866 * Initialize a newly created scope to be an empty child of the given scope.
12867 *
12868 * @param outerScope the outer scope in which types might be overridden
12869 */
12870 TypeOverrideManager_TypeOverrideScope(this._outerScope);
12871
12872 /**
12873 * Apply a set of overrides that were previously captured.
12874 *
12875 * @param overrides the overrides to be applied
12876 */
12877 void applyOverrides(Map<VariableElement, DartType> overrides) {
12878 _overridenTypes.addAll(overrides);
12879 }
12880
12881 /**
12882 * Return a table mapping the elements whose type is overridden in the current scope to the
12883 * overriding type.
12884 *
12885 * @return the overrides in the current scope
12886 */
12887 Map<VariableElement, DartType> captureLocalOverrides() => _overridenTypes;
12888
12889 /**
12890 * Return a map from the elements for the variables in the given list that hav e their types
12891 * overridden to the overriding type.
12892 *
12893 * @param variableList the list of variables whose overriding types are to be captured
12894 * @return a table mapping elements to their overriding types
12895 */
12896 Map<VariableElement, DartType> captureOverrides(
12897 VariableDeclarationList variableList) {
12898 Map<VariableElement, DartType> overrides =
12899 new HashMap<VariableElement, DartType>();
12900 if (variableList.isConst || variableList.isFinal) {
12901 for (VariableDeclaration variable in variableList.variables) {
12902 VariableElement element = variable.element;
12903 if (element != null) {
12904 DartType type = _overridenTypes[element];
12905 if (type != null) {
12906 overrides[element] = type;
12907 }
12908 }
12909 }
12910 }
12911 return overrides;
12912 }
12913
12914 /**
12915 * Return the overridden type of the given element, or `null` if the type of t he element
12916 * has not been overridden.
12917 *
12918 * @param element the element whose type might have been overridden
12919 * @return the overridden type of the given element
12920 */
12921 DartType getType(Element element) {
12922 if (element is PropertyAccessorElement) {
12923 element = (element as PropertyAccessorElement).variable;
12924 }
12925 DartType type = _overridenTypes[element];
12926 if (_overridenTypes.containsKey(element)) {
12927 return type;
12928 }
12929 if (type != null) {
12930 return type;
12931 } else if (_outerScope != null) {
12932 return _outerScope.getType(element);
12933 }
12934 return null;
12935 }
12936
12937 /**
12938 * Clears the overridden type of the given [element].
12939 */
12940 void resetType(VariableElement element) {
12941 _overridenTypes[element] = null;
12942 }
12943
12944 /**
12945 * Set the overridden type of the given element to the given type
12946 *
12947 * @param element the element whose type might have been overridden
12948 * @param type the overridden type of the given element
12949 */
12950 void setType(VariableElement element, DartType type) {
12951 _overridenTypes[element] = type;
12952 }
12953 }
12954
12955 /**
12956 * Instances of the class `TypeParameterScope` implement the scope defined by th e type
12957 * parameters in a class.
12958 */
12959 class TypeParameterScope extends EnclosedScope {
12960 /**
12961 * Initialize a newly created scope enclosed within another scope.
12962 *
12963 * @param enclosingScope the scope in which this scope is lexically enclosed
12964 * @param typeElement the element representing the type represented by this sc ope
12965 */
12966 TypeParameterScope(Scope enclosingScope, ClassElement typeElement)
12967 : super(enclosingScope) {
12968 if (typeElement == null) {
12969 throw new IllegalArgumentException("class element cannot be null");
12970 }
12971 _defineTypeParameters(typeElement);
12972 }
12973
12974 /**
12975 * Define the type parameters for the class.
12976 *
12977 * @param typeElement the element representing the type represented by this sc ope
12978 */
12979 void _defineTypeParameters(ClassElement typeElement) {
12980 for (TypeParameterElement typeParameter in typeElement.typeParameters) {
12981 define(typeParameter);
12982 }
12983 }
12984 }
12985
12986 /**
12987 * Instances of the class `TypePromotionManager` manage the ability to promote t ypes of local
12988 * variables and formal parameters from their declared types based on control fl ow.
12989 */
12990 class TypePromotionManager {
12991 /**
12992 * The current promotion scope, or `null` if no scope has been entered.
12993 */
12994 TypePromotionManager_TypePromoteScope currentScope;
12995
12996 /**
12997 * Returns the elements with promoted types.
12998 */
12999 Iterable<Element> get promotedElements => currentScope.promotedElements;
13000
13001 /**
13002 * Enter a new promotions scope.
13003 */
13004 void enterScope() {
13005 currentScope = new TypePromotionManager_TypePromoteScope(currentScope);
13006 }
13007
13008 /**
13009 * Exit the current promotion scope.
13010 */
13011 void exitScope() {
13012 if (currentScope == null) {
13013 throw new IllegalStateException("No scope to exit");
13014 }
13015 currentScope = currentScope._outerScope;
13016 }
13017
13018 /**
13019 * Returns static type of the given variable - declared or promoted.
13020 *
13021 * @return the static type of the given variable - declared or promoted
13022 */
13023 DartType getStaticType(VariableElement variable) {
13024 DartType staticType = getType(variable);
13025 if (staticType == null) {
13026 staticType = variable.type;
13027 }
13028 return staticType;
13029 }
13030
13031 /**
13032 * Return the promoted type of the given element, or `null` if the type of the element has
13033 * not been promoted.
13034 *
13035 * @param element the element whose type might have been promoted
13036 * @return the promoted type of the given element
13037 */
13038 DartType getType(Element element) {
13039 if (currentScope == null) {
13040 return null;
13041 }
13042 return currentScope.getType(element);
13043 }
13044
13045 /**
13046 * Set the promoted type of the given element to the given type.
13047 *
13048 * @param element the element whose type might have been promoted
13049 * @param type the promoted type of the given element
13050 */
13051 void setType(Element element, DartType type) {
13052 if (currentScope == null) {
13053 throw new IllegalStateException("Cannot promote without a scope");
13054 }
13055 currentScope.setType(element, type);
13056 }
13057 }
13058
13059 /**
13060 * Instances of the class `TypePromoteScope` represent a scope in which the type s of
13061 * elements can be promoted.
13062 */
13063 class TypePromotionManager_TypePromoteScope {
13064 /**
13065 * The outer scope in which types might be promoter.
13066 */
13067 final TypePromotionManager_TypePromoteScope _outerScope;
13068
13069 /**
13070 * A table mapping elements to the promoted type of that element.
13071 */
13072 HashMap<Element, DartType> _promotedTypes = new HashMap<Element, DartType>();
13073
13074 /**
13075 * Initialize a newly created scope to be an empty child of the given scope.
13076 *
13077 * @param outerScope the outer scope in which types might be promoted
13078 */
13079 TypePromotionManager_TypePromoteScope(this._outerScope);
13080
13081 /**
13082 * Returns the elements with promoted types.
13083 */
13084 Iterable<Element> get promotedElements => _promotedTypes.keys.toSet();
13085
13086 /**
13087 * Return the promoted type of the given element, or `null` if the type of the element has
13088 * not been promoted.
13089 *
13090 * @param element the element whose type might have been promoted
13091 * @return the promoted type of the given element
13092 */
13093 DartType getType(Element element) {
13094 DartType type = _promotedTypes[element];
13095 if (type == null && element is PropertyAccessorElement) {
13096 type = _promotedTypes[element.variable];
13097 }
13098 if (type != null) {
13099 return type;
13100 } else if (_outerScope != null) {
13101 return _outerScope.getType(element);
13102 }
13103 return null;
13104 }
13105
13106 /**
13107 * Set the promoted type of the given element to the given type.
13108 *
13109 * @param element the element whose type might have been promoted
13110 * @param type the promoted type of the given element
13111 */
13112 void setType(Element element, DartType type) {
13113 _promotedTypes[element] = type;
13114 }
13115 }
13116
13117 /**
13118 * The interface `TypeProvider` defines the behavior of objects that provide acc ess to types
13119 * defined by the language.
13120 */
13121 abstract class TypeProvider {
13122 /**
13123 * Return the type representing the built-in type 'bool'.
13124 */
13125 InterfaceType get boolType;
13126
13127 /**
13128 * Return the type representing the type 'bottom'.
13129 */
13130 DartType get bottomType;
13131
13132 /**
13133 * Return the type representing the built-in type 'Deprecated'.
13134 */
13135 InterfaceType get deprecatedType;
13136
13137 /**
13138 * Return the type representing the built-in type 'double'.
13139 */
13140 InterfaceType get doubleType;
13141
13142 /**
13143 * Return the type representing the built-in type 'dynamic'.
13144 */
13145 DartType get dynamicType;
13146
13147 /**
13148 * Return the type representing the built-in type 'Function'.
13149 */
13150 InterfaceType get functionType;
13151
13152 /**
13153 * Return the type representing 'Future<dynamic>'.
13154 */
13155 InterfaceType get futureDynamicType;
13156
13157 /**
13158 * Return the type representing 'Future<Null>'.
13159 */
13160 InterfaceType get futureNullType;
13161
13162 /**
13163 * Return the type representing the built-in type 'Future'.
13164 */
13165 InterfaceType get futureType;
13166
13167 /**
13168 * Return the type representing the built-in type 'int'.
13169 */
13170 InterfaceType get intType;
13171
13172 /**
13173 * Return the type representing the type 'Iterable<dynamic>'.
13174 */
13175 InterfaceType get iterableDynamicType;
13176
13177 /**
13178 * Return the type representing the built-in type 'Iterable'.
13179 */
13180 InterfaceType get iterableType;
13181
13182 /**
13183 * Return the type representing the built-in type 'List'.
13184 */
13185 InterfaceType get listType;
13186
13187 /**
13188 * Return the type representing the built-in type 'Map'.
13189 */
13190 InterfaceType get mapType;
13191
13192 /**
13193 * Return a list containing all of the types that cannot be either extended or
13194 * implemented.
13195 */
13196 List<InterfaceType> get nonSubtypableTypes;
13197
13198 /**
13199 * Return a [DartObjectImpl] representing the `null` object.
13200 */
13201 DartObjectImpl get nullObject;
13202
13203 /**
13204 * Return the type representing the built-in type 'Null'.
13205 */
13206 InterfaceType get nullType;
13207
13208 /**
13209 * Return the type representing the built-in type 'num'.
13210 */
13211 InterfaceType get numType;
13212
13213 /**
13214 * Return the type representing the built-in type 'Object'.
13215 */
13216 InterfaceType get objectType;
13217
13218 /**
13219 * Return the type representing the built-in type 'StackTrace'.
13220 */
13221 InterfaceType get stackTraceType;
13222
13223 /**
13224 * Return the type representing 'Stream<dynamic>'.
13225 */
13226 InterfaceType get streamDynamicType;
13227
13228 /**
13229 * Return the type representing the built-in type 'Stream'.
13230 */
13231 InterfaceType get streamType;
13232
13233 /**
13234 * Return the type representing the built-in type 'String'.
13235 */
13236 InterfaceType get stringType;
13237
13238 /**
13239 * Return the type representing the built-in type 'Symbol'.
13240 */
13241 InterfaceType get symbolType;
13242
13243 /**
13244 * Return the type representing the built-in type 'Type'.
13245 */
13246 InterfaceType get typeType;
13247
13248 /**
13249 * Return the type representing typenames that can't be resolved.
13250 */
13251 DartType get undefinedType;
13252 }
13253
13254 /**
13255 * Instances of the class `TypeProviderImpl` provide access to types defined by the language
13256 * by looking for those types in the element model for the core library.
13257 */
13258 class TypeProviderImpl implements TypeProvider {
13259 /**
13260 * The type representing the built-in type 'bool'.
13261 */
13262 InterfaceType _boolType;
13263
13264 /**
13265 * The type representing the type 'bottom'.
13266 */
13267 DartType _bottomType;
13268
13269 /**
13270 * The type representing the built-in type 'double'.
13271 */
13272 InterfaceType _doubleType;
13273
13274 /**
13275 * The type representing the built-in type 'Deprecated'.
13276 */
13277 InterfaceType _deprecatedType;
13278
13279 /**
13280 * The type representing the built-in type 'dynamic'.
13281 */
13282 DartType _dynamicType;
13283
13284 /**
13285 * The type representing the built-in type 'Function'.
13286 */
13287 InterfaceType _functionType;
13288
13289 /**
13290 * The type representing 'Future<dynamic>'.
13291 */
13292 InterfaceType _futureDynamicType;
13293
13294 /**
13295 * The type representing 'Future<Null>'.
13296 */
13297 InterfaceType _futureNullType;
13298
13299 /**
13300 * The type representing the built-in type 'Future'.
13301 */
13302 InterfaceType _futureType;
13303
13304 /**
13305 * The type representing the built-in type 'int'.
13306 */
13307 InterfaceType _intType;
13308
13309 /**
13310 * The type representing 'Iterable<dynamic>'.
13311 */
13312 InterfaceType _iterableDynamicType;
13313
13314 /**
13315 * The type representing the built-in type 'Iterable'.
13316 */
13317 InterfaceType _iterableType;
13318
13319 /**
13320 * The type representing the built-in type 'List'.
13321 */
13322 InterfaceType _listType;
13323
13324 /**
13325 * The type representing the built-in type 'Map'.
13326 */
13327 InterfaceType _mapType;
13328
13329 /**
13330 * An shared object representing the value 'null'.
13331 */
13332 DartObjectImpl _nullObject;
13333
13334 /**
13335 * The type representing the type 'Null'.
13336 */
13337 InterfaceType _nullType;
13338
13339 /**
13340 * The type representing the built-in type 'num'.
13341 */
13342 InterfaceType _numType;
13343
13344 /**
13345 * The type representing the built-in type 'Object'.
13346 */
13347 InterfaceType _objectType;
13348
13349 /**
13350 * The type representing the built-in type 'StackTrace'.
13351 */
13352 InterfaceType _stackTraceType;
13353
13354 /**
13355 * The type representing 'Stream<dynamic>'.
13356 */
13357 InterfaceType _streamDynamicType;
13358
13359 /**
13360 * The type representing the built-in type 'Stream'.
13361 */
13362 InterfaceType _streamType;
13363
13364 /**
13365 * The type representing the built-in type 'String'.
13366 */
13367 InterfaceType _stringType;
13368
13369 /**
13370 * The type representing the built-in type 'Symbol'.
13371 */
13372 InterfaceType _symbolType;
13373
13374 /**
13375 * The type representing the built-in type 'Type'.
13376 */
13377 InterfaceType _typeType;
13378
13379 /**
13380 * The type representing typenames that can't be resolved.
13381 */
13382 DartType _undefinedType;
13383
13384 /**
13385 * Initialize a newly created type provider to provide the types defined in
13386 * the given [coreLibrary] and [asyncLibrary].
13387 */
13388 TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) {
13389 Namespace coreNamespace =
13390 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary);
13391 Namespace asyncNamespace =
13392 new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary);
13393 _initializeFrom(coreNamespace, asyncNamespace);
13394 }
13395
13396 /**
13397 * Initialize a newly created type provider to provide the types defined in
13398 * the given [Namespace]s.
13399 */
13400 TypeProviderImpl.forNamespaces(
13401 Namespace coreNamespace, Namespace asyncNamespace) {
13402 _initializeFrom(coreNamespace, asyncNamespace);
13403 }
13404
13405 @override
13406 InterfaceType get boolType => _boolType;
13407
13408 @override
13409 DartType get bottomType => _bottomType;
13410
13411 @override
13412 InterfaceType get deprecatedType => _deprecatedType;
13413
13414 @override
13415 InterfaceType get doubleType => _doubleType;
13416
13417 @override
13418 DartType get dynamicType => _dynamicType;
13419
13420 @override
13421 InterfaceType get functionType => _functionType;
13422
13423 @override
13424 InterfaceType get futureDynamicType => _futureDynamicType;
13425
13426 @override
13427 InterfaceType get futureNullType => _futureNullType;
13428
13429 @override
13430 InterfaceType get futureType => _futureType;
13431
13432 @override
13433 InterfaceType get intType => _intType;
13434
13435 @override
13436 InterfaceType get iterableDynamicType => _iterableDynamicType;
13437
13438 @override
13439 InterfaceType get iterableType => _iterableType;
13440
13441 @override
13442 InterfaceType get listType => _listType;
13443
13444 @override
13445 InterfaceType get mapType => _mapType;
13446
13447 @override
13448 List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
13449 nullType,
13450 numType,
13451 intType,
13452 doubleType,
13453 boolType,
13454 stringType
13455 ];
13456
13457 @override
13458 DartObjectImpl get nullObject {
13459 if (_nullObject == null) {
13460 _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
13461 }
13462 return _nullObject;
13463 }
13464
13465 @override
13466 InterfaceType get nullType => _nullType;
13467
13468 @override
13469 InterfaceType get numType => _numType;
13470
13471 @override
13472 InterfaceType get objectType => _objectType;
13473
13474 @override
13475 InterfaceType get stackTraceType => _stackTraceType;
13476
13477 @override
13478 InterfaceType get streamDynamicType => _streamDynamicType;
13479
13480 @override
13481 InterfaceType get streamType => _streamType;
13482
13483 @override
13484 InterfaceType get stringType => _stringType;
13485
13486 @override
13487 InterfaceType get symbolType => _symbolType;
13488
13489 @override
13490 InterfaceType get typeType => _typeType;
13491
13492 @override
13493 DartType get undefinedType => _undefinedType;
13494
13495 /**
13496 * Return the type with the given name from the given namespace, or `null` if there is no
13497 * class with the given name.
13498 *
13499 * @param namespace the namespace in which to search for the given name
13500 * @param typeName the name of the type being searched for
13501 * @return the type that was found
13502 */
13503 InterfaceType _getType(Namespace namespace, String typeName) {
13504 Element element = namespace.get(typeName);
13505 if (element == null) {
13506 AnalysisEngine.instance.logger
13507 .logInformation("No definition of type $typeName");
13508 return null;
13509 }
13510 return (element as ClassElement).type;
13511 }
13512
13513 /**
13514 * Initialize the types provided by this type provider from the given
13515 * [Namespace]s.
13516 */
13517 void _initializeFrom(Namespace coreNamespace, Namespace asyncNamespace) {
13518 _boolType = _getType(coreNamespace, "bool");
13519 _bottomType = BottomTypeImpl.instance;
13520 _deprecatedType = _getType(coreNamespace, "Deprecated");
13521 _doubleType = _getType(coreNamespace, "double");
13522 _dynamicType = DynamicTypeImpl.instance;
13523 _functionType = _getType(coreNamespace, "Function");
13524 _futureType = _getType(asyncNamespace, "Future");
13525 _intType = _getType(coreNamespace, "int");
13526 _iterableType = _getType(coreNamespace, "Iterable");
13527 _listType = _getType(coreNamespace, "List");
13528 _mapType = _getType(coreNamespace, "Map");
13529 _nullType = _getType(coreNamespace, "Null");
13530 _numType = _getType(coreNamespace, "num");
13531 _objectType = _getType(coreNamespace, "Object");
13532 _stackTraceType = _getType(coreNamespace, "StackTrace");
13533 _streamType = _getType(asyncNamespace, "Stream");
13534 _stringType = _getType(coreNamespace, "String");
13535 _symbolType = _getType(coreNamespace, "Symbol");
13536 _typeType = _getType(coreNamespace, "Type");
13537 _undefinedType = UndefinedTypeImpl.instance;
13538 _futureDynamicType = _futureType.substitute4(<DartType>[_dynamicType]);
13539 _futureNullType = _futureType.substitute4(<DartType>[_nullType]);
13540 _iterableDynamicType = _iterableType.substitute4(<DartType>[_dynamicType]);
13541 _streamDynamicType = _streamType.substitute4(<DartType>[_dynamicType]);
13542 }
13543 }
13544
13545 /**
13546 * Instances of the class `TypeResolverVisitor` are used to resolve the types as sociated with
13547 * the elements in the element model. This includes the types of superclasses, m ixins, interfaces,
13548 * fields, methods, parameters, and local variables. As a side-effect, this also finishes building
13549 * the type hierarchy.
13550 */
13551 class TypeResolverVisitor extends ScopedVisitor {
13552 /**
13553 * The type representing the type 'dynamic'.
13554 */
13555 DartType _dynamicType;
13556
13557 /**
13558 * The type representing typenames that can't be resolved.
13559 */
13560 DartType _undefinedType;
13561
13562 /**
13563 * The flag specifying if currently visited class references 'super' expressio n.
13564 */
13565 bool _hasReferenceToSuper = false;
13566
13567 /**
13568 * Initialize a newly created visitor to resolve the nodes in an AST node.
13569 *
13570 * [definingLibrary] is the element for the library containing the node being
13571 * visited.
13572 * [source] is the source representing the compilation unit containing the
13573 * node being visited.
13574 * [typeProvider] is the object used to access the types from the core
13575 * library.
13576 * [errorListener] is the error listener that will be informed of any errors
13577 * that are found during resolution.
13578 * [nameScope] is the scope used to resolve identifiers in the node that will
13579 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
13580 * created based on [definingLibrary] and [typeProvider].
13581 */
13582 TypeResolverVisitor(LibraryElement definingLibrary, Source source,
13583 TypeProvider typeProvider, AnalysisErrorListener errorListener,
13584 {Scope nameScope})
13585 : super(definingLibrary, source, typeProvider, errorListener,
13586 nameScope: nameScope) {
13587 _dynamicType = typeProvider.dynamicType;
13588 _undefinedType = typeProvider.undefinedType;
13589 }
13590
13591 @override
13592 Object visitAnnotation(Annotation node) {
13593 //
13594 // Visit annotations, if the annotation is @proxy, on a class, and "proxy"
13595 // resolves to the proxy annotation in dart.core, then create create the
13596 // ElementAnnotationImpl and set it as the metadata on the enclosing class.
13597 //
13598 // Element resolution is done in the ElementResolver, and this work will be
13599 // done in the general case for all annotations in the ElementResolver.
13600 // The reason we resolve this particular element early is so that
13601 // ClassElement.isProxy() returns the correct information during all
13602 // phases of the ElementResolver.
13603 //
13604 super.visitAnnotation(node);
13605 Identifier identifier = node.name;
13606 if (identifier.name.endsWith(ElementAnnotationImpl.PROXY_VARIABLE_NAME) &&
13607 node.parent is ClassDeclaration) {
13608 Element element = nameScope.lookup(identifier, definingLibrary);
13609 if (element != null &&
13610 element.library.isDartCore &&
13611 element is PropertyAccessorElement) {
13612 // This is the @proxy from dart.core
13613 ClassDeclaration classDeclaration = node.parent as ClassDeclaration;
13614 ElementAnnotationImpl elementAnnotation =
13615 new ElementAnnotationImpl(element);
13616 node.elementAnnotation = elementAnnotation;
13617 (classDeclaration.element as ClassElementImpl).metadata =
13618 <ElementAnnotationImpl>[elementAnnotation];
13619 }
13620 }
13621 return null;
13622 }
13623
13624 @override
13625 Object visitCatchClause(CatchClause node) {
13626 super.visitCatchClause(node);
13627 SimpleIdentifier exception = node.exceptionParameter;
13628 if (exception != null) {
13629 // If an 'on' clause is provided the type of the exception parameter is
13630 // the type in the 'on' clause. Otherwise, the type of the exception
13631 // parameter is 'Object'.
13632 TypeName exceptionTypeName = node.exceptionType;
13633 DartType exceptionType;
13634 if (exceptionTypeName == null) {
13635 exceptionType = typeProvider.dynamicType;
13636 } else {
13637 exceptionType = _getType(exceptionTypeName);
13638 }
13639 _recordType(exception, exceptionType);
13640 Element element = exception.staticElement;
13641 if (element is VariableElementImpl) {
13642 element.type = exceptionType;
13643 } else {
13644 // TODO(brianwilkerson) Report the internal error
13645 }
13646 }
13647 SimpleIdentifier stackTrace = node.stackTraceParameter;
13648 if (stackTrace != null) {
13649 _recordType(stackTrace, typeProvider.stackTraceType);
13650 Element element = stackTrace.staticElement;
13651 if (element is VariableElementImpl) {
13652 element.type = typeProvider.stackTraceType;
13653 } else {
13654 // TODO(brianwilkerson) Report the internal error
13655 }
13656 }
13657 return null;
13658 }
13659
13660 @override
13661 Object visitClassDeclaration(ClassDeclaration node) {
13662 _hasReferenceToSuper = false;
13663 super.visitClassDeclaration(node);
13664 ClassElementImpl classElement = _getClassElement(node.name);
13665 if (classElement != null) {
13666 classElement.hasReferenceToSuper = _hasReferenceToSuper;
13667 }
13668 return null;
13669 }
13670
13671 @override
13672 void visitClassDeclarationInScope(ClassDeclaration node) {
13673 super.visitClassDeclarationInScope(node);
13674 ExtendsClause extendsClause = node.extendsClause;
13675 WithClause withClause = node.withClause;
13676 ImplementsClause implementsClause = node.implementsClause;
13677 ClassElementImpl classElement = _getClassElement(node.name);
13678 InterfaceType superclassType = null;
13679 if (extendsClause != null) {
13680 ErrorCode errorCode = (withClause == null
13681 ? CompileTimeErrorCode.EXTENDS_NON_CLASS
13682 : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
13683 superclassType = _resolveType(extendsClause.superclass, errorCode,
13684 CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
13685 if (!identical(superclassType, typeProvider.objectType)) {
13686 classElement.validMixin = false;
13687 }
13688 }
13689 if (classElement != null) {
13690 if (superclassType == null) {
13691 InterfaceType objectType = typeProvider.objectType;
13692 if (!identical(classElement.type, objectType)) {
13693 superclassType = objectType;
13694 }
13695 }
13696 classElement.supertype = superclassType;
13697 }
13698 _resolve(classElement, withClause, implementsClause);
13699 return null;
13700 }
13701
13702 @override
13703 void visitClassMembersInScope(ClassDeclaration node) {
13704 //
13705 // Process field declarations before constructors and methods so that the
13706 // types of field formal parameters can be correctly resolved.
13707 //
13708 List<ClassMember> nonFields = new List<ClassMember>();
13709 node.visitChildren(
13710 new _TypeResolverVisitor_visitClassMembersInScope(this, nonFields));
13711 int count = nonFields.length;
13712 for (int i = 0; i < count; i++) {
13713 nonFields[i].accept(this);
13714 }
13715 }
13716
13717 @override
13718 Object visitClassTypeAlias(ClassTypeAlias node) {
13719 super.visitClassTypeAlias(node);
13720 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
13721 InterfaceType superclassType = _resolveType(node.superclass, errorCode,
13722 CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
13723 if (superclassType == null) {
13724 superclassType = typeProvider.objectType;
13725 }
13726 ClassElementImpl classElement = _getClassElement(node.name);
13727 if (classElement != null) {
13728 classElement.supertype = superclassType;
13729 }
13730 _resolve(classElement, node.withClause, node.implementsClause);
13731 return null;
13732 }
13733
13734 @override
13735 Object visitConstructorDeclaration(ConstructorDeclaration node) {
13736 super.visitConstructorDeclaration(node);
13737 ExecutableElementImpl element = node.element as ExecutableElementImpl;
13738 if (element == null) {
13739 ClassDeclaration classNode =
13740 node.getAncestor((node) => node is ClassDeclaration);
13741 StringBuffer buffer = new StringBuffer();
13742 buffer.write("The element for the constructor ");
13743 buffer.write(node.name == null ? "<unnamed>" : node.name.name);
13744 buffer.write(" in ");
13745 if (classNode == null) {
13746 buffer.write("<unknown class>");
13747 } else {
13748 buffer.write(classNode.name.name);
13749 }
13750 buffer.write(" in ");
13751 buffer.write(source.fullName);
13752 buffer.write(" was not set while trying to resolve types.");
13753 AnalysisEngine.instance.logger.logError(buffer.toString(),
13754 new CaughtException(new AnalysisException(), null));
13755 } else {
13756 ClassElement definingClass = element.enclosingElement as ClassElement;
13757 element.returnType = definingClass.type;
13758 FunctionTypeImpl type = new FunctionTypeImpl(element);
13759 type.typeArguments = definingClass.type.typeArguments;
13760 element.type = type;
13761 }
13762 return null;
13763 }
13764
13765 @override
13766 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
13767 super.visitDeclaredIdentifier(node);
13768 DartType declaredType;
13769 TypeName typeName = node.type;
13770 if (typeName == null) {
13771 declaredType = _dynamicType;
13772 } else {
13773 declaredType = _getType(typeName);
13774 }
13775 LocalVariableElementImpl element = node.element as LocalVariableElementImpl;
13776 element.type = declaredType;
13777 return null;
13778 }
13779
13780 @override
13781 Object visitFieldFormalParameter(FieldFormalParameter node) {
13782 super.visitFieldFormalParameter(node);
13783 Element element = node.identifier.staticElement;
13784 if (element is ParameterElementImpl) {
13785 ParameterElementImpl parameter = element;
13786 FormalParameterList parameterList = node.parameters;
13787 if (parameterList == null) {
13788 DartType type;
13789 TypeName typeName = node.type;
13790 if (typeName == null) {
13791 type = _dynamicType;
13792 if (parameter is FieldFormalParameterElement) {
13793 FieldElement fieldElement =
13794 (parameter as FieldFormalParameterElement).field;
13795 if (fieldElement != null) {
13796 type = fieldElement.type;
13797 }
13798 }
13799 } else {
13800 type = _getType(typeName);
13801 }
13802 parameter.type = type;
13803 } else {
13804 _setFunctionTypedParameterType(parameter, node.type, node.parameters);
13805 }
13806 } else {
13807 // TODO(brianwilkerson) Report this internal error
13808 }
13809 return null;
13810 }
13811
13812 @override
13813 Object visitFunctionDeclaration(FunctionDeclaration node) {
13814 super.visitFunctionDeclaration(node);
13815 ExecutableElementImpl element = node.element as ExecutableElementImpl;
13816 if (element == null) {
13817 StringBuffer buffer = new StringBuffer();
13818 buffer.write("The element for the top-level function ");
13819 buffer.write(node.name);
13820 buffer.write(" in ");
13821 buffer.write(source.fullName);
13822 buffer.write(" was not set while trying to resolve types.");
13823 AnalysisEngine.instance.logger.logError(buffer.toString(),
13824 new CaughtException(new AnalysisException(), null));
13825 }
13826 element.returnType = _computeReturnType(node.returnType);
13827 FunctionTypeImpl type = new FunctionTypeImpl(element);
13828 ClassElement definingClass =
13829 element.getAncestor((element) => element is ClassElement);
13830 if (definingClass != null) {
13831 type.typeArguments = definingClass.type.typeArguments;
13832 }
13833 element.type = type;
13834 return null;
13835 }
13836
13837 @override
13838 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
13839 FunctionTypeAliasElementImpl element =
13840 node.element as FunctionTypeAliasElementImpl;
13841 super.visitFunctionTypeAlias(node);
13842 element.returnType = _computeReturnType(node.returnType);
13843 return null;
13844 }
13845
13846 @override
13847 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
13848 super.visitFunctionTypedFormalParameter(node);
13849 Element element = node.identifier.staticElement;
13850 if (element is ParameterElementImpl) {
13851 _setFunctionTypedParameterType(element, node.returnType, node.parameters);
13852 } else {
13853 // TODO(brianwilkerson) Report this internal error
13854 }
13855 return null;
13856 }
13857
13858 @override
13859 Object visitMethodDeclaration(MethodDeclaration node) {
13860 super.visitMethodDeclaration(node);
13861 ExecutableElementImpl element = node.element as ExecutableElementImpl;
13862 if (element == null) {
13863 ClassDeclaration classNode =
13864 node.getAncestor((node) => node is ClassDeclaration);
13865 StringBuffer buffer = new StringBuffer();
13866 buffer.write("The element for the method ");
13867 buffer.write(node.name.name);
13868 buffer.write(" in ");
13869 if (classNode == null) {
13870 buffer.write("<unknown class>");
13871 } else {
13872 buffer.write(classNode.name.name);
13873 }
13874 buffer.write(" in ");
13875 buffer.write(source.fullName);
13876 buffer.write(" was not set while trying to resolve types.");
13877 AnalysisEngine.instance.logger.logError(buffer.toString(),
13878 new CaughtException(new AnalysisException(), null));
13879 }
13880 element.returnType = _computeReturnType(node.returnType);
13881 FunctionTypeImpl type = new FunctionTypeImpl(element);
13882 ClassElement definingClass =
13883 element.getAncestor((element) => element is ClassElement);
13884 if (definingClass != null) {
13885 type.typeArguments = definingClass.type.typeArguments;
13886 }
13887 element.type = type;
13888 if (element is PropertyAccessorElement) {
13889 PropertyAccessorElement accessor = element as PropertyAccessorElement;
13890 PropertyInducingElementImpl variable =
13891 accessor.variable as PropertyInducingElementImpl;
13892 if (accessor.isGetter) {
13893 variable.type = type.returnType;
13894 } else if (variable.type == null) {
13895 List<DartType> parameterTypes = type.normalParameterTypes;
13896 if (parameterTypes != null && parameterTypes.length > 0) {
13897 variable.type = parameterTypes[0];
13898 }
13899 }
13900 }
13901 return null;
13902 }
13903
13904 @override
13905 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
13906 super.visitSimpleFormalParameter(node);
13907 DartType declaredType;
13908 TypeName typeName = node.type;
13909 if (typeName == null) {
13910 declaredType = _dynamicType;
13911 } else {
13912 declaredType = _getType(typeName);
13913 }
13914 Element element = node.identifier.staticElement;
13915 if (element is ParameterElement) {
13916 (element as ParameterElementImpl).type = declaredType;
13917 } else {
13918 // TODO(brianwilkerson) Report the internal error.
13919 }
13920 return null;
13921 }
13922
13923 @override
13924 Object visitSuperExpression(SuperExpression node) {
13925 _hasReferenceToSuper = true;
13926 return super.visitSuperExpression(node);
13927 }
13928
13929 @override
13930 Object visitTypeName(TypeName node) {
13931 super.visitTypeName(node);
13932 Identifier typeName = node.name;
13933 TypeArgumentList argumentList = node.typeArguments;
13934 Element element = nameScope.lookup(typeName, definingLibrary);
13935 if (element == null) {
13936 //
13937 // Check to see whether the type name is either 'dynamic' or 'void',
13938 // neither of which are in the name scope and hence will not be found by
13939 // normal means.
13940 //
13941 if (typeName.name == _dynamicType.name) {
13942 _setElement(typeName, _dynamicType.element);
13943 if (argumentList != null) {
13944 // TODO(brianwilkerson) Report this error
13945 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, dynamicType.getName(), 0, argumentList.getArguments().size());
13946 }
13947 typeName.staticType = _dynamicType;
13948 node.type = _dynamicType;
13949 return null;
13950 }
13951 VoidTypeImpl voidType = VoidTypeImpl.instance;
13952 if (typeName.name == voidType.name) {
13953 // There is no element for 'void'.
13954 if (argumentList != null) {
13955 // TODO(brianwilkerson) Report this error
13956 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, voidType.getName(), 0, argumentList.getArguments().size());
13957 }
13958 typeName.staticType = voidType;
13959 node.type = voidType;
13960 return null;
13961 }
13962 //
13963 // If not, the look to see whether we might have created the wrong AST
13964 // structure for a constructor name. If so, fix the AST structure and then
13965 // proceed.
13966 //
13967 AstNode parent = node.parent;
13968 if (typeName is PrefixedIdentifier &&
13969 parent is ConstructorName &&
13970 argumentList == null) {
13971 ConstructorName name = parent;
13972 if (name.name == null) {
13973 PrefixedIdentifier prefixedIdentifier =
13974 typeName as PrefixedIdentifier;
13975 SimpleIdentifier prefix = prefixedIdentifier.prefix;
13976 element = nameScope.lookup(prefix, definingLibrary);
13977 if (element is PrefixElement) {
13978 if (parent.parent is InstanceCreationExpression &&
13979 (parent.parent as InstanceCreationExpression).isConst) {
13980 // If, if this is a const expression, then generate a
13981 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
13982 reportErrorForNode(
13983 CompileTimeErrorCode.CONST_WITH_NON_TYPE,
13984 prefixedIdentifier.identifier,
13985 [prefixedIdentifier.identifier.name]);
13986 } else {
13987 // Else, if this expression is a new expression, report a
13988 // NEW_WITH_NON_TYPE warning.
13989 reportErrorForNode(
13990 StaticWarningCode.NEW_WITH_NON_TYPE,
13991 prefixedIdentifier.identifier,
13992 [prefixedIdentifier.identifier.name]);
13993 }
13994 _setElement(prefix, element);
13995 return null;
13996 } else if (element != null) {
13997 //
13998 // Rewrite the constructor name. The parser, when it sees a
13999 // constructor named "a.b", cannot tell whether "a" is a prefix and
14000 // "b" is a class name, or whether "a" is a class name and "b" is a
14001 // constructor name. It arbitrarily chooses the former, but in this
14002 // case was wrong.
14003 //
14004 name.name = prefixedIdentifier.identifier;
14005 name.period = prefixedIdentifier.period;
14006 node.name = prefix;
14007 typeName = prefix;
14008 }
14009 }
14010 }
14011 }
14012 // check element
14013 bool elementValid = element is! MultiplyDefinedElement;
14014 if (elementValid &&
14015 element is! ClassElement &&
14016 _isTypeNameInInstanceCreationExpression(node)) {
14017 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
14018 InstanceCreationExpression creation =
14019 node.parent.parent as InstanceCreationExpression;
14020 if (creation.isConst) {
14021 if (element == null) {
14022 reportErrorForNode(
14023 CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
14024 } else {
14025 reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE,
14026 typeNameSimple, [typeName]);
14027 }
14028 elementValid = false;
14029 } else {
14030 if (element != null) {
14031 reportErrorForNode(
14032 StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
14033 elementValid = false;
14034 }
14035 }
14036 }
14037 if (elementValid && element == null) {
14038 // We couldn't resolve the type name.
14039 // TODO(jwren) Consider moving the check for
14040 // CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE from the
14041 // ErrorVerifier, so that we don't have two errors on a built in
14042 // identifier being used as a class name.
14043 // See CompileTimeErrorCodeTest.test_builtInIdentifierAsType().
14044 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
14045 RedirectingConstructorKind redirectingConstructorKind;
14046 if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) {
14047 reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
14048 typeName, [typeName.name]);
14049 } else if (typeNameSimple.name == "boolean") {
14050 reportErrorForNode(
14051 StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
14052 } else if (_isTypeNameInCatchClause(node)) {
14053 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
14054 [typeName.name]);
14055 } else if (_isTypeNameInAsExpression(node)) {
14056 reportErrorForNode(
14057 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
14058 } else if (_isTypeNameInIsExpression(node)) {
14059 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
14060 typeName, [typeName.name]);
14061 } else if ((redirectingConstructorKind =
14062 _getRedirectingConstructorKind(node)) !=
14063 null) {
14064 ErrorCode errorCode = (redirectingConstructorKind ==
14065 RedirectingConstructorKind.CONST
14066 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
14067 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
14068 reportErrorForNode(errorCode, typeName, [typeName.name]);
14069 } else if (_isTypeNameInTypeArgumentList(node)) {
14070 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
14071 typeName, [typeName.name]);
14072 } else {
14073 reportErrorForNode(
14074 StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
14075 }
14076 elementValid = false;
14077 }
14078 if (!elementValid) {
14079 if (element is MultiplyDefinedElement) {
14080 _setElement(typeName, element);
14081 } else {
14082 _setElement(typeName, _dynamicType.element);
14083 }
14084 typeName.staticType = _undefinedType;
14085 node.type = _undefinedType;
14086 return null;
14087 }
14088 DartType type = null;
14089 if (element is ClassElement) {
14090 _setElement(typeName, element);
14091 type = element.type;
14092 } else if (element is FunctionTypeAliasElement) {
14093 _setElement(typeName, element);
14094 type = element.type;
14095 } else if (element is TypeParameterElement) {
14096 _setElement(typeName, element);
14097 type = element.type;
14098 if (argumentList != null) {
14099 // Type parameters cannot have type arguments.
14100 // TODO(brianwilkerson) Report this error.
14101 // resolver.reportError(ResolverErrorCode.?, keyType);
14102 }
14103 } else if (element is MultiplyDefinedElement) {
14104 List<Element> elements = element.conflictingElements;
14105 type = _getTypeWhenMultiplyDefined(elements);
14106 if (type != null) {
14107 node.type = type;
14108 }
14109 } else {
14110 // The name does not represent a type.
14111 RedirectingConstructorKind redirectingConstructorKind;
14112 if (_isTypeNameInCatchClause(node)) {
14113 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
14114 [typeName.name]);
14115 } else if (_isTypeNameInAsExpression(node)) {
14116 reportErrorForNode(
14117 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
14118 } else if (_isTypeNameInIsExpression(node)) {
14119 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName,
14120 [typeName.name]);
14121 } else if ((redirectingConstructorKind =
14122 _getRedirectingConstructorKind(node)) !=
14123 null) {
14124 ErrorCode errorCode = (redirectingConstructorKind ==
14125 RedirectingConstructorKind.CONST
14126 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
14127 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
14128 reportErrorForNode(errorCode, typeName, [typeName.name]);
14129 } else if (_isTypeNameInTypeArgumentList(node)) {
14130 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
14131 typeName, [typeName.name]);
14132 } else {
14133 AstNode parent = typeName.parent;
14134 while (parent is TypeName) {
14135 parent = parent.parent;
14136 }
14137 if (parent is ExtendsClause ||
14138 parent is ImplementsClause ||
14139 parent is WithClause ||
14140 parent is ClassTypeAlias) {
14141 // Ignored. The error will be reported elsewhere.
14142 } else {
14143 reportErrorForNode(
14144 StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
14145 }
14146 }
14147 _setElement(typeName, _dynamicType.element);
14148 typeName.staticType = _dynamicType;
14149 node.type = _dynamicType;
14150 return null;
14151 }
14152 if (argumentList != null) {
14153 NodeList<TypeName> arguments = argumentList.arguments;
14154 int argumentCount = arguments.length;
14155 List<DartType> parameters = _getTypeArguments(type);
14156 int parameterCount = parameters.length;
14157 List<DartType> typeArguments = new List<DartType>(parameterCount);
14158 if (argumentCount == parameterCount) {
14159 for (int i = 0; i < parameterCount; i++) {
14160 TypeName argumentTypeName = arguments[i];
14161 DartType argumentType = _getType(argumentTypeName);
14162 if (argumentType == null) {
14163 argumentType = _dynamicType;
14164 }
14165 typeArguments[i] = argumentType;
14166 }
14167 } else {
14168 reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node,
14169 [typeName.name, parameterCount, argumentCount]);
14170 for (int i = 0; i < parameterCount; i++) {
14171 typeArguments[i] = _dynamicType;
14172 }
14173 }
14174 if (type is InterfaceTypeImpl) {
14175 InterfaceTypeImpl interfaceType = type as InterfaceTypeImpl;
14176 type = interfaceType.substitute4(typeArguments);
14177 } else if (type is FunctionTypeImpl) {
14178 FunctionTypeImpl functionType = type as FunctionTypeImpl;
14179 type = functionType.substitute3(typeArguments);
14180 } else {
14181 // TODO(brianwilkerson) Report this internal error.
14182 }
14183 } else {
14184 //
14185 // Check for the case where there are no type arguments given for a
14186 // parameterized type.
14187 //
14188 List<DartType> parameters = _getTypeArguments(type);
14189 int parameterCount = parameters.length;
14190 if (parameterCount > 0) {
14191 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
14192 List<DartType> arguments = new List<DartType>(parameterCount);
14193 for (int i = 0; i < parameterCount; i++) {
14194 arguments[i] = dynamicType;
14195 }
14196 type = type.substitute2(arguments, parameters);
14197 }
14198 }
14199 typeName.staticType = type;
14200 node.type = type;
14201 return null;
14202 }
14203
14204 @override
14205 Object visitTypeParameter(TypeParameter node) {
14206 super.visitTypeParameter(node);
14207 TypeName bound = node.bound;
14208 if (bound != null) {
14209 TypeParameterElementImpl typeParameter =
14210 node.name.staticElement as TypeParameterElementImpl;
14211 if (typeParameter != null) {
14212 typeParameter.bound = bound.type;
14213 }
14214 }
14215 return null;
14216 }
14217
14218 @override
14219 Object visitVariableDeclaration(VariableDeclaration node) {
14220 super.visitVariableDeclaration(node);
14221 DartType declaredType;
14222 TypeName typeName = (node.parent as VariableDeclarationList).type;
14223 if (typeName == null) {
14224 declaredType = _dynamicType;
14225 } else {
14226 declaredType = _getType(typeName);
14227 }
14228 Element element = node.name.staticElement;
14229 if (element is VariableElement) {
14230 (element as VariableElementImpl).type = declaredType;
14231 if (element is PropertyInducingElement) {
14232 PropertyInducingElement variableElement = element;
14233 PropertyAccessorElementImpl getter =
14234 variableElement.getter as PropertyAccessorElementImpl;
14235 getter.returnType = declaredType;
14236 FunctionTypeImpl getterType = new FunctionTypeImpl(getter);
14237 ClassElement definingClass =
14238 element.getAncestor((element) => element is ClassElement);
14239 if (definingClass != null) {
14240 getterType.typeArguments = definingClass.type.typeArguments;
14241 }
14242 getter.type = getterType;
14243 PropertyAccessorElementImpl setter =
14244 variableElement.setter as PropertyAccessorElementImpl;
14245 if (setter != null) {
14246 List<ParameterElement> parameters = setter.parameters;
14247 if (parameters.length > 0) {
14248 (parameters[0] as ParameterElementImpl).type = declaredType;
14249 }
14250 setter.returnType = VoidTypeImpl.instance;
14251 FunctionTypeImpl setterType = new FunctionTypeImpl(setter);
14252 if (definingClass != null) {
14253 setterType.typeArguments = definingClass.type.typeArguments;
14254 }
14255 setter.type = setterType;
14256 }
14257 }
14258 } else {
14259 // TODO(brianwilkerson) Report the internal error.
14260 }
14261 return null;
14262 }
14263
14264 /**
14265 * Given a type name representing the return type of a function, compute the r eturn type of the
14266 * function.
14267 *
14268 * @param returnType the type name representing the return type of the functio n
14269 * @return the return type that was computed
14270 */
14271 DartType _computeReturnType(TypeName returnType) {
14272 if (returnType == null) {
14273 return _dynamicType;
14274 } else {
14275 return returnType.type;
14276 }
14277 }
14278
14279 /**
14280 * Return the class element that represents the class whose name was provided.
14281 *
14282 * @param identifier the name from the declaration of a class
14283 * @return the class element that represents the class
14284 */
14285 ClassElementImpl _getClassElement(SimpleIdentifier identifier) {
14286 // TODO(brianwilkerson) Seems like we should be using
14287 // ClassDeclaration.getElement().
14288 if (identifier == null) {
14289 // TODO(brianwilkerson) Report this
14290 // Internal error: We should never build a class declaration without a
14291 // name.
14292 return null;
14293 }
14294 Element element = identifier.staticElement;
14295 if (element is! ClassElementImpl) {
14296 // TODO(brianwilkerson) Report this
14297 // Internal error: Failed to create an element for a class declaration.
14298 return null;
14299 }
14300 return element as ClassElementImpl;
14301 }
14302
14303 /**
14304 * Return an array containing all of the elements associated with the paramete rs in the given
14305 * list.
14306 *
14307 * @param parameterList the list of parameters whose elements are to be return ed
14308 * @return the elements associated with the parameters
14309 */
14310 List<ParameterElement> _getElements(FormalParameterList parameterList) {
14311 List<ParameterElement> elements = new List<ParameterElement>();
14312 for (FormalParameter parameter in parameterList.parameters) {
14313 ParameterElement element =
14314 parameter.identifier.staticElement as ParameterElement;
14315 // TODO(brianwilkerson) Understand why the element would be null.
14316 if (element != null) {
14317 elements.add(element);
14318 }
14319 }
14320 return elements;
14321 }
14322
14323 /**
14324 * The number of type arguments in the given type name does not match the numb er of parameters in
14325 * the corresponding class element. Return the error code that should be used to report this
14326 * error.
14327 *
14328 * @param node the type name with the wrong number of type arguments
14329 * @return the error code that should be used to report that the wrong number of type arguments
14330 * were provided
14331 */
14332 ErrorCode _getInvalidTypeParametersErrorCode(TypeName node) {
14333 AstNode parent = node.parent;
14334 if (parent is ConstructorName) {
14335 parent = parent.parent;
14336 if (parent is InstanceCreationExpression) {
14337 if (parent.isConst) {
14338 return CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS;
14339 } else {
14340 return StaticWarningCode.NEW_WITH_INVALID_TYPE_PARAMETERS;
14341 }
14342 }
14343 }
14344 return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
14345 }
14346
14347 /**
14348 * Checks if the given type name is the target in a redirected constructor.
14349 *
14350 * @param typeName the type name to analyze
14351 * @return some [RedirectingConstructorKind] if the given type name is used as the type in a
14352 * redirected constructor, or `null` otherwise
14353 */
14354 RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
14355 AstNode parent = typeName.parent;
14356 if (parent is ConstructorName) {
14357 ConstructorName constructorName = parent as ConstructorName;
14358 parent = constructorName.parent;
14359 if (parent is ConstructorDeclaration) {
14360 if (identical(parent.redirectedConstructor, constructorName)) {
14361 if (parent.constKeyword != null) {
14362 return RedirectingConstructorKind.CONST;
14363 }
14364 return RedirectingConstructorKind.NORMAL;
14365 }
14366 }
14367 }
14368 return null;
14369 }
14370
14371 /**
14372 * Return the type represented by the given type name.
14373 *
14374 * @param typeName the type name representing the type to be returned
14375 * @return the type represented by the type name
14376 */
14377 DartType _getType(TypeName typeName) {
14378 DartType type = typeName.type;
14379 if (type == null) {
14380 return _undefinedType;
14381 }
14382 return type;
14383 }
14384
14385 /**
14386 * Return the type arguments associated with the given type.
14387 *
14388 * @param type the type whole type arguments are to be returned
14389 * @return the type arguments associated with the given type
14390 */
14391 List<DartType> _getTypeArguments(DartType type) {
14392 if (type is InterfaceType) {
14393 return type.typeArguments;
14394 } else if (type is FunctionType) {
14395 return type.typeArguments;
14396 }
14397 return DartType.EMPTY_LIST;
14398 }
14399
14400 /**
14401 * Returns the simple identifier of the given (may be qualified) type name.
14402 *
14403 * @param typeName the (may be qualified) qualified type name
14404 * @return the simple identifier of the given (may be qualified) type name.
14405 */
14406 SimpleIdentifier _getTypeSimpleIdentifier(Identifier typeName) {
14407 if (typeName is SimpleIdentifier) {
14408 return typeName;
14409 } else {
14410 return (typeName as PrefixedIdentifier).identifier;
14411 }
14412 }
14413
14414 /**
14415 * Given the multiple elements to which a single name could potentially be res olved, return the
14416 * single interface type that should be used, or `null` if there is no clear c hoice.
14417 *
14418 * @param elements the elements to which a single name could potentially be re solved
14419 * @return the single interface type that should be used for the type name
14420 */
14421 InterfaceType _getTypeWhenMultiplyDefined(List<Element> elements) {
14422 InterfaceType type = null;
14423 for (Element element in elements) {
14424 if (element is ClassElement) {
14425 if (type != null) {
14426 return null;
14427 }
14428 type = element.type;
14429 }
14430 }
14431 return type;
14432 }
14433
14434 /**
14435 * Checks if the given type name is used as the type in an as expression.
14436 *
14437 * @param typeName the type name to analyzer
14438 * @return `true` if the given type name is used as the type in an as expressi on
14439 */
14440 bool _isTypeNameInAsExpression(TypeName typeName) {
14441 AstNode parent = typeName.parent;
14442 if (parent is AsExpression) {
14443 AsExpression asExpression = parent;
14444 return identical(asExpression.type, typeName);
14445 }
14446 return false;
14447 }
14448
14449 /**
14450 * Checks if the given type name is used as the exception type in a catch clau se.
14451 *
14452 * @param typeName the type name to analyzer
14453 * @return `true` if the given type name is used as the exception type in a ca tch clause
14454 */
14455 bool _isTypeNameInCatchClause(TypeName typeName) {
14456 AstNode parent = typeName.parent;
14457 if (parent is CatchClause) {
14458 CatchClause catchClause = parent;
14459 return identical(catchClause.exceptionType, typeName);
14460 }
14461 return false;
14462 }
14463
14464 /**
14465 * Checks if the given type name is used as the type in an instance creation e xpression.
14466 *
14467 * @param typeName the type name to analyzer
14468 * @return `true` if the given type name is used as the type in an instance cr eation
14469 * expression
14470 */
14471 bool _isTypeNameInInstanceCreationExpression(TypeName typeName) {
14472 AstNode parent = typeName.parent;
14473 if (parent is ConstructorName &&
14474 parent.parent is InstanceCreationExpression) {
14475 ConstructorName constructorName = parent;
14476 return constructorName != null &&
14477 identical(constructorName.type, typeName);
14478 }
14479 return false;
14480 }
14481
14482 /**
14483 * Checks if the given type name is used as the type in an is expression.
14484 *
14485 * @param typeName the type name to analyzer
14486 * @return `true` if the given type name is used as the type in an is expressi on
14487 */
14488 bool _isTypeNameInIsExpression(TypeName typeName) {
14489 AstNode parent = typeName.parent;
14490 if (parent is IsExpression) {
14491 IsExpression isExpression = parent;
14492 return identical(isExpression.type, typeName);
14493 }
14494 return false;
14495 }
14496
14497 /**
14498 * Checks if the given type name used in a type argument list.
14499 *
14500 * @param typeName the type name to analyzer
14501 * @return `true` if the given type name is in a type argument list
14502 */
14503 bool _isTypeNameInTypeArgumentList(TypeName typeName) =>
14504 typeName.parent is TypeArgumentList;
14505
14506 /**
14507 * Record that the static type of the given node is the given type.
14508 *
14509 * @param expression the node whose type is to be recorded
14510 * @param type the static type of the node
14511 */
14512 Object _recordType(Expression expression, DartType type) {
14513 if (type == null) {
14514 expression.staticType = _dynamicType;
14515 } else {
14516 expression.staticType = type;
14517 }
14518 return null;
14519 }
14520
14521 /**
14522 * Resolve the types in the given with and implements clauses and associate th ose types with the
14523 * given class element.
14524 *
14525 * @param classElement the class element with which the mixin and interface ty pes are to be
14526 * associated
14527 * @param withClause the with clause to be resolved
14528 * @param implementsClause the implements clause to be resolved
14529 */
14530 void _resolve(ClassElementImpl classElement, WithClause withClause,
14531 ImplementsClause implementsClause) {
14532 if (withClause != null) {
14533 List<InterfaceType> mixinTypes = _resolveTypes(
14534 withClause.mixinTypes,
14535 CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
14536 CompileTimeErrorCode.MIXIN_OF_ENUM,
14537 CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
14538 if (classElement != null) {
14539 classElement.mixins = mixinTypes;
14540 classElement.withClauseRange =
14541 new SourceRange(withClause.offset, withClause.length);
14542 }
14543 }
14544 if (implementsClause != null) {
14545 NodeList<TypeName> interfaces = implementsClause.interfaces;
14546 List<InterfaceType> interfaceTypes = _resolveTypes(
14547 interfaces,
14548 CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
14549 CompileTimeErrorCode.IMPLEMENTS_ENUM,
14550 CompileTimeErrorCode.IMPLEMENTS_DYNAMIC);
14551 if (classElement != null) {
14552 classElement.interfaces = interfaceTypes;
14553 }
14554 // TODO(brianwilkerson) Move the following checks to ErrorVerifier.
14555 int count = interfaces.length;
14556 List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false);
14557 for (int i = 0; i < detectedRepeatOnIndex.length; i++) {
14558 detectedRepeatOnIndex[i] = false;
14559 }
14560 for (int i = 0; i < count; i++) {
14561 TypeName typeName = interfaces[i];
14562 if (!detectedRepeatOnIndex[i]) {
14563 Element element = typeName.name.staticElement;
14564 for (int j = i + 1; j < count; j++) {
14565 TypeName typeName2 = interfaces[j];
14566 Identifier identifier2 = typeName2.name;
14567 String name2 = identifier2.name;
14568 Element element2 = identifier2.staticElement;
14569 if (element != null && element == element2) {
14570 detectedRepeatOnIndex[j] = true;
14571 reportErrorForNode(
14572 CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
14573 }
14574 }
14575 }
14576 }
14577 }
14578 }
14579
14580 /**
14581 * Return the type specified by the given name.
14582 *
14583 * @param typeName the type name specifying the type to be returned
14584 * @param nonTypeError the error to produce if the type name is defined to be something other than
14585 * a type
14586 * @param enumTypeError the error to produce if the type name is defined to be an enum
14587 * @param dynamicTypeError the error to produce if the type name is "dynamic"
14588 * @return the type specified by the type name
14589 */
14590 InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError,
14591 ErrorCode enumTypeError, ErrorCode dynamicTypeError) {
14592 DartType type = typeName.type;
14593 if (type is InterfaceType) {
14594 ClassElement element = type.element;
14595 if (element != null && element.isEnum) {
14596 reportErrorForNode(enumTypeError, typeName);
14597 return null;
14598 }
14599 return type;
14600 }
14601 // If the type is not an InterfaceType, then visitTypeName() sets the type
14602 // to be a DynamicTypeImpl
14603 Identifier name = typeName.name;
14604 if (name.name == sc.Keyword.DYNAMIC.syntax) {
14605 reportErrorForNode(dynamicTypeError, name, [name.name]);
14606 } else {
14607 reportErrorForNode(nonTypeError, name, [name.name]);
14608 }
14609 return null;
14610 }
14611
14612 /**
14613 * Resolve the types in the given list of type names.
14614 *
14615 * @param typeNames the type names to be resolved
14616 * @param nonTypeError the error to produce if the type name is defined to be something other than
14617 * a type
14618 * @param enumTypeError the error to produce if the type name is defined to be an enum
14619 * @param dynamicTypeError the error to produce if the type name is "dynamic"
14620 * @return an array containing all of the types that were resolved.
14621 */
14622 List<InterfaceType> _resolveTypes(
14623 NodeList<TypeName> typeNames,
14624 ErrorCode nonTypeError,
14625 ErrorCode enumTypeError,
14626 ErrorCode dynamicTypeError) {
14627 List<InterfaceType> types = new List<InterfaceType>();
14628 for (TypeName typeName in typeNames) {
14629 InterfaceType type =
14630 _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError);
14631 if (type != null) {
14632 types.add(type);
14633 }
14634 }
14635 return types;
14636 }
14637
14638 void _setElement(Identifier typeName, Element element) {
14639 if (element != null) {
14640 if (typeName is SimpleIdentifier) {
14641 typeName.staticElement = element;
14642 } else if (typeName is PrefixedIdentifier) {
14643 PrefixedIdentifier identifier = typeName;
14644 identifier.identifier.staticElement = element;
14645 SimpleIdentifier prefix = identifier.prefix;
14646 Element prefixElement = nameScope.lookup(prefix, definingLibrary);
14647 if (prefixElement != null) {
14648 prefix.staticElement = prefixElement;
14649 }
14650 }
14651 }
14652 }
14653
14654 /**
14655 * Given a parameter element, create a function type based on the given return type and parameter
14656 * list and associate the created type with the element.
14657 *
14658 * @param element the parameter element whose type is to be set
14659 * @param returnType the (possibly `null`) return type of the function
14660 * @param parameterList the list of parameters to the function
14661 */
14662 void _setFunctionTypedParameterType(ParameterElementImpl element,
14663 TypeName returnType, FormalParameterList parameterList) {
14664 List<ParameterElement> parameters = _getElements(parameterList);
14665 FunctionTypeAliasElementImpl aliasElement =
14666 new FunctionTypeAliasElementImpl.forNode(null);
14667 aliasElement.synthetic = true;
14668 aliasElement.shareParameters(parameters);
14669 aliasElement.returnType = _computeReturnType(returnType);
14670 // FunctionTypeAliasElementImpl assumes the enclosing element is a
14671 // CompilationUnitElement (because non-synthetic function types can only be
14672 // declared at top level), so to avoid breaking things, go find the
14673 // compilation unit element.
14674 aliasElement.enclosingElement =
14675 element.getAncestor((element) => element is CompilationUnitElement);
14676 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(aliasElement);
14677 ClassElement definingClass =
14678 element.getAncestor((element) => element is ClassElement);
14679 if (definingClass != null) {
14680 aliasElement.shareTypeParameters(definingClass.typeParameters);
14681 type.typeArguments = definingClass.type.typeArguments;
14682 } else {
14683 FunctionTypeAliasElement alias =
14684 element.getAncestor((element) => element is FunctionTypeAliasElement);
14685 while (alias != null && alias.isSynthetic) {
14686 alias =
14687 alias.getAncestor((element) => element is FunctionTypeAliasElement);
14688 }
14689 if (alias != null) {
14690 aliasElement.typeParameters = alias.typeParameters;
14691 type.typeArguments = alias.type.typeArguments;
14692 } else {
14693 type.typeArguments = DartType.EMPTY_LIST;
14694 }
14695 }
14696 element.type = type;
14697 }
14698
14699 /**
14700 * @return `true` if the name of the given [TypeName] is an built-in identifie r.
14701 */
14702 static bool _isBuiltInIdentifier(TypeName node) {
14703 sc.Token token = node.name.beginToken;
14704 return token.type == sc.TokenType.KEYWORD;
14705 }
14706
14707 /**
14708 * @return `true` if given [TypeName] is used as a type annotation.
14709 */
14710 static bool _isTypeAnnotation(TypeName node) {
14711 AstNode parent = node.parent;
14712 if (parent is VariableDeclarationList) {
14713 return identical(parent.type, node);
14714 }
14715 if (parent is FieldFormalParameter) {
14716 return identical(parent.type, node);
14717 }
14718 if (parent is SimpleFormalParameter) {
14719 return identical(parent.type, node);
14720 }
14721 return false;
14722 }
14723 }
14724
14725 /**
14726 * The interface `TypeSystem` defines the behavior of an object representing
14727 * the type system. This provides a common location to put methods that act on
14728 * types but may need access to more global data structures, and it paves the
14729 * way for a possible future where we may wish to make the type system
14730 * pluggable.
14731 */
14732 abstract class TypeSystem {
14733 /**
14734 * Return the [TypeProvider] associated with this [TypeSystem].
14735 */
14736 TypeProvider get typeProvider;
14737
14738 /**
14739 * Compute the least upper bound of two types.
14740 */
14741 DartType getLeastUpperBound(DartType type1, DartType type2);
14742
14743 /**
14744 * Return `true` if the [leftType] is a subtype of the [rightType] (that is,
14745 * if leftType <: rightType).
14746 */
14747 bool isSubtypeOf(DartType leftType, DartType rightType);
14748 }
14749
14750 /**
14751 * Implementation of [TypeSystem] using the rules in the Dart specification.
14752 */
14753 class TypeSystemImpl implements TypeSystem {
14754 @override
14755 final TypeProvider typeProvider;
14756
14757 TypeSystemImpl(this.typeProvider);
14758
14759 @override
14760 DartType getLeastUpperBound(DartType type1, DartType type2) {
14761 // The least upper bound relation is reflexive.
14762 if (identical(type1, type2)) {
14763 return type1;
14764 }
14765 // The least upper bound of dynamic and any type T is dynamic.
14766 if (type1.isDynamic) {
14767 return type1;
14768 }
14769 if (type2.isDynamic) {
14770 return type2;
14771 }
14772 // The least upper bound of void and any type T != dynamic is void.
14773 if (type1.isVoid) {
14774 return type1;
14775 }
14776 if (type2.isVoid) {
14777 return type2;
14778 }
14779 // The least upper bound of bottom and any type T is T.
14780 if (type1.isBottom) {
14781 return type2;
14782 }
14783 if (type2.isBottom) {
14784 return type1;
14785 }
14786 // Let U be a type variable with upper bound B. The least upper bound of U
14787 // and a type T is the least upper bound of B and T.
14788 while (type1 is TypeParameterType) {
14789 // TODO(paulberry): is this correct in the complex of F-bounded
14790 // polymorphism?
14791 DartType bound = (type1 as TypeParameterType).element.bound;
14792 if (bound == null) {
14793 bound = typeProvider.objectType;
14794 }
14795 type1 = bound;
14796 }
14797 while (type2 is TypeParameterType) {
14798 // TODO(paulberry): is this correct in the context of F-bounded
14799 // polymorphism?
14800 DartType bound = (type2 as TypeParameterType).element.bound;
14801 if (bound == null) {
14802 bound = typeProvider.objectType;
14803 }
14804 type2 = bound;
14805 }
14806 // The least upper bound of a function type and an interface type T is the
14807 // least upper bound of Function and T.
14808 if (type1 is FunctionType && type2 is InterfaceType) {
14809 type1 = typeProvider.functionType;
14810 }
14811 if (type2 is FunctionType && type1 is InterfaceType) {
14812 type2 = typeProvider.functionType;
14813 }
14814
14815 // At this point type1 and type2 should both either be interface types or
14816 // function types.
14817 if (type1 is InterfaceType && type2 is InterfaceType) {
14818 InterfaceType result =
14819 InterfaceTypeImpl.computeLeastUpperBound(type1, type2);
14820 if (result == null) {
14821 return typeProvider.dynamicType;
14822 }
14823 return result;
14824 } else if (type1 is FunctionType && type2 is FunctionType) {
14825 FunctionType result =
14826 FunctionTypeImpl.computeLeastUpperBound(type1, type2);
14827 if (result == null) {
14828 return typeProvider.functionType;
14829 }
14830 return result;
14831 } else {
14832 // Should never happen. As a defensive measure, return the dynamic type.
14833 assert(false);
14834 return typeProvider.dynamicType;
14835 }
14836 }
14837
14838 @override
14839 bool isSubtypeOf(DartType leftType, DartType rightType) {
14840 return leftType.isSubtypeOf(rightType);
14841 }
14842 }
14843
14844 /**
14845 * Instances of the class [UnusedLocalElementsVerifier] traverse an element
14846 * structure looking for cases of [HintCode.UNUSED_ELEMENT],
14847 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc.
14848 */
14849 class UnusedLocalElementsVerifier extends RecursiveElementVisitor {
14850 /**
14851 * The error listener to which errors will be reported.
14852 */
14853 final AnalysisErrorListener _errorListener;
14854
14855 /**
14856 * The elements know to be used.
14857 */
14858 final UsedLocalElements _usedElements;
14859
14860 /**
14861 * Create a new instance of the [UnusedLocalElementsVerifier].
14862 */
14863 UnusedLocalElementsVerifier(this._errorListener, this._usedElements);
14864
14865 @override
14866 visitClassElement(ClassElement element) {
14867 if (!_isUsedElement(element)) {
14868 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
14869 [element.kind.displayName, element.displayName]);
14870 }
14871 super.visitClassElement(element);
14872 }
14873
14874 @override
14875 visitFieldElement(FieldElement element) {
14876 if (!_isReadMember(element)) {
14877 _reportErrorForElement(
14878 HintCode.UNUSED_FIELD, element, [element.displayName]);
14879 }
14880 super.visitFieldElement(element);
14881 }
14882
14883 @override
14884 visitFunctionElement(FunctionElement element) {
14885 if (!_isUsedElement(element)) {
14886 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
14887 [element.kind.displayName, element.displayName]);
14888 }
14889 super.visitFunctionElement(element);
14890 }
14891
14892 @override
14893 visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
14894 if (!_isUsedElement(element)) {
14895 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
14896 [element.kind.displayName, element.displayName]);
14897 }
14898 super.visitFunctionTypeAliasElement(element);
14899 }
14900
14901 @override
14902 visitLocalVariableElement(LocalVariableElement element) {
14903 if (!_isUsedElement(element) && !_isNamedUnderscore(element)) {
14904 HintCode errorCode;
14905 if (_usedElements.isCatchException(element)) {
14906 errorCode = HintCode.UNUSED_CATCH_CLAUSE;
14907 } else if (_usedElements.isCatchStackTrace(element)) {
14908 errorCode = HintCode.UNUSED_CATCH_STACK;
14909 } else {
14910 errorCode = HintCode.UNUSED_LOCAL_VARIABLE;
14911 }
14912 _reportErrorForElement(errorCode, element, [element.displayName]);
14913 }
14914 }
14915
14916 @override
14917 visitMethodElement(MethodElement element) {
14918 if (!_isUsedMember(element)) {
14919 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
14920 [element.kind.displayName, element.displayName]);
14921 }
14922 super.visitMethodElement(element);
14923 }
14924
14925 @override
14926 visitPropertyAccessorElement(PropertyAccessorElement element) {
14927 if (!_isUsedMember(element)) {
14928 _reportErrorForElement(HintCode.UNUSED_ELEMENT, element,
14929 [element.kind.displayName, element.displayName]);
14930 }
14931 super.visitPropertyAccessorElement(element);
14932 }
14933
14934 bool _isNamedUnderscore(LocalVariableElement element) {
14935 String name = element.name;
14936 if (name != null) {
14937 for (int index = name.length - 1; index >= 0; --index) {
14938 if (name.codeUnitAt(index) != 0x5F) {
14939 // 0x5F => '_'
14940 return false;
14941 }
14942 }
14943 return true;
14944 }
14945 return false;
14946 }
14947
14948 bool _isReadMember(Element element) {
14949 if (element.isPublic) {
14950 return true;
14951 }
14952 if (element.isSynthetic) {
14953 return true;
14954 }
14955 return _usedElements.readMembers.contains(element.displayName);
14956 }
14957
14958 bool _isUsedElement(Element element) {
14959 if (element.isSynthetic) {
14960 return true;
14961 }
14962 if (element is LocalVariableElement ||
14963 element is FunctionElement && !element.isStatic) {
14964 // local variable or function
14965 } else {
14966 if (element.isPublic) {
14967 return true;
14968 }
14969 }
14970 return _usedElements.elements.contains(element);
14971 }
14972
14973 bool _isUsedMember(Element element) {
14974 if (element.isPublic) {
14975 return true;
14976 }
14977 if (element.isSynthetic) {
14978 return true;
14979 }
14980 if (_usedElements.members.contains(element.displayName)) {
14981 return true;
14982 }
14983 return _usedElements.elements.contains(element);
14984 }
14985
14986 void _reportErrorForElement(
14987 ErrorCode errorCode, Element element, List<Object> arguments) {
14988 if (element != null) {
14989 _errorListener.onError(new AnalysisError(
14990 element.source,
14991 element.nameOffset,
14992 element.displayName.length,
14993 errorCode,
14994 arguments));
14995 }
14996 }
14997 }
14998
14999 /**
15000 * A container with information about used imports prefixes and used imported
15001 * elements.
15002 */
15003 class UsedImportedElements {
15004 /**
15005 * The set of referenced [PrefixElement]s.
15006 */
15007 final Set<PrefixElement> prefixes = new HashSet<PrefixElement>();
15008
15009 /**
15010 * The set of referenced top-level [Element]s.
15011 */
15012 final Set<Element> elements = new HashSet<Element>();
15013 }
15014
15015 /**
15016 * A container with sets of used [Element]s.
15017 * All these elements are defined in a single compilation unit or a library.
15018 */
15019 class UsedLocalElements {
15020 /**
15021 * Resolved, locally defined elements that are used or potentially can be
15022 * used.
15023 */
15024 final HashSet<Element> elements = new HashSet<Element>();
15025
15026 /**
15027 * [LocalVariableElement]s that represent exceptions in [CatchClause]s.
15028 */
15029 final HashSet<LocalVariableElement> catchExceptionElements =
15030 new HashSet<LocalVariableElement>();
15031
15032 /**
15033 * [LocalVariableElement]s that represent stack traces in [CatchClause]s.
15034 */
15035 final HashSet<LocalVariableElement> catchStackTraceElements =
15036 new HashSet<LocalVariableElement>();
15037
15038 /**
15039 * Names of resolved or unresolved class members that are referenced in the
15040 * library.
15041 */
15042 final HashSet<String> members = new HashSet<String>();
15043
15044 /**
15045 * Names of resolved or unresolved class members that are read in the
15046 * library.
15047 */
15048 final HashSet<String> readMembers = new HashSet<String>();
15049
15050 UsedLocalElements();
15051
15052 factory UsedLocalElements.merge(List<UsedLocalElements> parts) {
15053 UsedLocalElements result = new UsedLocalElements();
15054 for (UsedLocalElements part in parts) {
15055 result.elements.addAll(part.elements);
15056 result.catchExceptionElements.addAll(part.catchExceptionElements);
15057 result.catchStackTraceElements.addAll(part.catchStackTraceElements);
15058 result.members.addAll(part.members);
15059 result.readMembers.addAll(part.readMembers);
15060 }
15061 return result;
15062 }
15063
15064 void addCatchException(LocalVariableElement element) {
15065 if (element != null) {
15066 catchExceptionElements.add(element);
15067 }
15068 }
15069
15070 void addCatchStackTrace(LocalVariableElement element) {
15071 if (element != null) {
15072 catchStackTraceElements.add(element);
15073 }
15074 }
15075
15076 void addElement(Element element) {
15077 if (element != null) {
15078 elements.add(element);
15079 }
15080 }
15081
15082 bool isCatchException(LocalVariableElement element) {
15083 return catchExceptionElements.contains(element);
15084 }
15085
15086 bool isCatchStackTrace(LocalVariableElement element) {
15087 return catchStackTraceElements.contains(element);
15088 }
15089 }
15090
15091 /**
15092 * Instances of the class `VariableResolverVisitor` are used to resolve
15093 * [SimpleIdentifier]s to local variables and formal parameters.
15094 */
15095 class VariableResolverVisitor extends ScopedVisitor {
15096 /**
15097 * The method or function that we are currently visiting, or `null` if we are not inside a
15098 * method or function.
15099 */
15100 ExecutableElement _enclosingFunction;
15101
15102 /**
15103 * Initialize a newly created visitor to resolve the nodes in an AST node.
15104 *
15105 * [definingLibrary] is the element for the library containing the node being
15106 * visited.
15107 * [source] is the source representing the compilation unit containing the
15108 * node being visited
15109 * [typeProvider] is the object used to access the types from the core
15110 * library.
15111 * [errorListener] is the error listener that will be informed of any errors
15112 * that are found during resolution.
15113 * [nameScope] is the scope used to resolve identifiers in the node that will
15114 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
15115 * created based on [definingLibrary] and [typeProvider].
15116 */
15117 VariableResolverVisitor(LibraryElement definingLibrary, Source source,
15118 TypeProvider typeProvider, AnalysisErrorListener errorListener,
15119 {Scope nameScope})
15120 : super(definingLibrary, source, typeProvider, errorListener,
15121 nameScope: nameScope);
15122
15123 /**
15124 * Initialize a newly created visitor to resolve the nodes in a compilation un it.
15125 *
15126 * @param library the library containing the compilation unit being resolved
15127 * @param source the source representing the compilation unit being visited
15128 * @param typeProvider the object used to access the types from the core libra ry
15129 *
15130 * Deprecated. Please use unnamed constructor instead.
15131 */
15132 @deprecated
15133 VariableResolverVisitor.con1(
15134 Library library, Source source, TypeProvider typeProvider)
15135 : this(
15136 library.libraryElement, source, typeProvider, library.errorListener,
15137 nameScope: library.libraryScope);
15138
15139 @override
15140 Object visitExportDirective(ExportDirective node) => null;
15141
15142 @override
15143 Object visitFunctionDeclaration(FunctionDeclaration node) {
15144 ExecutableElement outerFunction = _enclosingFunction;
15145 try {
15146 _enclosingFunction = node.element;
15147 return super.visitFunctionDeclaration(node);
15148 } finally {
15149 _enclosingFunction = outerFunction;
15150 }
15151 }
15152
15153 @override
15154 Object visitFunctionExpression(FunctionExpression node) {
15155 if (node.parent is! FunctionDeclaration) {
15156 ExecutableElement outerFunction = _enclosingFunction;
15157 try {
15158 _enclosingFunction = node.element;
15159 return super.visitFunctionExpression(node);
15160 } finally {
15161 _enclosingFunction = outerFunction;
15162 }
15163 } else {
15164 return super.visitFunctionExpression(node);
15165 }
15166 }
15167
15168 @override
15169 Object visitImportDirective(ImportDirective node) => null;
15170
15171 @override
15172 Object visitMethodDeclaration(MethodDeclaration node) {
15173 ExecutableElement outerFunction = _enclosingFunction;
15174 try {
15175 _enclosingFunction = node.element;
15176 return super.visitMethodDeclaration(node);
15177 } finally {
15178 _enclosingFunction = outerFunction;
15179 }
15180 }
15181
15182 @override
15183 Object visitSimpleIdentifier(SimpleIdentifier node) {
15184 // Ignore if already resolved - declaration or type.
15185 if (node.staticElement != null) {
15186 return null;
15187 }
15188 // Ignore if qualified.
15189 AstNode parent = node.parent;
15190 if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
15191 return null;
15192 }
15193 if (parent is PropertyAccess && identical(parent.propertyName, node)) {
15194 return null;
15195 }
15196 if (parent is MethodInvocation &&
15197 identical(parent.methodName, node) &&
15198 parent.realTarget != null) {
15199 return null;
15200 }
15201 if (parent is ConstructorName) {
15202 return null;
15203 }
15204 if (parent is Label) {
15205 return null;
15206 }
15207 // Prepare VariableElement.
15208 Element element = nameScope.lookup(node, definingLibrary);
15209 if (element is! VariableElement) {
15210 return null;
15211 }
15212 // Must be local or parameter.
15213 ElementKind kind = element.kind;
15214 if (kind == ElementKind.LOCAL_VARIABLE) {
15215 node.staticElement = element;
15216 LocalVariableElementImpl variableImpl =
15217 element as LocalVariableElementImpl;
15218 if (node.inSetterContext()) {
15219 variableImpl.markPotentiallyMutatedInScope();
15220 if (element.enclosingElement != _enclosingFunction) {
15221 variableImpl.markPotentiallyMutatedInClosure();
15222 }
15223 }
15224 } else if (kind == ElementKind.PARAMETER) {
15225 node.staticElement = element;
15226 if (node.inSetterContext()) {
15227 ParameterElementImpl parameterImpl = element as ParameterElementImpl;
15228 parameterImpl.markPotentiallyMutatedInScope();
15229 // If we are in some closure, check if it is not the same as where
15230 // variable is declared.
15231 if (_enclosingFunction != null &&
15232 (element.enclosingElement != _enclosingFunction)) {
15233 parameterImpl.markPotentiallyMutatedInClosure();
15234 }
15235 }
15236 }
15237 return null;
15238 }
15239 }
15240
15241 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor {
15242 final ConstantVerifier verifier;
15243
15244 List<ParameterElement> parameterElements;
15245
15246 _ConstantVerifier_validateInitializerExpression(
15247 TypeProvider typeProvider,
15248 ErrorReporter errorReporter,
15249 this.verifier,
15250 this.parameterElements,
15251 DeclaredVariables declaredVariables)
15252 : super(new ConstantEvaluationEngine(typeProvider, declaredVariables),
15253 errorReporter);
15254
15255 @override
15256 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
15257 Element element = node.staticElement;
15258 for (ParameterElement parameterElement in parameterElements) {
15259 if (identical(parameterElement, element) && parameterElement != null) {
15260 DartType type = parameterElement.type;
15261 if (type != null) {
15262 if (type.isDynamic) {
15263 return new DartObjectImpl(
15264 verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE);
15265 } else if (type.isSubtypeOf(verifier._boolType)) {
15266 return new DartObjectImpl(
15267 verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE);
15268 } else if (type.isSubtypeOf(verifier._typeProvider.doubleType)) {
15269 return new DartObjectImpl(
15270 verifier._typeProvider.doubleType, DoubleState.UNKNOWN_VALUE);
15271 } else if (type.isSubtypeOf(verifier._intType)) {
15272 return new DartObjectImpl(
15273 verifier._typeProvider.intType, IntState.UNKNOWN_VALUE);
15274 } else if (type.isSubtypeOf(verifier._numType)) {
15275 return new DartObjectImpl(
15276 verifier._typeProvider.numType, NumState.UNKNOWN_VALUE);
15277 } else if (type.isSubtypeOf(verifier._stringType)) {
15278 return new DartObjectImpl(
15279 verifier._typeProvider.stringType, StringState.UNKNOWN_VALUE);
15280 }
15281 //
15282 // We don't test for other types of objects (such as List, Map,
15283 // Function or Type) because there are no operations allowed on such
15284 // types other than '==' and '!=', which means that we don't need to
15285 // know the type when there is no specific data about the state of
15286 // such objects.
15287 //
15288 }
15289 return new DartObjectImpl(
15290 type is InterfaceType ? type : verifier._typeProvider.objectType,
15291 GenericState.UNKNOWN_VALUE);
15292 }
15293 }
15294 return super.visitSimpleIdentifier(node);
15295 }
15296 }
15297
15298 class _ElementBuilder_visitClassDeclaration extends UnifyingAstVisitor<Object> {
15299 final ElementBuilder builder;
15300
15301 List<ClassMember> nonFields;
15302
15303 _ElementBuilder_visitClassDeclaration(this.builder, this.nonFields) : super();
15304
15305 @override
15306 Object visitConstructorDeclaration(ConstructorDeclaration node) {
15307 nonFields.add(node);
15308 return null;
15309 }
15310
15311 @override
15312 Object visitMethodDeclaration(MethodDeclaration node) {
15313 nonFields.add(node);
15314 return null;
15315 }
15316
15317 @override
15318 Object visitNode(AstNode node) => node.accept(builder);
15319 }
15320
15321 class _ResolverVisitor_isVariableAccessedInClosure
15322 extends RecursiveAstVisitor<Object> {
15323 final Element variable;
15324
15325 bool result = false;
15326
15327 bool _inClosure = false;
15328
15329 _ResolverVisitor_isVariableAccessedInClosure(this.variable);
15330
15331 @override
15332 Object visitFunctionExpression(FunctionExpression node) {
15333 bool inClosure = this._inClosure;
15334 try {
15335 this._inClosure = true;
15336 return super.visitFunctionExpression(node);
15337 } finally {
15338 this._inClosure = inClosure;
15339 }
15340 }
15341
15342 @override
15343 Object visitSimpleIdentifier(SimpleIdentifier node) {
15344 if (result) {
15345 return null;
15346 }
15347 if (_inClosure && identical(node.staticElement, variable)) {
15348 result = true;
15349 }
15350 return null;
15351 }
15352 }
15353
15354 class _ResolverVisitor_isVariablePotentiallyMutatedIn
15355 extends RecursiveAstVisitor<Object> {
15356 final Element variable;
15357
15358 bool result = false;
15359
15360 _ResolverVisitor_isVariablePotentiallyMutatedIn(this.variable);
15361
15362 @override
15363 Object visitSimpleIdentifier(SimpleIdentifier node) {
15364 if (result) {
15365 return null;
15366 }
15367 if (identical(node.staticElement, variable)) {
15368 if (node.inSetterContext()) {
15369 result = true;
15370 }
15371 }
15372 return null;
15373 }
15374 }
15375
15376 class _TypeResolverVisitor_visitClassMembersInScope
15377 extends UnifyingAstVisitor<Object> {
15378 final TypeResolverVisitor TypeResolverVisitor_this;
15379
15380 List<ClassMember> nonFields;
15381
15382 _TypeResolverVisitor_visitClassMembersInScope(
15383 this.TypeResolverVisitor_this, this.nonFields)
15384 : super();
15385
15386 @override
15387 Object visitConstructorDeclaration(ConstructorDeclaration node) {
15388 nonFields.add(node);
15389 return null;
15390 }
15391
15392 @override
15393 Object visitExtendsClause(ExtendsClause node) => null;
15394
15395 @override
15396 Object visitImplementsClause(ImplementsClause node) => null;
15397
15398 @override
15399 Object visitMethodDeclaration(MethodDeclaration node) {
15400 nonFields.add(node);
15401 return null;
15402 }
15403
15404 @override
15405 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this);
15406
15407 @override
15408 Object visitWithClause(WithClause node) => null;
15409 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698