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

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

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library engine.resolver; 5 library analyzer.src.generated.resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'constant.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
11 import 'element.dart'; 11 import 'package:analyzer/dart/ast/visitor.dart';
12 import 'element_resolver.dart'; 12 import 'package:analyzer/dart/element/element.dart';
13 import 'engine.dart'; 13 import 'package:analyzer/dart/element/type.dart';
14 import 'error.dart'; 14 import 'package:analyzer/dart/element/visitor.dart';
15 import 'error_verifier.dart'; 15 import 'package:analyzer/error/error.dart';
16 import 'html.dart' as ht; 16 import 'package:analyzer/error/listener.dart';
17 import 'java_core.dart'; 17 import 'package:analyzer/exception/exception.dart';
18 import 'java_engine.dart'; 18 import 'package:analyzer/src/dart/ast/ast.dart';
19 import 'scanner.dart' as sc; 19 import 'package:analyzer/src/dart/ast/utilities.dart';
20 import 'sdk.dart' show DartSdk, SdkLibrary; 20 import 'package:analyzer/src/dart/element/element.dart';
21 import 'source.dart'; 21 import 'package:analyzer/src/dart/element/type.dart';
22 import 'static_type_analyzer.dart'; 22 import 'package:analyzer/src/dart/element/utilities.dart';
23 import 'utilities_dart.dart'; 23 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
24 import 'package:analyzer/src/dart/resolver/scope.dart';
25 import 'package:analyzer/src/error/codes.dart';
26 import 'package:analyzer/src/generated/constant.dart';
27 import 'package:analyzer/src/generated/element_resolver.dart';
28 import 'package:analyzer/src/generated/engine.dart';
29 import 'package:analyzer/src/generated/error_verifier.dart';
30 import 'package:analyzer/src/generated/source.dart';
31 import 'package:analyzer/src/generated/static_type_analyzer.dart';
32 import 'package:analyzer/src/generated/type_system.dart';
33 import 'package:analyzer/src/generated/utilities_dart.dart';
24 34
25 /** 35 export 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
26 * Callback signature used by ImplicitConstructorBuilder to register 36 export 'package:analyzer/src/dart/resolver/scope.dart';
27 * computations to be performed, and their dependencies. A call to this 37 export 'package:analyzer/src/generated/type_system.dart';
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 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
48
49 typedef bool _SubtypeChecker<T>(T t1, T t2);
50 38
51 /** 39 /**
52 * Instances of the class `BestPracticesVerifier` traverse an AST structure look ing for 40 * Instances of the class `BestPracticesVerifier` traverse an AST structure look ing for
53 * violations of Dart best practices. 41 * violations of Dart best practices.
54 */ 42 */
55 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { 43 class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
56 // static String _HASHCODE_GETTER_NAME = "hashCode"; 44 // static String _HASHCODE_GETTER_NAME = "hashCode";
57 45
58 static String _NULL_TYPE_NAME = "Null"; 46 static String _NULL_TYPE_NAME = "Null";
59 47
60 static String _TO_INT_METHOD_NAME = "toInt"; 48 static String _TO_INT_METHOD_NAME = "toInt";
61 49
62 /** 50 /**
63 * The class containing the AST nodes being visited, or `null` if we are not i n the scope of 51 * The class containing the AST nodes being visited, or `null` if we are not i n the scope of
64 * a class. 52 * a class.
65 */ 53 */
66 ClassElement _enclosingClass; 54 ClassElementImpl _enclosingClass;
55
56 /**
57 * A flag indicating whether a surrounding member (compilation unit or class)
58 * is deprecated.
59 */
60 bool inDeprecatedMember;
67 61
68 /** 62 /**
69 * The error reporter by which errors will be reported. 63 * The error reporter by which errors will be reported.
70 */ 64 */
71 final ErrorReporter _errorReporter; 65 final ErrorReporter _errorReporter;
72 66
73 /** 67 /**
68 * The type [Null].
69 */
70 final InterfaceType _nullType;
71
72 /**
74 * The type Future<Null>, which is needed for determining whether it is safe 73 * The type Future<Null>, which is needed for determining whether it is safe
75 * to have a bare "return;" in an async method. 74 * to have a bare "return;" in an async method.
76 */ 75 */
77 final InterfaceType _futureNullType; 76 final InterfaceType _futureNullType;
78 77
79 /** 78 /**
80 * The type system primitives 79 * The type system primitives
81 */ 80 */
82 TypeSystem _typeSystem; 81 TypeSystem _typeSystem;
83 82
84 /** 83 /**
84 * The current library
85 */
86 LibraryElement _currentLibrary;
87
88 /**
89 * The inheritance manager used to find overridden methods.
90 */
91 InheritanceManager _manager;
92
93 /**
85 * Create a new instance of the [BestPracticesVerifier]. 94 * Create a new instance of the [BestPracticesVerifier].
86 * 95 *
87 * @param errorReporter the error reporter 96 * @param errorReporter the error reporter
88 */ 97 */
89 BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider, 98 BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider,
99 this._currentLibrary, this._manager,
90 {TypeSystem typeSystem}) 100 {TypeSystem typeSystem})
91 : _futureNullType = typeProvider.futureNullType, 101 : _nullType = typeProvider.nullType,
92 _typeSystem = (typeSystem != null) ? typeSystem : new TypeSystemImpl(); 102 _futureNullType = typeProvider.futureNullType,
103 _typeSystem = typeSystem ?? new TypeSystemImpl() {
104 inDeprecatedMember = _currentLibrary.isDeprecated;
105 }
106
107 @override
108 Object visitAnnotation(Annotation node) {
109 if (node.elementAnnotation?.isFactory == true) {
110 AstNode parent = node.parent;
111 if (parent is MethodDeclaration) {
112 _checkForInvalidFactory(parent);
113 } else {
114 _errorReporter
115 .reportErrorForNode(HintCode.INVALID_FACTORY_ANNOTATION, node, []);
116 }
117 }
118 return super.visitAnnotation(node);
119 }
93 120
94 @override 121 @override
95 Object visitArgumentList(ArgumentList node) { 122 Object visitArgumentList(ArgumentList node) {
123 for (Expression argument in node.arguments) {
124 ParameterElement parameter = argument.bestParameterElement;
125 if (parameter?.parameterKind == ParameterKind.POSITIONAL) {
126 _checkForDeprecatedMemberUse(parameter, argument);
127 }
128 }
96 _checkForArgumentTypesNotAssignableInList(node); 129 _checkForArgumentTypesNotAssignableInList(node);
97 return super.visitArgumentList(node); 130 return super.visitArgumentList(node);
98 } 131 }
99 132
100 @override 133 @override
101 Object visitAsExpression(AsExpression node) { 134 Object visitAsExpression(AsExpression node) {
102 _checkForUnnecessaryCast(node); 135 _checkForUnnecessaryCast(node);
103 return super.visitAsExpression(node); 136 return super.visitAsExpression(node);
104 } 137 }
105 138
106 @override 139 @override
140 Object visitAssertStatement(AssertStatement node) {
141 _checkForPossibleNullCondition(node.condition);
142 return super.visitAssertStatement(node);
143 }
144
145 @override
107 Object visitAssignmentExpression(AssignmentExpression node) { 146 Object visitAssignmentExpression(AssignmentExpression node) {
108 sc.TokenType operatorType = node.operator.type; 147 TokenType operatorType = node.operator.type;
109 if (operatorType == sc.TokenType.EQ) { 148 if (operatorType == TokenType.EQ) {
110 _checkForUseOfVoidResult(node.rightHandSide); 149 _checkForUseOfVoidResult(node.rightHandSide);
111 _checkForInvalidAssignment(node.leftHandSide, node.rightHandSide); 150 _checkForInvalidAssignment(node.leftHandSide, node.rightHandSide);
112 } else { 151 } else {
113 _checkForDeprecatedMemberUse(node.bestElement, node); 152 _checkForDeprecatedMemberUse(node.bestElement, node);
114 } 153 }
115 return super.visitAssignmentExpression(node); 154 return super.visitAssignmentExpression(node);
116 } 155 }
117 156
118 @override 157 @override
119 Object visitBinaryExpression(BinaryExpression node) { 158 Object visitBinaryExpression(BinaryExpression node) {
120 _checkForDivisionOptimizationHint(node); 159 _checkForDivisionOptimizationHint(node);
121 _checkForDeprecatedMemberUse(node.bestElement, node); 160 _checkForDeprecatedMemberUse(node.bestElement, node);
122 return super.visitBinaryExpression(node); 161 return super.visitBinaryExpression(node);
123 } 162 }
124 163
125 @override 164 @override
126 Object visitClassDeclaration(ClassDeclaration node) { 165 Object visitClassDeclaration(ClassDeclaration node) {
127 ClassElement outerClass = _enclosingClass; 166 ClassElementImpl outerClass = _enclosingClass;
167 bool wasInDeprecatedMember = inDeprecatedMember;
168 ClassElement element = AbstractClassElementImpl.getImpl(node.element);
169 if (element != null && element.isDeprecated) {
170 inDeprecatedMember = true;
171 }
128 try { 172 try {
129 _enclosingClass = node.element; 173 _enclosingClass = element;
130 // Commented out until we decide that we want this hint in the analyzer 174 // Commented out until we decide that we want this hint in the analyzer
131 // checkForOverrideEqualsButNotHashCode(node); 175 // checkForOverrideEqualsButNotHashCode(node);
132 return super.visitClassDeclaration(node); 176 return super.visitClassDeclaration(node);
133 } finally { 177 } finally {
134 _enclosingClass = outerClass; 178 _enclosingClass = outerClass;
179 inDeprecatedMember = wasInDeprecatedMember;
135 } 180 }
136 } 181 }
137 182
138 @override 183 @override
184 Object visitConditionalExpression(ConditionalExpression node) {
185 _checkForPossibleNullCondition(node.condition);
186 return super.visitConditionalExpression(node);
187 }
188
189 @override
190 Object visitConstructorDeclaration(ConstructorDeclaration node) {
191 if (node.element.isFactory) {
192 if (node.body is BlockFunctionBody) {
193 // Check the block for a return statement, if not, create the hint.
194 if (!ExitDetector.exits(node.body)) {
195 _errorReporter.reportErrorForNode(
196 HintCode.MISSING_RETURN, node, [node.returnType.name]);
197 }
198 }
199 }
200 return super.visitConstructorDeclaration(node);
201 }
202
203 @override
204 Object visitDoStatement(DoStatement node) {
205 _checkForPossibleNullCondition(node.condition);
206 return super.visitDoStatement(node);
207 }
208
209 @override
139 Object visitExportDirective(ExportDirective node) { 210 Object visitExportDirective(ExportDirective node) {
140 _checkForDeprecatedMemberUse(node.uriElement, node); 211 _checkForDeprecatedMemberUse(node.uriElement, node);
141 return super.visitExportDirective(node); 212 return super.visitExportDirective(node);
142 } 213 }
143 214
144 @override 215 @override
216 Object visitForStatement(ForStatement node) {
217 _checkForPossibleNullCondition(node.condition);
218 return super.visitForStatement(node);
219 }
220
221 @override
145 Object visitFunctionDeclaration(FunctionDeclaration node) { 222 Object visitFunctionDeclaration(FunctionDeclaration node) {
146 _checkForMissingReturn(node.returnType, node.functionExpression.body); 223 bool wasInDeprecatedMember = inDeprecatedMember;
147 return super.visitFunctionDeclaration(node); 224 ExecutableElement element = node.element;
225 if (element != null && element.isDeprecated) {
226 inDeprecatedMember = true;
227 }
228 try {
229 _checkForMissingReturn(node.returnType, node.functionExpression.body);
230 return super.visitFunctionDeclaration(node);
231 } finally {
232 inDeprecatedMember = wasInDeprecatedMember;
233 }
234 }
235
236 @override
237 Object visitIfStatement(IfStatement node) {
238 _checkForPossibleNullCondition(node.condition);
239 return super.visitIfStatement(node);
148 } 240 }
149 241
150 @override 242 @override
151 Object visitImportDirective(ImportDirective node) { 243 Object visitImportDirective(ImportDirective node) {
152 _checkForDeprecatedMemberUse(node.uriElement, node); 244 _checkForDeprecatedMemberUse(node.uriElement, node);
153 ImportElement importElement = node.element; 245 ImportElement importElement = node.element;
154 if (importElement != null) { 246 if (importElement != null && importElement.isDeferred) {
155 if (importElement.isDeferred) { 247 _checkForLoadLibraryFunction(node, importElement);
156 _checkForLoadLibraryFunction(node, importElement);
157 }
158 } 248 }
159 return super.visitImportDirective(node); 249 return super.visitImportDirective(node);
160 } 250 }
161 251
162 @override 252 @override
163 Object visitIndexExpression(IndexExpression node) { 253 Object visitIndexExpression(IndexExpression node) {
164 _checkForDeprecatedMemberUse(node.bestElement, node); 254 _checkForDeprecatedMemberUse(node.bestElement, node);
165 return super.visitIndexExpression(node); 255 return super.visitIndexExpression(node);
166 } 256 }
167 257
168 @override 258 @override
169 Object visitInstanceCreationExpression(InstanceCreationExpression node) { 259 Object visitInstanceCreationExpression(InstanceCreationExpression node) {
170 _checkForDeprecatedMemberUse(node.staticElement, node); 260 _checkForDeprecatedMemberUse(node.staticElement, node);
171 return super.visitInstanceCreationExpression(node); 261 return super.visitInstanceCreationExpression(node);
172 } 262 }
173 263
174 @override 264 @override
175 Object visitIsExpression(IsExpression node) { 265 Object visitIsExpression(IsExpression node) {
176 _checkAllTypeChecks(node); 266 _checkAllTypeChecks(node);
177 return super.visitIsExpression(node); 267 return super.visitIsExpression(node);
178 } 268 }
179 269
180 @override 270 @override
181 Object visitMethodDeclaration(MethodDeclaration node) { 271 Object visitMethodDeclaration(MethodDeclaration node) {
182 // This was determined to not be a good hint, see: dartbug.com/16029 272 bool wasInDeprecatedMember = inDeprecatedMember;
183 //checkForOverridingPrivateMember(node); 273 ExecutableElement element = node.element;
184 _checkForMissingReturn(node.returnType, node.body); 274 if (element != null && element.isDeprecated) {
185 return super.visitMethodDeclaration(node); 275 inDeprecatedMember = true;
276 }
277 try {
278 // This was determined to not be a good hint, see: dartbug.com/16029
279 //checkForOverridingPrivateMember(node);
280 _checkForMissingReturn(node.returnType, node.body);
281 _checkForUnnecessaryNoSuchMethod(node);
282 return super.visitMethodDeclaration(node);
283 } finally {
284 inDeprecatedMember = wasInDeprecatedMember;
285 }
186 } 286 }
187 287
188 @override 288 @override
289 Object visitMethodInvocation(MethodInvocation node) {
290 Expression realTarget = node.realTarget;
291 _checkForAbstractSuperMemberReference(realTarget, node.methodName);
292 _checkForCanBeNullAfterNullAware(
293 realTarget, node.operator, null, node.methodName);
294 DartType staticInvokeType = node.staticInvokeType;
295 if (staticInvokeType is InterfaceType) {
296 MethodElement methodElement = staticInvokeType.lookUpMethod(
297 FunctionElement.CALL_METHOD_NAME, _currentLibrary);
298 _checkForDeprecatedMemberUse(methodElement, node);
299 }
300 return super.visitMethodInvocation(node);
301 }
302
303 @override
189 Object visitPostfixExpression(PostfixExpression node) { 304 Object visitPostfixExpression(PostfixExpression node) {
190 _checkForDeprecatedMemberUse(node.bestElement, node); 305 _checkForDeprecatedMemberUse(node.bestElement, node);
191 return super.visitPostfixExpression(node); 306 return super.visitPostfixExpression(node);
192 } 307 }
193 308
194 @override 309 @override
195 Object visitPrefixExpression(PrefixExpression node) { 310 Object visitPrefixExpression(PrefixExpression node) {
196 _checkForDeprecatedMemberUse(node.bestElement, node); 311 _checkForDeprecatedMemberUse(node.bestElement, node);
197 return super.visitPrefixExpression(node); 312 return super.visitPrefixExpression(node);
198 } 313 }
199 314
200 @override 315 @override
316 Object visitPropertyAccess(PropertyAccess node) {
317 Expression realTarget = node.realTarget;
318 _checkForAbstractSuperMemberReference(realTarget, node.propertyName);
319 _checkForCanBeNullAfterNullAware(
320 realTarget, node.operator, node.propertyName, null);
321 return super.visitPropertyAccess(node);
322 }
323
324 @override
201 Object visitRedirectingConstructorInvocation( 325 Object visitRedirectingConstructorInvocation(
202 RedirectingConstructorInvocation node) { 326 RedirectingConstructorInvocation node) {
203 _checkForDeprecatedMemberUse(node.staticElement, node); 327 _checkForDeprecatedMemberUse(node.staticElement, node);
204 return super.visitRedirectingConstructorInvocation(node); 328 return super.visitRedirectingConstructorInvocation(node);
205 } 329 }
206 330
207 @override 331 @override
208 Object visitSimpleIdentifier(SimpleIdentifier node) { 332 Object visitSimpleIdentifier(SimpleIdentifier node) {
209 _checkForDeprecatedMemberUseAtIdentifier(node); 333 _checkForDeprecatedMemberUseAtIdentifier(node);
334 _checkForInvalidProtectedMemberAccess(node);
210 return super.visitSimpleIdentifier(node); 335 return super.visitSimpleIdentifier(node);
211 } 336 }
212 337
213 @override 338 @override
214 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { 339 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
215 _checkForDeprecatedMemberUse(node.staticElement, node); 340 _checkForDeprecatedMemberUse(node.staticElement, node);
216 return super.visitSuperConstructorInvocation(node); 341 return super.visitSuperConstructorInvocation(node);
217 } 342 }
218 343
219 @override 344 @override
220 Object visitVariableDeclaration(VariableDeclaration node) { 345 Object visitVariableDeclaration(VariableDeclaration node) {
221 _checkForUseOfVoidResult(node.initializer); 346 _checkForUseOfVoidResult(node.initializer);
222 _checkForInvalidAssignment(node.name, node.initializer); 347 _checkForInvalidAssignment(node.name, node.initializer);
223 return super.visitVariableDeclaration(node); 348 return super.visitVariableDeclaration(node);
224 } 349 }
225 350
351 @override
352 Object visitWhileStatement(WhileStatement node) {
353 _checkForPossibleNullCondition(node.condition);
354 return super.visitWhileStatement(node);
355 }
356
226 /** 357 /**
227 * Check for the passed is expression for the unnecessary type check hint code s as well as null 358 * Check for the passed is expression for the unnecessary type check hint code s as well as null
228 * checks expressed using an is expression. 359 * checks expressed using an is expression.
229 * 360 *
230 * @param node the is expression to check 361 * @param node the is expression to check
231 * @return `true` if and only if a hint code is generated on the passed node 362 * @return `true` if and only if a hint code is generated on the passed node
232 * See [HintCode.TYPE_CHECK_IS_NOT_NULL], [HintCode.TYPE_CHECK_IS_NULL], 363 * See [HintCode.TYPE_CHECK_IS_NOT_NULL], [HintCode.TYPE_CHECK_IS_NULL],
233 * [HintCode.UNNECESSARY_TYPE_CHECK_TRUE], and 364 * [HintCode.UNNECESSARY_TYPE_CHECK_TRUE], and
234 * [HintCode.UNNECESSARY_TYPE_CHECK_FALSE]. 365 * [HintCode.UNNECESSARY_TYPE_CHECK_FALSE].
235 */ 366 */
236 bool _checkAllTypeChecks(IsExpression node) { 367 bool _checkAllTypeChecks(IsExpression node) {
237 Expression expression = node.expression; 368 Expression expression = node.expression;
238 TypeName typeName = node.type; 369 TypeName typeName = node.type;
239 DartType lhsType = expression.staticType; 370 DartType lhsType = expression.staticType;
240 DartType rhsType = typeName.type; 371 DartType rhsType = typeName.type;
241 if (lhsType == null || rhsType == null) { 372 if (lhsType == null || rhsType == null) {
242 return false; 373 return false;
243 } 374 }
244 String rhsNameStr = typeName.name.name; 375 String rhsNameStr = typeName.name.name;
245 // if x is dynamic 376 // if x is dynamic
246 if (rhsType.isDynamic && rhsNameStr == sc.Keyword.DYNAMIC.syntax) { 377 if (rhsType.isDynamic && rhsNameStr == Keyword.DYNAMIC.syntax) {
247 if (node.notOperator == null) { 378 if (node.notOperator == null) {
248 // the is case 379 // the is case
249 _errorReporter.reportErrorForNode( 380 _errorReporter.reportErrorForNode(
250 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node); 381 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node);
251 } else { 382 } else {
252 // the is not case 383 // the is not case
253 _errorReporter.reportErrorForNode( 384 _errorReporter.reportErrorForNode(
254 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node); 385 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node);
255 } 386 }
256 return true; 387 return true;
257 } 388 }
258 Element rhsElement = rhsType.element; 389 Element rhsElement = rhsType.element;
259 LibraryElement libraryElement = 390 LibraryElement libraryElement = rhsElement?.library;
260 rhsElement != null ? rhsElement.library : null;
261 if (libraryElement != null && libraryElement.isDartCore) { 391 if (libraryElement != null && libraryElement.isDartCore) {
262 // if x is Object or null is Null 392 // if x is Object or null is Null
263 if (rhsType.isObject || 393 if (rhsType.isObject ||
264 (expression is NullLiteral && rhsNameStr == _NULL_TYPE_NAME)) { 394 (expression is NullLiteral && rhsNameStr == _NULL_TYPE_NAME)) {
265 if (node.notOperator == null) { 395 if (node.notOperator == null) {
266 // the is case 396 // the is case
267 _errorReporter.reportErrorForNode( 397 _errorReporter.reportErrorForNode(
268 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node); 398 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node);
269 } else { 399 } else {
270 // the is not case 400 // the is not case
271 _errorReporter.reportErrorForNode( 401 _errorReporter.reportErrorForNode(
272 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node); 402 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node);
273 } 403 }
274 return true; 404 return true;
275 } else if (rhsNameStr == _NULL_TYPE_NAME) { 405 } else if (rhsNameStr == _NULL_TYPE_NAME) {
276 if (node.notOperator == null) { 406 if (node.notOperator == null) {
277 // the is case 407 // the is case
278 _errorReporter.reportErrorForNode(HintCode.TYPE_CHECK_IS_NULL, node); 408 _errorReporter.reportErrorForNode(HintCode.TYPE_CHECK_IS_NULL, node);
279 } else { 409 } else {
280 // the is not case 410 // the is not case
281 _errorReporter.reportErrorForNode( 411 _errorReporter.reportErrorForNode(
282 HintCode.TYPE_CHECK_IS_NOT_NULL, node); 412 HintCode.TYPE_CHECK_IS_NOT_NULL, node);
283 } 413 }
284 return true; 414 return true;
285 } 415 }
286 } 416 }
287 return false; 417 return false;
288 } 418 }
289 419
420 void _checkForAbstractSuperMemberReference(
421 Expression target, SimpleIdentifier name) {
422 if (target is SuperExpression) {
423 Element element = name.staticElement;
424 if (element is ExecutableElement && element.isAbstract) {
425 if (!_enclosingClass.hasNoSuchMethod) {
426 ExecutableElement concrete = null;
427 if (element.kind == ElementKind.METHOD) {
428 concrete = _enclosingClass.lookUpInheritedConcreteMethod(
429 element.displayName, _currentLibrary);
430 } else if (element.kind == ElementKind.GETTER) {
431 concrete = _enclosingClass.lookUpInheritedConcreteGetter(
432 element.displayName, _currentLibrary);
433 } else if (element.kind == ElementKind.SETTER) {
434 concrete = _enclosingClass.lookUpInheritedConcreteSetter(
435 element.displayName, _currentLibrary);
436 }
437 if (concrete == null) {
438 _errorReporter.reportTypeErrorForNode(
439 HintCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
440 name,
441 [element.kind.displayName, name.name]);
442 }
443 }
444 }
445 }
446 }
447
290 /** 448 /**
291 * This verifies that the passed expression can be assigned to its correspondi ng parameters. 449 * This verifies that the passed expression can be assigned to its correspondi ng parameters.
292 * 450 *
293 * This method corresponds to ErrorVerifier.checkForArgumentTypeNotAssignable. 451 * This method corresponds to ErrorVerifier.checkForArgumentTypeNotAssignable.
294 * 452 *
295 * TODO (jwren) In the ErrorVerifier there are other warnings that we could ha ve a corresponding 453 * TODO (jwren) In the ErrorVerifier there are other warnings that we could ha ve a corresponding
296 * hint for: see other callers of ErrorVerifier.checkForArgumentTypeNotAssigna ble(..). 454 * hint for: see other callers of ErrorVerifier.checkForArgumentTypeNotAssigna ble(..).
297 * 455 *
298 * @param expression the expression to evaluate 456 * @param expression the expression to evaluate
299 * @param expectedStaticType the expected static type of the parameter 457 * @param expectedStaticType the expected static type of the parameter
(...skipping 18 matching lines...) Expand all
318 if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) { 476 if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) {
319 // A warning was created in the ErrorVerifier, return false, don't 477 // A warning was created in the ErrorVerifier, return false, don't
320 // create a hint when a warning has already been created. 478 // create a hint when a warning has already been created.
321 return false; 479 return false;
322 } 480 }
323 } 481 }
324 // 482 //
325 // Hint case: test propagated type information 483 // Hint case: test propagated type information
326 // 484 //
327 // Compute the best types to use. 485 // Compute the best types to use.
328 DartType expectedBestType = expectedPropagatedType != null 486 DartType expectedBestType = expectedPropagatedType ?? expectedStaticType;
329 ? expectedPropagatedType 487 DartType actualBestType = actualPropagatedType ?? actualStaticType;
330 : expectedStaticType;
331 DartType actualBestType =
332 actualPropagatedType != null ? actualPropagatedType : actualStaticType;
333 if (actualBestType != null && expectedBestType != null) { 488 if (actualBestType != null && expectedBestType != null) {
334 if (!_typeSystem.isAssignableTo(actualBestType, expectedBestType)) { 489 if (!_typeSystem.isAssignableTo(actualBestType, expectedBestType)) {
335 _errorReporter.reportTypeErrorForNode( 490 _errorReporter.reportTypeErrorForNode(
336 hintCode, expression, [actualBestType, expectedBestType]); 491 hintCode, expression, [actualBestType, expectedBestType]);
337 return true; 492 return true;
338 } 493 }
339 } 494 }
340 return false; 495 return false;
341 } 496 }
342 497
343 /** 498 /**
344 * This verifies that the passed argument can be assigned to its corresponding parameter. 499 * This verifies that the passed argument can be assigned to its corresponding parameter.
345 * 500 *
346 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableForAr gument. 501 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableForAr gument.
347 * 502 *
348 * @param argument the argument to evaluate 503 * @param argument the argument to evaluate
349 * @return `true` if and only if an hint code is generated on the passed node 504 * @return `true` if and only if an hint code is generated on the passed node
350 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. 505 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
351 */ 506 */
352 bool _checkForArgumentTypeNotAssignableForArgument(Expression argument) { 507 bool _checkForArgumentTypeNotAssignableForArgument(Expression argument) {
353 if (argument == null) { 508 if (argument == null) {
354 return false; 509 return false;
355 } 510 }
356 ParameterElement staticParameterElement = argument.staticParameterElement; 511 ParameterElement staticParameterElement = argument.staticParameterElement;
357 DartType staticParameterType = 512 DartType staticParameterType = staticParameterElement?.type;
358 staticParameterElement == null ? null : staticParameterElement.type;
359 ParameterElement propagatedParameterElement = 513 ParameterElement propagatedParameterElement =
360 argument.propagatedParameterElement; 514 argument.propagatedParameterElement;
361 DartType propagatedParameterType = propagatedParameterElement == null 515 DartType propagatedParameterType = propagatedParameterElement?.type;
362 ? null
363 : propagatedParameterElement.type;
364 return _checkForArgumentTypeNotAssignableWithExpectedTypes( 516 return _checkForArgumentTypeNotAssignableWithExpectedTypes(
365 argument, 517 argument,
366 staticParameterType, 518 staticParameterType,
367 propagatedParameterType, 519 propagatedParameterType,
368 HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); 520 HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE);
369 } 521 }
370 522
371 /** 523 /**
372 * This verifies that the passed expression can be assigned to its correspondi ng parameters. 524 * This verifies that the passed expression can be assigned to its correspondi ng parameters.
373 * 525 *
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 bool problemReported = false; 560 bool problemReported = false;
409 for (Expression argument in argumentList.arguments) { 561 for (Expression argument in argumentList.arguments) {
410 if (_checkForArgumentTypeNotAssignableForArgument(argument)) { 562 if (_checkForArgumentTypeNotAssignableForArgument(argument)) {
411 problemReported = true; 563 problemReported = true;
412 } 564 }
413 } 565 }
414 return problemReported; 566 return problemReported;
415 } 567 }
416 568
417 /** 569 /**
570 * Produce a hint if the given [target] could have a value of `null`, and
571 * [identifier] is not a name of a getter or a method that exists in the
572 * class [Null].
573 */
574 void _checkForCanBeNullAfterNullAware(Expression target, Token operator,
575 SimpleIdentifier propertyName, SimpleIdentifier methodName) {
576 if (operator?.type == TokenType.QUESTION_PERIOD) {
577 return;
578 }
579 bool isNullTypeMember() {
580 if (propertyName != null) {
581 String name = propertyName.name;
582 return _nullType.lookUpGetter(name, _currentLibrary) != null;
583 }
584 if (methodName != null) {
585 String name = methodName.name;
586 return _nullType.lookUpMethod(name, _currentLibrary) != null;
587 }
588 return false;
589 }
590
591 target = target?.unParenthesized;
592 if (target is MethodInvocation) {
593 if (target.operator?.type == TokenType.QUESTION_PERIOD &&
594 !isNullTypeMember()) {
595 _errorReporter.reportErrorForNode(
596 HintCode.CAN_BE_NULL_AFTER_NULL_AWARE, target);
597 }
598 } else if (target is PropertyAccess) {
599 if (target.operator.type == TokenType.QUESTION_PERIOD &&
600 !isNullTypeMember()) {
601 _errorReporter.reportErrorForNode(
602 HintCode.CAN_BE_NULL_AFTER_NULL_AWARE, target);
603 }
604 }
605 }
606
607 /**
418 * Given some [Element], look at the associated metadata and report the use of the member if 608 * Given some [Element], look at the associated metadata and report the use of the member if
419 * it is declared as deprecated. 609 * it is declared as deprecated.
420 * 610 *
421 * @param element some element to check for deprecated use of 611 * @param element some element to check for deprecated use of
422 * @param node the node use for the location of the error 612 * @param node the node use for the location of the error
423 * @return `true` if and only if a hint code is generated on the passed node 613 * @return `true` if and only if a hint code is generated on the passed node
424 * See [HintCode.DEPRECATED_MEMBER_USE]. 614 * See [HintCode.DEPRECATED_MEMBER_USE].
425 */ 615 */
426 bool _checkForDeprecatedMemberUse(Element element, AstNode node) { 616 void _checkForDeprecatedMemberUse(Element element, AstNode node) {
427 if (element != null && element.isDeprecated) { 617 bool isDeprecated(Element element) {
618 if (element == null) {
619 return false;
620 } else if (element is PropertyAccessorElement && element.isSynthetic) {
621 // TODO(brianwilkerson) Why isn't this the implementation for PropertyAc cessorElement?
622 Element variable = element.variable;
623 if (variable == null) {
624 return false;
625 }
626 return variable.isDeprecated;
627 }
628 return element.isDeprecated;
629 }
630
631 if (!inDeprecatedMember && isDeprecated(element)) {
428 String displayName = element.displayName; 632 String displayName = element.displayName;
429 if (element is ConstructorElement) { 633 if (element is ConstructorElement) {
430 // TODO(jwren) We should modify ConstructorElement.getDisplayName(), 634 // TODO(jwren) We should modify ConstructorElement.getDisplayName(),
431 // or have the logic centralized elsewhere, instead of doing this logic 635 // or have the logic centralized elsewhere, instead of doing this logic
432 // here. 636 // here.
433 ConstructorElement constructorElement = element; 637 displayName = element.enclosingElement.displayName;
434 displayName = constructorElement.enclosingElement.displayName; 638 if (!element.displayName.isEmpty) {
435 if (!constructorElement.displayName.isEmpty) { 639 displayName = "$displayName.${element.displayName}";
436 displayName = "$displayName.${constructorElement.displayName}";
437 } 640 }
641 } else if (displayName == FunctionElement.CALL_METHOD_NAME &&
642 node is MethodInvocation &&
643 node.staticInvokeType is InterfaceType) {
644 displayName =
645 "${node.staticInvokeType.displayName}.${element.displayName}";
438 } 646 }
439 _errorReporter.reportErrorForNode( 647 _errorReporter.reportErrorForNode(
440 HintCode.DEPRECATED_MEMBER_USE, node, [displayName]); 648 HintCode.DEPRECATED_MEMBER_USE, node, [displayName]);
441 return true;
442 } 649 }
443 return false;
444 } 650 }
445 651
446 /** 652 /**
447 * For [SimpleIdentifier]s, only call [checkForDeprecatedMemberUse] 653 * For [SimpleIdentifier]s, only call [checkForDeprecatedMemberUse]
448 * if the node is not in a declaration context. 654 * if the node is not in a declaration context.
449 * 655 *
450 * Also, if the identifier is a constructor name in a constructor invocation, then calls to the 656 * Also, if the identifier is a constructor name in a constructor invocation, then calls to the
451 * deprecated constructor will be caught by 657 * deprecated constructor will be caught by
452 * [visitInstanceCreationExpression] and 658 * [visitInstanceCreationExpression] and
453 * [visitSuperConstructorInvocation], and can be ignored by 659 * [visitSuperConstructorInvocation], and can be ignored by
454 * this visit method. 660 * this visit method.
455 * 661 *
456 * @param identifier some simple identifier to check for deprecated use of 662 * @param identifier some simple identifier to check for deprecated use of
457 * @return `true` if and only if a hint code is generated on the passed node 663 * @return `true` if and only if a hint code is generated on the passed node
458 * See [HintCode.DEPRECATED_MEMBER_USE]. 664 * See [HintCode.DEPRECATED_MEMBER_USE].
459 */ 665 */
460 bool _checkForDeprecatedMemberUseAtIdentifier(SimpleIdentifier identifier) { 666 void _checkForDeprecatedMemberUseAtIdentifier(SimpleIdentifier identifier) {
461 if (identifier.inDeclarationContext()) { 667 if (identifier.inDeclarationContext()) {
462 return false; 668 return;
463 } 669 }
464 AstNode parent = identifier.parent; 670 AstNode parent = identifier.parent;
465 if ((parent is ConstructorName && identical(identifier, parent.name)) || 671 if ((parent is ConstructorName && identical(identifier, parent.name)) ||
672 (parent is ConstructorDeclaration &&
673 identical(identifier, parent.returnType)) ||
466 (parent is SuperConstructorInvocation && 674 (parent is SuperConstructorInvocation &&
467 identical(identifier, parent.constructorName)) || 675 identical(identifier, parent.constructorName)) ||
468 parent is HideCombinator) { 676 parent is HideCombinator) {
469 return false; 677 return;
470 } 678 }
471 return _checkForDeprecatedMemberUse(identifier.bestElement, identifier); 679 _checkForDeprecatedMemberUse(identifier.bestElement, identifier);
472 } 680 }
473 681
474 /** 682 /**
475 * Check for the passed binary expression for the [HintCode.DIVISION_OPTIMIZAT ION]. 683 * Check for the passed binary expression for the [HintCode.DIVISION_OPTIMIZAT ION].
476 * 684 *
477 * @param node the binary expression to check 685 * @param node the binary expression to check
478 * @return `true` if and only if a hint code is generated on the passed node 686 * @return `true` if and only if a hint code is generated on the passed node
479 * See [HintCode.DIVISION_OPTIMIZATION]. 687 * See [HintCode.DIVISION_OPTIMIZATION].
480 */ 688 */
481 bool _checkForDivisionOptimizationHint(BinaryExpression node) { 689 bool _checkForDivisionOptimizationHint(BinaryExpression node) {
482 // Return if the operator is not '/' 690 // Return if the operator is not '/'
483 if (node.operator.type != sc.TokenType.SLASH) { 691 if (node.operator.type != TokenType.SLASH) {
484 return false; 692 return false;
485 } 693 }
486 // Return if the '/' operator is not defined in core, or if we don't know 694 // Return if the '/' operator is not defined in core, or if we don't know
487 // its static or propagated type 695 // its static or propagated type
488 MethodElement methodElement = node.bestElement; 696 MethodElement methodElement = node.bestElement;
489 if (methodElement == null) { 697 if (methodElement == null) {
490 return false; 698 return false;
491 } 699 }
492 LibraryElement libraryElement = methodElement.library; 700 LibraryElement libraryElement = methodElement.library;
493 if (libraryElement != null && !libraryElement.isDartCore) { 701 if (libraryElement != null && !libraryElement.isDartCore) {
494 return false; 702 return false;
495 } 703 }
496 // Report error if the (x/y) has toInt() invoked on it 704 // Report error if the (x/y) has toInt() invoked on it
497 if (node.parent is ParenthesizedExpression) { 705 AstNode parent = node.parent;
706 if (parent is ParenthesizedExpression) {
498 ParenthesizedExpression parenthesizedExpression = 707 ParenthesizedExpression parenthesizedExpression =
499 _wrapParenthesizedExpression(node.parent as ParenthesizedExpression); 708 _wrapParenthesizedExpression(parent);
500 if (parenthesizedExpression.parent is MethodInvocation) { 709 AstNode grandParent = parenthesizedExpression.parent;
501 MethodInvocation methodInvocation = 710 if (grandParent is MethodInvocation) {
502 parenthesizedExpression.parent as MethodInvocation; 711 if (_TO_INT_METHOD_NAME == grandParent.methodName.name &&
503 if (_TO_INT_METHOD_NAME == methodInvocation.methodName.name && 712 grandParent.argumentList.arguments.isEmpty) {
504 methodInvocation.argumentList.arguments.isEmpty) {
505 _errorReporter.reportErrorForNode( 713 _errorReporter.reportErrorForNode(
506 HintCode.DIVISION_OPTIMIZATION, methodInvocation); 714 HintCode.DIVISION_OPTIMIZATION, grandParent);
507 return true; 715 return true;
508 } 716 }
509 } 717 }
510 } 718 }
511 return false; 719 return false;
512 } 720 }
513 721
514 /** 722 /**
515 * This verifies that the passed left hand side and right hand side represent a valid assignment. 723 * This verifies that the passed left hand side and right hand side represent a valid assignment.
516 * 724 *
(...skipping 22 matching lines...) Expand all
539 if (leftType != null && bestRightType != null) { 747 if (leftType != null && bestRightType != null) {
540 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) { 748 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) {
541 _errorReporter.reportTypeErrorForNode( 749 _errorReporter.reportTypeErrorForNode(
542 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]); 750 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]);
543 return true; 751 return true;
544 } 752 }
545 } 753 }
546 return false; 754 return false;
547 } 755 }
548 756
757 void _checkForInvalidFactory(MethodDeclaration decl) {
758 // Check declaration.
759 // Note that null return types are expected to be flagged by other analyses.
760 DartType returnType = decl.returnType?.type;
761 if (returnType is VoidType) {
762 _errorReporter.reportErrorForNode(HintCode.INVALID_FACTORY_METHOD_DECL,
763 decl.name, [decl.name.toString()]);
764 return;
765 }
766
767 // Check implementation.
768
769 FunctionBody body = decl.body;
770 if (body is EmptyFunctionBody) {
771 // Abstract methods are OK.
772 return;
773 }
774
775 // `new Foo()` or `null`.
776 bool factoryExpression(Expression expression) =>
777 expression is InstanceCreationExpression || expression is NullLiteral;
778
779 if (body is ExpressionFunctionBody && factoryExpression(body.expression)) {
780 return;
781 } else if (body is BlockFunctionBody) {
782 NodeList<Statement> statements = body.block.statements;
783 if (statements.isNotEmpty) {
784 Statement last = statements.last;
785 if (last is ReturnStatement && factoryExpression(last.expression)) {
786 return;
787 }
788 }
789 }
790
791 _errorReporter.reportErrorForNode(HintCode.INVALID_FACTORY_METHOD_IMPL,
792 decl.name, [decl.name.toString()]);
793 }
794
795 /**
796 * Produces a hint if the given identifier is a protected closure, field or
797 * getter/setter, method closure or invocation accessed outside a subclass.
798 */
799 void _checkForInvalidProtectedMemberAccess(SimpleIdentifier identifier) {
800 if (identifier.inDeclarationContext()) {
801 return;
802 }
803
804 bool isProtected(Element element) {
805 if (element is PropertyAccessorElement &&
806 element.enclosingElement is ClassElement &&
807 (element.isProtected || element.variable.isProtected)) {
808 return true;
809 }
810 if (element is MethodElement &&
811 element.enclosingElement is ClassElement &&
812 element.isProtected) {
813 return true;
814 }
815 return false;
816 }
817
818 bool inCommentReference(SimpleIdentifier identifier) =>
819 identifier.getAncestor((AstNode node) => node is CommentReference) !=
820 null;
821
822 bool inCurrentLibrary(Element element) =>
823 element.library == _currentLibrary;
824
825 Element element = identifier.bestElement;
826 if (isProtected(element) &&
827 !inCurrentLibrary(element) &&
828 !inCommentReference(identifier)) {
829 ClassElement definingClass = element.enclosingElement;
830 ClassDeclaration accessingClass =
831 identifier.getAncestor((AstNode node) => node is ClassDeclaration);
832 if (accessingClass == null ||
833 !_hasTypeOrSuperType(accessingClass.element, definingClass.type)) {
834 _errorReporter.reportErrorForNode(
835 HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
836 identifier,
837 [identifier.name.toString(), definingClass.name]);
838 }
839 }
840 }
841
549 /** 842 /**
550 * Check that the imported library does not define a loadLibrary function. The import has already 843 * Check that the imported library does not define a loadLibrary function. The import has already
551 * been determined to be deferred when this is called. 844 * been determined to be deferred when this is called.
552 * 845 *
553 * @param node the import directive to evaluate 846 * @param node the import directive to evaluate
554 * @param importElement the [ImportElement] retrieved from the node 847 * @param importElement the [ImportElement] retrieved from the node
555 * @return `true` if and only if an error code is generated on the passed node 848 * @return `true` if and only if an error code is generated on the passed node
556 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION]. 849 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION].
557 */ 850 */
558 bool _checkForLoadLibraryFunction( 851 bool _checkForLoadLibraryFunction(
(...skipping 18 matching lines...) Expand all
577 * `null`, avoiding these implicit returns is considered a best practice. 870 * `null`, avoiding these implicit returns is considered a best practice.
578 * 871 *
579 * Note: for async functions/methods, this hint only applies when the 872 * Note: for async functions/methods, this hint only applies when the
580 * function has a return type that Future<Null> is not assignable to. 873 * function has a return type that Future<Null> is not assignable to.
581 * 874 *
582 * @param node the binary expression to check 875 * @param node the binary expression to check
583 * @param body the function body 876 * @param body the function body
584 * @return `true` if and only if a hint code is generated on the passed node 877 * @return `true` if and only if a hint code is generated on the passed node
585 * See [HintCode.MISSING_RETURN]. 878 * See [HintCode.MISSING_RETURN].
586 */ 879 */
587 bool _checkForMissingReturn(TypeName returnType, FunctionBody body) { 880 void _checkForMissingReturn(TypeName returnType, FunctionBody body) {
588 // Check that the method or function has a return type, and a function body 881 // Check that the method or function has a return type, and a function body
589 if (returnType == null || body == null) { 882 if (returnType == null || body == null) {
590 return false; 883 return;
591 } 884 }
592 // Check that the body is a BlockFunctionBody 885 // Check that the body is a BlockFunctionBody
593 if (body is! BlockFunctionBody) { 886 if (body is BlockFunctionBody) {
594 return false; 887 // Generators are never required to have a return statement.
888 if (body.isGenerator) {
889 return;
890 }
891 // Check that the type is resolvable, and is not "void"
892 DartType returnTypeType = returnType.type;
893 if (returnTypeType == null || returnTypeType.isVoid) {
894 return;
895 }
896 // For async, give no hint if Future<Null> is assignable to the return
897 // type.
898 if (body.isAsynchronous &&
899 _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) {
900 return;
901 }
902 // Check the block for a return statement, if not, create the hint
903 if (!ExitDetector.exits(body)) {
904 _errorReporter.reportErrorForNode(
905 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
906 }
595 } 907 }
596 // Generators are never required to have a return statement.
597 if (body.isGenerator) {
598 return false;
599 }
600 // Check that the type is resolvable, and is not "void"
601 DartType returnTypeType = returnType.type;
602 if (returnTypeType == null || returnTypeType.isVoid) {
603 return false;
604 }
605 // For async, give no hint if Future<Null> is assignable to the return
606 // type.
607 if (body.isAsynchronous &&
608 _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) {
609 return false;
610 }
611 // Check the block for a return statement, if not, create the hint
612 BlockFunctionBody blockFunctionBody = body as BlockFunctionBody;
613 if (!ExitDetector.exits(blockFunctionBody)) {
614 _errorReporter.reportErrorForNode(
615 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
616 return true;
617 }
618 return false;
619 } 908 }
620 909
621 /** 910 /**
622 * Check for the passed class declaration for the 911 * Produce a hint if the given [condition] could have a value of `null`.
623 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
624 *
625 * @param node the class declaration to check
626 * @return `true` if and only if a hint code is generated on the passed node
627 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
628 */ 912 */
629 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { 913 void _checkForPossibleNullCondition(Expression condition) {
630 // ClassElement classElement = node.element; 914 condition = condition?.unParenthesized;
631 // if (classElement == null) { 915 if (condition is BinaryExpression) {
632 // return false; 916 _checkForPossibleNullConditionInBinaryExpression(condition);
633 // } 917 } else if (condition is PrefixExpression) {
634 // MethodElement equalsOperatorMethodElement = 918 _checkForPossibleNullConditionInPrefixExpression(condition);
635 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme); 919 } else {
636 // if (equalsOperatorMethodElement != null) { 920 _checkForPossibleNullConditionInSimpleExpression(condition);
637 // PropertyAccessorElement hashCodeElement = 921 }
638 // classElement.getGetter(_HASHCODE_GETTER_NAME); 922 }
639 // if (hashCodeElement == null) { 923
640 // _errorReporter.reportErrorForNode( 924 /**
641 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, 925 * Produce a hint if any of the parts of the given binary [condition] could
642 // node.name, 926 * have a value of `null`.
643 // [classElement.displayName]); 927 */
644 // return true; 928 void _checkForPossibleNullConditionInBinaryExpression(
645 // } 929 BinaryExpression condition) {
646 // } 930 TokenType type = condition.operator?.type;
647 // return false; 931 if (type == TokenType.AMPERSAND_AMPERSAND || type == TokenType.BAR_BAR) {
648 // } 932 _checkForPossibleNullCondition(condition.leftOperand);
933 _checkForPossibleNullCondition(condition.rightOperand);
934 }
935 }
936
937 /**
938 * Produce a hint if the operand of the given prefix [condition] could
939 * have a value of `null`.
940 */
941 void _checkForPossibleNullConditionInPrefixExpression(
942 PrefixExpression condition) {
943 if (condition.operator?.type == TokenType.BANG) {
944 _checkForPossibleNullCondition(condition.operand);
945 }
946 }
947
948 /**
949 * Produce a hint if the given [condition] could have a value of `null`.
950 */
951 void _checkForPossibleNullConditionInSimpleExpression(Expression condition) {
952 if (condition is MethodInvocation) {
953 if (condition.operator?.type == TokenType.QUESTION_PERIOD) {
954 _errorReporter.reportErrorForNode(
955 HintCode.NULL_AWARE_IN_CONDITION, condition);
956 }
957 } else if (condition is PropertyAccess) {
958 if (condition.operator?.type == TokenType.QUESTION_PERIOD) {
959 _errorReporter.reportErrorForNode(
960 HintCode.NULL_AWARE_IN_CONDITION, condition);
961 }
962 }
963 }
649 964
650 /** 965 /**
651 * Check for the passed as expression for the [HintCode.UNNECESSARY_CAST] hint code. 966 * Check for the passed as expression for the [HintCode.UNNECESSARY_CAST] hint code.
652 * 967 *
653 * @param node the as expression to check 968 * @param node the as expression to check
654 * @return `true` if and only if a hint code is generated on the passed node 969 * @return `true` if and only if a hint code is generated on the passed node
655 * See [HintCode.UNNECESSARY_CAST]. 970 * See [HintCode.UNNECESSARY_CAST].
656 */ 971 */
657 bool _checkForUnnecessaryCast(AsExpression node) { 972 bool _checkForUnnecessaryCast(AsExpression node) {
658 // TODO(jwren) After dartbug.com/13732, revisit this, we should be able to 973 // TODO(jwren) After dartbug.com/13732, revisit this, we should be able to
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
690 !lhsType.isDynamic && 1005 !lhsType.isDynamic &&
691 !rhsType.isDynamic && 1006 !rhsType.isDynamic &&
692 lhsType.isMoreSpecificThan(rhsType)) { 1007 lhsType.isMoreSpecificThan(rhsType)) {
693 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node); 1008 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node);
694 return true; 1009 return true;
695 } 1010 }
696 return false; 1011 return false;
697 } 1012 }
698 1013
699 /** 1014 /**
700 * Check for situations where the result of a method or function is used, when it returns 'void'. 1015 * Generate a hint for `noSuchMethod` methods that do nothing except of
1016 * calling another `noSuchMethod` that is not defined by `Object`.
701 * 1017 *
702 * TODO(jwren) Many other situations of use could be covered. We currently cov er the cases var x = 1018 * @return `true` if and only if a hint code is generated on the passed node
703 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m (), f(m()), return 1019 * See [HintCode.UNNECESSARY_NO_SUCH_METHOD].
704 * m(). 1020 */
1021 bool _checkForUnnecessaryNoSuchMethod(MethodDeclaration node) {
1022 if (node.name.name != FunctionElement.NO_SUCH_METHOD_METHOD_NAME) {
1023 return false;
1024 }
1025 bool isNonObjectNoSuchMethodInvocation(Expression invocation) {
1026 if (invocation is MethodInvocation &&
1027 invocation.target is SuperExpression &&
1028 invocation.argumentList.arguments.length == 1) {
1029 SimpleIdentifier name = invocation.methodName;
1030 if (name.name == FunctionElement.NO_SUCH_METHOD_METHOD_NAME) {
1031 Element methodElement = name.staticElement;
1032 Element classElement = methodElement?.enclosingElement;
1033 return methodElement is MethodElement &&
1034 classElement is ClassElement &&
1035 !classElement.type.isObject;
1036 }
1037 }
1038 return false;
1039 }
1040
1041 FunctionBody body = node.body;
1042 if (body is ExpressionFunctionBody) {
1043 if (isNonObjectNoSuchMethodInvocation(body.expression)) {
1044 _errorReporter.reportErrorForNode(
1045 HintCode.UNNECESSARY_NO_SUCH_METHOD, node);
1046 return true;
1047 }
1048 } else if (body is BlockFunctionBody) {
1049 List<Statement> statements = body.block.statements;
1050 if (statements.length == 1) {
1051 Statement returnStatement = statements.first;
1052 if (returnStatement is ReturnStatement &&
1053 isNonObjectNoSuchMethodInvocation(returnStatement.expression)) {
1054 _errorReporter.reportErrorForNode(
1055 HintCode.UNNECESSARY_NO_SUCH_METHOD, node);
1056 return true;
1057 }
1058 }
1059 }
1060 return false;
1061 }
1062
1063 /**
1064 * Check for situations where the result of a method or function is used, when
1065 * it returns 'void'.
705 * 1066 *
706 * @param node expression on the RHS of some assignment
707 * @return `true` if and only if a hint code is generated on the passed node
708 * See [HintCode.USE_OF_VOID_RESULT]. 1067 * See [HintCode.USE_OF_VOID_RESULT].
709 */ 1068 */
710 bool _checkForUseOfVoidResult(Expression expression) { 1069 void _checkForUseOfVoidResult(Expression expression) {
711 if (expression == null || expression is! MethodInvocation) { 1070 // TODO(jwren) Many other situations of use could be covered. We currently
1071 // cover the cases var x = m() and x = m(), but we could also cover cases
1072 // such as m().x, m()[k], a + m(), f(m()), return m().
1073 if (expression is MethodInvocation) {
1074 if (identical(expression.staticType, VoidTypeImpl.instance)) {
1075 SimpleIdentifier methodName = expression.methodName;
1076 _errorReporter.reportErrorForNode(
1077 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
1078 }
1079 }
1080 }
1081
1082 /**
1083 * Check for the passed class declaration for the
1084 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
1085 *
1086 * @param node the class declaration to check
1087 * @return `true` if and only if a hint code is generated on the passed node
1088 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
1089 */
1090 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
1091 // ClassElement classElement = node.element;
1092 // if (classElement == null) {
1093 // return false;
1094 // }
1095 // MethodElement equalsOperatorMethodElement =
1096 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
1097 // if (equalsOperatorMethodElement != null) {
1098 // PropertyAccessorElement hashCodeElement =
1099 // classElement.getGetter(_HASHCODE_GETTER_NAME);
1100 // if (hashCodeElement == null) {
1101 // _errorReporter.reportErrorForNode(
1102 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
1103 // node.name,
1104 // [classElement.displayName]);
1105 // return true;
1106 // }
1107 // }
1108 // return false;
1109 // }
1110
1111 bool _hasTypeOrSuperType(ClassElement element, InterfaceType type) {
1112 if (element == null) {
712 return false; 1113 return false;
713 } 1114 }
714 MethodInvocation methodInvocation = expression as MethodInvocation; 1115 ClassElement typeElement = type.element;
715 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) { 1116 return element == typeElement ||
716 SimpleIdentifier methodName = methodInvocation.methodName; 1117 element.allSupertypes
717 _errorReporter.reportErrorForNode( 1118 .any((InterfaceType t) => t.element == typeElement);
718 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
719 return true;
720 }
721 return false;
722 } 1119 }
723 1120
724 /** 1121 /**
725 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the 1122 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the
726 * expression that is a parenthesized expression, but whose parent is not a pa renthesized 1123 * expression that is a parenthesized expression, but whose parent is not a pa renthesized
727 * expression. 1124 * expression.
728 * 1125 *
729 * For example given the code `(((e)))`: `(e) -> (((e)))`. 1126 * For example given the code `(((e)))`: `(e) -> (((e)))`.
730 * 1127 *
731 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression 1128 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression
732 * @return the first parent or grand-parent that is a parenthesized expression , that does not have 1129 * @return the first parent or grand-parent that is a parenthesized expression , that does not have
733 * a parenthesized expression parent 1130 * a parenthesized expression parent
734 */ 1131 */
735 static ParenthesizedExpression _wrapParenthesizedExpression( 1132 static ParenthesizedExpression _wrapParenthesizedExpression(
736 ParenthesizedExpression parenthesizedExpression) { 1133 ParenthesizedExpression parenthesizedExpression) {
737 if (parenthesizedExpression.parent is ParenthesizedExpression) { 1134 AstNode parent = parenthesizedExpression.parent;
738 return _wrapParenthesizedExpression( 1135 if (parent is ParenthesizedExpression) {
739 parenthesizedExpression.parent as ParenthesizedExpression); 1136 return _wrapParenthesizedExpression(parent);
740 } 1137 }
741 return parenthesizedExpression; 1138 return parenthesizedExpression;
742 } 1139 }
743 } 1140 }
744 1141
745 /** 1142 /**
746 * Instances of the class `ClassScope` implement the scope defined by a class. 1143 * Utilities for [LibraryElementImpl] building.
747 */ 1144 */
748 class ClassScope extends EnclosedScope { 1145 class BuildLibraryElementUtils {
749 /** 1146 /**
750 * Initialize a newly created scope enclosed within another scope. 1147 * Look through all of the compilation units defined for the given [library],
751 * 1148 * looking for getters and setters that are defined in different compilation
752 * @param enclosingScope the scope in which this scope is lexically enclosed 1149 * units but that have the same names. If any are found, make sure that they
753 * @param typeElement the element representing the type represented by this sc ope 1150 * have the same variable element.
754 */ 1151 */
755 ClassScope(Scope enclosingScope, ClassElement typeElement) 1152 static void patchTopLevelAccessors(LibraryElementImpl library) {
756 : super(enclosingScope) { 1153 // Without parts getters/setters already share the same variable element.
757 if (typeElement == null) { 1154 List<CompilationUnitElement> parts = library.parts;
758 throw new IllegalArgumentException("class element cannot be null"); 1155 if (parts.isEmpty) {
1156 return;
759 } 1157 }
760 _defineMembers(typeElement); 1158 // Collect getters and setters.
761 } 1159 HashMap<String, PropertyAccessorElement> getters =
762 1160 new HashMap<String, PropertyAccessorElement>();
763 @override 1161 List<PropertyAccessorElement> setters = <PropertyAccessorElement>[];
764 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { 1162 _collectAccessors(getters, setters, library.definingCompilationUnit);
765 if (existing is PropertyAccessorElement && duplicate is MethodElement) { 1163 int partLength = parts.length;
766 if (existing.nameOffset < duplicate.nameOffset) { 1164 for (int i = 0; i < partLength; i++) {
767 return new AnalysisError( 1165 CompilationUnitElement unit = parts[i];
768 duplicate.source, 1166 _collectAccessors(getters, setters, unit);
769 duplicate.nameOffset, 1167 }
770 duplicate.nameLength, 1168 // Move every setter to the corresponding getter's variable (if exists).
771 CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME, 1169 int setterLength = setters.length;
772 [existing.displayName]); 1170 for (int j = 0; j < setterLength; j++) {
773 } else { 1171 PropertyAccessorElement setter = setters[j];
774 return new AnalysisError( 1172 PropertyAccessorElement getter = getters[setter.displayName];
775 existing.source, 1173 if (getter != null) {
776 existing.nameOffset, 1174 TopLevelVariableElementImpl variable = getter.variable;
777 existing.nameLength, 1175 TopLevelVariableElementImpl setterVariable = setter.variable;
778 CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME, 1176 CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement;
779 [existing.displayName]); 1177 setterUnit.replaceTopLevelVariable(setterVariable, variable);
1178 variable.setter = setter;
1179 (setter as PropertyAccessorElementImpl).variable = variable;
780 } 1180 }
781 } 1181 }
782 return super.getErrorForDuplicate(existing, duplicate);
783 } 1182 }
784 1183
785 /** 1184 /**
786 * Define the instance members defined by the class. 1185 * Add all of the non-synthetic [getters] and [setters] defined in the given
787 * 1186 * [unit] that have no corresponding accessor to one of the given collections.
788 * @param typeElement the element representing the type represented by this sc ope
789 */ 1187 */
790 void _defineMembers(ClassElement typeElement) { 1188 static void _collectAccessors(Map<String, PropertyAccessorElement> getters,
791 for (PropertyAccessorElement accessor in typeElement.accessors) { 1189 List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
792 define(accessor); 1190 List<PropertyAccessorElement> accessors = unit.accessors;
793 } 1191 int length = accessors.length;
794 for (MethodElement method in typeElement.methods) { 1192 for (int i = 0; i < length; i++) {
795 define(method); 1193 PropertyAccessorElement accessor = accessors[i];
1194 if (accessor.isGetter) {
1195 if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
1196 getters[accessor.displayName] = accessor;
1197 }
1198 } else {
1199 if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
1200 setters.add(accessor);
1201 }
1202 }
796 } 1203 }
797 } 1204 }
798 } 1205 }
799 1206
800 /**
801 * A `CompilationUnitBuilder` builds an element model for a single compilation
802 * unit.
803 */
804 class CompilationUnitBuilder {
805 /**
806 * Build the compilation unit element for the given [source] based on the
807 * compilation [unit] associated with the source. Throw an AnalysisException
808 * if the element could not be built. [librarySource] is the source for the
809 * containing library.
810 */
811 CompilationUnitElementImpl buildCompilationUnit(
812 Source source, CompilationUnit unit, Source librarySource) {
813 return PerformanceStatistics.resolve.makeCurrentWhile(() {
814 if (unit == null) {
815 return null;
816 }
817 ElementHolder holder = new ElementHolder();
818 ElementBuilder builder = new ElementBuilder(holder);
819 unit.accept(builder);
820 CompilationUnitElementImpl element =
821 new CompilationUnitElementImpl(source.shortName);
822 element.accessors = holder.accessors;
823 element.enums = holder.enums;
824 element.functions = holder.functions;
825 element.source = source;
826 element.librarySource = librarySource;
827 element.typeAliases = holder.typeAliases;
828 element.types = holder.types;
829 element.topLevelVariables = holder.topLevelVariables;
830 unit.element = element;
831 holder.validate();
832 return element;
833 });
834 }
835 }
836
837 /** 1207 /**
838 * Instances of the class `ConstantVerifier` traverse an AST structure looking f or additional 1208 * Instances of the class `ConstantVerifier` traverse an AST structure looking f or additional
839 * errors and warnings not covered by the parser and resolver. In particular, it looks for errors 1209 * errors and warnings not covered by the parser and resolver. In particular, it looks for errors
840 * and warnings related to constant expressions. 1210 * and warnings related to constant expressions.
841 */ 1211 */
842 class ConstantVerifier extends RecursiveAstVisitor<Object> { 1212 class ConstantVerifier extends RecursiveAstVisitor<Object> {
843 /** 1213 /**
844 * The error reporter by which errors will be reported. 1214 * The error reporter by which errors will be reported.
845 */ 1215 */
846 final ErrorReporter _errorReporter; 1216 final ErrorReporter _errorReporter;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
899 this._numType = _typeProvider.numType; 1269 this._numType = _typeProvider.numType;
900 this._stringType = _typeProvider.stringType; 1270 this._stringType = _typeProvider.stringType;
901 } 1271 }
902 1272
903 @override 1273 @override
904 Object visitAnnotation(Annotation node) { 1274 Object visitAnnotation(Annotation node) {
905 super.visitAnnotation(node); 1275 super.visitAnnotation(node);
906 // check annotation creation 1276 // check annotation creation
907 Element element = node.element; 1277 Element element = node.element;
908 if (element is ConstructorElement) { 1278 if (element is ConstructorElement) {
909 ConstructorElement constructorElement = element; 1279 // should be 'const' constructor
910 // should 'const' constructor 1280 if (!element.isConst) {
911 if (!constructorElement.isConst) {
912 _errorReporter.reportErrorForNode( 1281 _errorReporter.reportErrorForNode(
913 CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node); 1282 CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node);
914 return null; 1283 return null;
915 } 1284 }
916 // should have arguments 1285 // should have arguments
917 ArgumentList argumentList = node.arguments; 1286 ArgumentList argumentList = node.arguments;
918 if (argumentList == null) { 1287 if (argumentList == null) {
919 _errorReporter.reportErrorForNode( 1288 _errorReporter.reportErrorForNode(
920 CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node); 1289 CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node);
921 return null; 1290 return null;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 1338
970 @override 1339 @override
971 Object visitListLiteral(ListLiteral node) { 1340 Object visitListLiteral(ListLiteral node) {
972 super.visitListLiteral(node); 1341 super.visitListLiteral(node);
973 if (node.constKeyword != null) { 1342 if (node.constKeyword != null) {
974 DartObjectImpl result; 1343 DartObjectImpl result;
975 for (Expression element in node.elements) { 1344 for (Expression element in node.elements) {
976 result = 1345 result =
977 _validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT); 1346 _validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT);
978 if (result != null) { 1347 if (result != null) {
979 _reportErrorIfFromDeferredLibrary(element, 1348 _reportErrorIfFromDeferredLibrary(
980 CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRA RY); 1349 element,
1350 CompileTimeErrorCode
1351 .NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY);
981 } 1352 }
982 } 1353 }
983 } 1354 }
984 return null; 1355 return null;
985 } 1356 }
986 1357
987 @override 1358 @override
988 Object visitMapLiteral(MapLiteral node) { 1359 Object visitMapLiteral(MapLiteral node) {
989 super.visitMapLiteral(node); 1360 super.visitMapLiteral(node);
990 bool isConst = node.constKeyword != null; 1361 bool isConst = node.constKeyword != null;
991 bool reportEqualKeys = true; 1362 bool reportEqualKeys = true;
992 HashSet<DartObject> keys = new HashSet<DartObject>(); 1363 HashSet<DartObject> keys = new HashSet<DartObject>();
993 List<Expression> invalidKeys = new List<Expression>(); 1364 List<Expression> invalidKeys = new List<Expression>();
994 for (MapLiteralEntry entry in node.entries) { 1365 for (MapLiteralEntry entry in node.entries) {
995 Expression key = entry.key; 1366 Expression key = entry.key;
996 if (isConst) { 1367 if (isConst) {
997 DartObjectImpl keyResult = 1368 DartObjectImpl keyResult =
998 _validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY); 1369 _validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY);
999 Expression valueExpression = entry.value; 1370 Expression valueExpression = entry.value;
1000 DartObjectImpl valueResult = _validate( 1371 DartObjectImpl valueResult = _validate(
1001 valueExpression, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE); 1372 valueExpression, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE);
1002 if (valueResult != null) { 1373 if (valueResult != null) {
1003 _reportErrorIfFromDeferredLibrary(valueExpression, 1374 _reportErrorIfFromDeferredLibrary(
1004 CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY) ; 1375 valueExpression,
1376 CompileTimeErrorCode
1377 .NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY);
1005 } 1378 }
1006 if (keyResult != null) { 1379 if (keyResult != null) {
1007 _reportErrorIfFromDeferredLibrary(key, 1380 _reportErrorIfFromDeferredLibrary(key,
1008 CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY); 1381 CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY);
1009 if (keys.contains(keyResult)) { 1382 if (keys.contains(keyResult)) {
1010 invalidKeys.add(key); 1383 invalidKeys.add(key);
1011 } else { 1384 } else {
1012 keys.add(keyResult); 1385 keys.add(keyResult);
1013 } 1386 }
1014 DartType type = keyResult.type; 1387 DartType type = keyResult.type;
1015 if (_implementsEqualsWhenNotAllowed(type)) { 1388 if (_implementsEqualsWhenNotAllowed(type)) {
1016 _errorReporter.reportErrorForNode( 1389 _errorReporter.reportErrorForNode(
1017 CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQ UALS, 1390 CompileTimeErrorCode
1391 .CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
1018 key, 1392 key,
1019 [type.displayName]); 1393 [type.displayName]);
1020 } 1394 }
1021 } 1395 }
1022 } else { 1396 } else {
1023 // Note: we throw the errors away because this isn't actually a const. 1397 // Note: we throw the errors away because this isn't actually a const.
1024 AnalysisErrorListener errorListener = 1398 AnalysisErrorListener errorListener =
1025 AnalysisErrorListener.NULL_LISTENER; 1399 AnalysisErrorListener.NULL_LISTENER;
1026 ErrorReporter subErrorReporter = 1400 ErrorReporter subErrorReporter =
1027 new ErrorReporter(errorListener, _errorReporter.source); 1401 new ErrorReporter(errorListener, _errorReporter.source);
1028 DartObjectImpl result = key.accept(new ConstantVisitor( 1402 DartObjectImpl result = key.accept(new ConstantVisitor(
1029 new ConstantEvaluationEngine(_typeProvider, declaredVariables, 1403 new ConstantEvaluationEngine(_typeProvider, declaredVariables,
1030 typeSystem: _typeSystem), 1404 typeSystem: _typeSystem),
1031 subErrorReporter)); 1405 subErrorReporter));
1032 if (result != null) { 1406 if (result != null) {
1033 if (keys.contains(result)) { 1407 if (keys.contains(result)) {
1034 invalidKeys.add(key); 1408 invalidKeys.add(key);
1035 } else { 1409 } else {
1036 keys.add(result); 1410 keys.add(result);
1037 } 1411 }
1038 } else { 1412 } else {
1039 reportEqualKeys = false; 1413 reportEqualKeys = false;
1040 } 1414 }
1041 } 1415 }
1042 } 1416 }
1043 if (reportEqualKeys) { 1417 if (reportEqualKeys) {
1044 for (Expression key in invalidKeys) { 1418 int length = invalidKeys.length;
1419 for (int i = 0; i < length; i++) {
1045 _errorReporter.reportErrorForNode( 1420 _errorReporter.reportErrorForNode(
1046 StaticWarningCode.EQUAL_KEYS_IN_MAP, key); 1421 StaticWarningCode.EQUAL_KEYS_IN_MAP, invalidKeys[i]);
1047 } 1422 }
1048 } 1423 }
1049 return null; 1424 return null;
1050 } 1425 }
1051 1426
1052 @override 1427 @override
1053 Object visitMethodDeclaration(MethodDeclaration node) { 1428 Object visitMethodDeclaration(MethodDeclaration node) {
1054 super.visitMethodDeclaration(node); 1429 super.visitMethodDeclaration(node);
1055 _validateDefaultValues(node.parameters); 1430 _validateDefaultValues(node.parameters);
1056 return null; 1431 return null;
1057 } 1432 }
1058 1433
1059 @override 1434 @override
1060 Object visitSwitchStatement(SwitchStatement node) { 1435 Object visitSwitchStatement(SwitchStatement node) {
1061 // TODO(paulberry): to minimize error messages, it would be nice to 1436 // TODO(paulberry): to minimize error messages, it would be nice to
1062 // compare all types with the most popular type rather than the first 1437 // compare all types with the most popular type rather than the first
1063 // type. 1438 // type.
1064 NodeList<SwitchMember> switchMembers = node.members; 1439 NodeList<SwitchMember> switchMembers = node.members;
1065 bool foundError = false; 1440 bool foundError = false;
1066 DartType firstType = null; 1441 DartType firstType = null;
1067 for (SwitchMember switchMember in switchMembers) { 1442 for (SwitchMember switchMember in switchMembers) {
1068 if (switchMember is SwitchCase) { 1443 if (switchMember is SwitchCase) {
1069 SwitchCase switchCase = switchMember; 1444 Expression expression = switchMember.expression;
1070 Expression expression = switchCase.expression;
1071 DartObjectImpl caseResult = _validate( 1445 DartObjectImpl caseResult = _validate(
1072 expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION); 1446 expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION);
1073 if (caseResult != null) { 1447 if (caseResult != null) {
1074 _reportErrorIfFromDeferredLibrary(expression, 1448 _reportErrorIfFromDeferredLibrary(
1075 CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LI BRARY); 1449 expression,
1450 CompileTimeErrorCode
1451 .NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LIBRARY);
1076 DartObject value = caseResult; 1452 DartObject value = caseResult;
1077 if (firstType == null) { 1453 if (firstType == null) {
1078 firstType = value.type; 1454 firstType = value.type;
1079 } else { 1455 } else {
1080 DartType nType = value.type; 1456 DartType nType = value.type;
1081 if (firstType != nType) { 1457 if (firstType != nType) {
1082 _errorReporter.reportErrorForNode( 1458 _errorReporter.reportErrorForNode(
1083 CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, 1459 CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES,
1084 expression, 1460 expression,
1085 [expression.toSource(), firstType.displayName]); 1461 [expression.toSource(), firstType.displayName]);
(...skipping 19 matching lines...) Expand all
1105 if (result == null) { 1481 if (result == null) {
1106 // Variables marked "const" should have had their values computed by 1482 // Variables marked "const" should have had their values computed by
1107 // ConstantValueComputer. Other variables will only have had their 1483 // ConstantValueComputer. Other variables will only have had their
1108 // values computed if the value was needed (e.g. final variables in a 1484 // values computed if the value was needed (e.g. final variables in a
1109 // class containing const constructors). 1485 // class containing const constructors).
1110 assert(!node.isConst); 1486 assert(!node.isConst);
1111 return null; 1487 return null;
1112 } 1488 }
1113 _reportErrors(result.errors, 1489 _reportErrors(result.errors,
1114 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE); 1490 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
1115 _reportErrorIfFromDeferredLibrary(initializer, 1491 _reportErrorIfFromDeferredLibrary(
1116 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DE FERRED_LIBRARY); 1492 initializer,
1493 CompileTimeErrorCode
1494 .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY);
1117 } 1495 }
1118 return null; 1496 return null;
1119 } 1497 }
1120 1498
1121 /** 1499 /**
1122 * This verifies that the passed switch statement does not have a case express ion with the 1500 * This verifies that the passed switch statement does not have a case express ion with the
1123 * operator '==' overridden. 1501 * operator '==' overridden.
1124 * 1502 *
1125 * @param node the switch statement to evaluate 1503 * @param node the switch statement to evaluate
1126 * @param type the common type of all 'case' expressions 1504 * @param type the common type of all 'case' expressions
(...skipping 19 matching lines...) Expand all
1146 */ 1524 */
1147 bool _implementsEqualsWhenNotAllowed(DartType type) { 1525 bool _implementsEqualsWhenNotAllowed(DartType type) {
1148 // ignore int or String 1526 // ignore int or String
1149 if (type == null || type == _intType || type == _typeProvider.stringType) { 1527 if (type == null || type == _intType || type == _typeProvider.stringType) {
1150 return false; 1528 return false;
1151 } else if (type == _typeProvider.doubleType) { 1529 } else if (type == _typeProvider.doubleType) {
1152 return true; 1530 return true;
1153 } 1531 }
1154 // prepare ClassElement 1532 // prepare ClassElement
1155 Element element = type.element; 1533 Element element = type.element;
1156 if (element is! ClassElement) { 1534 if (element is ClassElement) {
1157 return false; 1535 // lookup for ==
1536 MethodElement method =
1537 element.lookUpConcreteMethod("==", _currentLibrary);
1538 if (method == null || method.enclosingElement.type.isObject) {
1539 return false;
1540 }
1541 // there is == that we don't like
1542 return true;
1158 } 1543 }
1159 ClassElement classElement = element as ClassElement; 1544 return false;
1160 // lookup for ==
1161 MethodElement method =
1162 classElement.lookUpConcreteMethod("==", _currentLibrary);
1163 if (method == null || method.enclosingElement.type.isObject) {
1164 return false;
1165 }
1166 // there is == that we don't like
1167 return true;
1168 } 1545 }
1169 1546
1170 /** 1547 /**
1171 * Given some computed [Expression], this method generates the passed [ErrorCo de] on 1548 * Given some computed [Expression], this method generates the passed [ErrorCo de] on
1172 * the node if its' value consists of information from a deferred library. 1549 * the node if its' value consists of information from a deferred library.
1173 * 1550 *
1174 * @param expression the expression to be tested for a deferred library refere nce 1551 * @param expression the expression to be tested for a deferred library refere nce
1175 * @param errorCode the error code to be used if the expression is or consists of a reference to a 1552 * @param errorCode the error code to be used if the expression is or consists of a reference to a
1176 * deferred library 1553 * deferred library
1177 */ 1554 */
1178 void _reportErrorIfFromDeferredLibrary( 1555 void _reportErrorIfFromDeferredLibrary(
1179 Expression expression, ErrorCode errorCode) { 1556 Expression expression, ErrorCode errorCode) {
1180 DeferredLibraryReferenceDetector referenceDetector = 1557 DeferredLibraryReferenceDetector referenceDetector =
1181 new DeferredLibraryReferenceDetector(); 1558 new DeferredLibraryReferenceDetector();
1182 expression.accept(referenceDetector); 1559 expression.accept(referenceDetector);
1183 if (referenceDetector.result) { 1560 if (referenceDetector.result) {
1184 _errorReporter.reportErrorForNode(errorCode, expression); 1561 _errorReporter.reportErrorForNode(errorCode, expression);
1185 } 1562 }
1186 } 1563 }
1187 1564
1188 /** 1565 /**
1189 * Report any errors in the given list. Except for special cases, use the give n error code rather 1566 * Report any errors in the given list. Except for special cases, use the give n error code rather
1190 * than the one reported in the error. 1567 * than the one reported in the error.
1191 * 1568 *
1192 * @param errors the errors that need to be reported 1569 * @param errors the errors that need to be reported
1193 * @param errorCode the error code to be used 1570 * @param errorCode the error code to be used
1194 */ 1571 */
1195 void _reportErrors(List<AnalysisError> errors, ErrorCode errorCode) { 1572 void _reportErrors(List<AnalysisError> errors, ErrorCode errorCode) {
1196 for (AnalysisError data in errors) { 1573 int length = errors.length;
1574 for (int i = 0; i < length; i++) {
1575 AnalysisError data = errors[i];
1197 ErrorCode dataErrorCode = data.errorCode; 1576 ErrorCode dataErrorCode = data.errorCode;
1198 if (identical(dataErrorCode, 1577 if (identical(dataErrorCode,
1199 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) || 1578 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) ||
1200 identical( 1579 identical(
1201 dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) || 1580 dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) ||
1202 identical(dataErrorCode, 1581 identical(dataErrorCode,
1203 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) || 1582 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) ||
1204 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) || 1583 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) ||
1205 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) || 1584 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) ||
1206 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) || 1585 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) ||
1207 identical(dataErrorCode, 1586 identical(dataErrorCode,
1208 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) || 1587 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) ||
1209 identical(dataErrorCode, 1588 identical(
1210 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMA TCH) || 1589 dataErrorCode,
1211 identical(dataErrorCode, 1590 CheckedModeCompileTimeErrorCode
1212 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMA TCH) || 1591 .CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH) ||
1592 identical(
1593 dataErrorCode,
1594 CheckedModeCompileTimeErrorCode
1595 .CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH) ||
1213 identical(dataErrorCode, 1596 identical(dataErrorCode,
1214 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH)) { 1597 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH)) {
1215 _errorReporter.reportError(data); 1598 _errorReporter.reportError(data);
1216 } else if (errorCode != null) { 1599 } else if (errorCode != null) {
1217 _errorReporter.reportError(new AnalysisError( 1600 _errorReporter.reportError(new AnalysisError(
1218 data.source, data.offset, data.length, errorCode)); 1601 data.source, data.offset, data.length, errorCode));
1219 } 1602 }
1220 } 1603 }
1221 } 1604 }
1222 1605
(...skipping 17 matching lines...) Expand all
1240 return result; 1623 return result;
1241 } 1624 }
1242 1625
1243 /** 1626 /**
1244 * Validate that if the passed arguments are constant expressions. 1627 * Validate that if the passed arguments are constant expressions.
1245 * 1628 *
1246 * @param argumentList the argument list to evaluate 1629 * @param argumentList the argument list to evaluate
1247 */ 1630 */
1248 void _validateConstantArguments(ArgumentList argumentList) { 1631 void _validateConstantArguments(ArgumentList argumentList) {
1249 for (Expression argument in argumentList.arguments) { 1632 for (Expression argument in argumentList.arguments) {
1250 if (argument is NamedExpression) { 1633 Expression realArgument =
1251 argument = (argument as NamedExpression).expression; 1634 argument is NamedExpression ? argument.expression : argument;
1252 }
1253 _validate( 1635 _validate(
1254 argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT); 1636 realArgument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
1255 } 1637 }
1256 } 1638 }
1257 1639
1258 /** 1640 /**
1259 * Validates that the expressions of the given initializers (of a constant con structor) are all 1641 * Validates that the expressions of the given initializers (of a constant con structor) are all
1260 * compile time constants. 1642 * compile time constants.
1261 * 1643 *
1262 * @param constructor the constant constructor declaration to validate 1644 * @param constructor the constant constructor declaration to validate
1263 */ 1645 */
1264 void _validateConstructorInitializers(ConstructorDeclaration constructor) { 1646 void _validateConstructorInitializers(ConstructorDeclaration constructor) {
1265 List<ParameterElement> parameterElements = 1647 List<ParameterElement> parameterElements =
1266 constructor.parameters.parameterElements; 1648 constructor.parameters.parameterElements;
1267 NodeList<ConstructorInitializer> initializers = constructor.initializers; 1649 NodeList<ConstructorInitializer> initializers = constructor.initializers;
1268 for (ConstructorInitializer initializer in initializers) { 1650 for (ConstructorInitializer initializer in initializers) {
1269 if (initializer is ConstructorFieldInitializer) { 1651 if (initializer is ConstructorFieldInitializer) {
1270 ConstructorFieldInitializer fieldInitializer = initializer;
1271 _validateInitializerExpression( 1652 _validateInitializerExpression(
1272 parameterElements, fieldInitializer.expression); 1653 parameterElements, initializer.expression);
1273 } 1654 }
1274 if (initializer is RedirectingConstructorInvocation) { 1655 if (initializer is RedirectingConstructorInvocation) {
1275 RedirectingConstructorInvocation invocation = initializer;
1276 _validateInitializerInvocationArguments( 1656 _validateInitializerInvocationArguments(
1277 parameterElements, invocation.argumentList); 1657 parameterElements, initializer.argumentList);
1278 } 1658 }
1279 if (initializer is SuperConstructorInvocation) { 1659 if (initializer is SuperConstructorInvocation) {
1280 SuperConstructorInvocation invocation = initializer;
1281 _validateInitializerInvocationArguments( 1660 _validateInitializerInvocationArguments(
1282 parameterElements, invocation.argumentList); 1661 parameterElements, initializer.argumentList);
1283 } 1662 }
1284 } 1663 }
1285 } 1664 }
1286 1665
1287 /** 1666 /**
1288 * Validate that the default value associated with each of the parameters in t he given list is a 1667 * Validate that the default value associated with each of the parameters in t he given list is a
1289 * compile time constant. 1668 * compile time constant.
1290 * 1669 *
1291 * @param parameters the list of parameters to be validated 1670 * @param parameters the list of parameters to be validated
1292 */ 1671 */
1293 void _validateDefaultValues(FormalParameterList parameters) { 1672 void _validateDefaultValues(FormalParameterList parameters) {
1294 if (parameters == null) { 1673 if (parameters == null) {
1295 return; 1674 return;
1296 } 1675 }
1297 for (FormalParameter parameter in parameters.parameters) { 1676 for (FormalParameter parameter in parameters.parameters) {
1298 if (parameter is DefaultFormalParameter) { 1677 if (parameter is DefaultFormalParameter) {
1299 DefaultFormalParameter defaultParameter = parameter; 1678 Expression defaultValue = parameter.defaultValue;
1300 Expression defaultValue = defaultParameter.defaultValue;
1301 DartObjectImpl result; 1679 DartObjectImpl result;
1302 if (defaultValue == null) { 1680 if (defaultValue == null) {
1303 result = 1681 result =
1304 new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE); 1682 new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE);
1305 } else { 1683 } else {
1306 result = _validate( 1684 result = _validate(
1307 defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE); 1685 defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE);
1308 if (result != null) { 1686 if (result != null) {
1309 _reportErrorIfFromDeferredLibrary(defaultValue, 1687 _reportErrorIfFromDeferredLibrary(
1310 CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LI BRARY); 1688 defaultValue,
1689 CompileTimeErrorCode
1690 .NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LIBRARY);
1311 } 1691 }
1312 } 1692 }
1313 VariableElementImpl element = parameter.element as VariableElementImpl; 1693 VariableElementImpl element = parameter.element as VariableElementImpl;
1314 element.evaluationResult = new EvaluationResultImpl(result); 1694 element.evaluationResult = new EvaluationResultImpl(result);
1315 } 1695 }
1316 } 1696 }
1317 } 1697 }
1318 1698
1319 /** 1699 /**
1320 * Validates that the expressions of any field initializers in the class decla ration are all 1700 * Validates that the expressions of any field initializers in the class decla ration are all
1321 * compile time constants. Since this is only required if the class has a cons tant constructor, 1701 * compile time constants. Since this is only required if the class has a cons tant constructor,
1322 * the error is reported at the constructor site. 1702 * the error is reported at the constructor site.
1323 * 1703 *
1324 * @param classDeclaration the class which should be validated 1704 * @param classDeclaration the class which should be validated
1325 * @param errorSite the site at which errors should be reported. 1705 * @param errorSite the site at which errors should be reported.
1326 */ 1706 */
1327 void _validateFieldInitializers( 1707 void _validateFieldInitializers(
1328 ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) { 1708 ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) {
1329 NodeList<ClassMember> members = classDeclaration.members; 1709 NodeList<ClassMember> members = classDeclaration.members;
1330 for (ClassMember member in members) { 1710 for (ClassMember member in members) {
1331 if (member is FieldDeclaration) { 1711 if (member is FieldDeclaration && !member.isStatic) {
1332 FieldDeclaration fieldDeclaration = member; 1712 for (VariableDeclaration variableDeclaration
1333 if (!fieldDeclaration.isStatic) { 1713 in member.fields.variables) {
1334 for (VariableDeclaration variableDeclaration 1714 Expression initializer = variableDeclaration.initializer;
1335 in fieldDeclaration.fields.variables) { 1715 if (initializer != null) {
1336 Expression initializer = variableDeclaration.initializer; 1716 // Ignore any errors produced during validation--if the constant
1337 if (initializer != null) { 1717 // can't be eavluated we'll just report a single error.
1338 // Ignore any errors produced during validation--if the constant 1718 AnalysisErrorListener errorListener =
1339 // can't be eavluated we'll just report a single error. 1719 AnalysisErrorListener.NULL_LISTENER;
1340 AnalysisErrorListener errorListener = 1720 ErrorReporter subErrorReporter =
1341 AnalysisErrorListener.NULL_LISTENER; 1721 new ErrorReporter(errorListener, _errorReporter.source);
1342 ErrorReporter subErrorReporter = 1722 DartObjectImpl result = initializer.accept(new ConstantVisitor(
1343 new ErrorReporter(errorListener, _errorReporter.source); 1723 new ConstantEvaluationEngine(_typeProvider, declaredVariables,
1344 DartObjectImpl result = initializer.accept(new ConstantVisitor( 1724 typeSystem: _typeSystem),
1345 new ConstantEvaluationEngine(_typeProvider, declaredVariables, 1725 subErrorReporter));
1346 typeSystem: _typeSystem), 1726 if (result == null) {
1347 subErrorReporter)); 1727 _errorReporter.reportErrorForNode(
1348 if (result == null) { 1728 CompileTimeErrorCode
1349 _errorReporter.reportErrorForNode( 1729 .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
1350 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZE D_BY_NON_CONST, 1730 errorSite,
1351 errorSite, 1731 [variableDeclaration.name.name]);
1352 [variableDeclaration.name.name]);
1353 }
1354 } 1732 }
1355 } 1733 }
1356 } 1734 }
1357 } 1735 }
1358 } 1736 }
1359 } 1737 }
1360 1738
1361 /** 1739 /**
1362 * Validates that the given expression is a compile time constant. 1740 * Validates that the given expression is a compile time constant.
1363 * 1741 *
1364 * @param parameterElements the elements of parameters of constant constructor , they are 1742 * @param parameterElements the elements of parameters of constant constructor , they are
1365 * considered as a valid potentially constant expressions 1743 * considered as a valid potentially constant expressions
1366 * @param expression the expression to validate 1744 * @param expression the expression to validate
1367 */ 1745 */
1368 void _validateInitializerExpression( 1746 void _validateInitializerExpression(
1369 List<ParameterElement> parameterElements, Expression expression) { 1747 List<ParameterElement> parameterElements, Expression expression) {
1370 RecordingErrorListener errorListener = new RecordingErrorListener(); 1748 RecordingErrorListener errorListener = new RecordingErrorListener();
1371 ErrorReporter subErrorReporter = 1749 ErrorReporter subErrorReporter =
1372 new ErrorReporter(errorListener, _errorReporter.source); 1750 new ErrorReporter(errorListener, _errorReporter.source);
1373 DartObjectImpl result = expression.accept( 1751 DartObjectImpl result = expression.accept(
1374 new _ConstantVerifier_validateInitializerExpression(_typeProvider, 1752 new _ConstantVerifier_validateInitializerExpression(_typeProvider,
1375 subErrorReporter, this, parameterElements, declaredVariables, 1753 subErrorReporter, this, parameterElements, declaredVariables,
1376 typeSystem: _typeSystem)); 1754 typeSystem: _typeSystem));
1377 _reportErrors(errorListener.errors, 1755 _reportErrors(errorListener.errors,
1378 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER); 1756 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
1379 if (result != null) { 1757 if (result != null) {
1380 _reportErrorIfFromDeferredLibrary(expression, 1758 _reportErrorIfFromDeferredLibrary(
1381 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_L IBRARY); 1759 expression,
1760 CompileTimeErrorCode
1761 .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY);
1382 } 1762 }
1383 } 1763 }
1384 1764
1385 /** 1765 /**
1386 * Validates that all of the arguments of a constructor initializer are compil e time constants. 1766 * Validates that all of the arguments of a constructor initializer are compil e time constants.
1387 * 1767 *
1388 * @param parameterElements the elements of parameters of constant constructor , they are 1768 * @param parameterElements the elements of parameters of constant constructor , they are
1389 * considered as a valid potentially constant expressions 1769 * considered as a valid potentially constant expressions
1390 * @param argumentList the argument list to validate 1770 * @param argumentList the argument list to validate
1391 */ 1771 */
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1452 * @param node the is expression to check 1832 * @param node the is expression to check
1453 * @return `true` if and only if a hint code is generated on the passed node 1833 * @return `true` if and only if a hint code is generated on the passed node
1454 * See [HintCode.IS_DOUBLE], 1834 * See [HintCode.IS_DOUBLE],
1455 * [HintCode.IS_INT], 1835 * [HintCode.IS_INT],
1456 * [HintCode.IS_NOT_DOUBLE], and 1836 * [HintCode.IS_NOT_DOUBLE], and
1457 * [HintCode.IS_NOT_INT]. 1837 * [HintCode.IS_NOT_INT].
1458 */ 1838 */
1459 bool _checkForIsDoubleHints(IsExpression node) { 1839 bool _checkForIsDoubleHints(IsExpression node) {
1460 TypeName typeName = node.type; 1840 TypeName typeName = node.type;
1461 DartType type = typeName.type; 1841 DartType type = typeName.type;
1462 if (type != null && type.element != null) { 1842 Element element = type?.element;
1463 Element element = type.element; 1843 if (element != null) {
1464 String typeNameStr = element.name; 1844 String typeNameStr = element.name;
1465 LibraryElement libraryElement = element.library; 1845 LibraryElement libraryElement = element.library;
1466 // if (typeNameStr.equals(INT_TYPE_NAME) && libraryElement != null 1846 // if (typeNameStr.equals(INT_TYPE_NAME) && libraryElement != null
1467 // && libraryElement.isDartCore()) { 1847 // && libraryElement.isDartCore()) {
1468 // if (node.getNotOperator() == null) { 1848 // if (node.getNotOperator() == null) {
1469 // errorReporter.reportError(HintCode.IS_INT, node); 1849 // errorReporter.reportError(HintCode.IS_INT, node);
1470 // } else { 1850 // } else {
1471 // errorReporter.reportError(HintCode.IS_NOT_INT, node); 1851 // errorReporter.reportError(HintCode.IS_NOT_INT, node);
1472 // } 1852 // }
1473 // return true; 1853 // return true;
(...skipping 27 matching lines...) Expand all
1501 * The type system for this visitor 1881 * The type system for this visitor
1502 */ 1882 */
1503 final TypeSystem _typeSystem; 1883 final TypeSystem _typeSystem;
1504 1884
1505 /** 1885 /**
1506 * Create a new instance of the [DeadCodeVerifier]. 1886 * Create a new instance of the [DeadCodeVerifier].
1507 * 1887 *
1508 * @param errorReporter the error reporter 1888 * @param errorReporter the error reporter
1509 */ 1889 */
1510 DeadCodeVerifier(this._errorReporter, {TypeSystem typeSystem}) 1890 DeadCodeVerifier(this._errorReporter, {TypeSystem typeSystem})
1511 : this._typeSystem = 1891 : this._typeSystem = typeSystem ?? new TypeSystemImpl();
1512 (typeSystem != null) ? typeSystem : new TypeSystemImpl();
1513 1892
1514 @override 1893 @override
1515 Object visitBinaryExpression(BinaryExpression node) { 1894 Object visitBinaryExpression(BinaryExpression node) {
1516 sc.Token operator = node.operator; 1895 Token operator = node.operator;
1517 bool isAmpAmp = operator.type == sc.TokenType.AMPERSAND_AMPERSAND; 1896 bool isAmpAmp = operator.type == TokenType.AMPERSAND_AMPERSAND;
1518 bool isBarBar = operator.type == sc.TokenType.BAR_BAR; 1897 bool isBarBar = operator.type == TokenType.BAR_BAR;
1519 if (isAmpAmp || isBarBar) { 1898 if (isAmpAmp || isBarBar) {
1520 Expression lhsCondition = node.leftOperand; 1899 Expression lhsCondition = node.leftOperand;
1521 if (!_isDebugConstant(lhsCondition)) { 1900 if (!_isDebugConstant(lhsCondition)) {
1522 EvaluationResultImpl lhsResult = _getConstantBooleanValue(lhsCondition); 1901 EvaluationResultImpl lhsResult = _getConstantBooleanValue(lhsCondition);
1523 if (lhsResult != null) { 1902 if (lhsResult != null) {
1524 if (lhsResult.value.toBoolValue() == true && isBarBar) { 1903 bool value = lhsResult.value.toBoolValue();
1904 if (value == true && isBarBar) {
1525 // report error on else block: true || !e! 1905 // report error on else block: true || !e!
1526 _errorReporter.reportErrorForNode( 1906 _errorReporter.reportErrorForNode(
1527 HintCode.DEAD_CODE, node.rightOperand); 1907 HintCode.DEAD_CODE, node.rightOperand);
1528 // only visit the LHS: 1908 // only visit the LHS:
1529 _safelyVisit(lhsCondition); 1909 lhsCondition?.accept(this);
1530 return null; 1910 return null;
1531 } else if (lhsResult.value.toBoolValue() == false && isAmpAmp) { 1911 } else if (value == false && isAmpAmp) {
1532 // report error on if block: false && !e! 1912 // report error on if block: false && !e!
1533 _errorReporter.reportErrorForNode( 1913 _errorReporter.reportErrorForNode(
1534 HintCode.DEAD_CODE, node.rightOperand); 1914 HintCode.DEAD_CODE, node.rightOperand);
1535 // only visit the LHS: 1915 // only visit the LHS:
1536 _safelyVisit(lhsCondition); 1916 lhsCondition?.accept(this);
1537 return null; 1917 return null;
1538 } 1918 }
1539 } 1919 }
1540 } 1920 }
1541 // How do we want to handle the RHS? It isn't dead code, but "pointless" 1921 // How do we want to handle the RHS? It isn't dead code, but "pointless"
1542 // or "obscure"... 1922 // or "obscure"...
1543 // Expression rhsCondition = node.getRightOperand(); 1923 // Expression rhsCondition = node.getRightOperand();
1544 // ValidResult rhsResult = getConstantBooleanValue(rhsCondition); 1924 // ValidResult rhsResult = getConstantBooleanValue(rhsCondition);
1545 // if (rhsResult != null) { 1925 // if (rhsResult != null) {
1546 // if (rhsResult == ValidResult.RESULT_TRUE && isBarBar) { 1926 // if (rhsResult == ValidResult.RESULT_TRUE && isBarBar) {
1547 // // report error on else block: !e! || true 1927 // // report error on else block: !e! || true
1548 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand()); 1928 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand());
1549 // // only visit the RHS: 1929 // // only visit the RHS:
1550 // safelyVisit(rhsCondition); 1930 // rhsCondition?.accept(this);
1551 // return null; 1931 // return null;
1552 // } else if (rhsResult == ValidResult.RESULT_FALSE && isAmpAmp) { 1932 // } else if (rhsResult == ValidResult.RESULT_FALSE && isAmpAmp) {
1553 // // report error on if block: !e! && false 1933 // // report error on if block: !e! && false
1554 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand()); 1934 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe rand());
1555 // // only visit the RHS: 1935 // // only visit the RHS:
1556 // safelyVisit(rhsCondition); 1936 // rhsCondition?.accept(this);
1557 // return null; 1937 // return null;
1558 // } 1938 // }
1559 // } 1939 // }
1560 } 1940 }
1561 return super.visitBinaryExpression(node); 1941 return super.visitBinaryExpression(node);
1562 } 1942 }
1563 1943
1564 /** 1944 /**
1565 * For each [Block], this method reports and error on all statements between t he end of the 1945 * For each [Block], this method reports and error on all statements between t he end of the
1566 * block and the first return statement (assuming there it is not at the end o f the block.) 1946 * block and the first return statement (assuming there it is not at the end o f the block.)
1567 * 1947 *
1568 * @param node the block to evaluate 1948 * @param node the block to evaluate
1569 */ 1949 */
1570 @override 1950 @override
1571 Object visitBlock(Block node) { 1951 Object visitBlock(Block node) {
1572 NodeList<Statement> statements = node.statements; 1952 NodeList<Statement> statements = node.statements;
1573 _checkForDeadStatementsInNodeList(statements); 1953 _checkForDeadStatementsInNodeList(statements);
1574 return null; 1954 return null;
1575 } 1955 }
1576 1956
1577 @override 1957 @override
1578 Object visitConditionalExpression(ConditionalExpression node) { 1958 Object visitConditionalExpression(ConditionalExpression node) {
1579 Expression conditionExpression = node.condition; 1959 Expression conditionExpression = node.condition;
1580 _safelyVisit(conditionExpression); 1960 conditionExpression?.accept(this);
1581 if (!_isDebugConstant(conditionExpression)) { 1961 if (!_isDebugConstant(conditionExpression)) {
1582 EvaluationResultImpl result = 1962 EvaluationResultImpl result =
1583 _getConstantBooleanValue(conditionExpression); 1963 _getConstantBooleanValue(conditionExpression);
1584 if (result != null) { 1964 if (result != null) {
1585 if (result.value.toBoolValue() == true) { 1965 if (result.value.toBoolValue() == true) {
1586 // report error on else block: true ? 1 : !2! 1966 // report error on else block: true ? 1 : !2!
1587 _errorReporter.reportErrorForNode( 1967 _errorReporter.reportErrorForNode(
1588 HintCode.DEAD_CODE, node.elseExpression); 1968 HintCode.DEAD_CODE, node.elseExpression);
1589 _safelyVisit(node.thenExpression); 1969 node.thenExpression?.accept(this);
1590 return null; 1970 return null;
1591 } else { 1971 } else {
1592 // report error on if block: false ? !1! : 2 1972 // report error on if block: false ? !1! : 2
1593 _errorReporter.reportErrorForNode( 1973 _errorReporter.reportErrorForNode(
1594 HintCode.DEAD_CODE, node.thenExpression); 1974 HintCode.DEAD_CODE, node.thenExpression);
1595 _safelyVisit(node.elseExpression); 1975 node.elseExpression?.accept(this);
1596 return null; 1976 return null;
1597 } 1977 }
1598 } 1978 }
1599 } 1979 }
1600 return super.visitConditionalExpression(node); 1980 return super.visitConditionalExpression(node);
1601 } 1981 }
1602 1982
1603 @override 1983 @override
1984 Object visitExportDirective(ExportDirective node) {
1985 ExportElement exportElement = node.element;
1986 if (exportElement != null) {
1987 // The element is null when the URI is invalid
1988 LibraryElement library = exportElement.exportedLibrary;
1989 if (library != null && !library.isSynthetic) {
1990 for (Combinator combinator in node.combinators) {
1991 _checkCombinator(exportElement.exportedLibrary, combinator);
1992 }
1993 }
1994 }
1995 return super.visitExportDirective(node);
1996 }
1997
1998 @override
1604 Object visitIfStatement(IfStatement node) { 1999 Object visitIfStatement(IfStatement node) {
1605 Expression conditionExpression = node.condition; 2000 Expression conditionExpression = node.condition;
1606 _safelyVisit(conditionExpression); 2001 conditionExpression?.accept(this);
1607 if (!_isDebugConstant(conditionExpression)) { 2002 if (!_isDebugConstant(conditionExpression)) {
1608 EvaluationResultImpl result = 2003 EvaluationResultImpl result =
1609 _getConstantBooleanValue(conditionExpression); 2004 _getConstantBooleanValue(conditionExpression);
1610 if (result != null) { 2005 if (result != null) {
1611 if (result.value.toBoolValue() == true) { 2006 if (result.value.toBoolValue() == true) {
1612 // report error on else block: if(true) {} else {!} 2007 // report error on else block: if(true) {} else {!}
1613 Statement elseStatement = node.elseStatement; 2008 Statement elseStatement = node.elseStatement;
1614 if (elseStatement != null) { 2009 if (elseStatement != null) {
1615 _errorReporter.reportErrorForNode( 2010 _errorReporter.reportErrorForNode(
1616 HintCode.DEAD_CODE, elseStatement); 2011 HintCode.DEAD_CODE, elseStatement);
1617 _safelyVisit(node.thenStatement); 2012 node.thenStatement?.accept(this);
1618 return null; 2013 return null;
1619 } 2014 }
1620 } else { 2015 } else {
1621 // report error on if block: if (false) {!} else {} 2016 // report error on if block: if (false) {!} else {}
1622 _errorReporter.reportErrorForNode( 2017 _errorReporter.reportErrorForNode(
1623 HintCode.DEAD_CODE, node.thenStatement); 2018 HintCode.DEAD_CODE, node.thenStatement);
1624 _safelyVisit(node.elseStatement); 2019 node.elseStatement?.accept(this);
1625 return null; 2020 return null;
1626 } 2021 }
1627 } 2022 }
1628 } 2023 }
1629 return super.visitIfStatement(node); 2024 return super.visitIfStatement(node);
1630 } 2025 }
1631 2026
1632 @override 2027 @override
2028 Object visitImportDirective(ImportDirective node) {
2029 ImportElement importElement = node.element;
2030 if (importElement != null) {
2031 // The element is null when the URI is invalid, but not when the URI is
2032 // valid but refers to a non-existent file.
2033 LibraryElement library = importElement.importedLibrary;
2034 if (library != null && !library.isSynthetic) {
2035 for (Combinator combinator in node.combinators) {
2036 _checkCombinator(library, combinator);
2037 }
2038 }
2039 }
2040 return super.visitImportDirective(node);
2041 }
2042
2043 @override
1633 Object visitSwitchCase(SwitchCase node) { 2044 Object visitSwitchCase(SwitchCase node) {
1634 _checkForDeadStatementsInNodeList(node.statements); 2045 _checkForDeadStatementsInNodeList(node.statements, allowMandated: true);
1635 return super.visitSwitchCase(node); 2046 return super.visitSwitchCase(node);
1636 } 2047 }
1637 2048
1638 @override 2049 @override
1639 Object visitSwitchDefault(SwitchDefault node) { 2050 Object visitSwitchDefault(SwitchDefault node) {
1640 _checkForDeadStatementsInNodeList(node.statements); 2051 _checkForDeadStatementsInNodeList(node.statements, allowMandated: true);
1641 return super.visitSwitchDefault(node); 2052 return super.visitSwitchDefault(node);
1642 } 2053 }
1643 2054
1644 @override 2055 @override
1645 Object visitTryStatement(TryStatement node) { 2056 Object visitTryStatement(TryStatement node) {
1646 _safelyVisit(node.body); 2057 node.body?.accept(this);
1647 _safelyVisit(node.finallyBlock); 2058 node.finallyBlock?.accept(this);
1648 NodeList<CatchClause> catchClauses = node.catchClauses; 2059 NodeList<CatchClause> catchClauses = node.catchClauses;
1649 int numOfCatchClauses = catchClauses.length; 2060 int numOfCatchClauses = catchClauses.length;
1650 List<DartType> visitedTypes = new List<DartType>(); 2061 List<DartType> visitedTypes = new List<DartType>();
1651 for (int i = 0; i < numOfCatchClauses; i++) { 2062 for (int i = 0; i < numOfCatchClauses; i++) {
1652 CatchClause catchClause = catchClauses[i]; 2063 CatchClause catchClause = catchClauses[i];
1653 if (catchClause.onKeyword != null) { 2064 if (catchClause.onKeyword != null) {
1654 // on-catch clause found, verify that the exception type is not a 2065 // on-catch clause found, verify that the exception type is not a
1655 // subtype of a previous on-catch exception type 2066 // subtype of a previous on-catch exception type
1656 TypeName typeName = catchClause.exceptionType; 2067 DartType currentType = catchClause.exceptionType?.type;
1657 if (typeName != null && typeName.type != null) { 2068 if (currentType != null) {
1658 DartType currentType = typeName.type;
1659 if (currentType.isObject) { 2069 if (currentType.isObject) {
1660 // Found catch clause clause that has Object as an exception type, 2070 // Found catch clause clause that has Object as an exception type,
1661 // this is equivalent to having a catch clause that doesn't have an 2071 // this is equivalent to having a catch clause that doesn't have an
1662 // exception type, visit the block, but generate an error on any 2072 // exception type, visit the block, but generate an error on any
1663 // following catch clauses (and don't visit them). 2073 // following catch clauses (and don't visit them).
1664 _safelyVisit(catchClause); 2074 catchClause?.accept(this);
1665 if (i + 1 != numOfCatchClauses) { 2075 if (i + 1 != numOfCatchClauses) {
1666 // this catch clause is not the last in the try statement 2076 // this catch clause is not the last in the try statement
1667 CatchClause nextCatchClause = catchClauses[i + 1]; 2077 CatchClause nextCatchClause = catchClauses[i + 1];
1668 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; 2078 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1669 int offset = nextCatchClause.offset; 2079 int offset = nextCatchClause.offset;
1670 int length = lastCatchClause.end - offset; 2080 int length = lastCatchClause.end - offset;
1671 _errorReporter.reportErrorForOffset( 2081 _errorReporter.reportErrorForOffset(
1672 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length); 2082 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length);
1673 return null; 2083 return null;
1674 } 2084 }
1675 } 2085 }
1676 for (DartType type in visitedTypes) { 2086 int length = visitedTypes.length;
2087 for (int j = 0; j < length; j++) {
2088 DartType type = visitedTypes[j];
1677 if (_typeSystem.isSubtypeOf(currentType, type)) { 2089 if (_typeSystem.isSubtypeOf(currentType, type)) {
1678 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; 2090 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1679 int offset = catchClause.offset; 2091 int offset = catchClause.offset;
1680 int length = lastCatchClause.end - offset; 2092 int length = lastCatchClause.end - offset;
1681 _errorReporter.reportErrorForOffset( 2093 _errorReporter.reportErrorForOffset(
1682 HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, 2094 HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
1683 offset, 2095 offset,
1684 length, 2096 length,
1685 [currentType.displayName, type.displayName]); 2097 [currentType.displayName, type.displayName]);
1686 return null; 2098 return null;
1687 } 2099 }
1688 } 2100 }
1689 visitedTypes.add(currentType); 2101 visitedTypes.add(currentType);
1690 } 2102 }
1691 _safelyVisit(catchClause); 2103 catchClause?.accept(this);
1692 } else { 2104 } else {
1693 // Found catch clause clause that doesn't have an exception type, 2105 // Found catch clause clause that doesn't have an exception type,
1694 // visit the block, but generate an error on any following catch clauses 2106 // visit the block, but generate an error on any following catch clauses
1695 // (and don't visit them). 2107 // (and don't visit them).
1696 _safelyVisit(catchClause); 2108 catchClause?.accept(this);
1697 if (i + 1 != numOfCatchClauses) { 2109 if (i + 1 != numOfCatchClauses) {
1698 // this catch clause is not the last in the try statement 2110 // this catch clause is not the last in the try statement
1699 CatchClause nextCatchClause = catchClauses[i + 1]; 2111 CatchClause nextCatchClause = catchClauses[i + 1];
1700 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; 2112 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1];
1701 int offset = nextCatchClause.offset; 2113 int offset = nextCatchClause.offset;
1702 int length = lastCatchClause.end - offset; 2114 int length = lastCatchClause.end - offset;
1703 _errorReporter.reportErrorForOffset( 2115 _errorReporter.reportErrorForOffset(
1704 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length); 2116 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length);
1705 return null; 2117 return null;
1706 } 2118 }
1707 } 2119 }
1708 } 2120 }
1709 return null; 2121 return null;
1710 } 2122 }
1711 2123
1712 @override 2124 @override
1713 Object visitWhileStatement(WhileStatement node) { 2125 Object visitWhileStatement(WhileStatement node) {
1714 Expression conditionExpression = node.condition; 2126 Expression conditionExpression = node.condition;
1715 _safelyVisit(conditionExpression); 2127 conditionExpression?.accept(this);
1716 if (!_isDebugConstant(conditionExpression)) { 2128 if (!_isDebugConstant(conditionExpression)) {
1717 EvaluationResultImpl result = 2129 EvaluationResultImpl result =
1718 _getConstantBooleanValue(conditionExpression); 2130 _getConstantBooleanValue(conditionExpression);
1719 if (result != null) { 2131 if (result != null) {
1720 if (result.value.toBoolValue() == false) { 2132 if (result.value.toBoolValue() == false) {
1721 // report error on if block: while (false) {!} 2133 // report error on if block: while (false) {!}
1722 _errorReporter.reportErrorForNode(HintCode.DEAD_CODE, node.body); 2134 _errorReporter.reportErrorForNode(HintCode.DEAD_CODE, node.body);
1723 return null; 2135 return null;
1724 } 2136 }
1725 } 2137 }
1726 } 2138 }
1727 _safelyVisit(node.body); 2139 node.body?.accept(this);
1728 return null; 2140 return null;
1729 } 2141 }
1730 2142
1731 /** 2143 /**
2144 * Resolve the names in the given [combinator] in the scope of the given
2145 * [library].
2146 */
2147 void _checkCombinator(LibraryElement library, Combinator combinator) {
2148 Namespace namespace =
2149 new NamespaceBuilder().createExportNamespaceForLibrary(library);
2150 NodeList<SimpleIdentifier> names;
2151 ErrorCode hintCode;
2152 if (combinator is HideCombinator) {
2153 names = combinator.hiddenNames;
2154 hintCode = HintCode.UNDEFINED_HIDDEN_NAME;
2155 } else {
2156 names = (combinator as ShowCombinator).shownNames;
2157 hintCode = HintCode.UNDEFINED_SHOWN_NAME;
2158 }
2159 for (SimpleIdentifier name in names) {
2160 String nameStr = name.name;
2161 Element element = namespace.get(nameStr);
2162 if (element == null) {
2163 element = namespace.get("$nameStr=");
2164 }
2165 if (element == null) {
2166 _errorReporter
2167 .reportErrorForNode(hintCode, name, [library.identifier, nameStr]);
2168 }
2169 }
2170 }
2171
2172 /**
1732 * Given some [NodeList] of [Statement]s, from either a [Block] or 2173 * Given some [NodeList] of [Statement]s, from either a [Block] or
1733 * [SwitchMember], this loops through the list in reverse order searching for statements 2174 * [SwitchMember], this loops through the list searching for dead statements.
1734 * after a return, unlabeled break or unlabeled continue statement to mark the m as dead code.
1735 * 2175 *
1736 * @param statements some ordered list of statements in a [Block] or [SwitchMe mber] 2176 * @param statements some ordered list of statements in a [Block] or [SwitchMe mber]
2177 * @param allowMandated allow dead statements mandated by the language spec.
2178 * This allows for a final break, continue, return, or throw statem ent
2179 * at the end of a switch case, that are mandated by the language s pec.
1737 */ 2180 */
1738 void _checkForDeadStatementsInNodeList(NodeList<Statement> statements) { 2181 void _checkForDeadStatementsInNodeList(NodeList<Statement> statements,
2182 {bool allowMandated: false}) {
2183 bool statementExits(Statement statement) {
2184 if (statement is BreakStatement) {
2185 return statement.label == null;
2186 } else if (statement is ContinueStatement) {
2187 return statement.label == null;
2188 }
2189 return ExitDetector.exits(statement);
2190 }
2191
1739 int size = statements.length; 2192 int size = statements.length;
1740 for (int i = 0; i < size; i++) { 2193 for (int i = 0; i < size; i++) {
1741 Statement currentStatement = statements[i]; 2194 Statement currentStatement = statements[i];
1742 _safelyVisit(currentStatement); 2195 currentStatement?.accept(this);
1743 bool returnOrBreakingStatement = currentStatement is ReturnStatement || 2196 if (statementExits(currentStatement) && i != size - 1) {
1744 (currentStatement is BreakStatement &&
1745 currentStatement.label == null) ||
1746 (currentStatement is ContinueStatement &&
1747 currentStatement.label == null);
1748 if (returnOrBreakingStatement && i != size - 1) {
1749 Statement nextStatement = statements[i + 1]; 2197 Statement nextStatement = statements[i + 1];
1750 Statement lastStatement = statements[size - 1]; 2198 Statement lastStatement = statements[size - 1];
2199 // If mandated statements are allowed, and only the last statement is
2200 // dead, and it's a BreakStatement, then assume it is a statement
2201 // mandated by the language spec, there to avoid a
2202 // CASE_BLOCK_NOT_TERMINATED error.
2203 if (allowMandated && i == size - 2 && nextStatement is BreakStatement) {
2204 return;
2205 }
1751 int offset = nextStatement.offset; 2206 int offset = nextStatement.offset;
1752 int length = lastStatement.end - offset; 2207 int length = lastStatement.end - offset;
1753 _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length); 2208 _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length);
1754 return; 2209 return;
1755 } 2210 }
1756 } 2211 }
1757 } 2212 }
1758 2213
1759 /** 2214 /**
1760 * Given some [Expression], this method returns [ValidResult.RESULT_TRUE] if i t is 2215 * Given some [Expression], this method returns [ValidResult.RESULT_TRUE] if i t is
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1792 2247
1793 /** 2248 /**
1794 * Return `true` if and only if the passed expression is resolved to a constan t variable. 2249 * Return `true` if and only if the passed expression is resolved to a constan t variable.
1795 * 2250 *
1796 * @param expression some conditional expression 2251 * @param expression some conditional expression
1797 * @return `true` if and only if the passed expression is resolved to a consta nt variable 2252 * @return `true` if and only if the passed expression is resolved to a consta nt variable
1798 */ 2253 */
1799 bool _isDebugConstant(Expression expression) { 2254 bool _isDebugConstant(Expression expression) {
1800 Element element = null; 2255 Element element = null;
1801 if (expression is Identifier) { 2256 if (expression is Identifier) {
1802 Identifier identifier = expression; 2257 element = expression.staticElement;
1803 element = identifier.staticElement;
1804 } else if (expression is PropertyAccess) { 2258 } else if (expression is PropertyAccess) {
1805 PropertyAccess propertyAccess = expression; 2259 element = expression.propertyName.staticElement;
1806 element = propertyAccess.propertyName.staticElement;
1807 } 2260 }
1808 if (element is PropertyAccessorElement) { 2261 if (element is PropertyAccessorElement) {
1809 PropertyInducingElement variable = element.variable; 2262 PropertyInducingElement variable = element.variable;
1810 return variable != null && variable.isConst; 2263 return variable != null && variable.isConst;
1811 } 2264 }
1812 return false; 2265 return false;
1813 } 2266 }
1814
1815 /**
1816 * If the given node is not `null`, visit this instance of the dead code verif ier.
1817 *
1818 * @param node the node to be visited
1819 */
1820 void _safelyVisit(AstNode node) {
1821 if (node != null) {
1822 node.accept(this);
1823 }
1824 }
1825 } 2267 }
1826 2268
1827 /** 2269 /**
1828 * Instances of the class `DeclarationResolver` are used to resolve declarations in an AST 2270 * A visitor that resolves declarations in an AST structure to already built
1829 * structure to already built elements. 2271 * elements.
2272 *
2273 * The resulting AST must have everything resolved that would have been resolved
2274 * by a [CompilationUnitBuilder] (that is, must be a valid [RESOLVED_UNIT1]).
2275 * This class must not assume that the [CompilationUnitElement] passed to it is
2276 * any more complete than a [COMPILATION_UNIT_ELEMENT].
1830 */ 2277 */
1831 class DeclarationResolver extends RecursiveAstVisitor<Object> { 2278 class DeclarationResolver extends RecursiveAstVisitor<Object>
2279 with ExistingElementResolver {
1832 /** 2280 /**
1833 * The compilation unit containing the AST nodes being visited. 2281 * The analysis context containing the sources to be analyzed.
1834 */ 2282 */
1835 CompilationUnitElement _enclosingUnit; 2283 AnalysisContext _context;
1836 2284
1837 /** 2285 /**
1838 * The function type alias containing the AST nodes being visited, or `null` i f we are not 2286 * The elements that are reachable from the compilation unit element. When a
1839 * in the scope of a function type alias. 2287 * compilation unit has been resolved, this set should be empty.
2288 */
2289 Set<Element> _expectedElements;
2290
2291 /**
2292 * The function type alias containing the AST nodes being visited, or `null`
2293 * if we are not in the scope of a function type alias.
1840 */ 2294 */
1841 FunctionTypeAliasElement _enclosingAlias; 2295 FunctionTypeAliasElement _enclosingAlias;
1842 2296
1843 /** 2297 /**
1844 * The class containing the AST nodes being visited, or `null` if we are not i n the scope of 2298 * The class containing the AST nodes being visited, or `null` if we are not
1845 * a class. 2299 * in the scope of a class.
1846 */ 2300 */
1847 ClassElement _enclosingClass; 2301 ClassElement _enclosingClass;
1848 2302
1849 /** 2303 /**
1850 * The method or function containing the AST nodes being visited, or `null` if we are not in 2304 * The method or function containing the AST nodes being visited, or `null` if
1851 * the scope of a method or function. 2305 * we are not in the scope of a method or function.
1852 */ 2306 */
1853 ExecutableElement _enclosingExecutable; 2307 ExecutableElement _enclosingExecutable;
1854 2308
1855 /** 2309 /**
1856 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the 2310 * The parameter containing the AST nodes being visited, or `null` if we are
1857 * scope of a parameter. 2311 * not in the scope of a parameter.
1858 */ 2312 */
1859 ParameterElement _enclosingParameter; 2313 ParameterElement _enclosingParameter;
1860 2314
1861 /** 2315 /**
1862 * Resolve the declarations within the given compilation unit to the elements rooted at the given 2316 * Resolve the declarations within the given compilation [unit] to the
1863 * element. 2317 * elements rooted at the given [element]. Throw an [ElementMismatchException]
1864 * 2318 * if the element model and compilation unit do not match each other.
1865 * @param unit the compilation unit to be resolved
1866 * @param element the root of the element model used to resolve the AST nodes
1867 */ 2319 */
1868 void resolve(CompilationUnit unit, CompilationUnitElement element) { 2320 void resolve(CompilationUnit unit, CompilationUnitElement element) {
2321 _context = element.context;
2322 ElementGatherer gatherer = new ElementGatherer();
2323 element.accept(gatherer);
2324 _expectedElements = gatherer.elements;
1869 _enclosingUnit = element; 2325 _enclosingUnit = element;
2326 _expectedElements.remove(element);
1870 unit.element = element; 2327 unit.element = element;
1871 unit.accept(this); 2328 unit.accept(this);
2329 _validateResolution();
1872 } 2330 }
1873 2331
1874 @override 2332 @override
1875 Object visitCatchClause(CatchClause node) { 2333 Object visitCatchClause(CatchClause node) {
1876 SimpleIdentifier exceptionParameter = node.exceptionParameter; 2334 SimpleIdentifier exceptionParameter = node.exceptionParameter;
1877 if (exceptionParameter != null) { 2335 if (exceptionParameter != null) {
1878 List<LocalVariableElement> localVariables = 2336 List<LocalVariableElement> localVariables =
1879 _enclosingExecutable.localVariables; 2337 _enclosingExecutable.localVariables;
1880 _findIdentifier(localVariables, exceptionParameter); 2338 _findIdentifier(localVariables, exceptionParameter);
1881 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; 2339 SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
1882 if (stackTraceParameter != null) { 2340 if (stackTraceParameter != null) {
1883 _findIdentifier(localVariables, stackTraceParameter); 2341 _findIdentifier(localVariables, stackTraceParameter);
1884 } 2342 }
1885 } 2343 }
1886 return super.visitCatchClause(node); 2344 return super.visitCatchClause(node);
1887 } 2345 }
1888 2346
1889 @override 2347 @override
1890 Object visitClassDeclaration(ClassDeclaration node) { 2348 Object visitClassDeclaration(ClassDeclaration node) {
1891 ClassElement outerClass = _enclosingClass; 2349 ClassElement outerClass = _enclosingClass;
1892 try { 2350 try {
1893 SimpleIdentifier className = node.name; 2351 SimpleIdentifier className = node.name;
1894 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); 2352 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
1895 return super.visitClassDeclaration(node); 2353 super.visitClassDeclaration(node);
2354 _resolveMetadata(node, node.metadata, _enclosingClass);
2355 return null;
1896 } finally { 2356 } finally {
1897 _enclosingClass = outerClass; 2357 _enclosingClass = outerClass;
1898 } 2358 }
1899 } 2359 }
1900 2360
1901 @override 2361 @override
1902 Object visitClassTypeAlias(ClassTypeAlias node) { 2362 Object visitClassTypeAlias(ClassTypeAlias node) {
1903 ClassElement outerClass = _enclosingClass; 2363 ClassElement outerClass = _enclosingClass;
1904 try { 2364 try {
1905 SimpleIdentifier className = node.name; 2365 SimpleIdentifier className = node.name;
1906 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); 2366 _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
1907 return super.visitClassTypeAlias(node); 2367 super.visitClassTypeAlias(node);
2368 _resolveMetadata(node, node.metadata, _enclosingClass);
2369 return null;
1908 } finally { 2370 } finally {
1909 _enclosingClass = outerClass; 2371 _enclosingClass = outerClass;
1910 } 2372 }
1911 } 2373 }
1912 2374
1913 @override 2375 @override
1914 Object visitConstructorDeclaration(ConstructorDeclaration node) { 2376 Object visitConstructorDeclaration(ConstructorDeclaration node) {
1915 ExecutableElement outerExecutable = _enclosingExecutable; 2377 ExecutableElement outerExecutable = _enclosingExecutable;
1916 try { 2378 try {
1917 SimpleIdentifier constructorName = node.name; 2379 SimpleIdentifier constructorName = node.name;
1918 if (constructorName == null) { 2380 if (constructorName == null) {
1919 _enclosingExecutable = _enclosingClass.unnamedConstructor; 2381 _enclosingExecutable = _enclosingClass.unnamedConstructor;
2382 if (_enclosingExecutable == null) {
2383 _mismatch('Could not find default constructor', node);
2384 }
1920 } else { 2385 } else {
1921 _enclosingExecutable = 2386 _enclosingExecutable =
1922 _enclosingClass.getNamedConstructor(constructorName.name); 2387 _enclosingClass.getNamedConstructor(constructorName.name);
2388 if (_enclosingExecutable == null) {
2389 _mismatch(
2390 'Could not find constructor element with name "${constructorName.n ame}',
2391 node);
2392 }
1923 constructorName.staticElement = _enclosingExecutable; 2393 constructorName.staticElement = _enclosingExecutable;
1924 } 2394 }
2395 _expectedElements.remove(_enclosingExecutable);
1925 node.element = _enclosingExecutable as ConstructorElement; 2396 node.element = _enclosingExecutable as ConstructorElement;
1926 return super.visitConstructorDeclaration(node); 2397 super.visitConstructorDeclaration(node);
2398 _resolveMetadata(node, node.metadata, _enclosingExecutable);
2399 return null;
1927 } finally { 2400 } finally {
1928 _enclosingExecutable = outerExecutable; 2401 _enclosingExecutable = outerExecutable;
1929 } 2402 }
1930 } 2403 }
1931 2404
1932 @override 2405 @override
1933 Object visitDeclaredIdentifier(DeclaredIdentifier node) { 2406 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
1934 SimpleIdentifier variableName = node.identifier; 2407 SimpleIdentifier variableName = node.identifier;
1935 _findIdentifier(_enclosingExecutable.localVariables, variableName); 2408 Element element =
1936 return super.visitDeclaredIdentifier(node); 2409 _findIdentifier(_enclosingExecutable.localVariables, variableName);
2410 super.visitDeclaredIdentifier(node);
2411 _resolveMetadata(node, node.metadata, element);
2412 return null;
1937 } 2413 }
1938 2414
1939 @override 2415 @override
1940 Object visitDefaultFormalParameter(DefaultFormalParameter node) { 2416 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
1941 SimpleIdentifier parameterName = node.parameter.identifier; 2417 SimpleIdentifier parameterName = node.parameter.identifier;
1942 ParameterElement element = _getElementForParameter(node, parameterName); 2418 ParameterElement element = _getElementForParameter(node, parameterName);
1943 Expression defaultValue = node.defaultValue; 2419 Expression defaultValue = node.defaultValue;
1944 if (defaultValue != null) { 2420 if (defaultValue != null) {
1945 ExecutableElement outerExecutable = _enclosingExecutable; 2421 ExecutableElement outerExecutable = _enclosingExecutable;
1946 try { 2422 try {
1947 if (element == null) { 2423 _enclosingExecutable = element.initializer;
1948 // TODO(brianwilkerson) Report this internal error.
1949 } else {
1950 _enclosingExecutable = element.initializer;
1951 }
1952 defaultValue.accept(this); 2424 defaultValue.accept(this);
1953 } finally { 2425 } finally {
1954 _enclosingExecutable = outerExecutable; 2426 _enclosingExecutable = outerExecutable;
1955 } 2427 }
1956 } 2428 }
1957 ParameterElement outerParameter = _enclosingParameter; 2429 ParameterElement outerParameter = _enclosingParameter;
1958 try { 2430 try {
1959 _enclosingParameter = element; 2431 _enclosingParameter = element;
1960 return super.visitDefaultFormalParameter(node); 2432 super.visitDefaultFormalParameter(node);
2433 _resolveMetadata(node, node.metadata, element);
2434 return null;
1961 } finally { 2435 } finally {
1962 _enclosingParameter = outerParameter; 2436 _enclosingParameter = outerParameter;
1963 } 2437 }
1964 } 2438 }
1965 2439
1966 @override 2440 @override
1967 Object visitEnumDeclaration(EnumDeclaration node) { 2441 Object visitEnumDeclaration(EnumDeclaration node) {
1968 ClassElement enclosingEnum = 2442 ClassElement enclosingEnum =
1969 _findIdentifier(_enclosingUnit.enums, node.name); 2443 _findIdentifier(_enclosingUnit.enums, node.name);
1970 List<FieldElement> constants = enclosingEnum.fields; 2444 List<FieldElement> constants = enclosingEnum.fields;
1971 for (EnumConstantDeclaration constant in node.constants) { 2445 for (EnumConstantDeclaration constant in node.constants) {
1972 _findIdentifier(constants, constant.name); 2446 _findIdentifier(constants, constant.name);
1973 } 2447 }
1974 return super.visitEnumDeclaration(node); 2448 super.visitEnumDeclaration(node);
2449 _resolveMetadata(node, node.metadata, enclosingEnum);
2450 return null;
1975 } 2451 }
1976 2452
1977 @override 2453 @override
1978 Object visitExportDirective(ExportDirective node) { 2454 Object visitExportDirective(ExportDirective node) {
1979 String uri = _getStringValue(node.uri); 2455 super.visitExportDirective(node);
1980 if (uri != null) { 2456 _resolveAnnotations(
1981 LibraryElement library = _enclosingUnit.library; 2457 node, node.metadata, _enclosingUnit.getAnnotations(node.offset));
1982 ExportElement exportElement = _findExport( 2458 return null;
1983 library.exports,
1984 _enclosingUnit.context.sourceFactory
1985 .resolveUri(_enclosingUnit.source, uri));
1986 node.element = exportElement;
1987 }
1988 return super.visitExportDirective(node);
1989 } 2459 }
1990 2460
1991 @override 2461 @override
2462 Object visitFieldDeclaration(FieldDeclaration node) {
2463 super.visitFieldDeclaration(node);
2464 _resolveMetadata(node, node.metadata, node.fields.variables[0].element);
2465 return null;
2466 }
2467
2468 @override
1992 Object visitFieldFormalParameter(FieldFormalParameter node) { 2469 Object visitFieldFormalParameter(FieldFormalParameter node) {
1993 if (node.parent is! DefaultFormalParameter) { 2470 if (node.parent is! DefaultFormalParameter) {
1994 SimpleIdentifier parameterName = node.identifier; 2471 SimpleIdentifier parameterName = node.identifier;
1995 ParameterElement element = _getElementForParameter(node, parameterName); 2472 ParameterElement element = _getElementForParameter(node, parameterName);
1996 ParameterElement outerParameter = _enclosingParameter; 2473 ParameterElement outerParameter = _enclosingParameter;
1997 try { 2474 try {
1998 _enclosingParameter = element; 2475 _enclosingParameter = element;
1999 return super.visitFieldFormalParameter(node); 2476 super.visitFieldFormalParameter(node);
2477 _resolveMetadata(node, node.metadata, element);
2478 return null;
2000 } finally { 2479 } finally {
2001 _enclosingParameter = outerParameter; 2480 _enclosingParameter = outerParameter;
2002 } 2481 }
2003 } else { 2482 } else {
2004 return super.visitFieldFormalParameter(node); 2483 return super.visitFieldFormalParameter(node);
2005 } 2484 }
2006 } 2485 }
2007 2486
2008 @override 2487 @override
2009 Object visitFunctionDeclaration(FunctionDeclaration node) { 2488 Object visitFunctionDeclaration(FunctionDeclaration node) {
2010 ExecutableElement outerExecutable = _enclosingExecutable; 2489 ExecutableElement outerExecutable = _enclosingExecutable;
2011 try { 2490 try {
2012 SimpleIdentifier functionName = node.name; 2491 SimpleIdentifier functionName = node.name;
2013 sc.Token property = node.propertyKeyword; 2492 Token property = node.propertyKeyword;
2014 if (property == null) { 2493 if (property == null) {
2015 if (_enclosingExecutable != null) { 2494 if (_enclosingExecutable != null) {
2016 _enclosingExecutable = 2495 _enclosingExecutable =
2017 _findIdentifier(_enclosingExecutable.functions, functionName); 2496 _findIdentifier(_enclosingExecutable.functions, functionName);
2018 } else { 2497 } else {
2019 _enclosingExecutable = 2498 _enclosingExecutable =
2020 _findIdentifier(_enclosingUnit.functions, functionName); 2499 _findIdentifier(_enclosingUnit.functions, functionName);
2021 } 2500 }
2022 } else { 2501 } else {
2023 PropertyAccessorElement accessor = 2502 if (_enclosingExecutable != null) {
2024 _findIdentifier(_enclosingUnit.accessors, functionName); 2503 _enclosingExecutable =
2025 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) { 2504 _findIdentifier(_enclosingExecutable.functions, functionName);
2026 accessor = accessor.variable.setter; 2505 } else {
2027 functionName.staticElement = accessor; 2506 List<PropertyAccessorElement> accessors;
2507 if (_enclosingClass != null) {
2508 accessors = _enclosingClass.accessors;
2509 } else {
2510 accessors = _enclosingUnit.accessors;
2511 }
2512 PropertyAccessorElement accessor;
2513 if (property.keyword == Keyword.GET) {
2514 accessor = _findIdentifier(accessors, functionName);
2515 } else if (property.keyword == Keyword.SET) {
2516 accessor = _findWithNameAndOffset(accessors, functionName,
2517 functionName.name + '=', functionName.offset);
2518 _expectedElements.remove(accessor);
2519 functionName.staticElement = accessor;
2520 }
2521 _enclosingExecutable = accessor;
2028 } 2522 }
2029 _enclosingExecutable = accessor;
2030 } 2523 }
2031 node.functionExpression.element = _enclosingExecutable; 2524 node.functionExpression.element = _enclosingExecutable;
2032 return super.visitFunctionDeclaration(node); 2525 super.visitFunctionDeclaration(node);
2526 _resolveMetadata(node, node.metadata, _enclosingExecutable);
2527 return null;
2033 } finally { 2528 } finally {
2034 _enclosingExecutable = outerExecutable; 2529 _enclosingExecutable = outerExecutable;
2035 } 2530 }
2036 } 2531 }
2037 2532
2038 @override 2533 @override
2039 Object visitFunctionExpression(FunctionExpression node) { 2534 Object visitFunctionExpression(FunctionExpression node) {
2040 if (node.parent is! FunctionDeclaration) { 2535 if (node.parent is! FunctionDeclaration) {
2041 FunctionElement element = 2536 FunctionElement element = _findAtOffset(
2042 _findAtOffset(_enclosingExecutable.functions, node.beginToken.offset); 2537 _enclosingExecutable.functions, node, node.beginToken.offset);
2538 _expectedElements.remove(element);
2043 node.element = element; 2539 node.element = element;
2044 } 2540 }
2045 ExecutableElement outerExecutable = _enclosingExecutable; 2541 ExecutableElement outerExecutable = _enclosingExecutable;
2046 try { 2542 try {
2047 _enclosingExecutable = node.element; 2543 _enclosingExecutable = node.element;
2048 return super.visitFunctionExpression(node); 2544 return super.visitFunctionExpression(node);
2049 } finally { 2545 } finally {
2050 _enclosingExecutable = outerExecutable; 2546 _enclosingExecutable = outerExecutable;
2051 } 2547 }
2052 } 2548 }
2053 2549
2054 @override 2550 @override
2055 Object visitFunctionTypeAlias(FunctionTypeAlias node) { 2551 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
2056 FunctionTypeAliasElement outerAlias = _enclosingAlias; 2552 FunctionTypeAliasElement outerAlias = _enclosingAlias;
2057 try { 2553 try {
2058 SimpleIdentifier aliasName = node.name; 2554 SimpleIdentifier aliasName = node.name;
2059 _enclosingAlias = 2555 _enclosingAlias =
2060 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName); 2556 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName);
2061 return super.visitFunctionTypeAlias(node); 2557 super.visitFunctionTypeAlias(node);
2558 _resolveMetadata(node, node.metadata, _enclosingAlias);
2559 return null;
2062 } finally { 2560 } finally {
2063 _enclosingAlias = outerAlias; 2561 _enclosingAlias = outerAlias;
2064 } 2562 }
2065 } 2563 }
2066 2564
2067 @override 2565 @override
2068 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { 2566 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
2069 if (node.parent is! DefaultFormalParameter) { 2567 if (node.parent is! DefaultFormalParameter) {
2070 SimpleIdentifier parameterName = node.identifier; 2568 SimpleIdentifier parameterName = node.identifier;
2071 ParameterElement element = _getElementForParameter(node, parameterName); 2569 ParameterElement element = _getElementForParameter(node, parameterName);
2072 ParameterElement outerParameter = _enclosingParameter; 2570 ParameterElement outerParameter = _enclosingParameter;
2073 try { 2571 try {
2074 _enclosingParameter = element; 2572 _enclosingParameter = element;
2075 return super.visitFunctionTypedFormalParameter(node); 2573 super.visitFunctionTypedFormalParameter(node);
2574 _resolveMetadata(node, node.metadata, _enclosingParameter);
2575 return null;
2076 } finally { 2576 } finally {
2077 _enclosingParameter = outerParameter; 2577 _enclosingParameter = outerParameter;
2078 } 2578 }
2079 } else { 2579 } else {
2080 return super.visitFunctionTypedFormalParameter(node); 2580 return super.visitFunctionTypedFormalParameter(node);
2081 } 2581 }
2082 } 2582 }
2083 2583
2084 @override 2584 @override
2085 Object visitImportDirective(ImportDirective node) { 2585 Object visitImportDirective(ImportDirective node) {
2086 String uri = _getStringValue(node.uri); 2586 super.visitImportDirective(node);
2087 if (uri != null) { 2587 _resolveAnnotations(
2088 LibraryElement library = _enclosingUnit.library; 2588 node, node.metadata, _enclosingUnit.getAnnotations(node.offset));
2089 ImportElement importElement = _findImport( 2589 return null;
2090 library.imports,
2091 _enclosingUnit.context.sourceFactory
2092 .resolveUri(_enclosingUnit.source, uri),
2093 node.prefix);
2094 node.element = importElement;
2095 }
2096 return super.visitImportDirective(node);
2097 } 2590 }
2098 2591
2099 @override 2592 @override
2100 Object visitLabeledStatement(LabeledStatement node) { 2593 Object visitLabeledStatement(LabeledStatement node) {
2101 for (Label label in node.labels) { 2594 for (Label label in node.labels) {
2102 SimpleIdentifier labelName = label.label; 2595 SimpleIdentifier labelName = label.label;
2103 _findIdentifier(_enclosingExecutable.labels, labelName); 2596 _findIdentifier(_enclosingExecutable.labels, labelName);
2104 } 2597 }
2105 return super.visitLabeledStatement(node); 2598 return super.visitLabeledStatement(node);
2106 } 2599 }
2107 2600
2108 @override 2601 @override
2109 Object visitLibraryDirective(LibraryDirective node) { 2602 Object visitLibraryDirective(LibraryDirective node) {
2110 node.element = _enclosingUnit.library; 2603 super.visitLibraryDirective(node);
2111 return super.visitLibraryDirective(node); 2604 _resolveAnnotations(
2605 node, node.metadata, _enclosingUnit.getAnnotations(node.offset));
2606 return null;
2112 } 2607 }
2113 2608
2114 @override 2609 @override
2115 Object visitMethodDeclaration(MethodDeclaration node) { 2610 Object visitMethodDeclaration(MethodDeclaration node) {
2116 ExecutableElement outerExecutable = _enclosingExecutable; 2611 ExecutableElement outerExecutable = _enclosingExecutable;
2117 try { 2612 try {
2118 sc.Token property = node.propertyKeyword; 2613 Token property = node.propertyKeyword;
2119 SimpleIdentifier methodName = node.name; 2614 SimpleIdentifier methodName = node.name;
2120 String nameOfMethod = methodName.name; 2615 String nameOfMethod = methodName.name;
2121 if (property == null) { 2616 if (property == null) {
2122 _enclosingExecutable = _findWithNameAndOffset( 2617 String elementName = nameOfMethod == '-' &&
2123 _enclosingClass.methods, nameOfMethod, methodName.offset); 2618 node.parameters != null &&
2619 node.parameters.parameters.isEmpty
2620 ? 'unary-'
2621 : nameOfMethod;
2622 _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods,
2623 methodName, elementName, methodName.offset);
2624 _expectedElements.remove(_enclosingExecutable);
2124 methodName.staticElement = _enclosingExecutable; 2625 methodName.staticElement = _enclosingExecutable;
2125 } else { 2626 } else {
2126 PropertyAccessorElement accessor = 2627 PropertyAccessorElement accessor;
2127 _findIdentifier(_enclosingClass.accessors, methodName); 2628 if (property.keyword == Keyword.GET) {
2128 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) { 2629 accessor = _findIdentifier(_enclosingClass.accessors, methodName);
2129 accessor = accessor.variable.setter; 2630 } else if (property.keyword == Keyword.SET) {
2631 accessor = _findWithNameAndOffset(_enclosingClass.accessors,
2632 methodName, nameOfMethod + '=', methodName.offset);
2633 _expectedElements.remove(accessor);
2130 methodName.staticElement = accessor; 2634 methodName.staticElement = accessor;
2131 } 2635 }
2132 _enclosingExecutable = accessor; 2636 _enclosingExecutable = accessor;
2133 } 2637 }
2134 return super.visitMethodDeclaration(node); 2638 super.visitMethodDeclaration(node);
2639 _resolveMetadata(node, node.metadata, _enclosingExecutable);
2640 return null;
2135 } finally { 2641 } finally {
2136 _enclosingExecutable = outerExecutable; 2642 _enclosingExecutable = outerExecutable;
2137 } 2643 }
2138 } 2644 }
2139 2645
2140 @override 2646 @override
2141 Object visitPartDirective(PartDirective node) { 2647 Object visitPartDirective(PartDirective node) {
2142 String uri = _getStringValue(node.uri); 2648 super.visitPartDirective(node);
2143 if (uri != null) { 2649 _resolveAnnotations(
2144 Source partSource = _enclosingUnit.context.sourceFactory 2650 node, node.metadata, _enclosingUnit.getAnnotations(node.offset));
2145 .resolveUri(_enclosingUnit.source, uri); 2651 return null;
2146 node.element = _findPart(_enclosingUnit.library.parts, partSource);
2147 }
2148 return super.visitPartDirective(node);
2149 } 2652 }
2150 2653
2151 @override 2654 @override
2152 Object visitPartOfDirective(PartOfDirective node) { 2655 Object visitPartOfDirective(PartOfDirective node) {
2153 node.element = _enclosingUnit.library; 2656 node.element = _enclosingUnit.library;
2154 return super.visitPartOfDirective(node); 2657 return super.visitPartOfDirective(node);
2155 } 2658 }
2156 2659
2157 @override 2660 @override
2158 Object visitSimpleFormalParameter(SimpleFormalParameter node) { 2661 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
2159 if (node.parent is! DefaultFormalParameter) { 2662 if (node.parent is! DefaultFormalParameter) {
2160 SimpleIdentifier parameterName = node.identifier; 2663 SimpleIdentifier parameterName = node.identifier;
2161 ParameterElement element = _getElementForParameter(node, parameterName); 2664 ParameterElement element = _getElementForParameter(node, parameterName);
2162 ParameterElement outerParameter = _enclosingParameter; 2665 ParameterElement outerParameter = _enclosingParameter;
2163 try { 2666 try {
2164 _enclosingParameter = element; 2667 _enclosingParameter = element;
2165 return super.visitSimpleFormalParameter(node); 2668 super.visitSimpleFormalParameter(node);
2669 _resolveMetadata(node, node.metadata, element);
2670 return null;
2166 } finally { 2671 } finally {
2167 _enclosingParameter = outerParameter; 2672 _enclosingParameter = outerParameter;
2168 } 2673 }
2169 } else {} 2674 } else {}
2170 return super.visitSimpleFormalParameter(node); 2675 return super.visitSimpleFormalParameter(node);
2171 } 2676 }
2172 2677
2173 @override 2678 @override
2174 Object visitSwitchCase(SwitchCase node) { 2679 Object visitSwitchCase(SwitchCase node) {
2175 for (Label label in node.labels) { 2680 for (Label label in node.labels) {
2176 SimpleIdentifier labelName = label.label; 2681 SimpleIdentifier labelName = label.label;
2177 _findIdentifier(_enclosingExecutable.labels, labelName); 2682 _findIdentifier(_enclosingExecutable.labels, labelName);
2178 } 2683 }
2179 return super.visitSwitchCase(node); 2684 return super.visitSwitchCase(node);
2180 } 2685 }
2181 2686
2182 @override 2687 @override
2183 Object visitSwitchDefault(SwitchDefault node) { 2688 Object visitSwitchDefault(SwitchDefault node) {
2184 for (Label label in node.labels) { 2689 for (Label label in node.labels) {
2185 SimpleIdentifier labelName = label.label; 2690 SimpleIdentifier labelName = label.label;
2186 _findIdentifier(_enclosingExecutable.labels, labelName); 2691 _findIdentifier(_enclosingExecutable.labels, labelName);
2187 } 2692 }
2188 return super.visitSwitchDefault(node); 2693 return super.visitSwitchDefault(node);
2189 } 2694 }
2190 2695
2191 @override 2696 @override
2697 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
2698 super.visitTopLevelVariableDeclaration(node);
2699 _resolveMetadata(node, node.metadata, node.variables.variables[0].element);
2700 return null;
2701 }
2702
2703 @override
2192 Object visitTypeParameter(TypeParameter node) { 2704 Object visitTypeParameter(TypeParameter node) {
2193 SimpleIdentifier parameterName = node.name; 2705 SimpleIdentifier parameterName = node.name;
2194 if (_enclosingClass != null) { 2706 Element element = null;
2195 _findIdentifier(_enclosingClass.typeParameters, parameterName); 2707 if (_enclosingExecutable != null) {
2196 } else if (_enclosingAlias != null) { 2708 element = _findIdentifier(
2197 _findIdentifier(_enclosingAlias.typeParameters, parameterName); 2709 _enclosingExecutable.typeParameters, parameterName,
2710 required: false);
2198 } 2711 }
2199 return super.visitTypeParameter(node); 2712 if (element == null) {
2713 if (_enclosingClass != null) {
2714 element =
2715 _findIdentifier(_enclosingClass.typeParameters, parameterName);
2716 } else if (_enclosingAlias != null) {
2717 element =
2718 _findIdentifier(_enclosingAlias.typeParameters, parameterName);
2719 }
2720 }
2721 if (element == null) {
2722 String name = parameterName.name;
2723 int offset = parameterName.offset;
2724 _mismatch(
2725 'Could not find type parameter with name "$name" at $offset', node);
2726 }
2727 super.visitTypeParameter(node);
2728 _resolveMetadata(node, node.metadata, element);
2729 return null;
2200 } 2730 }
2201 2731
2202 @override 2732 @override
2203 Object visitVariableDeclaration(VariableDeclaration node) { 2733 Object visitVariableDeclaration(VariableDeclaration node) {
2204 VariableElement element = null; 2734 VariableElement element = null;
2205 SimpleIdentifier variableName = node.name; 2735 SimpleIdentifier variableName = node.name;
2206 if (_enclosingExecutable != null) { 2736 if (_enclosingExecutable != null) {
2207 element = 2737 element = _findIdentifier(
2208 _findIdentifier(_enclosingExecutable.localVariables, variableName); 2738 _enclosingExecutable.localVariables, variableName,
2739 required: false);
2209 } 2740 }
2210 if (element == null && _enclosingClass != null) { 2741 if (element == null && _enclosingClass != null) {
2211 element = _findIdentifier(_enclosingClass.fields, variableName); 2742 element = _findIdentifier(_enclosingClass.fields, variableName,
2743 required: false);
2212 } 2744 }
2213 if (element == null && _enclosingUnit != null) { 2745 if (element == null && _enclosingUnit != null) {
2214 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName); 2746 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName);
2215 } 2747 }
2216 Expression initializer = node.initializer; 2748 Expression initializer = node.initializer;
2217 if (initializer != null) { 2749 if (initializer != null) {
2218 ExecutableElement outerExecutable = _enclosingExecutable; 2750 ExecutableElement outerExecutable = _enclosingExecutable;
2219 try { 2751 try {
2220 if (element == null) { 2752 _enclosingExecutable = element.initializer;
2221 // TODO(brianwilkerson) Report this internal error.
2222 } else {
2223 _enclosingExecutable = element.initializer;
2224 }
2225 return super.visitVariableDeclaration(node); 2753 return super.visitVariableDeclaration(node);
2226 } finally { 2754 } finally {
2227 _enclosingExecutable = outerExecutable; 2755 _enclosingExecutable = outerExecutable;
2228 } 2756 }
2229 } 2757 }
2230 return super.visitVariableDeclaration(node); 2758 return super.visitVariableDeclaration(node);
2231 } 2759 }
2232 2760
2233 /** 2761 @override
2234 * Return the element in the given array of elements that was created for the declaration at the 2762 Object visitVariableDeclarationList(VariableDeclarationList node) {
2235 * given offset. This method should only be used when there is no name 2763 super.visitVariableDeclarationList(node);
2236 * 2764 if (node.parent is! FieldDeclaration &&
2237 * @param elements the elements of the appropriate kind that exist in the curr ent context 2765 node.parent is! TopLevelVariableDeclaration) {
2238 * @param offset the offset of the name of the element to be returned 2766 _resolveMetadata(node, node.metadata, node.variables[0].element);
2239 * @return the element at the given offset
2240 */
2241 Element _findAtOffset(List<Element> elements, int offset) =>
2242 _findWithNameAndOffset(elements, "", offset);
2243
2244 /**
2245 * Return the export element from the given array whose library has the given source, or
2246 * `null` if there is no such export.
2247 *
2248 * @param exports the export elements being searched
2249 * @param source the source of the library associated with the export element to being searched
2250 * for
2251 * @return the export element whose library has the given source
2252 */
2253 ExportElement _findExport(List<ExportElement> exports, Source source) {
2254 for (ExportElement export in exports) {
2255 if (export.exportedLibrary.source == source) {
2256 return export;
2257 }
2258 } 2767 }
2259 return null; 2768 return null;
2260 } 2769 }
2261 2770
2262 /** 2771 /**
2263 * Return the element in the given array of elements that was created for the declaration with the 2772 * Return the element in the given list of [elements] that was created for the
2264 * given name. 2773 * declaration at the given [offset]. Throw an [ElementMismatchException] if
2774 * an element at that offset cannot be found.
2265 * 2775 *
2266 * @param elements the elements of the appropriate kind that exist in the curr ent context 2776 * This method should only be used when there is no name associated with the
2267 * @param identifier the name node in the declaration of the element to be ret urned 2777 * node.
2268 * @return the element created for the declaration with the given name
2269 */ 2778 */
2270 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier) { 2779 Element _findAtOffset(List<Element> elements, AstNode node, int offset) =>
2271 Element element = 2780 _findWithNameAndOffset(elements, node, '', offset);
2272 _findWithNameAndOffset(elements, identifier.name, identifier.offset); 2781
2782 /**
2783 * Return the element in the given list of [elements] that was created for the
2784 * declaration with the given [identifier]. As a side-effect, associate the
2785 * returned element with the identifier. Throw an [ElementMismatchException]
2786 * if an element corresponding to the identifier cannot be found unless
2787 * [required] is `false`, in which case return `null`.
2788 */
2789 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier,
2790 {bool required: true}) {
2791 Element element = _findWithNameAndOffset(
2792 elements, identifier, identifier.name, identifier.offset,
2793 required: required);
2794 _expectedElements.remove(element);
2273 identifier.staticElement = element; 2795 identifier.staticElement = element;
2274 return element; 2796 return element;
2275 } 2797 }
2276 2798
2277 /** 2799 /**
2278 * Return the import element from the given array whose library has the given source and that has 2800 * Return the element in the given list of [elements] that was created for the
2279 * the given prefix, or `null` if there is no such import. 2801 * declaration with the given [name] at the given [offset]. Throw an
2280 * 2802 * [ElementMismatchException] if an element corresponding to the identifier
2281 * @param imports the import elements being searched 2803 * cannot be found unless [required] is `false`, in which case return `null`.
2282 * @param source the source of the library associated with the import element to being searched
2283 * for
2284 * @param prefix the prefix with which the library was imported
2285 * @return the import element whose library has the given source and prefix
2286 */ 2804 */
2287 ImportElement _findImport( 2805 Element _findWithNameAndOffset(
2288 List<ImportElement> imports, Source source, SimpleIdentifier prefix) { 2806 List<Element> elements, AstNode node, String name, int offset,
2289 for (ImportElement element in imports) { 2807 {bool required: true}) {
2290 if (element.importedLibrary.source == source) { 2808 int length = elements.length;
2291 PrefixElement prefixElement = element.prefix; 2809 for (int i = 0; i < length; i++) {
2292 if (prefix == null) { 2810 Element element = elements[i];
2293 if (prefixElement == null) { 2811 if (element.nameOffset == offset && element.name == name) {
2294 return element; 2812 return element;
2295 }
2296 } else {
2297 if (prefixElement != null &&
2298 prefix.name == prefixElement.displayName) {
2299 return element;
2300 }
2301 }
2302 } 2813 }
2303 } 2814 }
2304 return null; 2815 if (!required) {
2816 return null;
2817 }
2818 for (int i = 0; i < length; i++) {
2819 Element element = elements[i];
2820 if (element.name == name) {
2821 _mismatch(
2822 'Found element with name "$name" at ${element.nameOffset}, '
2823 'but expected offset of $offset',
2824 node);
2825 }
2826 if (element.nameOffset == offset) {
2827 _mismatch(
2828 'Found element with name "${element.name}" at $offset, '
2829 'but expected element with name "$name"',
2830 node);
2831 }
2832 }
2833 _mismatch('Could not find element with name "$name" at $offset', node);
2834 return null; // Never reached
2305 } 2835 }
2306 2836
2307 /** 2837 /**
2308 * Return the element for the part with the given source, or `null` if there i s no element 2838 * Search the most closely enclosing list of parameter elements for a
2309 * for the given source. 2839 * parameter, defined by the given [node], with the given [parameterName].
2310 * 2840 * Return the element that was found, or throw an [ElementMismatchException]
2311 * @param parts the elements for the parts 2841 * if an element corresponding to the identifier cannot be found.
2312 * @param partSource the source for the part whose element is to be returned
2313 * @return the element for the part with the given source
2314 */
2315 CompilationUnitElement _findPart(
2316 List<CompilationUnitElement> parts, Source partSource) {
2317 for (CompilationUnitElement part in parts) {
2318 if (part.source == partSource) {
2319 return part;
2320 }
2321 }
2322 return null;
2323 }
2324
2325 /**
2326 * Return the element in the given array of elements that was created for the declaration with the
2327 * given name at the given offset.
2328 *
2329 * @param elements the elements of the appropriate kind that exist in the curr ent context
2330 * @param name the name of the element to be returned
2331 * @param offset the offset of the name of the element to be returned
2332 * @return the element with the given name and offset
2333 */
2334 Element _findWithNameAndOffset(
2335 List<Element> elements, String name, int offset) {
2336 for (Element element in elements) {
2337 if (element.nameOffset == offset && element.displayName == name) {
2338 return element;
2339 }
2340 }
2341 return null;
2342 }
2343
2344 /**
2345 * Search the most closely enclosing list of parameters for a parameter with t he given name.
2346 *
2347 * @param node the node defining the parameter with the given name
2348 * @param parameterName the name of the parameter being searched for
2349 * @return the element representing the parameter with that name
2350 */ 2842 */
2351 ParameterElement _getElementForParameter( 2843 ParameterElement _getElementForParameter(
2352 FormalParameter node, SimpleIdentifier parameterName) { 2844 FormalParameter node, SimpleIdentifier parameterName) {
2353 List<ParameterElement> parameters = null; 2845 List<ParameterElement> parameters = null;
2354 if (_enclosingParameter != null) { 2846 if (_enclosingParameter != null) {
2355 parameters = _enclosingParameter.parameters; 2847 parameters = _enclosingParameter.parameters;
2356 } 2848 }
2357 if (parameters == null && _enclosingExecutable != null) { 2849 if (parameters == null && _enclosingExecutable != null) {
2358 parameters = _enclosingExecutable.parameters; 2850 parameters = _enclosingExecutable.parameters;
2359 } 2851 }
2360 if (parameters == null && _enclosingAlias != null) { 2852 if (parameters == null && _enclosingAlias != null) {
2361 parameters = _enclosingAlias.parameters; 2853 parameters = _enclosingAlias.parameters;
2362 } 2854 }
2363 ParameterElement element = 2855 if (parameters == null) {
2364 parameters == null ? null : _findIdentifier(parameters, parameterName);
2365 if (element == null) {
2366 StringBuffer buffer = new StringBuffer(); 2856 StringBuffer buffer = new StringBuffer();
2367 buffer.writeln("Invalid state found in the Analysis Engine:"); 2857 buffer.writeln('Could not find parameter in enclosing scope');
2368 buffer.writeln( 2858 buffer.writeln(
2369 "DeclarationResolver.getElementForParameter() is visiting a parameter that does not appear to be in a method or function."); 2859 '(_enclosingParameter == null) == ${_enclosingParameter == null}');
2370 buffer.writeln("Ancestors:"); 2860 buffer.writeln(
2371 AstNode parent = node.parent; 2861 '(_enclosingExecutable == null) == ${_enclosingExecutable == null}');
2372 while (parent != null) { 2862 buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}');
2373 buffer.writeln(parent.runtimeType.toString()); 2863 _mismatch(buffer.toString(), parameterName);
2374 buffer.writeln("---------"); 2864 }
2375 parent = parent.parent; 2865 return _findIdentifier(parameters, parameterName);
2866 }
2867
2868 /**
2869 * Associate each of the annotation [nodes] with the corresponding
2870 * [ElementAnnotation] in [annotations]. If there is a problem, report it
2871 * against the given [parent] node.
2872 */
2873 void _resolveAnnotations(AstNode parent, NodeList<Annotation> nodes,
2874 List<ElementAnnotation> annotations) {
2875 int nodeCount = nodes.length;
2876 if (nodeCount != annotations.length) {
2877 _mismatch(
2878 'Found $nodeCount annotation nodes and '
2879 '${annotations.length} element annotations',
2880 parent);
2881 }
2882 for (int i = 0; i < nodeCount; i++) {
2883 nodes[i].elementAnnotation = annotations[i];
2884 }
2885 }
2886
2887 /**
2888 * If [element] is not `null`, associate each of the annotation [nodes] with
2889 * the corresponding [ElementAnnotation] in [element.metadata]. If there is a
2890 * problem, report it against the given [parent] node.
2891 *
2892 * If [element] is `null`, do nothing--this allows us to be robust in the
2893 * case where we are operating on an element model that hasn't been fully
2894 * built.
2895 */
2896 void _resolveMetadata(
2897 AstNode parent, NodeList<Annotation> nodes, Element element) {
2898 if (element != null) {
2899 _resolveAnnotations(parent, nodes, element.metadata);
2900 }
2901 }
2902
2903 /**
2904 * Throw an exception if there are non-synthetic elements in the element model
2905 * that were not associated with an AST node.
2906 */
2907 void _validateResolution() {
2908 if (_expectedElements.isNotEmpty) {
2909 StringBuffer buffer = new StringBuffer();
2910 buffer.write(_expectedElements.length);
2911 buffer.writeln(' unmatched elements found:');
2912 for (Element element in _expectedElements) {
2913 buffer.write(' ');
2914 buffer.writeln(element);
2376 } 2915 }
2377 AnalysisEngine.instance.logger.logError(buffer.toString(), 2916 throw new ElementMismatchException(buffer.toString());
2378 new CaughtException(new AnalysisException(), null)); 2917 }
2379 }
2380 return element;
2381 }
2382
2383 /**
2384 * Return the value of the given string literal, or `null` if the string is no t a constant
2385 * string without any string interpolation.
2386 *
2387 * @param literal the string literal whose value is to be returned
2388 * @return the value of the given string literal
2389 */
2390 String _getStringValue(StringLiteral literal) {
2391 if (literal is StringInterpolation) {
2392 return null;
2393 }
2394 return literal.stringValue;
2395 } 2918 }
2396 } 2919 }
2397 2920
2398 /** 2921 /**
2399 * Instances of the class `ElementBuilder` traverse an AST structure and build t he element 2922 * A visitor that resolves directives in an AST structure to already built
2400 * model representing the AST structure. 2923 * elements.
2924 *
2925 * The resulting AST must have everything resolved that would have been resolved
2926 * by a [DirectiveElementBuilder].
2401 */ 2927 */
2402 class ElementBuilder extends RecursiveAstVisitor<Object> { 2928 class DirectiveResolver extends SimpleAstVisitor {
2403 /** 2929 LibraryElement _enclosingLibrary;
2404 * The element holder associated with the element that is currently being buil t.
2405 */
2406 ElementHolder _currentHolder;
2407
2408 /**
2409 * A flag indicating whether a variable declaration is in the context of a fie ld declaration.
2410 */
2411 bool _inFieldContext = false;
2412
2413 /**
2414 * A flag indicating whether a variable declaration is within the body of a me thod or function.
2415 */
2416 bool _inFunction = false;
2417
2418 /**
2419 * A flag indicating whether the class currently being visited can be used as a mixin.
2420 */
2421 bool _isValidMixin = false;
2422
2423 /**
2424 * A collection holding the function types defined in a class that need to hav e their type
2425 * arguments set to the types of the type parameters for the class, or `null` if we are not
2426 * currently processing nodes within a class.
2427 */
2428 List<FunctionTypeImpl> _functionTypesToFix = null;
2429
2430 /**
2431 * A table mapping field names to field elements for the fields defined in the current class, or
2432 * `null` if we are not in the scope of a class.
2433 */
2434 HashMap<String, FieldElement> _fieldMap;
2435
2436 /**
2437 * Initialize a newly created element builder to build the elements for a comp ilation unit.
2438 *
2439 * @param initialHolder the element holder associated with the compilation uni t being built
2440 */
2441 ElementBuilder(ElementHolder initialHolder) {
2442 _currentHolder = initialHolder;
2443 }
2444 2930
2445 @override 2931 @override
2446 Object visitBlock(Block node) { 2932 void visitCompilationUnit(CompilationUnit node) {
2447 bool wasInField = _inFieldContext; 2933 _enclosingLibrary = node.element.library;
2448 _inFieldContext = false; 2934 for (Directive directive in node.directives) {
2449 try { 2935 directive.accept(this);
2450 node.visitChildren(this); 2936 }
2451 } finally {
2452 _inFieldContext = wasInField;
2453 }
2454 return null;
2455 } 2937 }
2456 2938
2457 @override 2939 @override
2458 Object visitCatchClause(CatchClause node) { 2940 void visitExportDirective(ExportDirective node) {
2459 SimpleIdentifier exceptionParameter = node.exceptionParameter; 2941 int nodeOffset = node.offset;
2460 if (exceptionParameter != null) { 2942 node.element = null;
2461 // exception 2943 for (ExportElement element in _enclosingLibrary.exports) {
2462 LocalVariableElementImpl exception = 2944 if (element.nameOffset == nodeOffset) {
2463 new LocalVariableElementImpl.forNode(exceptionParameter); 2945 node.element = element;
2464 if (node.exceptionType == null) { 2946 break;
2465 exception.hasImplicitType = true;
2466 } 2947 }
2467 _currentHolder.addLocalVariable(exception); 2948 }
2468 exceptionParameter.staticElement = exception; 2949 }
2469 // stack trace 2950
2470 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; 2951 @override
2471 if (stackTraceParameter != null) { 2952 void visitImportDirective(ImportDirective node) {
2472 LocalVariableElementImpl stackTrace = 2953 int nodeOffset = node.offset;
2473 new LocalVariableElementImpl.forNode(stackTraceParameter); 2954 node.element = null;
2474 _currentHolder.addLocalVariable(stackTrace); 2955 for (ImportElement element in _enclosingLibrary.imports) {
2475 stackTraceParameter.staticElement = stackTrace; 2956 if (element.nameOffset == nodeOffset) {
2957 node.element = element;
2958 break;
2476 } 2959 }
2477 } 2960 }
2478 return super.visitCatchClause(node);
2479 } 2961 }
2480 2962
2481 @override 2963 @override
2482 Object visitClassDeclaration(ClassDeclaration node) { 2964 void visitLibraryDirective(LibraryDirective node) {
2483 ElementHolder holder = new ElementHolder(); 2965 node.element = _enclosingLibrary;
2484 _isValidMixin = true;
2485 _functionTypesToFix = new List<FunctionTypeImpl>();
2486 //
2487 // Process field declarations before constructors and methods so that field
2488 // formal parameters can be correctly resolved to their fields.
2489 //
2490 ElementHolder previousHolder = _currentHolder;
2491 _currentHolder = holder;
2492 try {
2493 List<ClassMember> nonFields = new List<ClassMember>();
2494 node.visitChildren(
2495 new _ElementBuilder_visitClassDeclaration(this, nonFields));
2496 _buildFieldMap(holder.fieldsWithoutFlushing);
2497 int count = nonFields.length;
2498 for (int i = 0; i < count; i++) {
2499 nonFields[i].accept(this);
2500 }
2501 } finally {
2502 _currentHolder = previousHolder;
2503 }
2504 SimpleIdentifier className = node.name;
2505 ClassElementImpl element = new ClassElementImpl.forNode(className);
2506 List<TypeParameterElement> typeParameters = holder.typeParameters;
2507 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
2508 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
2509 interfaceType.typeArguments = typeArguments;
2510 element.type = interfaceType;
2511 List<ConstructorElement> constructors = holder.constructors;
2512 if (constructors.length == 0) {
2513 //
2514 // Create the default constructor.
2515 //
2516 constructors = _createDefaultConstructors(interfaceType);
2517 }
2518 _setDocRange(element, node);
2519 element.abstract = node.isAbstract;
2520 element.accessors = holder.accessors;
2521 element.constructors = constructors;
2522 element.fields = holder.fields;
2523 element.methods = holder.methods;
2524 element.typeParameters = typeParameters;
2525 element.validMixin = _isValidMixin;
2526 int functionTypeCount = _functionTypesToFix.length;
2527 for (int i = 0; i < functionTypeCount; i++) {
2528 _functionTypesToFix[i].typeArguments = typeArguments;
2529 }
2530 _functionTypesToFix = null;
2531 _currentHolder.addType(element);
2532 className.staticElement = element;
2533 _fieldMap = null;
2534 holder.validate();
2535 return null;
2536 }
2537
2538 /**
2539 * Implementation of this method should be synchronized with
2540 * [visitClassDeclaration].
2541 */
2542 void visitClassDeclarationIncrementally(ClassDeclaration node) {
2543 //
2544 // Process field declarations before constructors and methods so that field
2545 // formal parameters can be correctly resolved to their fields.
2546 //
2547 ClassElement classElement = node.element;
2548 _buildFieldMap(classElement.fields);
2549 }
2550
2551 @override
2552 Object visitClassTypeAlias(ClassTypeAlias node) {
2553 ElementHolder holder = new ElementHolder();
2554 _functionTypesToFix = new List<FunctionTypeImpl>();
2555 _visitChildren(holder, node);
2556 SimpleIdentifier className = node.name;
2557 ClassElementImpl element = new ClassElementImpl.forNode(className);
2558 element.abstract = node.abstractKeyword != null;
2559 element.mixinApplication = true;
2560 List<TypeParameterElement> typeParameters = holder.typeParameters;
2561 element.typeParameters = typeParameters;
2562 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
2563 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
2564 interfaceType.typeArguments = typeArguments;
2565 element.type = interfaceType;
2566 // set default constructor
2567 for (FunctionTypeImpl functionType in _functionTypesToFix) {
2568 functionType.typeArguments = typeArguments;
2569 }
2570 _functionTypesToFix = null;
2571 _currentHolder.addType(element);
2572 className.staticElement = element;
2573 holder.validate();
2574 return null;
2575 }
2576
2577 @override
2578 Object visitConstructorDeclaration(ConstructorDeclaration node) {
2579 _isValidMixin = false;
2580 ElementHolder holder = new ElementHolder();
2581 bool wasInFunction = _inFunction;
2582 _inFunction = true;
2583 try {
2584 _visitChildren(holder, node);
2585 } finally {
2586 _inFunction = wasInFunction;
2587 }
2588 FunctionBody body = node.body;
2589 SimpleIdentifier constructorName = node.name;
2590 ConstructorElementImpl element =
2591 new ConstructorElementImpl.forNode(constructorName);
2592 _setDocRange(element, node);
2593 if (node.externalKeyword != null) {
2594 element.external = true;
2595 }
2596 if (node.factoryKeyword != null) {
2597 element.factory = true;
2598 }
2599 element.functions = holder.functions;
2600 element.labels = holder.labels;
2601 element.localVariables = holder.localVariables;
2602 element.parameters = holder.parameters;
2603 element.const2 = node.constKeyword != null;
2604 if (body.isAsynchronous) {
2605 element.asynchronous = true;
2606 }
2607 if (body.isGenerator) {
2608 element.generator = true;
2609 }
2610 _currentHolder.addConstructor(element);
2611 node.element = element;
2612 if (constructorName == null) {
2613 Identifier returnType = node.returnType;
2614 if (returnType != null) {
2615 element.nameOffset = returnType.offset;
2616 element.nameEnd = returnType.end;
2617 }
2618 } else {
2619 constructorName.staticElement = element;
2620 element.periodOffset = node.period.offset;
2621 element.nameEnd = constructorName.end;
2622 }
2623 holder.validate();
2624 return null;
2625 }
2626
2627 @override
2628 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
2629 SimpleIdentifier variableName = node.identifier;
2630 LocalVariableElementImpl element =
2631 new LocalVariableElementImpl.forNode(variableName);
2632 ForEachStatement statement = node.parent as ForEachStatement;
2633 int declarationEnd = node.offset + node.length;
2634 int statementEnd = statement.offset + statement.length;
2635 element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1);
2636 element.const3 = node.isConst;
2637 element.final2 = node.isFinal;
2638 if (node.type == null) {
2639 element.hasImplicitType = true;
2640 }
2641 _currentHolder.addLocalVariable(element);
2642 variableName.staticElement = element;
2643 return super.visitDeclaredIdentifier(node);
2644 }
2645
2646 @override
2647 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
2648 ElementHolder holder = new ElementHolder();
2649 NormalFormalParameter normalParameter = node.parameter;
2650 SimpleIdentifier parameterName = normalParameter.identifier;
2651 ParameterElementImpl parameter;
2652 if (normalParameter is FieldFormalParameter) {
2653 parameter = new DefaultFieldFormalParameterElementImpl(parameterName);
2654 FieldElement field =
2655 _fieldMap == null ? null : _fieldMap[parameterName.name];
2656 if (field != null) {
2657 (parameter as DefaultFieldFormalParameterElementImpl).field = field;
2658 }
2659 } else {
2660 parameter = new DefaultParameterElementImpl(parameterName);
2661 }
2662 parameter.const3 = node.isConst;
2663 parameter.final2 = node.isFinal;
2664 parameter.parameterKind = node.kind;
2665 // set initializer, default value range
2666 Expression defaultValue = node.defaultValue;
2667 if (defaultValue != null) {
2668 _visit(holder, defaultValue);
2669 FunctionElementImpl initializer =
2670 new FunctionElementImpl.forOffset(defaultValue.beginToken.offset);
2671 initializer.functions = holder.functions;
2672 initializer.labels = holder.labels;
2673 initializer.localVariables = holder.localVariables;
2674 initializer.parameters = holder.parameters;
2675 initializer.synthetic = true;
2676 parameter.initializer = initializer;
2677 parameter.defaultValueCode = defaultValue.toSource();
2678 }
2679 // visible range
2680 _setParameterVisibleRange(node, parameter);
2681 if (normalParameter is SimpleFormalParameter &&
2682 normalParameter.type == null) {
2683 parameter.hasImplicitType = true;
2684 }
2685 _currentHolder.addParameter(parameter);
2686 parameterName.staticElement = parameter;
2687 normalParameter.accept(this);
2688 holder.validate();
2689 return null;
2690 }
2691
2692 @override
2693 Object visitEnumDeclaration(EnumDeclaration node) {
2694 SimpleIdentifier enumName = node.name;
2695 ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
2696 enumElement.enum2 = true;
2697 _setDocRange(enumElement, node);
2698 InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
2699 enumElement.type = enumType;
2700 // The equivalent code for enums in the spec shows a single constructor,
2701 // but that constructor is not callable (since it is a compile-time error
2702 // to subclass, mix-in, implement, or explicitly instantiate an enum). So
2703 // we represent this as having no constructors.
2704 enumElement.constructors = ConstructorElement.EMPTY_LIST;
2705 _currentHolder.addEnum(enumElement);
2706 enumName.staticElement = enumElement;
2707 return super.visitEnumDeclaration(node);
2708 }
2709
2710 @override
2711 Object visitFieldDeclaration(FieldDeclaration node) {
2712 bool wasInField = _inFieldContext;
2713 _inFieldContext = true;
2714 try {
2715 node.visitChildren(this);
2716 } finally {
2717 _inFieldContext = wasInField;
2718 }
2719 return null;
2720 }
2721
2722 @override
2723 Object visitFieldFormalParameter(FieldFormalParameter node) {
2724 if (node.parent is! DefaultFormalParameter) {
2725 SimpleIdentifier parameterName = node.identifier;
2726 FieldElement field =
2727 _fieldMap == null ? null : _fieldMap[parameterName.name];
2728 FieldFormalParameterElementImpl parameter =
2729 new FieldFormalParameterElementImpl(parameterName);
2730 parameter.const3 = node.isConst;
2731 parameter.final2 = node.isFinal;
2732 parameter.parameterKind = node.kind;
2733 if (field != null) {
2734 parameter.field = field;
2735 }
2736 _currentHolder.addParameter(parameter);
2737 parameterName.staticElement = parameter;
2738 }
2739 //
2740 // The children of this parameter include any parameters defined on the type
2741 // of this parameter.
2742 //
2743 ElementHolder holder = new ElementHolder();
2744 _visitChildren(holder, node);
2745 ParameterElementImpl element = node.element;
2746 element.parameters = holder.parameters;
2747 element.typeParameters = holder.typeParameters;
2748 holder.validate();
2749 return null;
2750 }
2751
2752 @override
2753 Object visitFunctionDeclaration(FunctionDeclaration node) {
2754 FunctionExpression expression = node.functionExpression;
2755 if (expression != null) {
2756 ElementHolder holder = new ElementHolder();
2757 bool wasInFunction = _inFunction;
2758 _inFunction = true;
2759 try {
2760 _visitChildren(holder, node);
2761 } finally {
2762 _inFunction = wasInFunction;
2763 }
2764 FunctionBody body = expression.body;
2765 sc.Token property = node.propertyKeyword;
2766 if (property == null || _inFunction) {
2767 SimpleIdentifier functionName = node.name;
2768 FunctionElementImpl element =
2769 new FunctionElementImpl.forNode(functionName);
2770 _setDocRange(element, node);
2771 if (node.externalKeyword != null) {
2772 element.external = true;
2773 }
2774 element.functions = holder.functions;
2775 element.labels = holder.labels;
2776 element.localVariables = holder.localVariables;
2777 element.parameters = holder.parameters;
2778 element.typeParameters = holder.typeParameters;
2779 if (body.isAsynchronous) {
2780 element.asynchronous = true;
2781 }
2782 if (body.isGenerator) {
2783 element.generator = true;
2784 }
2785 if (_inFunction) {
2786 Block enclosingBlock = node.getAncestor((node) => node is Block);
2787 if (enclosingBlock != null) {
2788 int functionEnd = node.offset + node.length;
2789 int blockEnd = enclosingBlock.offset + enclosingBlock.length;
2790 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
2791 }
2792 }
2793 if (node.returnType == null) {
2794 element.hasImplicitReturnType = true;
2795 }
2796 _currentHolder.addFunction(element);
2797 expression.element = element;
2798 functionName.staticElement = element;
2799 } else {
2800 SimpleIdentifier propertyNameNode = node.name;
2801 if (propertyNameNode == null) {
2802 // TODO(brianwilkerson) Report this internal error.
2803 return null;
2804 }
2805 String propertyName = propertyNameNode.name;
2806 TopLevelVariableElementImpl variable = _currentHolder
2807 .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl;
2808 if (variable == null) {
2809 variable = new TopLevelVariableElementImpl(node.name.name, -1);
2810 variable.final2 = true;
2811 variable.synthetic = true;
2812 _currentHolder.addTopLevelVariable(variable);
2813 }
2814 if (node.isGetter) {
2815 PropertyAccessorElementImpl getter =
2816 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2817 _setDocRange(getter, node);
2818 if (node.externalKeyword != null) {
2819 getter.external = true;
2820 }
2821 getter.functions = holder.functions;
2822 getter.labels = holder.labels;
2823 getter.localVariables = holder.localVariables;
2824 if (body.isAsynchronous) {
2825 getter.asynchronous = true;
2826 }
2827 if (body.isGenerator) {
2828 getter.generator = true;
2829 }
2830 getter.variable = variable;
2831 getter.getter = true;
2832 getter.static = true;
2833 variable.getter = getter;
2834 if (node.returnType == null) {
2835 getter.hasImplicitReturnType = true;
2836 }
2837 _currentHolder.addAccessor(getter);
2838 expression.element = getter;
2839 propertyNameNode.staticElement = getter;
2840 } else {
2841 PropertyAccessorElementImpl setter =
2842 new PropertyAccessorElementImpl.forNode(propertyNameNode);
2843 _setDocRange(setter, node);
2844 if (node.externalKeyword != null) {
2845 setter.external = true;
2846 }
2847 setter.functions = holder.functions;
2848 setter.labels = holder.labels;
2849 setter.localVariables = holder.localVariables;
2850 setter.parameters = holder.parameters;
2851 if (body.isAsynchronous) {
2852 setter.asynchronous = true;
2853 }
2854 if (body.isGenerator) {
2855 setter.generator = true;
2856 }
2857 setter.variable = variable;
2858 setter.setter = true;
2859 setter.static = true;
2860 variable.setter = setter;
2861 variable.final2 = false;
2862 _currentHolder.addAccessor(setter);
2863 expression.element = setter;
2864 propertyNameNode.staticElement = setter;
2865 }
2866 }
2867 holder.validate();
2868 }
2869 return null;
2870 }
2871
2872 @override
2873 Object visitFunctionExpression(FunctionExpression node) {
2874 if (node.parent is FunctionDeclaration) {
2875 // visitFunctionDeclaration has already created the element for the
2876 // declaration. We just need to visit children.
2877 return super.visitFunctionExpression(node);
2878 }
2879 ElementHolder holder = new ElementHolder();
2880 bool wasInFunction = _inFunction;
2881 _inFunction = true;
2882 try {
2883 _visitChildren(holder, node);
2884 } finally {
2885 _inFunction = wasInFunction;
2886 }
2887 FunctionBody body = node.body;
2888 FunctionElementImpl element =
2889 new FunctionElementImpl.forOffset(node.beginToken.offset);
2890 element.functions = holder.functions;
2891 element.labels = holder.labels;
2892 element.localVariables = holder.localVariables;
2893 element.parameters = holder.parameters;
2894 element.typeParameters = holder.typeParameters;
2895 if (body.isAsynchronous) {
2896 element.asynchronous = true;
2897 }
2898 if (body.isGenerator) {
2899 element.generator = true;
2900 }
2901 if (_inFunction) {
2902 Block enclosingBlock = node.getAncestor((node) => node is Block);
2903 if (enclosingBlock != null) {
2904 int functionEnd = node.offset + node.length;
2905 int blockEnd = enclosingBlock.offset + enclosingBlock.length;
2906 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
2907 }
2908 }
2909 FunctionTypeImpl type = new FunctionTypeImpl(element);
2910 if (_functionTypesToFix != null) {
2911 _functionTypesToFix.add(type);
2912 }
2913 element.type = type;
2914 element.hasImplicitReturnType = true;
2915 _currentHolder.addFunction(element);
2916 node.element = element;
2917 holder.validate();
2918 return null;
2919 }
2920
2921 @override
2922 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
2923 ElementHolder holder = new ElementHolder();
2924 _visitChildren(holder, node);
2925 SimpleIdentifier aliasName = node.name;
2926 List<ParameterElement> parameters = holder.parameters;
2927 List<TypeParameterElement> typeParameters = holder.typeParameters;
2928 FunctionTypeAliasElementImpl element =
2929 new FunctionTypeAliasElementImpl.forNode(aliasName);
2930 _setDocRange(element, node);
2931 element.parameters = parameters;
2932 element.typeParameters = typeParameters;
2933 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element);
2934 type.typeArguments = _createTypeParameterTypes(typeParameters);
2935 element.type = type;
2936 _currentHolder.addTypeAlias(element);
2937 aliasName.staticElement = element;
2938 holder.validate();
2939 return null;
2940 }
2941
2942 @override
2943 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
2944 if (node.parent is! DefaultFormalParameter) {
2945 SimpleIdentifier parameterName = node.identifier;
2946 ParameterElementImpl parameter =
2947 new ParameterElementImpl.forNode(parameterName);
2948 parameter.parameterKind = node.kind;
2949 _setParameterVisibleRange(node, parameter);
2950 _currentHolder.addParameter(parameter);
2951 parameterName.staticElement = parameter;
2952 }
2953 //
2954 // The children of this parameter include any parameters defined on the type
2955 //of this parameter.
2956 //
2957 ElementHolder holder = new ElementHolder();
2958 _visitChildren(holder, node);
2959 ParameterElementImpl element = node.element;
2960 element.parameters = holder.parameters;
2961 element.typeParameters = holder.typeParameters;
2962 holder.validate();
2963 return null;
2964 }
2965
2966 @override
2967 Object visitLabeledStatement(LabeledStatement node) {
2968 bool onSwitchStatement = node.statement is SwitchStatement;
2969 for (Label label in node.labels) {
2970 SimpleIdentifier labelName = label.label;
2971 LabelElementImpl element =
2972 new LabelElementImpl(labelName, onSwitchStatement, false);
2973 _currentHolder.addLabel(element);
2974 labelName.staticElement = element;
2975 }
2976 return super.visitLabeledStatement(node);
2977 }
2978
2979 @override
2980 Object visitMethodDeclaration(MethodDeclaration node) {
2981 try {
2982 ElementHolder holder = new ElementHolder();
2983 bool wasInFunction = _inFunction;
2984 _inFunction = true;
2985 try {
2986 _visitChildren(holder, node);
2987 } finally {
2988 _inFunction = wasInFunction;
2989 }
2990 bool isStatic = node.isStatic;
2991 sc.Token property = node.propertyKeyword;
2992 FunctionBody body = node.body;
2993 if (property == null) {
2994 SimpleIdentifier methodName = node.name;
2995 String nameOfMethod = methodName.name;
2996 if (nameOfMethod == sc.TokenType.MINUS.lexeme &&
2997 node.parameters.parameters.length == 0) {
2998 nameOfMethod = "unary-";
2999 }
3000 MethodElementImpl element =
3001 new MethodElementImpl(nameOfMethod, methodName.offset);
3002 _setDocRange(element, node);
3003 element.abstract = node.isAbstract;
3004 if (node.externalKeyword != null) {
3005 element.external = true;
3006 }
3007 element.functions = holder.functions;
3008 element.labels = holder.labels;
3009 element.localVariables = holder.localVariables;
3010 element.parameters = holder.parameters;
3011 element.static = isStatic;
3012 element.typeParameters = holder.typeParameters;
3013 if (body.isAsynchronous) {
3014 element.asynchronous = true;
3015 }
3016 if (body.isGenerator) {
3017 element.generator = true;
3018 }
3019 if (node.returnType == null) {
3020 element.hasImplicitReturnType = true;
3021 }
3022 _currentHolder.addMethod(element);
3023 methodName.staticElement = element;
3024 } else {
3025 SimpleIdentifier propertyNameNode = node.name;
3026 String propertyName = propertyNameNode.name;
3027 FieldElementImpl field =
3028 _currentHolder.getField(propertyName) as FieldElementImpl;
3029 if (field == null) {
3030 field = new FieldElementImpl(node.name.name, -1);
3031 field.final2 = true;
3032 field.static = isStatic;
3033 field.synthetic = true;
3034 _currentHolder.addField(field);
3035 }
3036 if (node.isGetter) {
3037 PropertyAccessorElementImpl getter =
3038 new PropertyAccessorElementImpl.forNode(propertyNameNode);
3039 _setDocRange(getter, node);
3040 if (node.externalKeyword != null) {
3041 getter.external = true;
3042 }
3043 getter.functions = holder.functions;
3044 getter.labels = holder.labels;
3045 getter.localVariables = holder.localVariables;
3046 if (body.isAsynchronous) {
3047 getter.asynchronous = true;
3048 }
3049 if (body.isGenerator) {
3050 getter.generator = true;
3051 }
3052 getter.variable = field;
3053 getter.abstract = node.isAbstract;
3054 getter.getter = true;
3055 getter.static = isStatic;
3056 field.getter = getter;
3057 if (node.returnType == null) {
3058 getter.hasImplicitReturnType = true;
3059 }
3060 _currentHolder.addAccessor(getter);
3061 propertyNameNode.staticElement = getter;
3062 } else {
3063 PropertyAccessorElementImpl setter =
3064 new PropertyAccessorElementImpl.forNode(propertyNameNode);
3065 _setDocRange(setter, node);
3066 if (node.externalKeyword != null) {
3067 setter.external = true;
3068 }
3069 setter.functions = holder.functions;
3070 setter.labels = holder.labels;
3071 setter.localVariables = holder.localVariables;
3072 setter.parameters = holder.parameters;
3073 if (body.isAsynchronous) {
3074 setter.asynchronous = true;
3075 }
3076 if (body.isGenerator) {
3077 setter.generator = true;
3078 }
3079 setter.variable = field;
3080 setter.abstract = node.isAbstract;
3081 setter.setter = true;
3082 setter.static = isStatic;
3083 field.setter = setter;
3084 field.final2 = false;
3085 _currentHolder.addAccessor(setter);
3086 propertyNameNode.staticElement = setter;
3087 }
3088 }
3089 holder.validate();
3090 } catch (exception, stackTrace) {
3091 if (node.name.staticElement == null) {
3092 ClassDeclaration classNode =
3093 node.getAncestor((node) => node is ClassDeclaration);
3094 StringBuffer buffer = new StringBuffer();
3095 buffer.write("The element for the method ");
3096 buffer.write(node.name);
3097 buffer.write(" in ");
3098 buffer.write(classNode.name);
3099 buffer.write(" was not set while trying to build the element model.");
3100 AnalysisEngine.instance.logger.logError(
3101 buffer.toString(), new CaughtException(exception, stackTrace));
3102 } else {
3103 String message =
3104 "Exception caught in ElementBuilder.visitMethodDeclaration()";
3105 AnalysisEngine.instance.logger
3106 .logError(message, new CaughtException(exception, stackTrace));
3107 }
3108 } finally {
3109 if (node.name.staticElement == null) {
3110 ClassDeclaration classNode =
3111 node.getAncestor((node) => node is ClassDeclaration);
3112 StringBuffer buffer = new StringBuffer();
3113 buffer.write("The element for the method ");
3114 buffer.write(node.name);
3115 buffer.write(" in ");
3116 buffer.write(classNode.name);
3117 buffer.write(" was not set while trying to resolve types.");
3118 AnalysisEngine.instance.logger.logError(
3119 buffer.toString(),
3120 new CaughtException(
3121 new AnalysisException(buffer.toString()), null));
3122 }
3123 }
3124 return null;
3125 }
3126
3127 @override
3128 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
3129 if (node.parent is! DefaultFormalParameter) {
3130 SimpleIdentifier parameterName = node.identifier;
3131 ParameterElementImpl parameter =
3132 new ParameterElementImpl.forNode(parameterName);
3133 parameter.const3 = node.isConst;
3134 parameter.final2 = node.isFinal;
3135 parameter.parameterKind = node.kind;
3136 _setParameterVisibleRange(node, parameter);
3137 if (node.type == null) {
3138 parameter.hasImplicitType = true;
3139 }
3140 _currentHolder.addParameter(parameter);
3141 parameterName.staticElement = parameter;
3142 }
3143 return super.visitSimpleFormalParameter(node);
3144 }
3145
3146 @override
3147 Object visitSuperExpression(SuperExpression node) {
3148 _isValidMixin = false;
3149 return super.visitSuperExpression(node);
3150 }
3151
3152 @override
3153 Object visitSwitchCase(SwitchCase node) {
3154 for (Label label in node.labels) {
3155 SimpleIdentifier labelName = label.label;
3156 LabelElementImpl element = new LabelElementImpl(labelName, false, true);
3157 _currentHolder.addLabel(element);
3158 labelName.staticElement = element;
3159 }
3160 return super.visitSwitchCase(node);
3161 }
3162
3163 @override
3164 Object visitSwitchDefault(SwitchDefault node) {
3165 for (Label label in node.labels) {
3166 SimpleIdentifier labelName = label.label;
3167 LabelElementImpl element = new LabelElementImpl(labelName, false, true);
3168 _currentHolder.addLabel(element);
3169 labelName.staticElement = element;
3170 }
3171 return super.visitSwitchDefault(node);
3172 }
3173
3174 @override
3175 Object visitTypeParameter(TypeParameter node) {
3176 SimpleIdentifier parameterName = node.name;
3177 TypeParameterElementImpl typeParameter =
3178 new TypeParameterElementImpl.forNode(parameterName);
3179 TypeParameterTypeImpl typeParameterType =
3180 new TypeParameterTypeImpl(typeParameter);
3181 typeParameter.type = typeParameterType;
3182 _currentHolder.addTypeParameter(typeParameter);
3183 parameterName.staticElement = typeParameter;
3184 return super.visitTypeParameter(node);
3185 }
3186
3187 @override
3188 Object visitVariableDeclaration(VariableDeclaration node) {
3189 bool isConst = node.isConst;
3190 bool isFinal = node.isFinal;
3191 bool hasInitializer = node.initializer != null;
3192 VariableElementImpl element;
3193 if (_inFieldContext) {
3194 SimpleIdentifier fieldName = node.name;
3195 FieldElementImpl field;
3196 if ((isConst || isFinal) && hasInitializer) {
3197 field = new ConstFieldElementImpl.forNode(fieldName);
3198 } else {
3199 field = new FieldElementImpl.forNode(fieldName);
3200 }
3201 element = field;
3202 if (node.parent.parent is FieldDeclaration) {
3203 _setDocRange(element, node.parent.parent);
3204 }
3205 if ((node.parent as VariableDeclarationList).type == null) {
3206 field.hasImplicitType = true;
3207 }
3208 _currentHolder.addField(field);
3209 fieldName.staticElement = field;
3210 } else if (_inFunction) {
3211 SimpleIdentifier variableName = node.name;
3212 LocalVariableElementImpl variable;
3213 if (isConst && hasInitializer) {
3214 variable = new ConstLocalVariableElementImpl.forNode(variableName);
3215 } else {
3216 variable = new LocalVariableElementImpl.forNode(variableName);
3217 }
3218 element = variable;
3219 Block enclosingBlock = node.getAncestor((node) => node is Block);
3220 // TODO(brianwilkerson) This isn't right for variables declared in a for
3221 // loop.
3222 variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
3223 if ((node.parent as VariableDeclarationList).type == null) {
3224 variable.hasImplicitType = true;
3225 }
3226 _currentHolder.addLocalVariable(variable);
3227 variableName.staticElement = element;
3228 } else {
3229 SimpleIdentifier variableName = node.name;
3230 TopLevelVariableElementImpl variable;
3231 if (isConst && hasInitializer) {
3232 variable = new ConstTopLevelVariableElementImpl(variableName);
3233 } else {
3234 variable = new TopLevelVariableElementImpl.forNode(variableName);
3235 }
3236 element = variable;
3237 if (node.parent.parent is TopLevelVariableDeclaration) {
3238 _setDocRange(element, node.parent.parent);
3239 }
3240 if ((node.parent as VariableDeclarationList).type == null) {
3241 variable.hasImplicitType = true;
3242 }
3243 _currentHolder.addTopLevelVariable(variable);
3244 variableName.staticElement = element;
3245 }
3246 element.const3 = isConst;
3247 element.final2 = isFinal;
3248 if (hasInitializer) {
3249 ElementHolder holder = new ElementHolder();
3250 bool wasInFieldContext = _inFieldContext;
3251 _inFieldContext = false;
3252 try {
3253 _visit(holder, node.initializer);
3254 } finally {
3255 _inFieldContext = wasInFieldContext;
3256 }
3257 FunctionElementImpl initializer =
3258 new FunctionElementImpl.forOffset(node.initializer.beginToken.offset);
3259 initializer.functions = holder.functions;
3260 initializer.labels = holder.labels;
3261 initializer.localVariables = holder.localVariables;
3262 initializer.synthetic = true;
3263 element.initializer = initializer;
3264 holder.validate();
3265 }
3266 if (element is PropertyInducingElementImpl) {
3267 if (_inFieldContext) {
3268 (element as FieldElementImpl).static =
3269 (node.parent.parent as FieldDeclaration).isStatic;
3270 }
3271 PropertyAccessorElementImpl getter =
3272 new PropertyAccessorElementImpl.forVariable(element);
3273 getter.getter = true;
3274 if (element.hasImplicitType) {
3275 getter.hasImplicitReturnType = true;
3276 }
3277 _currentHolder.addAccessor(getter);
3278 element.getter = getter;
3279 if (!isConst && !isFinal) {
3280 PropertyAccessorElementImpl setter =
3281 new PropertyAccessorElementImpl.forVariable(element);
3282 setter.setter = true;
3283 ParameterElementImpl parameter =
3284 new ParameterElementImpl("_${element.name}", element.nameOffset);
3285 parameter.synthetic = true;
3286 parameter.parameterKind = ParameterKind.REQUIRED;
3287 setter.parameters = <ParameterElement>[parameter];
3288 _currentHolder.addAccessor(setter);
3289 element.setter = setter;
3290 }
3291 }
3292 return null;
3293 }
3294
3295 /**
3296 * Build the table mapping field names to field elements for the fields define d in the current
3297 * class.
3298 *
3299 * @param fields the field elements defined in the current class
3300 */
3301 void _buildFieldMap(List<FieldElement> fields) {
3302 _fieldMap = new HashMap<String, FieldElement>();
3303 int count = fields.length;
3304 for (int i = 0; i < count; i++) {
3305 FieldElement field = fields[i];
3306 _fieldMap[field.name] = field;
3307 }
3308 }
3309
3310 /**
3311 * Creates the [ConstructorElement]s array with the single default constructor element.
3312 *
3313 * @param interfaceType the interface type for which to create a default const ructor
3314 * @return the [ConstructorElement]s array with the single default constructor element
3315 */
3316 List<ConstructorElement> _createDefaultConstructors(
3317 InterfaceTypeImpl interfaceType) {
3318 ConstructorElementImpl constructor =
3319 new ConstructorElementImpl.forNode(null);
3320 constructor.synthetic = true;
3321 constructor.returnType = interfaceType;
3322 FunctionTypeImpl type = new FunctionTypeImpl(constructor);
3323 _functionTypesToFix.add(type);
3324 constructor.type = type;
3325 return <ConstructorElement>[constructor];
3326 }
3327
3328 /**
3329 * Create the types associated with the given type parameters, setting the typ e of each type
3330 * parameter, and return an array of types corresponding to the given paramete rs.
3331 *
3332 * @param typeParameters the type parameters for which types are to be created
3333 * @return an array of types corresponding to the given parameters
3334 */
3335 List<DartType> _createTypeParameterTypes(
3336 List<TypeParameterElement> typeParameters) {
3337 int typeParameterCount = typeParameters.length;
3338 List<DartType> typeArguments = new List<DartType>(typeParameterCount);
3339 for (int i = 0; i < typeParameterCount; i++) {
3340 TypeParameterElementImpl typeParameter =
3341 typeParameters[i] as TypeParameterElementImpl;
3342 TypeParameterTypeImpl typeParameterType =
3343 new TypeParameterTypeImpl(typeParameter);
3344 typeParameter.type = typeParameterType;
3345 typeArguments[i] = typeParameterType;
3346 }
3347 return typeArguments;
3348 }
3349
3350 /**
3351 * Return the body of the function that contains the given parameter, or `null ` if no
3352 * function body could be found.
3353 *
3354 * @param node the parameter contained in the function whose body is to be ret urned
3355 * @return the body of the function that contains the given parameter
3356 */
3357 FunctionBody _getFunctionBody(FormalParameter node) {
3358 AstNode parent = node.parent;
3359 while (parent != null) {
3360 if (parent is ConstructorDeclaration) {
3361 return parent.body;
3362 } else if (parent is FunctionExpression) {
3363 return parent.body;
3364 } else if (parent is MethodDeclaration) {
3365 return parent.body;
3366 }
3367 parent = parent.parent;
3368 }
3369 return null;
3370 }
3371
3372 /**
3373 * If the given [node] has a documentation comment, remember its range
3374 * into the given [element].
3375 */
3376 void _setDocRange(ElementImpl element, AnnotatedNode node) {
3377 Comment comment = node.documentationComment;
3378 if (comment != null && comment.isDocumentation) {
3379 element.setDocRange(comment.offset, comment.length);
3380 }
3381 }
3382
3383 /**
3384 * Sets the visible source range for formal parameter.
3385 */
3386 void _setParameterVisibleRange(
3387 FormalParameter node, ParameterElementImpl element) {
3388 FunctionBody body = _getFunctionBody(node);
3389 if (body != null) {
3390 element.setVisibleRange(body.offset, body.length);
3391 }
3392 }
3393
3394 /**
3395 * Make the given holder be the current holder while visiting the given node.
3396 *
3397 * @param holder the holder that will gather elements that are built while vis iting the children
3398 * @param node the node to be visited
3399 */
3400 void _visit(ElementHolder holder, AstNode node) {
3401 if (node != null) {
3402 ElementHolder previousHolder = _currentHolder;
3403 _currentHolder = holder;
3404 try {
3405 node.accept(this);
3406 } finally {
3407 _currentHolder = previousHolder;
3408 }
3409 }
3410 }
3411
3412 /**
3413 * Make the given holder be the current holder while visiting the children of the given node.
3414 *
3415 * @param holder the holder that will gather elements that are built while vis iting the children
3416 * @param node the node whose children are to be visited
3417 */
3418 void _visitChildren(ElementHolder holder, AstNode node) {
3419 if (node != null) {
3420 ElementHolder previousHolder = _currentHolder;
3421 _currentHolder = holder;
3422 try {
3423 node.visitChildren(this);
3424 } finally {
3425 _currentHolder = previousHolder;
3426 }
3427 }
3428 } 2966 }
3429 } 2967 }
3430 2968
3431 /** 2969 /**
3432 * Instances of the class `ElementHolder` hold on to elements created while trav ersing an AST 2970 * Instances of the class `ElementHolder` hold on to elements created while trav ersing an AST
3433 * structure so that they can be accessed when creating their enclosing element. 2971 * structure so that they can be accessed when creating their enclosing element.
3434 */ 2972 */
3435 class ElementHolder { 2973 class ElementHolder {
3436 List<PropertyAccessorElement> _accessors; 2974 List<PropertyAccessorElement> _accessors;
3437 2975
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
3668 _typeAliases.add(element); 3206 _typeAliases.add(element);
3669 } 3207 }
3670 3208
3671 void addTypeParameter(TypeParameterElement element) { 3209 void addTypeParameter(TypeParameterElement element) {
3672 if (_typeParameters == null) { 3210 if (_typeParameters == null) {
3673 _typeParameters = new List<TypeParameterElement>(); 3211 _typeParameters = new List<TypeParameterElement>();
3674 } 3212 }
3675 _typeParameters.add(element); 3213 _typeParameters.add(element);
3676 } 3214 }
3677 3215
3678 FieldElement getField(String fieldName) { 3216 FieldElement getField(String fieldName, {bool synthetic: false}) {
3679 if (_fields == null) { 3217 if (_fields == null) {
3680 return null; 3218 return null;
3681 } 3219 }
3682 for (FieldElement field in _fields) { 3220 int length = _fields.length;
3683 if (field.name == fieldName) { 3221 for (int i = 0; i < length; i++) {
3222 FieldElement field = _fields[i];
3223 if (field.name == fieldName && field.isSynthetic == synthetic) {
3684 return field; 3224 return field;
3685 } 3225 }
3686 } 3226 }
3687 return null; 3227 return null;
3688 } 3228 }
3689 3229
3690 TopLevelVariableElement getTopLevelVariable(String variableName) { 3230 TopLevelVariableElement getTopLevelVariable(String variableName) {
3691 if (_topLevelVariables == null) { 3231 if (_topLevelVariables == null) {
3692 return null; 3232 return null;
3693 } 3233 }
3694 for (TopLevelVariableElement variable in _topLevelVariables) { 3234 int length = _topLevelVariables.length;
3235 for (int i = 0; i < length; i++) {
3236 TopLevelVariableElement variable = _topLevelVariables[i];
3695 if (variable.name == variableName) { 3237 if (variable.name == variableName) {
3696 return variable; 3238 return variable;
3697 } 3239 }
3698 } 3240 }
3699 return null; 3241 return null;
3700 } 3242 }
3701 3243
3702 void validate() { 3244 void validate() {
3703 StringBuffer buffer = new StringBuffer(); 3245 StringBuffer buffer = new StringBuffer();
3704 if (_accessors != null) { 3246 if (_accessors != null) {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
3782 buffer.write(_typeParameters.length); 3324 buffer.write(_typeParameters.length);
3783 buffer.write(" type parameters"); 3325 buffer.write(" type parameters");
3784 } 3326 }
3785 if (buffer.length > 0) { 3327 if (buffer.length > 0) {
3786 AnalysisEngine.instance.logger 3328 AnalysisEngine.instance.logger
3787 .logError("Failed to capture elements: $buffer"); 3329 .logError("Failed to capture elements: $buffer");
3788 } 3330 }
3789 } 3331 }
3790 } 3332 }
3791 3333
3792 /** 3334 class ElementMismatchException extends AnalysisException {
3793 * Instances of the class `EnclosedScope` implement a scope that is lexically en closed in
3794 * another scope.
3795 */
3796 class EnclosedScope extends Scope {
3797 /** 3335 /**
3798 * The scope in which this scope is lexically enclosed. 3336 * Initialize a newly created exception to have the given [message] and
3337 * [cause].
3799 */ 3338 */
3800 final Scope enclosingScope; 3339 ElementMismatchException(String message, [CaughtException cause = null])
3801 3340 : super(message, cause);
3802 /**
3803 * A table mapping names that will be defined in this scope, but right now are not initialized.
3804 * According to the scoping rules these names are hidden, even if they were de fined in an outer
3805 * scope.
3806 */
3807 HashMap<String, Element> _hiddenElements = new HashMap<String, Element>();
3808
3809 /**
3810 * A flag indicating whether there are any names defined in this scope.
3811 */
3812 bool _hasHiddenName = false;
3813
3814 /**
3815 * Initialize a newly created scope enclosed within another scope.
3816 *
3817 * @param enclosingScope the scope in which this scope is lexically enclosed
3818 */
3819 EnclosedScope(this.enclosingScope);
3820
3821 @override
3822 AnalysisErrorListener get errorListener => enclosingScope.errorListener;
3823
3824 /**
3825 * Record that given element is declared in this scope, but hasn't been initia lized yet, so it is
3826 * error to use. If there is already an element with the given name defined in an outer scope,
3827 * then it will become unavailable.
3828 *
3829 * @param element the element declared, but not initialized in this scope
3830 */
3831 void hide(Element element) {
3832 if (element != null) {
3833 String name = element.name;
3834 if (name != null && !name.isEmpty) {
3835 _hiddenElements[name] = element;
3836 _hasHiddenName = true;
3837 }
3838 }
3839 }
3840
3841 @override
3842 Element internalLookup(
3843 Identifier identifier, String name, LibraryElement referencingLibrary) {
3844 Element element = localLookup(name, referencingLibrary);
3845 if (element != null) {
3846 return element;
3847 }
3848 // May be there is a hidden Element.
3849 if (_hasHiddenName) {
3850 Element hiddenElement = _hiddenElements[name];
3851 if (hiddenElement != null) {
3852 errorListener.onError(new AnalysisError(
3853 getSource(identifier),
3854 identifier.offset,
3855 identifier.length,
3856 CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, []));
3857 return hiddenElement;
3858 }
3859 }
3860 // Check enclosing scope.
3861 return enclosingScope.internalLookup(identifier, name, referencingLibrary);
3862 }
3863 } 3341 }
3864 3342
3865 /** 3343 /**
3866 * Instances of the class `EnumMemberBuilder` build the members in enum declarat ions. 3344 * Instances of the class `EnumMemberBuilder` build the members in enum declarat ions.
3867 */ 3345 */
3868 class EnumMemberBuilder extends RecursiveAstVisitor<Object> { 3346 class EnumMemberBuilder extends RecursiveAstVisitor<Object> {
3869 /** 3347 /**
3870 * The type provider used to access the types needed to build an element model for enum 3348 * The type provider used to access the types needed to build an element model for enum
3871 * declarations. 3349 * declarations.
3872 */ 3350 */
3873 final TypeProvider _typeProvider; 3351 final TypeProvider _typeProvider;
3874 3352
3875 /** 3353 /**
3876 * Initialize a newly created enum member builder. 3354 * Initialize a newly created enum member builder.
3877 * 3355 *
3878 * @param typeProvider the type provider used to access the types needed to bu ild an element model 3356 * @param typeProvider the type provider used to access the types needed to bu ild an element model
3879 * for enum declarations 3357 * for enum declarations
3880 */ 3358 */
3881 EnumMemberBuilder(this._typeProvider); 3359 EnumMemberBuilder(this._typeProvider);
3882 3360
3883 @override 3361 @override
3884 Object visitEnumDeclaration(EnumDeclaration node) { 3362 Object visitEnumDeclaration(EnumDeclaration node) {
3885 // 3363 //
3886 // Finish building the enum. 3364 // Finish building the enum.
3887 // 3365 //
3888 ClassElementImpl enumElement = node.name.staticElement as ClassElementImpl; 3366 EnumElementImpl enumElement = node.name.staticElement as EnumElementImpl;
3889 InterfaceType enumType = enumElement.type; 3367 InterfaceType enumType = enumElement.type;
3890 enumElement.supertype = _typeProvider.objectType;
3891 // 3368 //
3892 // Populate the fields. 3369 // Populate the fields.
3893 // 3370 //
3894 List<FieldElement> fields = new List<FieldElement>(); 3371 List<FieldElement> fields = new List<FieldElement>();
3895 List<PropertyAccessorElement> getters = new List<PropertyAccessorElement>(); 3372 List<PropertyAccessorElement> getters = new List<PropertyAccessorElement>();
3896 InterfaceType intType = _typeProvider.intType; 3373 InterfaceType intType = _typeProvider.intType;
3897 String indexFieldName = "index"; 3374 String indexFieldName = "index";
3898 FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1); 3375 FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1);
3899 indexField.final2 = true; 3376 indexField.final2 = true;
3900 indexField.synthetic = true; 3377 indexField.synthetic = true;
3901 indexField.type = intType; 3378 indexField.type = intType;
3902 fields.add(indexField); 3379 fields.add(indexField);
3903 getters.add(_createGetter(indexField)); 3380 getters.add(_createGetter(indexField));
3904 ConstFieldElementImpl valuesField = new ConstFieldElementImpl("values", -1); 3381 ConstFieldElementImpl valuesField = new ConstFieldElementImpl("values", -1);
3905 valuesField.static = true; 3382 valuesField.static = true;
3906 valuesField.const3 = true; 3383 valuesField.const3 = true;
3907 valuesField.synthetic = true; 3384 valuesField.synthetic = true;
3908 valuesField.type = _typeProvider.listType.substitute4(<DartType>[enumType]); 3385 valuesField.type = _typeProvider.listType.instantiate(<DartType>[enumType]);
3909 fields.add(valuesField); 3386 fields.add(valuesField);
3910 getters.add(_createGetter(valuesField)); 3387 getters.add(_createGetter(valuesField));
3911 // 3388 //
3912 // Build the enum constants. 3389 // Build the enum constants.
3913 // 3390 //
3914 NodeList<EnumConstantDeclaration> constants = node.constants; 3391 NodeList<EnumConstantDeclaration> constants = node.constants;
3915 List<DartObjectImpl> constantValues = new List<DartObjectImpl>(); 3392 List<DartObjectImpl> constantValues = new List<DartObjectImpl>();
3916 int constantCount = constants.length; 3393 int constantCount = constants.length;
3917 for (int i = 0; i < constantCount; i++) { 3394 for (int i = 0; i < constantCount; i++) {
3918 SimpleIdentifier constantName = constants[i].name; 3395 EnumConstantDeclaration constant = constants[i];
3919 FieldElementImpl constantField = 3396 FieldElementImpl constantField = constant.name.staticElement;
3920 new ConstFieldElementImpl.forNode(constantName);
3921 constantField.static = true;
3922 constantField.const3 = true;
3923 constantField.type = enumType;
3924 // 3397 //
3925 // Create a value for the constant. 3398 // Create a value for the constant.
3926 // 3399 //
3927 HashMap<String, DartObjectImpl> fieldMap = 3400 HashMap<String, DartObjectImpl> fieldMap =
3928 new HashMap<String, DartObjectImpl>(); 3401 new HashMap<String, DartObjectImpl>();
3929 fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i)); 3402 fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i));
3930 DartObjectImpl value = 3403 DartObjectImpl value =
3931 new DartObjectImpl(enumType, new GenericState(fieldMap)); 3404 new DartObjectImpl(enumType, new GenericState(fieldMap));
3932 constantValues.add(value); 3405 constantValues.add(value);
3933 constantField.evaluationResult = new EvaluationResultImpl(value); 3406 constantField.evaluationResult = new EvaluationResultImpl(value);
3934 fields.add(constantField); 3407 fields.add(constantField);
3935 getters.add(_createGetter(constantField)); 3408 getters.add(constantField.getter);
3936 constantName.staticElement = constantField;
3937 } 3409 }
3938 // 3410 //
3939 // Build the value of the 'values' field. 3411 // Build the value of the 'values' field.
3940 // 3412 //
3941 valuesField.evaluationResult = new EvaluationResultImpl( 3413 valuesField.evaluationResult = new EvaluationResultImpl(
3942 new DartObjectImpl(valuesField.type, new ListState(constantValues))); 3414 new DartObjectImpl(valuesField.type, new ListState(constantValues)));
3943 // 3415 //
3944 // Finish building the enum. 3416 // Finish building the enum.
3945 // 3417 //
3946 enumElement.fields = fields; 3418 enumElement.fields = fields;
3947 enumElement.accessors = getters; 3419 enumElement.accessors = getters;
3948 // Client code isn't allowed to invoke the constructor, so we do not model 3420 // Client code isn't allowed to invoke the constructor, so we do not model
3949 // it. 3421 // it.
3950 return super.visitEnumDeclaration(node); 3422 return super.visitEnumDeclaration(node);
3951 } 3423 }
3952 3424
3953 /** 3425 /**
3954 * Create a getter that corresponds to the given field. 3426 * Create a getter that corresponds to the given [field].
3955 *
3956 * @param field the field for which a getter is to be created
3957 * @return the getter that was created
3958 */ 3427 */
3959 PropertyAccessorElement _createGetter(FieldElementImpl field) { 3428 PropertyAccessorElement _createGetter(FieldElementImpl field) {
3960 PropertyAccessorElementImpl getter = 3429 return new PropertyAccessorElementImpl_ImplicitGetter(field);
3961 new PropertyAccessorElementImpl.forVariable(field);
3962 getter.getter = true;
3963 getter.returnType = field.type;
3964 getter.type = new FunctionTypeImpl(getter);
3965 field.getter = getter;
3966 return getter;
3967 } 3430 }
3968 } 3431 }
3969 3432
3433 /**
3434 * A mixin for classes that use an existing element model to resolve a portion
3435 * of an AST structure.
3436 */
3437 class ExistingElementResolver {
3438 /**
3439 * The compilation unit containing the AST nodes being visited.
3440 */
3441 CompilationUnitElementImpl _enclosingUnit;
3442
3443 /**
3444 * Throw an [ElementMismatchException] to report that the element model and th e
3445 * AST do not match. The [message] will have the path to the given [node]
3446 * appended to it.
3447 */
3448 void _mismatch(String message, AstNode node) {
3449 StringBuffer buffer = new StringBuffer();
3450 buffer.write('Mismatch in ');
3451 buffer.write(runtimeType);
3452 buffer.write(' while resolving ');
3453 buffer.writeln(_enclosingUnit?.source?.fullName);
3454 buffer.writeln(message);
3455 buffer.write('Path to root:');
3456 String separator = ' ';
3457 AstNode parent = node;
3458 while (parent != null) {
3459 buffer.write(separator);
3460 buffer.write(parent.runtimeType.toString());
3461 separator = ', ';
3462 parent = parent.parent;
3463 }
3464 throw new ElementMismatchException(buffer.toString());
3465 }
3466 }
3467
3970 /** 3468 /**
3971 * Instances of the class `ExitDetector` determine whether the visited AST node is guaranteed 3469 * Instances of the class `ExitDetector` determine whether the visited AST node is guaranteed
3972 * to terminate by executing a `return` statement, `throw` expression, `rethrow` 3470 * to terminate by executing a `return` statement, `throw` expression, `rethrow`
3973 * expression, or simple infinite loop such as `while(true)`. 3471 * expression, or simple infinite loop such as `while(true)`.
3974 */ 3472 */
3975 class ExitDetector extends GeneralizingAstVisitor<bool> { 3473 class ExitDetector extends GeneralizingAstVisitor<bool> {
3976 /** 3474 /**
3977 * Set to `true` when a `break` is encountered, and reset to `false` when a 3475 * Set to `true` when a `break` is encountered, and reset to `false` when a
3978 * `do`, `while`, `for` or `switch` block is entered. 3476 * `do`, `while`, `for` or `switch` block is entered.
3979 */ 3477 */
3980 bool _enclosingBlockContainsBreak = false; 3478 bool _enclosingBlockContainsBreak = false;
3981 3479
3480 /**
3481 * Set to `true` when a `continue` is encountered, and reset to `false` when a
3482 * `do`, `while`, `for` or `switch` block is entered.
3483 */
3484 bool _enclosingBlockContainsContinue = false;
3485
3486 /**
3487 * Add node when a labelled `break` is encountered.
3488 */
3489 Set<AstNode> _enclosingBlockBreaksLabel = new Set<AstNode>();
3490
3982 @override 3491 @override
3983 bool visitArgumentList(ArgumentList node) => 3492 bool visitArgumentList(ArgumentList node) =>
3984 _visitExpressions(node.arguments); 3493 _visitExpressions(node.arguments);
3985 3494
3986 @override 3495 @override
3987 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression); 3496 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression);
3988 3497
3989 @override 3498 @override
3990 bool visitAssertStatement(AssertStatement node) => false; 3499 bool visitAssertStatement(AssertStatement node) => false;
3991 3500
3992 @override 3501 @override
3993 bool visitAssignmentExpression(AssignmentExpression node) { 3502 bool visitAssignmentExpression(AssignmentExpression node) {
3994 Expression leftHandSide = node.leftHandSide; 3503 Expression leftHandSide = node.leftHandSide;
3995 if (_nodeExits(leftHandSide)) { 3504 if (_nodeExits(leftHandSide)) {
3996 return true; 3505 return true;
3997 } 3506 }
3998 if (node.operator.type == sc.TokenType.QUESTION_QUESTION_EQ) { 3507 TokenType operatorType = node.operator.type;
3508 if (operatorType == TokenType.AMPERSAND_AMPERSAND_EQ ||
3509 operatorType == TokenType.BAR_BAR_EQ ||
3510 operatorType == TokenType.QUESTION_QUESTION_EQ) {
3999 return false; 3511 return false;
4000 } 3512 }
4001 if (leftHandSide is PropertyAccess && 3513 if (leftHandSide is PropertyAccess &&
4002 leftHandSide.operator.type == sc.TokenType.QUESTION_PERIOD) { 3514 leftHandSide.operator.type == TokenType.QUESTION_PERIOD) {
4003 return false; 3515 return false;
4004 } 3516 }
4005 return _nodeExits(node.rightHandSide); 3517 return _nodeExits(node.rightHandSide);
4006 } 3518 }
4007 3519
4008 @override 3520 @override
4009 bool visitAwaitExpression(AwaitExpression node) => 3521 bool visitAwaitExpression(AwaitExpression node) =>
4010 _nodeExits(node.expression); 3522 _nodeExits(node.expression);
4011 3523
4012 @override 3524 @override
4013 bool visitBinaryExpression(BinaryExpression node) { 3525 bool visitBinaryExpression(BinaryExpression node) {
4014 Expression lhsExpression = node.leftOperand; 3526 Expression lhsExpression = node.leftOperand;
4015 Expression rhsExpression = node.rightOperand; 3527 Expression rhsExpression = node.rightOperand;
4016 sc.TokenType operatorType = node.operator.type; 3528 TokenType operatorType = node.operator.type;
4017 // If the operator is ||, then only consider the RHS of the binary 3529 // If the operator is ||, then only consider the RHS of the binary
4018 // expression if the left hand side is the false literal. 3530 // expression if the left hand side is the false literal.
4019 // TODO(jwren) Do we want to take constant expressions into account, 3531 // TODO(jwren) Do we want to take constant expressions into account,
4020 // evaluate if(false) {} differently than if(<condition>), when <condition> 3532 // evaluate if(false) {} differently than if(<condition>), when <condition>
4021 // evaluates to a constant false value? 3533 // evaluates to a constant false value?
4022 if (operatorType == sc.TokenType.BAR_BAR) { 3534 if (operatorType == TokenType.BAR_BAR) {
4023 if (lhsExpression is BooleanLiteral) { 3535 if (lhsExpression is BooleanLiteral) {
4024 BooleanLiteral booleanLiteral = lhsExpression; 3536 if (!lhsExpression.value) {
4025 if (!booleanLiteral.value) {
4026 return _nodeExits(rhsExpression); 3537 return _nodeExits(rhsExpression);
4027 } 3538 }
4028 } 3539 }
4029 return _nodeExits(lhsExpression); 3540 return _nodeExits(lhsExpression);
4030 } 3541 }
4031 // If the operator is &&, then only consider the RHS of the binary 3542 // If the operator is &&, then only consider the RHS of the binary
4032 // expression if the left hand side is the true literal. 3543 // expression if the left hand side is the true literal.
4033 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) { 3544 if (operatorType == TokenType.AMPERSAND_AMPERSAND) {
4034 if (lhsExpression is BooleanLiteral) { 3545 if (lhsExpression is BooleanLiteral) {
4035 BooleanLiteral booleanLiteral = lhsExpression; 3546 if (lhsExpression.value) {
4036 if (booleanLiteral.value) {
4037 return _nodeExits(rhsExpression); 3547 return _nodeExits(rhsExpression);
4038 } 3548 }
4039 } 3549 }
4040 return _nodeExits(lhsExpression); 3550 return _nodeExits(lhsExpression);
4041 } 3551 }
4042 // If the operator is ??, then don't consider the RHS of the binary 3552 // If the operator is ??, then don't consider the RHS of the binary
4043 // expression. 3553 // expression.
4044 if (operatorType == sc.TokenType.QUESTION_QUESTION) { 3554 if (operatorType == TokenType.QUESTION_QUESTION) {
4045 return _nodeExits(lhsExpression); 3555 return _nodeExits(lhsExpression);
4046 } 3556 }
4047 return _nodeExits(lhsExpression) || _nodeExits(rhsExpression); 3557 return _nodeExits(lhsExpression) || _nodeExits(rhsExpression);
4048 } 3558 }
4049 3559
4050 @override 3560 @override
4051 bool visitBlock(Block node) => _visitStatements(node.statements); 3561 bool visitBlock(Block node) => _visitStatements(node.statements);
4052 3562
4053 @override 3563 @override
4054 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block); 3564 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block);
4055 3565
4056 @override 3566 @override
4057 bool visitBreakStatement(BreakStatement node) { 3567 bool visitBreakStatement(BreakStatement node) {
4058 _enclosingBlockContainsBreak = true; 3568 _enclosingBlockContainsBreak = true;
3569 if (node.label != null) {
3570 _enclosingBlockBreaksLabel.add(node.target);
3571 }
4059 return false; 3572 return false;
4060 } 3573 }
4061 3574
4062 @override 3575 @override
4063 bool visitCascadeExpression(CascadeExpression node) => 3576 bool visitCascadeExpression(CascadeExpression node) =>
4064 _nodeExits(node.target) || _visitExpressions(node.cascadeSections); 3577 _nodeExits(node.target) || _visitExpressions(node.cascadeSections);
4065 3578
4066 @override 3579 @override
4067 bool visitConditionalExpression(ConditionalExpression node) { 3580 bool visitConditionalExpression(ConditionalExpression node) {
4068 Expression conditionExpression = node.condition; 3581 Expression conditionExpression = node.condition;
4069 Expression thenStatement = node.thenExpression; 3582 Expression thenStatement = node.thenExpression;
4070 Expression elseStatement = node.elseExpression; 3583 Expression elseStatement = node.elseExpression;
4071 // TODO(jwren) Do we want to take constant expressions into account, 3584 // TODO(jwren) Do we want to take constant expressions into account,
4072 // evaluate if(false) {} differently than if(<condition>), when <condition> 3585 // evaluate if(false) {} differently than if(<condition>), when <condition>
4073 // evaluates to a constant false value? 3586 // evaluates to a constant false value?
4074 if (_nodeExits(conditionExpression)) { 3587 if (_nodeExits(conditionExpression)) {
4075 return true; 3588 return true;
4076 } 3589 }
4077 if (thenStatement == null || elseStatement == null) { 3590 if (thenStatement == null || elseStatement == null) {
4078 return false; 3591 return false;
4079 } 3592 }
4080 return thenStatement.accept(this) && elseStatement.accept(this); 3593 return thenStatement.accept(this) && elseStatement.accept(this);
4081 } 3594 }
4082 3595
4083 @override 3596 @override
4084 bool visitContinueStatement(ContinueStatement node) => false; 3597 bool visitContinueStatement(ContinueStatement node) {
3598 _enclosingBlockContainsContinue = true;
3599 return false;
3600 }
4085 3601
4086 @override 3602 @override
4087 bool visitDoStatement(DoStatement node) { 3603 bool visitDoStatement(DoStatement node) {
4088 bool outerBreakValue = _enclosingBlockContainsBreak; 3604 bool outerBreakValue = _enclosingBlockContainsBreak;
3605 bool outerContinueValue = _enclosingBlockContainsContinue;
4089 _enclosingBlockContainsBreak = false; 3606 _enclosingBlockContainsBreak = false;
3607 _enclosingBlockContainsContinue = false;
4090 try { 3608 try {
3609 bool bodyExits = _nodeExits(node.body);
3610 bool containsBreakOrContinue =
3611 _enclosingBlockContainsBreak || _enclosingBlockContainsContinue;
3612 // Even if we determine that the body "exits", there might be break or
3613 // continue statements that actually mean it _doesn't_ always exit.
3614 if (bodyExits && !containsBreakOrContinue) {
3615 return true;
3616 }
4091 Expression conditionExpression = node.condition; 3617 Expression conditionExpression = node.condition;
4092 if (_nodeExits(conditionExpression)) { 3618 if (_nodeExits(conditionExpression)) {
4093 return true; 3619 return true;
4094 } 3620 }
4095 // TODO(jwren) Do we want to take all constant expressions into account? 3621 // TODO(jwren) Do we want to take all constant expressions into account?
4096 if (conditionExpression is BooleanLiteral) { 3622 if (conditionExpression is BooleanLiteral) {
4097 BooleanLiteral booleanLiteral = conditionExpression; 3623 // If do {} while (true), and the body doesn't break, then return true.
4098 // If do {} while (true), and the body doesn't return or the body 3624 if (conditionExpression.value && !_enclosingBlockContainsBreak) {
4099 // doesn't have a break, then return true.
4100 bool blockReturns = _nodeExits(node.body);
4101 if (booleanLiteral.value &&
4102 (blockReturns || !_enclosingBlockContainsBreak)) {
4103 return true; 3625 return true;
4104 } 3626 }
4105 } 3627 }
4106 return false; 3628 return false;
4107 } finally { 3629 } finally {
4108 _enclosingBlockContainsBreak = outerBreakValue; 3630 _enclosingBlockContainsBreak = outerBreakValue;
3631 _enclosingBlockContainsContinue = outerContinueValue;
4109 } 3632 }
4110 } 3633 }
4111 3634
4112 @override 3635 @override
4113 bool visitEmptyStatement(EmptyStatement node) => false; 3636 bool visitEmptyStatement(EmptyStatement node) => false;
4114 3637
4115 @override 3638 @override
4116 bool visitExpressionStatement(ExpressionStatement node) => 3639 bool visitExpressionStatement(ExpressionStatement node) =>
4117 _nodeExits(node.expression); 3640 _nodeExits(node.expression);
4118 3641
(...skipping 20 matching lines...) Expand all
4139 if (node.initialization != null && _nodeExits(node.initialization)) { 3662 if (node.initialization != null && _nodeExits(node.initialization)) {
4140 return true; 3663 return true;
4141 } 3664 }
4142 Expression conditionExpression = node.condition; 3665 Expression conditionExpression = node.condition;
4143 if (conditionExpression != null && _nodeExits(conditionExpression)) { 3666 if (conditionExpression != null && _nodeExits(conditionExpression)) {
4144 return true; 3667 return true;
4145 } 3668 }
4146 if (_visitExpressions(node.updaters)) { 3669 if (_visitExpressions(node.updaters)) {
4147 return true; 3670 return true;
4148 } 3671 }
3672 bool blockReturns = _nodeExits(node.body);
4149 // TODO(jwren) Do we want to take all constant expressions into account? 3673 // TODO(jwren) Do we want to take all constant expressions into account?
4150 // If for(; true; ) (or for(;;)), and the body doesn't return or the body 3674 // If for(; true; ) (or for(;;)), and the body doesn't return or the body
4151 // doesn't have a break, then return true. 3675 // doesn't have a break, then return true.
4152 bool implicitOrExplictTrue = conditionExpression == null || 3676 bool implicitOrExplictTrue = conditionExpression == null ||
4153 (conditionExpression is BooleanLiteral && conditionExpression.value); 3677 (conditionExpression is BooleanLiteral && conditionExpression.value);
4154 if (implicitOrExplictTrue) { 3678 if (implicitOrExplictTrue) {
4155 bool blockReturns = _nodeExits(node.body);
4156 if (blockReturns || !_enclosingBlockContainsBreak) { 3679 if (blockReturns || !_enclosingBlockContainsBreak) {
4157 return true; 3680 return true;
4158 } 3681 }
4159 } 3682 }
4160 return false; 3683 return false;
4161 } finally { 3684 } finally {
4162 _enclosingBlockContainsBreak = outerBreakValue; 3685 _enclosingBlockContainsBreak = outerBreakValue;
4163 } 3686 }
4164 } 3687 }
4165 3688
(...skipping 18 matching lines...) Expand all
4184 @override 3707 @override
4185 bool visitIfStatement(IfStatement node) { 3708 bool visitIfStatement(IfStatement node) {
4186 Expression conditionExpression = node.condition; 3709 Expression conditionExpression = node.condition;
4187 Statement thenStatement = node.thenStatement; 3710 Statement thenStatement = node.thenStatement;
4188 Statement elseStatement = node.elseStatement; 3711 Statement elseStatement = node.elseStatement;
4189 if (_nodeExits(conditionExpression)) { 3712 if (_nodeExits(conditionExpression)) {
4190 return true; 3713 return true;
4191 } 3714 }
4192 // TODO(jwren) Do we want to take all constant expressions into account? 3715 // TODO(jwren) Do we want to take all constant expressions into account?
4193 if (conditionExpression is BooleanLiteral) { 3716 if (conditionExpression is BooleanLiteral) {
4194 BooleanLiteral booleanLiteral = conditionExpression; 3717 if (conditionExpression.value) {
4195 if (booleanLiteral.value) { 3718 // if (true) ...
4196 // if(true) ...
4197 return _nodeExits(thenStatement); 3719 return _nodeExits(thenStatement);
4198 } else if (elseStatement != null) { 3720 } else if (elseStatement != null) {
4199 // if (false) ... 3721 // if (false) ...
4200 return _nodeExits(elseStatement); 3722 return _nodeExits(elseStatement);
4201 } 3723 }
4202 } 3724 }
3725 bool thenExits = _nodeExits(thenStatement);
3726 bool elseExits = _nodeExits(elseStatement);
4203 if (thenStatement == null || elseStatement == null) { 3727 if (thenStatement == null || elseStatement == null) {
4204 return false; 3728 return false;
4205 } 3729 }
4206 return _nodeExits(thenStatement) && _nodeExits(elseStatement); 3730 return thenExits && elseExits;
4207 } 3731 }
4208 3732
4209 @override 3733 @override
4210 bool visitIndexExpression(IndexExpression node) { 3734 bool visitIndexExpression(IndexExpression node) {
4211 Expression target = node.realTarget; 3735 Expression target = node.realTarget;
4212 if (_nodeExits(target)) { 3736 if (_nodeExits(target)) {
4213 return true; 3737 return true;
4214 } 3738 }
4215 if (_nodeExits(node.index)) { 3739 if (_nodeExits(node.index)) {
4216 return true; 3740 return true;
4217 } 3741 }
4218 return false; 3742 return false;
4219 } 3743 }
4220 3744
4221 @override 3745 @override
4222 bool visitInstanceCreationExpression(InstanceCreationExpression node) => 3746 bool visitInstanceCreationExpression(InstanceCreationExpression node) =>
4223 _nodeExits(node.argumentList); 3747 _nodeExits(node.argumentList);
4224 3748
4225 @override 3749 @override
4226 bool visitIsExpression(IsExpression node) => node.expression.accept(this); 3750 bool visitIsExpression(IsExpression node) => node.expression.accept(this);
4227 3751
4228 @override 3752 @override
4229 bool visitLabel(Label node) => false; 3753 bool visitLabel(Label node) => false;
4230 3754
4231 @override 3755 @override
4232 bool visitLabeledStatement(LabeledStatement node) => 3756 bool visitLabeledStatement(LabeledStatement node) {
4233 node.statement.accept(this); 3757 try {
3758 bool statementExits = _nodeExits(node.statement);
3759 bool neverBrokeFromLabel =
3760 !_enclosingBlockBreaksLabel.contains(node.statement);
3761 return statementExits && neverBrokeFromLabel;
3762 } finally {
3763 _enclosingBlockBreaksLabel.remove(node.statement);
3764 }
3765 }
4234 3766
4235 @override 3767 @override
4236 bool visitLiteral(Literal node) => false; 3768 bool visitLiteral(Literal node) => false;
4237 3769
4238 @override 3770 @override
4239 bool visitMethodInvocation(MethodInvocation node) { 3771 bool visitMethodInvocation(MethodInvocation node) {
4240 Expression target = node.realTarget; 3772 Expression target = node.realTarget;
4241 if (target != null) { 3773 if (target != null) {
4242 if (target.accept(this)) { 3774 if (target.accept(this)) {
4243 return true; 3775 return true;
4244 } 3776 }
4245 if (node.operator.type == sc.TokenType.QUESTION_PERIOD) { 3777 if (node.operator.type == TokenType.QUESTION_PERIOD) {
4246 return false; 3778 return false;
4247 } 3779 }
4248 } 3780 }
4249 return _nodeExits(node.argumentList); 3781 return _nodeExits(node.argumentList);
4250 } 3782 }
4251 3783
4252 @override 3784 @override
4253 bool visitNamedExpression(NamedExpression node) => 3785 bool visitNamedExpression(NamedExpression node) =>
4254 node.expression.accept(this); 3786 node.expression.accept(this);
4255 3787
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
4287 @override 3819 @override
4288 bool visitSwitchDefault(SwitchDefault node) => 3820 bool visitSwitchDefault(SwitchDefault node) =>
4289 _visitStatements(node.statements); 3821 _visitStatements(node.statements);
4290 3822
4291 @override 3823 @override
4292 bool visitSwitchStatement(SwitchStatement node) { 3824 bool visitSwitchStatement(SwitchStatement node) {
4293 bool outerBreakValue = _enclosingBlockContainsBreak; 3825 bool outerBreakValue = _enclosingBlockContainsBreak;
4294 _enclosingBlockContainsBreak = false; 3826 _enclosingBlockContainsBreak = false;
4295 try { 3827 try {
4296 bool hasDefault = false; 3828 bool hasDefault = false;
3829 bool hasNonExitingCase = false;
4297 List<SwitchMember> members = node.members; 3830 List<SwitchMember> members = node.members;
4298 for (int i = 0; i < members.length; i++) { 3831 for (int i = 0; i < members.length; i++) {
4299 SwitchMember switchMember = members[i]; 3832 SwitchMember switchMember = members[i];
4300 if (switchMember is SwitchDefault) { 3833 if (switchMember is SwitchDefault) {
4301 hasDefault = true; 3834 hasDefault = true;
4302 // If this is the last member and there are no statements, return 3835 // If this is the last member and there are no statements, then it
4303 // false 3836 // does not exit.
4304 if (switchMember.statements.isEmpty && i + 1 == members.length) { 3837 if (switchMember.statements.isEmpty && i + 1 == members.length) {
4305 return false; 3838 hasNonExitingCase = true;
3839 continue;
4306 } 3840 }
4307 } 3841 }
4308 // For switch members with no statements, don't visit the children, 3842 // For switch members with no statements, don't visit the children.
4309 // otherwise, return false if no return is found in the children 3843 // Otherwise, if there children statements don't exit, mark this as a
4310 // statements. 3844 // non-exiting case.
4311 if (!switchMember.statements.isEmpty && !switchMember.accept(this)) { 3845 if (!switchMember.statements.isEmpty && !switchMember.accept(this)) {
4312 return false; 3846 hasNonExitingCase = true;
4313 } 3847 }
4314 } 3848 }
4315 // All of the members exit, determine whether there are possible cases 3849 if (hasNonExitingCase) {
4316 // that are not caught by the members. 3850 return false;
4317 DartType type = node.expression == null ? null : node.expression.bestType;
4318 if (type is InterfaceType) {
4319 ClassElement element = type.element;
4320 if (element != null && element.isEnum) {
4321 // If some of the enum values are not covered, then a warning will
4322 // have already been generated, so there's no point in generating a
4323 // hint.
4324 return true;
4325 }
4326 } 3851 }
3852 // As all cases exit, return whether that list includes `default`.
4327 return hasDefault; 3853 return hasDefault;
4328 } finally { 3854 } finally {
4329 _enclosingBlockContainsBreak = outerBreakValue; 3855 _enclosingBlockContainsBreak = outerBreakValue;
4330 } 3856 }
4331 } 3857 }
4332 3858
4333 @override 3859 @override
4334 bool visitThisExpression(ThisExpression node) => false; 3860 bool visitThisExpression(ThisExpression node) => false;
4335 3861
4336 @override 3862 @override
4337 bool visitThrowExpression(ThrowExpression node) => true; 3863 bool visitThrowExpression(ThrowExpression node) => true;
4338 3864
4339 @override 3865 @override
4340 bool visitTryStatement(TryStatement node) { 3866 bool visitTryStatement(TryStatement node) {
4341 if (_nodeExits(node.body)) { 3867 if (_nodeExits(node.finallyBlock)) {
4342 return true; 3868 return true;
4343 } 3869 }
4344 Block finallyBlock = node.finallyBlock; 3870 if (!_nodeExits(node.body)) {
4345 if (_nodeExits(finallyBlock)) { 3871 return false;
4346 return true;
4347 } 3872 }
4348 return false; 3873 for (CatchClause c in node.catchClauses) {
3874 if (!_nodeExits(c.body)) {
3875 return false;
3876 }
3877 }
3878 return true;
4349 } 3879 }
4350 3880
4351 @override 3881 @override
4352 bool visitTypeName(TypeName node) => false; 3882 bool visitTypeName(TypeName node) => false;
4353 3883
4354 @override 3884 @override
4355 bool visitVariableDeclaration(VariableDeclaration node) { 3885 bool visitVariableDeclaration(VariableDeclaration node) {
4356 Expression initializer = node.initializer; 3886 Expression initializer = node.initializer;
4357 if (initializer != null) { 3887 if (initializer != null) {
4358 return initializer.accept(this); 3888 return initializer.accept(this);
(...skipping 18 matching lines...) Expand all
4377 3907
4378 @override 3908 @override
4379 bool visitWhileStatement(WhileStatement node) { 3909 bool visitWhileStatement(WhileStatement node) {
4380 bool outerBreakValue = _enclosingBlockContainsBreak; 3910 bool outerBreakValue = _enclosingBlockContainsBreak;
4381 _enclosingBlockContainsBreak = false; 3911 _enclosingBlockContainsBreak = false;
4382 try { 3912 try {
4383 Expression conditionExpression = node.condition; 3913 Expression conditionExpression = node.condition;
4384 if (conditionExpression.accept(this)) { 3914 if (conditionExpression.accept(this)) {
4385 return true; 3915 return true;
4386 } 3916 }
3917 node.body.accept(this);
4387 // TODO(jwren) Do we want to take all constant expressions into account? 3918 // TODO(jwren) Do we want to take all constant expressions into account?
4388 if (conditionExpression is BooleanLiteral) { 3919 if (conditionExpression is BooleanLiteral) {
4389 BooleanLiteral booleanLiteral = conditionExpression; 3920 // If while(true), and the body doesn't have a break, then return true.
4390 // If while(true), and the body doesn't return or the body doesn't have 3921 // The body might be found to exit, but if there are any break
4391 // a break, then return true. 3922 // statements, then it is a faulty finding. In other words:
4392 bool blockReturns = node.body.accept(this); 3923 //
4393 if (booleanLiteral.value && 3924 // * If the body exits, and does not contain a break statement, then
4394 (blockReturns || !_enclosingBlockContainsBreak)) { 3925 // it exits.
3926 // * If the body does not exit, and does not contain a break statement,
3927 // then it loops infinitely (also an exit).
3928 //
3929 // As both conditions forbid any break statements to be found, the logic
3930 // just boils down to checking [_enclosingBlockContainsBreak].
3931 if (conditionExpression.value && !_enclosingBlockContainsBreak) {
4395 return true; 3932 return true;
4396 } 3933 }
4397 } 3934 }
4398 return false; 3935 return false;
4399 } finally { 3936 } finally {
4400 _enclosingBlockContainsBreak = outerBreakValue; 3937 _enclosingBlockContainsBreak = outerBreakValue;
4401 } 3938 }
4402 } 3939 }
4403 3940
3941 @override
3942 bool visitYieldStatement(YieldStatement node) => _nodeExits(node.expression);
3943
4404 /** 3944 /**
4405 * Return `true` if the given node exits. 3945 * Return `true` if the given node exits.
4406 * 3946 *
4407 * @param node the node being tested 3947 * @param node the node being tested
4408 * @return `true` if the given node exits 3948 * @return `true` if the given node exits
4409 */ 3949 */
4410 bool _nodeExits(AstNode node) { 3950 bool _nodeExits(AstNode node) {
4411 if (node == null) { 3951 if (node == null) {
4412 return false; 3952 return false;
4413 } 3953 }
4414 return node.accept(this); 3954 return node.accept(this);
4415 } 3955 }
4416 3956
4417 bool _visitExpressions(NodeList<Expression> expressions) { 3957 bool _visitExpressions(NodeList<Expression> expressions) {
4418 for (int i = expressions.length - 1; i >= 0; i--) { 3958 for (int i = expressions.length - 1; i >= 0; i--) {
4419 if (expressions[i].accept(this)) { 3959 if (expressions[i].accept(this)) {
4420 return true; 3960 return true;
4421 } 3961 }
4422 } 3962 }
4423 return false; 3963 return false;
4424 } 3964 }
4425 3965
4426 bool _visitStatements(NodeList<Statement> statements) { 3966 bool _visitStatements(NodeList<Statement> statements) {
4427 for (int i = statements.length - 1; i >= 0; i--) { 3967 for (int i = 0; i < statements.length; i++) {
4428 if (statements[i].accept(this)) { 3968 if (statements[i].accept(this)) {
4429 return true; 3969 return true;
4430 } 3970 }
4431 } 3971 }
4432 return false; 3972 return false;
4433 } 3973 }
4434 3974
4435 bool _visitVariableDeclarations( 3975 bool _visitVariableDeclarations(
4436 NodeList<VariableDeclaration> variableDeclarations) { 3976 NodeList<VariableDeclaration> variableDeclarations) {
4437 for (int i = variableDeclarations.length - 1; i >= 0; i--) { 3977 for (int i = variableDeclarations.length - 1; i >= 0; i--) {
4438 if (variableDeclarations[i].accept(this)) { 3978 if (variableDeclarations[i].accept(this)) {
4439 return true; 3979 return true;
4440 } 3980 }
4441 } 3981 }
4442 return false; 3982 return false;
4443 } 3983 }
4444 3984
4445 /** 3985 /**
4446 * Return `true` if the given [node] exits. 3986 * Return `true` if the given [node] exits.
4447 */ 3987 */
4448 static bool exits(AstNode node) { 3988 static bool exits(AstNode node) {
4449 return new ExitDetector()._nodeExits(node); 3989 return new ExitDetector()._nodeExits(node);
4450 } 3990 }
4451 } 3991 }
4452 3992
4453 /** 3993 /**
4454 * The scope defined by a function.
4455 */
4456 class FunctionScope extends EnclosedScope {
4457 /**
4458 * The element representing the function that defines this scope.
4459 */
4460 final ExecutableElement _functionElement;
4461
4462 /**
4463 * A flag indicating whether the parameters have already been defined, used to
4464 * prevent the parameters from being defined multiple times.
4465 */
4466 bool _parametersDefined = false;
4467
4468 /**
4469 * Initialize a newly created scope enclosed within the [enclosingScope] that
4470 * represents the given [_functionElement].
4471 */
4472 FunctionScope(Scope enclosingScope, this._functionElement)
4473 : super(new EnclosedScope(new EnclosedScope(enclosingScope))) {
4474 if (_functionElement == null) {
4475 throw new IllegalArgumentException("function element cannot be null");
4476 }
4477 _defineTypeParameters();
4478 }
4479
4480 /**
4481 * Define the parameters for the given function in the scope that encloses
4482 * this function.
4483 */
4484 void defineParameters() {
4485 if (_parametersDefined) {
4486 return;
4487 }
4488 _parametersDefined = true;
4489 Scope parameterScope = enclosingScope;
4490 for (ParameterElement parameter in _functionElement.parameters) {
4491 if (!parameter.isInitializingFormal) {
4492 parameterScope.define(parameter);
4493 }
4494 }
4495 }
4496
4497 /**
4498 * Define the type parameters for the function.
4499 */
4500 void _defineTypeParameters() {
4501 Scope typeParameterScope = enclosingScope.enclosingScope;
4502 for (TypeParameterElement typeParameter
4503 in _functionElement.typeParameters) {
4504 typeParameterScope.define(typeParameter);
4505 }
4506 }
4507 }
4508
4509 /**
4510 * The scope defined by a function type alias.
4511 */
4512 class FunctionTypeScope extends EnclosedScope {
4513 final FunctionTypeAliasElement _typeElement;
4514
4515 bool _parametersDefined = false;
4516
4517 /**
4518 * Initialize a newly created scope enclosed within the [enclosingScope] that
4519 * represents the given [_typeElement].
4520 */
4521 FunctionTypeScope(Scope enclosingScope, this._typeElement)
4522 : super(new EnclosedScope(enclosingScope)) {
4523 _defineTypeParameters();
4524 }
4525
4526 /**
4527 * Define the parameters for the function type alias.
4528 */
4529 void defineParameters() {
4530 if (_parametersDefined) {
4531 return;
4532 }
4533 _parametersDefined = true;
4534 for (ParameterElement parameter in _typeElement.parameters) {
4535 define(parameter);
4536 }
4537 }
4538
4539 /**
4540 * Define the type parameters for the function type alias.
4541 */
4542 void _defineTypeParameters() {
4543 Scope typeParameterScope = enclosingScope;
4544 for (TypeParameterElement typeParameter in _typeElement.typeParameters) {
4545 typeParameterScope.define(typeParameter);
4546 }
4547 }
4548 }
4549
4550 /**
4551 * A visitor that visits ASTs and fills [UsedImportedElements]. 3994 * A visitor that visits ASTs and fills [UsedImportedElements].
4552 */ 3995 */
4553 class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor { 3996 class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
4554 final LibraryElement library; 3997 final LibraryElement library;
4555 final UsedImportedElements usedElements = new UsedImportedElements(); 3998 final UsedImportedElements usedElements = new UsedImportedElements();
4556 3999
4557 GatherUsedImportedElementsVisitor(this.library); 4000 GatherUsedImportedElementsVisitor(this.library);
4558 4001
4559 @override 4002 @override
4560 void visitExportDirective(ExportDirective node) { 4003 void visitExportDirective(ExportDirective node) {
4561 _visitMetadata(node.metadata); 4004 _visitDirective(node);
4562 } 4005 }
4563 4006
4564 @override 4007 @override
4565 void visitImportDirective(ImportDirective node) { 4008 void visitImportDirective(ImportDirective node) {
4566 _visitMetadata(node.metadata); 4009 _visitDirective(node);
4567 } 4010 }
4568 4011
4569 @override 4012 @override
4570 void visitLibraryDirective(LibraryDirective node) { 4013 void visitLibraryDirective(LibraryDirective node) {
4571 _visitMetadata(node.metadata); 4014 _visitDirective(node);
4572 }
4573
4574 @override
4575 void visitPrefixedIdentifier(PrefixedIdentifier node) {
4576 // If the prefixed identifier references some A.B, where A is a library
4577 // prefix, then we can lookup the associated ImportDirective in
4578 // prefixElementMap and remove it from the unusedImports list.
4579 SimpleIdentifier prefixIdentifier = node.prefix;
4580 Element element = prefixIdentifier.staticElement;
4581 if (element is PrefixElement) {
4582 usedElements.prefixes.add(element);
4583 return;
4584 }
4585 // Otherwise, pass the prefixed identifier element and name onto
4586 // visitIdentifier.
4587 _visitIdentifier(element, prefixIdentifier.name);
4588 } 4015 }
4589 4016
4590 @override 4017 @override
4591 void visitSimpleIdentifier(SimpleIdentifier node) { 4018 void visitSimpleIdentifier(SimpleIdentifier node) {
4592 _visitIdentifier(node.staticElement, node.name); 4019 _visitIdentifier(node, node.staticElement);
4593 } 4020 }
4594 4021
4595 void _visitIdentifier(Element element, String name) { 4022 /**
4023 * If the given [identifier] is prefixed with a [PrefixElement], fill the
4024 * corresponding `UsedImportedElements.prefixMap` entry and return `true`.
4025 */
4026 bool _recordPrefixMap(SimpleIdentifier identifier, Element element) {
4027 bool recordIfTargetIsPrefixElement(Expression target) {
4028 if (target is SimpleIdentifier && target.staticElement is PrefixElement) {
4029 List<Element> prefixedElements = usedElements.prefixMap
4030 .putIfAbsent(target.staticElement, () => <Element>[]);
4031 prefixedElements.add(element);
4032 return true;
4033 }
4034 return false;
4035 }
4036
4037 AstNode parent = identifier.parent;
4038 if (parent is MethodInvocation && parent.methodName == identifier) {
4039 return recordIfTargetIsPrefixElement(parent.target);
4040 }
4041 if (parent is PrefixedIdentifier && parent.identifier == identifier) {
4042 return recordIfTargetIsPrefixElement(parent.prefix);
4043 }
4044 return false;
4045 }
4046
4047 /**
4048 * Visit identifiers used by the given [directive].
4049 */
4050 void _visitDirective(Directive directive) {
4051 directive.documentationComment?.accept(this);
4052 directive.metadata.accept(this);
4053 }
4054
4055 void _visitIdentifier(SimpleIdentifier identifier, Element element) {
4596 if (element == null) { 4056 if (element == null) {
4597 return; 4057 return;
4598 } 4058 }
4599 // If the element is multiply defined then call this method recursively for 4059 // If the element is multiply defined then call this method recursively for
4600 // each of the conflicting elements. 4060 // each of the conflicting elements.
4601 if (element is MultiplyDefinedElement) { 4061 if (element is MultiplyDefinedElement) {
4602 MultiplyDefinedElement multiplyDefinedElement = element; 4062 List<Element> conflictingElements = element.conflictingElements;
4603 for (Element elt in multiplyDefinedElement.conflictingElements) { 4063 int length = conflictingElements.length;
4604 _visitIdentifier(elt, name); 4064 for (int i = 0; i < length; i++) {
4065 Element elt = conflictingElements[i];
4066 _visitIdentifier(identifier, elt);
4605 } 4067 }
4606 return; 4068 return;
4607 } else if (element is PrefixElement) { 4069 }
4608 usedElements.prefixes.add(element); 4070
4071 // Record `importPrefix.identifier` into 'prefixMap'.
4072 if (_recordPrefixMap(identifier, element)) {
4073 return;
4074 }
4075
4076 if (element is PrefixElement) {
4077 usedElements.prefixMap.putIfAbsent(element, () => <Element>[]);
4609 return; 4078 return;
4610 } else if (element.enclosingElement is! CompilationUnitElement) { 4079 } else if (element.enclosingElement is! CompilationUnitElement) {
4611 // Identifiers that aren't a prefix element and whose enclosing element 4080 // Identifiers that aren't a prefix element and whose enclosing element
4612 // isn't a CompilationUnit are ignored- this covers the case the 4081 // isn't a CompilationUnit are ignored- this covers the case the
4613 // identifier is a relative-reference, a reference to an identifier not 4082 // identifier is a relative-reference, a reference to an identifier not
4614 // imported by this library. 4083 // imported by this library.
4615 return; 4084 return;
4616 } 4085 }
4617 // Ignore if an unknown library. 4086 // Ignore if an unknown library.
4618 LibraryElement containingLibrary = element.library; 4087 LibraryElement containingLibrary = element.library;
4619 if (containingLibrary == null) { 4088 if (containingLibrary == null) {
4620 return; 4089 return;
4621 } 4090 }
4622 // Ignore if a local element. 4091 // Ignore if a local element.
4623 if (library == containingLibrary) { 4092 if (library == containingLibrary) {
4624 return; 4093 return;
4625 } 4094 }
4626 // Remember the element. 4095 // Remember the element.
4627 usedElements.elements.add(element); 4096 usedElements.elements.add(element);
4628 } 4097 }
4629
4630 /**
4631 * Given some [NodeList] of [Annotation]s, ensure that the identifiers are vis ited by
4632 * this visitor. Specifically, this covers the cases where AST nodes don't hav e their identifiers
4633 * visited by this visitor, but still need their annotations visited.
4634 *
4635 * @param annotations the list of annotations to visit
4636 */
4637 void _visitMetadata(NodeList<Annotation> annotations) {
4638 int count = annotations.length;
4639 for (int i = 0; i < count; i++) {
4640 annotations[i].accept(this);
4641 }
4642 }
4643 } 4098 }
4644 4099
4645 /** 4100 /**
4646 * An [AstVisitor] that fills [UsedLocalElements]. 4101 * An [AstVisitor] that fills [UsedLocalElements].
4647 */ 4102 */
4648 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor { 4103 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor {
4649 final UsedLocalElements usedElements = new UsedLocalElements(); 4104 final UsedLocalElements usedElements = new UsedLocalElements();
4650 4105
4651 final LibraryElement _enclosingLibrary; 4106 final LibraryElement _enclosingLibrary;
4652 ClassElement _enclosingClass; 4107 ClassElement _enclosingClass;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
4757 return; 4212 return;
4758 } 4213 }
4759 // ignore places where the element is not actually used 4214 // ignore places where the element is not actually used
4760 if (node.parent is TypeName) { 4215 if (node.parent is TypeName) {
4761 if (element is ClassElement) { 4216 if (element is ClassElement) {
4762 AstNode parent2 = node.parent.parent; 4217 AstNode parent2 = node.parent.parent;
4763 if (parent2 is IsExpression) { 4218 if (parent2 is IsExpression) {
4764 return; 4219 return;
4765 } 4220 }
4766 if (parent2 is VariableDeclarationList) { 4221 if (parent2 is VariableDeclarationList) {
4767 return; 4222 // If it's a field's type, it still counts as used.
4223 if (parent2.parent is! FieldDeclaration) {
4224 return;
4225 }
4768 } 4226 }
4769 } 4227 }
4770 } 4228 }
4771 // OK 4229 // OK
4772 usedElements.addElement(element); 4230 usedElements.addElement(element);
4773 } 4231 }
4774 4232
4775 static bool _isReadIdentifier(SimpleIdentifier node) { 4233 static bool _isReadIdentifier(SimpleIdentifier node) {
4776 // not reading at all 4234 // not reading at all
4777 if (!node.inGetterContext()) { 4235 if (!node.inGetterContext()) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
4817 */ 4275 */
4818 InheritanceManager _manager; 4276 InheritanceManager _manager;
4819 4277
4820 GatherUsedLocalElementsVisitor _usedLocalElementsVisitor; 4278 GatherUsedLocalElementsVisitor _usedLocalElementsVisitor;
4821 4279
4822 HintGenerator(this._compilationUnits, this._context, this._errorListener) { 4280 HintGenerator(this._compilationUnits, this._context, this._errorListener) {
4823 _library = _compilationUnits[0].element.library; 4281 _library = _compilationUnits[0].element.library;
4824 _usedImportedElementsVisitor = 4282 _usedImportedElementsVisitor =
4825 new GatherUsedImportedElementsVisitor(_library); 4283 new GatherUsedImportedElementsVisitor(_library);
4826 _enableDart2JSHints = _context.analysisOptions.dart2jsHint; 4284 _enableDart2JSHints = _context.analysisOptions.dart2jsHint;
4827 _manager = new InheritanceManager(_compilationUnits[0].element.library); 4285 _manager =
4286 new InheritanceManager(_library, includeAbstractFromSuperclasses: true);
4828 _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library); 4287 _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library);
4829 } 4288 }
4830 4289
4831 void generateForLibrary() { 4290 void generateForLibrary() {
4832 PerformanceStatistics.hints.makeCurrentWhile(() { 4291 PerformanceStatistics.hints.makeCurrentWhile(() {
4833 for (CompilationUnit unit in _compilationUnits) { 4292 int length = _compilationUnits.length;
4293 for (int i = 0; i < length; i++) {
4294 CompilationUnit unit = _compilationUnits[i];
4834 CompilationUnitElement element = unit.element; 4295 CompilationUnitElement element = unit.element;
4835 if (element != null) { 4296 if (element != null) {
4836 _generateForCompilationUnit(unit, element.source); 4297 _generateForCompilationUnit(unit, element.source);
4837 } 4298 }
4838 } 4299 }
4839 CompilationUnit definingUnit = _compilationUnits[0]; 4300 CompilationUnit definingUnit = _compilationUnits[0];
4840 ErrorReporter definingUnitErrorReporter = 4301 ErrorReporter definingUnitErrorReporter =
4841 new ErrorReporter(_errorListener, definingUnit.element.source); 4302 new ErrorReporter(_errorListener, definingUnit.element.source);
4842 { 4303 {
4843 ImportsVerifier importsVerifier = new ImportsVerifier(); 4304 ImportsVerifier importsVerifier = new ImportsVerifier();
4844 importsVerifier.addImports(definingUnit); 4305 importsVerifier.addImports(definingUnit);
4845 importsVerifier 4306 importsVerifier
4846 .removeUsedElements(_usedImportedElementsVisitor.usedElements); 4307 .removeUsedElements(_usedImportedElementsVisitor.usedElements);
4847 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter); 4308 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter);
4848 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter); 4309 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter);
4310 importsVerifier.generateUnusedShownNameHints(definingUnitErrorReporter);
4849 } 4311 }
4850 _library.accept(new UnusedLocalElementsVerifier( 4312 _library.accept(new UnusedLocalElementsVerifier(
4851 _errorListener, _usedLocalElementsVisitor.usedElements)); 4313 _errorListener, _usedLocalElementsVisitor.usedElements));
4852 }); 4314 });
4853 } 4315 }
4854 4316
4855 void _generateForCompilationUnit(CompilationUnit unit, Source source) { 4317 void _generateForCompilationUnit(CompilationUnit unit, Source source) {
4856 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); 4318 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source);
4857 unit.accept(_usedImportedElementsVisitor); 4319 unit.accept(_usedImportedElementsVisitor);
4858 // dead code analysis 4320 // dead code analysis
4859 unit.accept( 4321 unit.accept(
4860 new DeadCodeVerifier(errorReporter, typeSystem: _context.typeSystem)); 4322 new DeadCodeVerifier(errorReporter, typeSystem: _context.typeSystem));
4861 unit.accept(_usedLocalElementsVisitor); 4323 unit.accept(_usedLocalElementsVisitor);
4862 // dart2js analysis 4324 // dart2js analysis
4863 if (_enableDart2JSHints) { 4325 if (_enableDart2JSHints) {
4864 unit.accept(new Dart2JSVerifier(errorReporter)); 4326 unit.accept(new Dart2JSVerifier(errorReporter));
4865 } 4327 }
4866 // Dart best practices 4328 // Dart best practices
4867 unit.accept(new BestPracticesVerifier(errorReporter, _context.typeProvider, 4329 unit.accept(new BestPracticesVerifier(
4330 errorReporter, _context.typeProvider, _library, _manager,
4868 typeSystem: _context.typeSystem)); 4331 typeSystem: _context.typeSystem));
4869 unit.accept(new OverrideVerifier(errorReporter, _manager)); 4332 unit.accept(new OverrideVerifier(errorReporter, _manager));
4870 // Find to-do comments 4333 // Find to-do comments
4871 new ToDoFinder(errorReporter).findIn(unit); 4334 new ToDoFinder(errorReporter).findIn(unit);
4872 // pub analysis 4335 // pub analysis
4873 // TODO(danrubel/jwren) Commented out until bugs in the pub verifier are 4336 // TODO(danrubel/jwren) Commented out until bugs in the pub verifier are
4874 // fixed 4337 // fixed
4875 // unit.accept(new PubVerifier(context, errorReporter)); 4338 // unit.accept(new PubVerifier(context, errorReporter));
4876 } 4339 }
4877 } 4340 }
4878 4341
4879 /** 4342 /**
4880 * Instances of the class {@code HtmlTagInfo} record information about the tags used in an HTML 4343 * Instances of the class `ImportsVerifier` visit all of the referenced librarie s in the source code
4881 * file. 4344 * verifying that all of the imports are used, otherwise a [HintCode.UNUSED_IMPO RT] hint is
4882 */ 4345 * generated with [generateUnusedImportHints].
4883 class HtmlTagInfo { 4346 *
4884 /** 4347 * Additionally, [generateDuplicateImportHints] generates [HintCode.DUPLICATE_IM PORT] hints and
4885 * An array containing all of the tags used in the HTML file. 4348 * [HintCode.UNUSED_SHOWN_NAME] hints.
4886 */
4887 List<String> allTags;
4888
4889 /**
4890 * A table mapping the id's defined in the HTML file to an array containing th e names of tags with
4891 * that identifier.
4892 */
4893 HashMap<String, String> idToTagMap;
4894
4895 /**
4896 * A table mapping the classes defined in the HTML file to an array containing the names of tags
4897 * with that class.
4898 */
4899 HashMap<String, List<String>> classToTagsMap;
4900
4901 /**
4902 * Initialize a newly created information holder to hold the given information about the tags in
4903 * an HTML file.
4904 *
4905 * @param allTags an array containing all of the tags used in the HTML file
4906 * @param idToTagMap a table mapping the id's defined in the HTML file to an a rray containing the
4907 * names of tags with that identifier
4908 * @param classToTagsMap a table mapping the classes defined in the HTML file to an array
4909 * containing the names of tags with that class
4910 */
4911 HtmlTagInfo(this.allTags, this.idToTagMap, this.classToTagsMap);
4912
4913 /**
4914 * Return an array containing the tags that have the given class, or {@code nu ll} if there are no
4915 * such tags.
4916 *
4917 * @return an array containing the tags that have the given class
4918 */
4919 List<String> getTagsWithClass(String identifier) {
4920 return classToTagsMap[identifier];
4921 }
4922
4923 /**
4924 * Return the tag that has the given identifier, or {@code null} if there is n o such tag (the
4925 * identifier is not defined).
4926 *
4927 * @return the tag that has the given identifier
4928 */
4929 String getTagWithId(String identifier) {
4930 return idToTagMap[identifier];
4931 }
4932 }
4933
4934 /**
4935 * Instances of the class {@code HtmlTagInfoBuilder} gather information about th e tags used in one
4936 * or more HTML structures.
4937 */
4938 class HtmlTagInfoBuilder implements ht.XmlVisitor {
4939 /**
4940 * The name of the 'id' attribute.
4941 */
4942 static final String ID_ATTRIBUTE = "id";
4943
4944 /**
4945 * The name of the 'class' attribute.
4946 */
4947 static final String ID_CLASS = "class";
4948
4949 /**
4950 * A set containing all of the tag names used in the HTML.
4951 */
4952 HashSet<String> tagSet = new HashSet<String>();
4953
4954 /**
4955 * A table mapping the id's that are defined to the tag name with that id.
4956 */
4957 HashMap<String, String> idMap = new HashMap<String, String>();
4958
4959 /**
4960 * A table mapping the classes that are defined to a set of the tag names with that class.
4961 */
4962 HashMap<String, HashSet<String>> classMap =
4963 new HashMap<String, HashSet<String>>();
4964
4965 /**
4966 * Initialize a newly created HTML tag info builder.
4967 */
4968 HtmlTagInfoBuilder();
4969
4970 /**
4971 * Create a tag information holder holding all of the information gathered abo ut the tags in the
4972 * HTML structures that were visited.
4973 *
4974 * @return the information gathered about the tags in the visited HTML structu res
4975 */
4976 HtmlTagInfo getTagInfo() {
4977 List<String> allTags = tagSet.toList();
4978 HashMap<String, List<String>> classToTagsMap =
4979 new HashMap<String, List<String>>();
4980 classMap.forEach((String key, Set<String> tags) {
4981 classToTagsMap[key] = tags.toList();
4982 });
4983 return new HtmlTagInfo(allTags, idMap, classToTagsMap);
4984 }
4985
4986 @override
4987 visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
4988 visitXmlTagNode(node);
4989 }
4990
4991 @override
4992 visitHtmlUnit(ht.HtmlUnit node) {
4993 node.visitChildren(this);
4994 }
4995
4996 @override
4997 visitXmlAttributeNode(ht.XmlAttributeNode node) {}
4998
4999 @override
5000 visitXmlTagNode(ht.XmlTagNode node) {
5001 node.visitChildren(this);
5002 String tagName = node.tag;
5003 tagSet.add(tagName);
5004 for (ht.XmlAttributeNode attribute in node.attributes) {
5005 String attributeName = attribute.name;
5006 if (attributeName == ID_ATTRIBUTE) {
5007 String attributeValue = attribute.text;
5008 if (attributeValue != null) {
5009 String tag = idMap[attributeValue];
5010 if (tag == null) {
5011 idMap[attributeValue] = tagName;
5012 } else {
5013 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken);
5014 }
5015 }
5016 } else if (attributeName == ID_CLASS) {
5017 String attributeValue = attribute.text;
5018 if (attributeValue != null) {
5019 HashSet<String> tagList = classMap[attributeValue];
5020 if (tagList == null) {
5021 tagList = new HashSet<String>();
5022 classMap[attributeValue] = tagList;
5023 } else {
5024 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken);
5025 }
5026 tagList.add(tagName);
5027 }
5028 }
5029 }
5030 }
5031
5032 // /**
5033 // * Report an error with the given error code at the given location. Use the given arguments to
5034 // * compose the error message.
5035 // *
5036 // * @param errorCode the error code of the error to be reported
5037 // * @param offset the offset of the first character to be highlighted
5038 // * @param length the number of characters to be highlighted
5039 // * @param arguments the arguments used to compose the error message
5040 // */
5041 // private void reportError(ErrorCode errorCode, Token token, Object... argumen ts) {
5042 // errorListener.onError(new AnalysisError(
5043 // htmlElement.getSource(),
5044 // token.getOffset(),
5045 // token.getLength(),
5046 // errorCode,
5047 // arguments));
5048 // }
5049 //
5050 // /**
5051 // * Report an error with the given error code at the given location. Use the given arguments to
5052 // * compose the error message.
5053 // *
5054 // * @param errorCode the error code of the error to be reported
5055 // * @param offset the offset of the first character to be highlighted
5056 // * @param length the number of characters to be highlighted
5057 // * @param arguments the arguments used to compose the error message
5058 // */
5059 // private void reportError(ErrorCode errorCode, int offset, int length, Object ... arguments) {
5060 // errorListener.onError(new AnalysisError(
5061 // htmlElement.getSource(),
5062 // offset,
5063 // length,
5064 // errorCode,
5065 // arguments));
5066 // }
5067 }
5068
5069 /**
5070 * Instances of the class `HtmlUnitBuilder` build an element model for a single HTML unit.
5071 */
5072 class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
5073 static String _SRC = "src";
5074
5075 /**
5076 * The analysis context in which the element model will be built.
5077 */
5078 final InternalAnalysisContext _context;
5079
5080 /**
5081 * The error listener to which errors will be reported.
5082 */
5083 RecordingErrorListener _errorListener;
5084
5085 /**
5086 * The HTML element being built.
5087 */
5088 HtmlElementImpl _htmlElement;
5089
5090 /**
5091 * The elements in the path from the HTML unit to the current tag node.
5092 */
5093 List<ht.XmlTagNode> _parentNodes;
5094
5095 /**
5096 * The script elements being built.
5097 */
5098 List<HtmlScriptElement> _scripts;
5099
5100 /**
5101 * A set of the libraries that were resolved while resolving the HTML unit.
5102 */
5103 Set<Library> _resolvedLibraries = new HashSet<Library>();
5104
5105 /**
5106 * Initialize a newly created HTML unit builder.
5107 *
5108 * @param context the analysis context in which the element model will be buil t
5109 */
5110 HtmlUnitBuilder(this._context) {
5111 this._errorListener = new RecordingErrorListener();
5112 }
5113
5114 /**
5115 * Return the listener to which analysis errors will be reported.
5116 *
5117 * @return the listener to which analysis errors will be reported
5118 */
5119 RecordingErrorListener get errorListener => _errorListener;
5120
5121 /**
5122 * Return an array containing information about all of the libraries that were resolved.
5123 *
5124 * @return an array containing the libraries that were resolved
5125 */
5126 Set<Library> get resolvedLibraries => _resolvedLibraries;
5127
5128 /**
5129 * Build the HTML element for the given source.
5130 *
5131 * @param source the source describing the compilation unit
5132 * @param unit the AST structure representing the HTML
5133 * @throws AnalysisException if the analysis could not be performed
5134 */
5135 HtmlElementImpl buildHtmlElement(Source source, ht.HtmlUnit unit) {
5136 HtmlElementImpl result = new HtmlElementImpl(_context, source.shortName);
5137 result.source = source;
5138 _htmlElement = result;
5139 unit.accept(this);
5140 _htmlElement = null;
5141 unit.element = result;
5142 return result;
5143 }
5144
5145 @override
5146 Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
5147 if (_parentNodes.contains(node)) {
5148 return _reportCircularity(node);
5149 }
5150 _parentNodes.add(node);
5151 try {
5152 Source htmlSource = _htmlElement.source;
5153 ht.XmlAttributeNode scriptAttribute = _getScriptSourcePath(node);
5154 String scriptSourcePath =
5155 scriptAttribute == null ? null : scriptAttribute.text;
5156 if (node.attributeEnd.type == ht.TokenType.GT &&
5157 scriptSourcePath == null) {
5158 EmbeddedHtmlScriptElementImpl script =
5159 new EmbeddedHtmlScriptElementImpl(node);
5160 try {
5161 LibraryResolver resolver = new LibraryResolver(_context);
5162 LibraryElementImpl library =
5163 resolver.resolveEmbeddedLibrary(htmlSource, node.script, true);
5164 script.scriptLibrary = library;
5165 _resolvedLibraries.addAll(resolver.resolvedLibraries);
5166 _errorListener.addAll(resolver.errorListener);
5167 } on AnalysisException catch (exception, stackTrace) {
5168 //TODO (danrubel): Handle or forward the exception
5169 AnalysisEngine.instance.logger.logError(
5170 "Could not resolve script tag",
5171 new CaughtException(exception, stackTrace));
5172 }
5173 node.scriptElement = script;
5174 _scripts.add(script);
5175 } else {
5176 ExternalHtmlScriptElementImpl script =
5177 new ExternalHtmlScriptElementImpl(node);
5178 if (scriptSourcePath != null) {
5179 try {
5180 scriptSourcePath = Uri.encodeFull(scriptSourcePath);
5181 // Force an exception to be thrown if the URI is invalid so that we
5182 // can report the problem.
5183 parseUriWithException(scriptSourcePath);
5184 Source scriptSource =
5185 _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
5186 script.scriptSource = scriptSource;
5187 if (!_context.exists(scriptSource)) {
5188 _reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST,
5189 scriptAttribute, [scriptSourcePath]);
5190 }
5191 } on URISyntaxException {
5192 _reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute,
5193 [scriptSourcePath]);
5194 }
5195 }
5196 node.scriptElement = script;
5197 _scripts.add(script);
5198 }
5199 } finally {
5200 _parentNodes.remove(node);
5201 }
5202 return null;
5203 }
5204
5205 @override
5206 Object visitHtmlUnit(ht.HtmlUnit node) {
5207 _parentNodes = new List<ht.XmlTagNode>();
5208 _scripts = new List<HtmlScriptElement>();
5209 try {
5210 node.visitChildren(this);
5211 _htmlElement.scripts = new List.from(_scripts);
5212 } finally {
5213 _scripts = null;
5214 _parentNodes = null;
5215 }
5216 return null;
5217 }
5218
5219 @override
5220 Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
5221
5222 @override
5223 Object visitXmlTagNode(ht.XmlTagNode node) {
5224 if (_parentNodes.contains(node)) {
5225 return _reportCircularity(node);
5226 }
5227 _parentNodes.add(node);
5228 try {
5229 node.visitChildren(this);
5230 } finally {
5231 _parentNodes.remove(node);
5232 }
5233 return null;
5234 }
5235
5236 /**
5237 * Return the first source attribute for the given tag node, or `null` if it d oes not exist.
5238 *
5239 * @param node the node containing attributes
5240 * @return the source attribute contained in the given tag
5241 */
5242 ht.XmlAttributeNode _getScriptSourcePath(ht.XmlTagNode node) {
5243 for (ht.XmlAttributeNode attribute in node.attributes) {
5244 if (attribute.name == _SRC) {
5245 return attribute;
5246 }
5247 }
5248 return null;
5249 }
5250
5251 Object _reportCircularity(ht.XmlTagNode node) {
5252 //
5253 // This should not be possible, but we have an error report that suggests
5254 // that it happened at least once. This code will guard against infinite
5255 // recursion and might help us identify the cause of the issue.
5256 //
5257 StringBuffer buffer = new StringBuffer();
5258 buffer.write("Found circularity in XML nodes: ");
5259 bool first = true;
5260 for (ht.XmlTagNode pathNode in _parentNodes) {
5261 if (first) {
5262 first = false;
5263 } else {
5264 buffer.write(", ");
5265 }
5266 String tagName = pathNode.tag;
5267 if (identical(pathNode, node)) {
5268 buffer.write("*");
5269 buffer.write(tagName);
5270 buffer.write("*");
5271 } else {
5272 buffer.write(tagName);
5273 }
5274 }
5275 AnalysisEngine.instance.logger.logError(buffer.toString());
5276 return null;
5277 }
5278
5279 /**
5280 * Report an error with the given error code at the given location. Use the gi ven arguments to
5281 * compose the error message.
5282 *
5283 * @param errorCode the error code of the error to be reported
5284 * @param offset the offset of the first character to be highlighted
5285 * @param length the number of characters to be highlighted
5286 * @param arguments the arguments used to compose the error message
5287 */
5288 void _reportErrorForOffset(
5289 ErrorCode errorCode, int offset, int length, List<Object> arguments) {
5290 _errorListener.onError(new AnalysisError(
5291 _htmlElement.source, offset, length, errorCode, arguments));
5292 }
5293
5294 /**
5295 * Report an error with the given error code at the location of the value of t he given attribute.
5296 * Use the given arguments to compose the error message.
5297 *
5298 * @param errorCode the error code of the error to be reported
5299 * @param offset the offset of the first character to be highlighted
5300 * @param length the number of characters to be highlighted
5301 * @param arguments the arguments used to compose the error message
5302 */
5303 void _reportValueError(ErrorCode errorCode, ht.XmlAttributeNode attribute,
5304 List<Object> arguments) {
5305 int offset = attribute.valueToken.offset + 1;
5306 int length = attribute.valueToken.length - 2;
5307 _reportErrorForOffset(errorCode, offset, length, arguments);
5308 }
5309 }
5310
5311 /**
5312 * Instances of the class `ImplicitLabelScope` represent the scope statements
5313 * that can be the target of unlabeled break and continue statements.
5314 */
5315 class ImplicitLabelScope {
5316 /**
5317 * The implicit label scope associated with the top level of a function.
5318 */
5319 static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null);
5320
5321 /**
5322 * The implicit label scope enclosing this implicit label scope.
5323 */
5324 final ImplicitLabelScope outerScope;
5325
5326 /**
5327 * The statement that acts as a target for break and/or continue statements
5328 * at this scoping level.
5329 */
5330 final Statement statement;
5331
5332 /**
5333 * Private constructor.
5334 */
5335 const ImplicitLabelScope._(this.outerScope, this.statement);
5336
5337 /**
5338 * Get the statement which should be the target of an unlabeled `break` or
5339 * `continue` statement, or `null` if there is no appropriate target.
5340 */
5341 Statement getTarget(bool isContinue) {
5342 if (outerScope == null) {
5343 // This scope represents the toplevel of a function body, so it doesn't
5344 // match either break or continue.
5345 return null;
5346 }
5347 if (isContinue && statement is SwitchStatement) {
5348 return outerScope.getTarget(isContinue);
5349 }
5350 return statement;
5351 }
5352
5353 /**
5354 * Initialize a newly created scope to represent a switch statement or loop
5355 * nested within the current scope. [statement] is the statement associated
5356 * with the newly created scope.
5357 */
5358 ImplicitLabelScope nest(Statement statement) =>
5359 new ImplicitLabelScope._(this, statement);
5360 }
5361
5362 /**
5363 * Instances of the class `ImportsVerifier` visit all of the referenced librarie s in the
5364 * source code verifying that all of the imports are used, otherwise a
5365 * [HintCode.UNUSED_IMPORT] is generated with
5366 * [generateUnusedImportHints].
5367 * 4349 *
5368 * While this class does not yet have support for an "Organize Imports" action, this logic built up 4350 * While this class does not yet have support for an "Organize Imports" action, this logic built up
5369 * in this class could be used for such an action in the future. 4351 * in this class could be used for such an action in the future.
5370 */ 4352 */
5371 class ImportsVerifier /*extends RecursiveAstVisitor<Object>*/ { 4353 class ImportsVerifier {
5372 /** 4354 /**
5373 * A list of [ImportDirective]s that the current library imports, as identifie rs are visited 4355 * A list of [ImportDirective]s that the current library imports, but does not use.
5374 * by this visitor and an import has been identified as being used by the libr ary, the 4356 *
5375 * [ImportDirective] is removed from this list. After all the sources in the l ibrary have 4357 * As identifiers are visited by this visitor and an import has been identifie d as being used
5376 * been evaluated, this list represents the set of unused imports. 4358 * by the library, the [ImportDirective] is removed from this list. After all the sources in the
4359 * library have been evaluated, this list represents the set of unused imports .
5377 * 4360 *
5378 * See [ImportsVerifier.generateUnusedImportErrors]. 4361 * See [ImportsVerifier.generateUnusedImportErrors].
5379 */ 4362 */
5380 final List<ImportDirective> _unusedImports = <ImportDirective>[]; 4363 final List<ImportDirective> _unusedImports = <ImportDirective>[];
5381 4364
5382 /** 4365 /**
5383 * After the list of [unusedImports] has been computed, this list is a proper subset of the 4366 * After the list of [unusedImports] has been computed, this list is a proper subset of the
5384 * unused imports that are listed more than once. 4367 * unused imports that are listed more than once.
5385 */ 4368 */
5386 final List<ImportDirective> _duplicateImports = <ImportDirective>[]; 4369 final List<ImportDirective> _duplicateImports = <ImportDirective>[];
5387 4370
5388 /** 4371 /**
5389 * This is a map between the set of [LibraryElement]s that the current library imports, and 4372 * This is a map between the set of [LibraryElement]s that the current library imports, and the
5390 * a list of [ImportDirective]s that imports the library. In cases where the c urrent library 4373 * list of [ImportDirective]s that import each [LibraryElement]. In cases wher e the current
5391 * imports a library with a single directive (such as `import lib1.dart;`), th e library 4374 * library imports a library with a single directive (such as `import lib1.dar t;`), the library
5392 * element will map to a list of one [ImportDirective], which will then be rem oved from the 4375 * element will map to a list of one [ImportDirective], which will then be rem oved from the
5393 * [unusedImports] list. In cases where the current library imports a library with multiple 4376 * [unusedImports] list. In cases where the current library imports a library with multiple
5394 * directives (such as `import lib1.dart; import lib1.dart show C;`), the 4377 * directives (such as `import lib1.dart; import lib1.dart show C;`), the [Lib raryElement] will
5395 * [LibraryElement] will be mapped to a list of the import directives, and the namespace 4378 * be mapped to a list of the import directives, and the namespace will need t o be used to
5396 * will need to be used to compute the correct [ImportDirective] being used, s ee 4379 * compute the correct [ImportDirective] being used; see [_namespaceMap].
5397 * [namespaceMap].
5398 */ 4380 */
5399 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap = 4381 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap =
5400 new HashMap<LibraryElement, List<ImportDirective>>(); 4382 new HashMap<LibraryElement, List<ImportDirective>>();
5401 4383
5402 /** 4384 /**
5403 * In cases where there is more than one import directive per library element, this mapping is 4385 * In cases where there is more than one import directive per library element, this mapping is
5404 * used to determine which of the multiple import directives are used by gener ating a 4386 * used to determine which of the multiple import directives are used by gener ating a
5405 * [Namespace] for each of the imports to do lookups in the same way that they are done from 4387 * [Namespace] for each of the imports to do lookups in the same way that they are done from
5406 * the [ElementResolver]. 4388 * the [ElementResolver].
5407 */ 4389 */
5408 final HashMap<ImportDirective, Namespace> _namespaceMap = 4390 final HashMap<ImportDirective, Namespace> _namespaceMap =
5409 new HashMap<ImportDirective, Namespace>(); 4391 new HashMap<ImportDirective, Namespace>();
5410 4392
5411 /** 4393 /**
5412 * This is a map between prefix elements and the import directives from which they are derived. In 4394 * This is a map between prefix elements and the import directives from which they are derived. In
5413 * cases where a type is referenced via a prefix element, the import directive can be marked as 4395 * cases where a type is referenced via a prefix element, the import directive can be marked as
5414 * used (removed from the unusedImports) by looking at the resolved `lib` in ` lib.X`, 4396 * used (removed from the unusedImports) by looking at the resolved `lib` in ` lib.X`,
5415 * instead of looking at which library the `lib.X` resolves. 4397 * instead of looking at which library the `lib.X` resolves.
5416 * 4398 *
5417 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl ement], 4399 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl ement],
5418 * it is possible to have an unreported unused import in situations where two imports use the same 4400 * it is possible to have an unreported unused import in situations where two imports use the same
5419 * prefix and at least one import directive is used. 4401 * prefix and at least one import directive is used.
5420 */ 4402 */
5421 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap = 4403 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap =
5422 new HashMap<PrefixElement, List<ImportDirective>>(); 4404 new HashMap<PrefixElement, List<ImportDirective>>();
5423 4405
4406 /**
4407 * A map of identifiers that the current library's imports show, but that the library does not
4408 * use.
4409 *
4410 * Each import directive maps to a list of the identifiers that are imported v ia the "show"
4411 * keyword.
4412 *
4413 * As each identifier is visited by this visitor, it is identified as being us ed by the library,
4414 * and the identifier is removed from this map (under the import that imported it). After all the
4415 * sources in the library have been evaluated, each list in this map's values present the set of
4416 * unused shown elements.
4417 *
4418 * See [ImportsVerifier.generateUnusedShownNameHints].
4419 */
4420 final HashMap<ImportDirective, List<SimpleIdentifier>> _unusedShownNamesMap =
4421 new HashMap<ImportDirective, List<SimpleIdentifier>>();
4422
5424 void addImports(CompilationUnit node) { 4423 void addImports(CompilationUnit node) {
5425 for (Directive directive in node.directives) { 4424 for (Directive directive in node.directives) {
5426 if (directive is ImportDirective) { 4425 if (directive is ImportDirective) {
5427 ImportDirective importDirective = directive; 4426 LibraryElement libraryElement = directive.uriElement;
5428 LibraryElement libraryElement = importDirective.uriElement; 4427 if (libraryElement == null) {
5429 if (libraryElement != null) { 4428 continue;
5430 _unusedImports.add(importDirective); 4429 }
5431 // 4430 _unusedImports.add(directive);
5432 // Initialize prefixElementMap 4431 //
5433 // 4432 // Initialize prefixElementMap
5434 if (importDirective.asKeyword != null) { 4433 //
5435 SimpleIdentifier prefixIdentifier = importDirective.prefix; 4434 if (directive.asKeyword != null) {
5436 if (prefixIdentifier != null) { 4435 SimpleIdentifier prefixIdentifier = directive.prefix;
5437 Element element = prefixIdentifier.staticElement; 4436 if (prefixIdentifier != null) {
5438 if (element is PrefixElement) { 4437 Element element = prefixIdentifier.staticElement;
5439 PrefixElement prefixElementKey = element; 4438 if (element is PrefixElement) {
5440 List<ImportDirective> list = 4439 List<ImportDirective> list = _prefixElementMap[element];
5441 _prefixElementMap[prefixElementKey]; 4440 if (list == null) {
5442 if (list == null) { 4441 list = new List<ImportDirective>();
5443 list = new List<ImportDirective>(); 4442 _prefixElementMap[element] = list;
5444 _prefixElementMap[prefixElementKey] = list;
5445 }
5446 list.add(importDirective);
5447 } 4443 }
5448 // TODO (jwren) Can the element ever not be a PrefixElement? 4444 list.add(directive);
5449 } 4445 }
4446 // TODO (jwren) Can the element ever not be a PrefixElement?
5450 } 4447 }
5451 // 4448 }
5452 // Initialize libraryMap: libraryElement -> importDirective 4449 //
5453 // 4450 // Initialize libraryMap: libraryElement -> importDirective
5454 _putIntoLibraryMap(libraryElement, importDirective); 4451 //
5455 // 4452 _putIntoLibraryMap(libraryElement, directive);
5456 // For this new addition to the libraryMap, also recursively add any 4453 //
5457 // exports from the libraryElement. 4454 // For this new addition to the libraryMap, also recursively add any
5458 // 4455 // exports from the libraryElement.
5459 _addAdditionalLibrariesForExports( 4456 //
5460 libraryElement, importDirective, new List<LibraryElement>()); 4457 _addAdditionalLibrariesForExports(
5461 } 4458 libraryElement, directive, new HashSet<LibraryElement>());
4459 _addShownNames(directive);
5462 } 4460 }
5463 } 4461 }
5464 if (_unusedImports.length > 1) { 4462 if (_unusedImports.length > 1) {
5465 // order the list of unusedImports to find duplicates in faster than 4463 // order the list of unusedImports to find duplicates in faster than
5466 // O(n^2) time 4464 // O(n^2) time
5467 List<ImportDirective> importDirectiveArray = 4465 List<ImportDirective> importDirectiveArray =
5468 new List<ImportDirective>.from(_unusedImports); 4466 new List<ImportDirective>.from(_unusedImports);
5469 importDirectiveArray.sort(ImportDirective.COMPARATOR); 4467 importDirectiveArray.sort(ImportDirective.COMPARATOR);
5470 ImportDirective currentDirective = importDirectiveArray[0]; 4468 ImportDirective currentDirective = importDirectiveArray[0];
5471 for (int i = 1; i < importDirectiveArray.length; i++) { 4469 for (int i = 1; i < importDirectiveArray.length; i++) {
(...skipping 15 matching lines...) Expand all
5487 4485
5488 /** 4486 /**
5489 * Any time after the defining compilation unit has been visited by this visit or, this method can 4487 * Any time after the defining compilation unit has been visited by this visit or, this method can
5490 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp ort directives 4488 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp ort directives
5491 * in the [duplicateImports] list. 4489 * in the [duplicateImports] list.
5492 * 4490 *
5493 * @param errorReporter the error reporter to report the set of [HintCode.DUPL ICATE_IMPORT] 4491 * @param errorReporter the error reporter to report the set of [HintCode.DUPL ICATE_IMPORT]
5494 * hints to 4492 * hints to
5495 */ 4493 */
5496 void generateDuplicateImportHints(ErrorReporter errorReporter) { 4494 void generateDuplicateImportHints(ErrorReporter errorReporter) {
5497 for (ImportDirective duplicateImport in _duplicateImports) { 4495 int length = _duplicateImports.length;
4496 for (int i = 0; i < length; i++) {
5498 errorReporter.reportErrorForNode( 4497 errorReporter.reportErrorForNode(
5499 HintCode.DUPLICATE_IMPORT, duplicateImport.uri); 4498 HintCode.DUPLICATE_IMPORT, _duplicateImports[i].uri);
5500 } 4499 }
5501 } 4500 }
5502 4501
5503 /** 4502 /**
5504 * After all of the compilation units have been visited by this visitor, this method can be called 4503 * Report an [HintCode.UNUSED_IMPORT] hint for each unused import.
5505 * to report an [HintCode.UNUSED_IMPORT] hint for each of the import directive s in the 4504 *
5506 * [unusedImports] list. 4505 * Only call this method after all of the compilation units have been visited by this visitor.
5507 * 4506 *
5508 * @param errorReporter the error reporter to report the set of [HintCode.UNUS ED_IMPORT] 4507 * @param errorReporter the error reporter used to report the set of [HintCode .UNUSED_IMPORT]
5509 * hints to 4508 * hints
5510 */ 4509 */
5511 void generateUnusedImportHints(ErrorReporter errorReporter) { 4510 void generateUnusedImportHints(ErrorReporter errorReporter) {
5512 for (ImportDirective unusedImport in _unusedImports) { 4511 int length = _unusedImports.length;
5513 // Check that the import isn't dart:core 4512 for (int i = 0; i < length; i++) {
4513 ImportDirective unusedImport = _unusedImports[i];
4514 // Check that the imported URI exists and isn't dart:core
5514 ImportElement importElement = unusedImport.element; 4515 ImportElement importElement = unusedImport.element;
5515 if (importElement != null) { 4516 if (importElement != null) {
5516 LibraryElement libraryElement = importElement.importedLibrary; 4517 LibraryElement libraryElement = importElement.importedLibrary;
5517 if (libraryElement != null && libraryElement.isDartCore) { 4518 if (libraryElement == null ||
4519 libraryElement.isDartCore ||
4520 libraryElement.isSynthetic) {
5518 continue; 4521 continue;
5519 } 4522 }
5520 } 4523 }
5521 errorReporter.reportErrorForNode( 4524 errorReporter.reportErrorForNode(
5522 HintCode.UNUSED_IMPORT, unusedImport.uri); 4525 HintCode.UNUSED_IMPORT, unusedImport.uri);
5523 } 4526 }
5524 } 4527 }
5525 4528
5526 /** 4529 /**
4530 * Report an [HintCode.UNUSED_SHOWN_NAME] hint for each unused shown name.
4531 *
4532 * Only call this method after all of the compilation units have been visited by this visitor.
4533 *
4534 * @param errorReporter the error reporter used to report the set of [HintCode .UNUSED_SHOWN_NAME]
4535 * hints
4536 */
4537 void generateUnusedShownNameHints(ErrorReporter reporter) {
4538 _unusedShownNamesMap.forEach(
4539 (ImportDirective importDirective, List<SimpleIdentifier> identifiers) {
4540 if (_unusedImports.contains(importDirective)) {
4541 // This import is actually wholly unused, not just one or more shown nam es from it.
4542 // This is then an "unused import", rather than unused shown names.
4543 return;
4544 }
4545 int length = identifiers.length;
4546 for (int i = 0; i < length; i++) {
4547 Identifier identifier = identifiers[i];
4548 reporter.reportErrorForNode(
4549 HintCode.UNUSED_SHOWN_NAME, identifier, [identifier.name]);
4550 }
4551 });
4552 }
4553
4554 /**
5527 * Remove elements from [_unusedImports] using the given [usedElements]. 4555 * Remove elements from [_unusedImports] using the given [usedElements].
5528 */ 4556 */
5529 void removeUsedElements(UsedImportedElements usedElements) { 4557 void removeUsedElements(UsedImportedElements usedElements) {
5530 // Stop if all the imports are known to be used. 4558 // Stop if all the imports and shown names are known to be used.
5531 if (_unusedImports.isEmpty) { 4559 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) {
5532 return; 4560 return;
5533 } 4561 }
5534 // Process import prefixes. 4562 // Process import prefixes.
5535 for (PrefixElement prefix in usedElements.prefixes) { 4563 usedElements.prefixMap
4564 .forEach((PrefixElement prefix, List<Element> elements) {
5536 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; 4565 List<ImportDirective> importDirectives = _prefixElementMap[prefix];
5537 if (importDirectives != null) { 4566 if (importDirectives != null) {
5538 for (ImportDirective importDirective in importDirectives) { 4567 int importLength = importDirectives.length;
4568 for (int i = 0; i < importLength; i++) {
4569 ImportDirective importDirective = importDirectives[i];
5539 _unusedImports.remove(importDirective); 4570 _unusedImports.remove(importDirective);
5540 } 4571 int elementLength = elements.length;
5541 } 4572 for (int j = 0; j < elementLength; j++) {
5542 } 4573 Element element = elements[j];
4574 _removeFromUnusedShownNamesMap(element, importDirective);
4575 }
4576 }
4577 }
4578 });
5543 // Process top-level elements. 4579 // Process top-level elements.
5544 for (Element element in usedElements.elements) { 4580 for (Element element in usedElements.elements) {
5545 // Stop if all the imports are known to be used. 4581 // Stop if all the imports and shown names are known to be used.
5546 if (_unusedImports.isEmpty) { 4582 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) {
5547 return; 4583 return;
5548 } 4584 }
5549 // Prepare import directives for this library. 4585 // Prepare import directives for this element's library.
5550 LibraryElement library = element.library; 4586 LibraryElement library = element.library;
5551 List<ImportDirective> importsLibrary = _libraryMap[library]; 4587 List<ImportDirective> importsLibrary = _libraryMap[library];
5552 if (importsLibrary == null) { 4588 if (importsLibrary == null) {
4589 // element's library is not imported. Must be the current library.
5553 continue; 4590 continue;
5554 } 4591 }
5555 // If there is only one import directive for this library, then it must be 4592 // If there is only one import directive for this library, then it must be
5556 // the directive that this element is imported with, remove it from the 4593 // the directive that this element is imported with, remove it from the
5557 // unusedImports list. 4594 // unusedImports list.
5558 if (importsLibrary.length == 1) { 4595 if (importsLibrary.length == 1) {
5559 ImportDirective usedImportDirective = importsLibrary[0]; 4596 ImportDirective usedImportDirective = importsLibrary[0];
5560 _unusedImports.remove(usedImportDirective); 4597 _unusedImports.remove(usedImportDirective);
4598 _removeFromUnusedShownNamesMap(element, usedImportDirective);
5561 continue; 4599 continue;
5562 } 4600 }
5563 // Otherwise, find import directives using namespaces. 4601 // Otherwise, find import directives using namespaces.
5564 String name = element.displayName; 4602 String name = element.displayName;
5565 for (ImportDirective importDirective in importsLibrary) { 4603 for (ImportDirective importDirective in importsLibrary) {
5566 Namespace namespace = _computeNamespace(importDirective); 4604 Namespace namespace = _computeNamespace(importDirective);
5567 if (namespace != null && namespace.get(name) != null) { 4605 if (namespace?.get(name) != null) {
5568 _unusedImports.remove(importDirective); 4606 _unusedImports.remove(importDirective);
4607 _removeFromUnusedShownNamesMap(element, importDirective);
5569 } 4608 }
5570 } 4609 }
5571 } 4610 }
5572 } 4611 }
5573 4612
5574 /** 4613 /**
5575 * Recursively add any exported library elements into the [libraryMap]. 4614 * Recursively add any exported library elements into the [libraryMap].
5576 */ 4615 */
5577 void _addAdditionalLibrariesForExports(LibraryElement library, 4616 void _addAdditionalLibrariesForExports(LibraryElement library,
5578 ImportDirective importDirective, List<LibraryElement> exportPath) { 4617 ImportDirective importDirective, Set<LibraryElement> visitedLibraries) {
5579 if (exportPath.contains(library)) { 4618 if (!visitedLibraries.add(library)) {
5580 return; 4619 return;
5581 } 4620 }
5582 exportPath.add(library); 4621 List<ExportElement> exports = library.exports;
5583 for (LibraryElement exportedLibraryElt in library.exportedLibraries) { 4622 int length = exports.length;
5584 _putIntoLibraryMap(exportedLibraryElt, importDirective); 4623 for (int i = 0; i < length; i++) {
4624 ExportElement exportElt = exports[i];
4625 LibraryElement exportedLibrary = exportElt.exportedLibrary;
4626 _putIntoLibraryMap(exportedLibrary, importDirective);
5585 _addAdditionalLibrariesForExports( 4627 _addAdditionalLibrariesForExports(
5586 exportedLibraryElt, importDirective, exportPath); 4628 exportedLibrary, importDirective, visitedLibraries);
5587 } 4629 }
5588 } 4630 }
5589 4631
5590 /** 4632 /**
5591 * Lookup and return the [Namespace] from the [namespaceMap], if the map does not 4633 * Add every shown name from [importDirective] into [_unusedShownNamesMap].
5592 * have the computed namespace, compute it and cache it in the map. If the imp ort directive is not 4634 */
5593 * resolved or is not resolvable, `null` is returned. 4635 void _addShownNames(ImportDirective importDirective) {
4636 if (importDirective.combinators == null) {
4637 return;
4638 }
4639 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>();
4640 _unusedShownNamesMap[importDirective] = identifiers;
4641 for (Combinator combinator in importDirective.combinators) {
4642 if (combinator is ShowCombinator) {
4643 for (SimpleIdentifier name in combinator.shownNames) {
4644 if (name.staticElement != null) {
4645 identifiers.add(name);
4646 }
4647 }
4648 }
4649 }
4650 }
4651
4652 /**
4653 * Lookup and return the [Namespace] from the [_namespaceMap].
4654 *
4655 * If the map does not have the computed namespace, compute it and cache it in the map. If
4656 * [importDirective] is not resolved or is not resolvable, `null` is returned.
5594 * 4657 *
5595 * @param importDirective the import directive used to compute the returned na mespace 4658 * @param importDirective the import directive used to compute the returned na mespace
5596 * @return the computed or looked up [Namespace] 4659 * @return the computed or looked up [Namespace]
5597 */ 4660 */
5598 Namespace _computeNamespace(ImportDirective importDirective) { 4661 Namespace _computeNamespace(ImportDirective importDirective) {
5599 Namespace namespace = _namespaceMap[importDirective]; 4662 Namespace namespace = _namespaceMap[importDirective];
5600 if (namespace == null) { 4663 if (namespace == null) {
5601 // If the namespace isn't in the namespaceMap, then compute and put it in 4664 // If the namespace isn't in the namespaceMap, then compute and put it in
5602 // the map. 4665 // the map.
5603 ImportElement importElement = importDirective.element; 4666 ImportElement importElement = importDirective.element;
(...skipping 14 matching lines...) Expand all
5618 */ 4681 */
5619 void _putIntoLibraryMap( 4682 void _putIntoLibraryMap(
5620 LibraryElement libraryElement, ImportDirective importDirective) { 4683 LibraryElement libraryElement, ImportDirective importDirective) {
5621 List<ImportDirective> importList = _libraryMap[libraryElement]; 4684 List<ImportDirective> importList = _libraryMap[libraryElement];
5622 if (importList == null) { 4685 if (importList == null) {
5623 importList = new List<ImportDirective>(); 4686 importList = new List<ImportDirective>();
5624 _libraryMap[libraryElement] = importList; 4687 _libraryMap[libraryElement] = importList;
5625 } 4688 }
5626 importList.add(importDirective); 4689 importList.add(importDirective);
5627 } 4690 }
4691
4692 /**
4693 * Remove [element] from the list of names shown by [importDirective].
4694 */
4695 void _removeFromUnusedShownNamesMap(
4696 Element element, ImportDirective importDirective) {
4697 List<SimpleIdentifier> identifiers = _unusedShownNamesMap[importDirective];
4698 if (identifiers == null) {
4699 return;
4700 }
4701 int length = identifiers.length;
4702 for (int i = 0; i < length; i++) {
4703 Identifier identifier = identifiers[i];
4704 if (element is PropertyAccessorElement) {
4705 // If the getter or setter of a variable is used, then the variable (the
4706 // shown name) is used.
4707 if (identifier.staticElement == element.variable) {
4708 identifiers.remove(identifier);
4709 break;
4710 }
4711 } else {
4712 if (identifier.staticElement == element) {
4713 identifiers.remove(identifier);
4714 break;
4715 }
4716 }
4717 }
4718 if (identifiers.isEmpty) {
4719 _unusedShownNamesMap.remove(importDirective);
4720 }
4721 }
5628 } 4722 }
5629 4723
5630 /** 4724 /**
5631 * Instances of the class `InheritanceManager` manage the knowledge of where cla ss members 4725 * Maintains and manages contextual type information used for
5632 * (methods, getters & setters) are inherited from. 4726 * inferring types.
5633 */ 4727 */
5634 class InheritanceManager { 4728 class InferenceContext {
5635 /** 4729 // TODO(leafp): Consider replacing these node properties with a
5636 * The [LibraryElement] that is managed by this manager. 4730 // hash table help in an instance of this class.
5637 */ 4731 static const String _typeProperty =
5638 LibraryElement _library; 4732 'analyzer.src.generated.InferenceContext.contextType';
5639 4733
5640 /** 4734 /**
5641 * This is a mapping between each [ClassElement] and a map between the [String ] member 4735 * The error listener on which to record inference information.
5642 * names and the associated [ExecutableElement] in the mixin and superclass ch ain. 4736 */
5643 */ 4737 final ErrorReporter _errorReporter;
5644 HashMap<ClassElement, MemberMap> _classLookup; 4738
5645 4739 /**
5646 /** 4740 * If true, emit hints when types are inferred
5647 * This is a mapping between each [ClassElement] and a map between the [String ] member 4741 */
5648 * names and the associated [ExecutableElement] in the interface set. 4742 final bool _inferenceHints;
5649 */ 4743
5650 HashMap<ClassElement, MemberMap> _interfaceLookup; 4744 /**
5651 4745 * Type provider, needed for type matching.
5652 /** 4746 */
5653 * A map between each visited [ClassElement] and the set of [AnalysisError]s f ound on 4747 final TypeProvider _typeProvider;
5654 * the class element. 4748
5655 */ 4749 /**
5656 HashMap<ClassElement, HashSet<AnalysisError>> _errorsInClassElement = 4750 * The type system in use.
5657 new HashMap<ClassElement, HashSet<AnalysisError>>(); 4751 */
5658 4752 final TypeSystem _typeSystem;
5659 /** 4753
5660 * Initialize a newly created inheritance manager. 4754 /**
5661 * 4755 * When no context type is available, this will track the least upper bound
5662 * @param library the library element context that the inheritance mappings ar e being generated 4756 * of all return statements in a lambda.
5663 */ 4757 *
5664 InheritanceManager(LibraryElement library) { 4758 * This will always be kept in sync with [_returnStack].
5665 this._library = library; 4759 */
5666 _classLookup = new HashMap<ClassElement, MemberMap>(); 4760 final List<DartType> _inferredReturn = <DartType>[];
5667 _interfaceLookup = new HashMap<ClassElement, MemberMap>(); 4761
5668 } 4762 /**
5669 4763 * A stack of return types for all of the enclosing
5670 /** 4764 * functions and methods.
5671 * Set the new library element context. 4765 */
5672 * 4766 final List<DartType> _returnStack = <DartType>[];
5673 * @param library the new library element 4767
5674 */ 4768 InferenceContext._(this._errorReporter, TypeProvider typeProvider,
5675 void set libraryElement(LibraryElement library) { 4769 this._typeSystem, this._inferenceHints)
5676 this._library = library; 4770 : _typeProvider = typeProvider;
5677 } 4771
5678 4772 /**
5679 /** 4773 * Get the return type of the current enclosing function, if any.
5680 * Return the set of [AnalysisError]s found on the passed [ClassElement], or 4774 *
5681 * `null` if there are none. 4775 * The type returned for a function is the type that is expected
5682 * 4776 * to be used in a return or yield context. For ordinary functions
5683 * @param classElt the class element to query 4777 * this is the same as the return type of the function. For async
5684 * @return the set of [AnalysisError]s found on the passed [ClassElement], or 4778 * functions returning Future<T> and for generator functions
5685 * `null` if there are none 4779 * returning Stream<T> or Iterable<T>, this is T.
5686 */ 4780 */
5687 HashSet<AnalysisError> getErrors(ClassElement classElt) => 4781 DartType get returnContext =>
5688 _errorsInClassElement[classElt]; 4782 _returnStack.isNotEmpty ? _returnStack.last : null;
5689 4783
5690 /** 4784 /**
5691 * Get and return a mapping between the set of all string names of the members inherited from the 4785 * Records the type of the expression of a return statement.
5692 * passed [ClassElement] superclass hierarchy, and the associated [ExecutableE lement]. 4786 *
5693 * 4787 * This will be used for inferring a block bodied lambda, if no context
5694 * @param classElt the class element to query 4788 * type was available.
5695 * @return a mapping between the set of all members inherited from the passed [ClassElement] 4789 */
5696 * superclass hierarchy, and the associated [ExecutableElement] 4790 void addReturnOrYieldType(DartType type) {
5697 */ 4791 if (_returnStack.isEmpty) {
5698 MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) => 4792 return;
5699 _computeClassChainLookupMap(classElt, new HashSet<ClassElement>()); 4793 }
5700 4794
5701 /** 4795 DartType inferred = _inferredReturn.last;
5702 * Get and return a mapping between the set of all string names of the members inherited from the 4796 inferred = _typeSystem.getLeastUpperBound(_typeProvider, type, inferred);
5703 * passed [ClassElement] interface hierarchy, and the associated [ExecutableEl ement]. 4797 _inferredReturn[_inferredReturn.length - 1] = inferred;
5704 * 4798 }
5705 * @param classElt the class element to query 4799
5706 * @return a mapping between the set of all string names of the members inheri ted from the passed 4800 /**
5707 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement]. 4801 * Match type [t1] against type [t2] as follows.
5708 */ 4802 * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
5709 MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) => 4803 * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
5710 _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>()); 4804 * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'`
5711 4805 * to derive a concrete instantation for I of the form `<T0, ..., Tn>`,
5712 /** 4806 * such that `I<T0, .., Tn> <: t2`
5713 * Given some [ClassElement] and some member name, this returns the 4807 */
5714 * [ExecutableElement] that the class inherits from the mixins, 4808 List<DartType> matchTypes(DartType t1, DartType t2) =>
5715 * superclasses or interfaces, that has the member name, if no member is inher ited `null` is 4809 (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null;
5716 * returned. 4810
5717 * 4811 /**
5718 * @param classElt the class element to query 4812 * Pop a return type off of the return stack.
5719 * @param memberName the name of the executable element to find and return 4813 *
5720 * @return the inherited executable element with the member name, or `null` if no such 4814 * Also record any inferred return type using [setType], unless this node
5721 * member exists 4815 * already has a context type. This recorded type will be the least upper
5722 */ 4816 * bound of all types added with [addReturnOrYieldType].
5723 ExecutableElement lookupInheritance( 4817 */
5724 ClassElement classElt, String memberName) { 4818 void popReturnContext(BlockFunctionBody node) {
5725 if (memberName == null || memberName.isEmpty) { 4819 if (_returnStack.isNotEmpty && _inferredReturn.isNotEmpty) {
4820 DartType context = _returnStack.removeLast() ?? DynamicTypeImpl.instance;
4821 DartType inferred = _inferredReturn.removeLast();
4822 if (inferred.isBottom) {
4823 return;
4824 }
4825
4826 if (context is FutureUnionType) {
4827 // Try and match the Future type first.
4828 if (_typeSystem.isSubtypeOf(inferred, context.futureOfType) ||
4829 _typeSystem.isSubtypeOf(inferred, context.type)) {
4830 setType(node, inferred);
4831 }
4832 } else if (_typeSystem.isSubtypeOf(inferred, context)) {
4833 setType(node, inferred);
4834 }
4835 } else {
4836 assert(false);
4837 }
4838 }
4839
4840 /**
4841 * Push a block function body's return type onto the return stack.
4842 */
4843 void pushReturnContext(BlockFunctionBody node) {
4844 _returnStack.add(getContext(node));
4845 _inferredReturn.add(BottomTypeImpl.instance);
4846 }
4847
4848 /**
4849 * Place an info node into the error stream indicating that a
4850 * [type] has been inferred as the type of [node].
4851 */
4852 void recordInference(Expression node, DartType type) {
4853 if (!_inferenceHints) {
4854 return;
4855 }
4856
4857 ErrorCode error;
4858 if (node is Literal) {
4859 error = StrongModeCode.INFERRED_TYPE_LITERAL;
4860 } else if (node is InstanceCreationExpression) {
4861 error = StrongModeCode.INFERRED_TYPE_ALLOCATION;
4862 } else if (node is FunctionExpression) {
4863 error = StrongModeCode.INFERRED_TYPE_CLOSURE;
4864 } else {
4865 error = StrongModeCode.INFERRED_TYPE;
4866 }
4867
4868 _errorReporter.reportErrorForNode(error, node, [node, type]);
4869 }
4870
4871 List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
4872 if (t1 == t2) {
4873 return t2.typeArguments;
4874 }
4875 List<DartType> tArgs1 = t1.typeArguments;
4876 List<DartType> tArgs2 = t2.typeArguments;
4877 // If t1 isn't a raw type, bail out
4878 if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) {
5726 return null; 4879 return null;
5727 } 4880 }
5728 ExecutableElement executable = _computeClassChainLookupMap( 4881
5729 classElt, new HashSet<ClassElement>()).get(memberName); 4882 // This is our inferred type argument list. We start at all dynamic,
5730 if (executable == null) { 4883 // and fill in with inferred types when we reach a match.
5731 return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>()) 4884 List<DartType> actuals =
5732 .get(memberName); 4885 new List<DartType>.filled(tArgs1.length, _typeProvider.dynamicType);
5733 } 4886
5734 return executable; 4887 // When we find the supertype of t1 with the same
5735 } 4888 // classname as t2 (see below), we have the following:
5736 4889 // If t1 is an instantiation of a class T1<X0, ..., Xn>
5737 /** 4890 // and t2 is an instantiation of a class T2<Y0, ...., Ym>
5738 * Given some [ClassElement] and some member name, this returns the 4891 // of the form t2 = T2<S0, ..., Sm>
5739 * [ExecutableElement] that the class either declares itself, or 4892 // then we want to choose instantiations for the Xi
5740 * inherits, that has the member name, if no member is inherited `null` is ret urned. 4893 // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
5741 * 4894 // To find this, we simply instantate T1 with
5742 * @param classElt the class element to query 4895 // X0, ..., Xn, and then find its superclass
5743 * @param memberName the name of the executable element to find and return 4896 // T2<T0', ..., Tn'>. We then solve the constraint
5744 * @return the inherited executable element with the member name, or `null` if no such 4897 // set T0' <: S0, ..., Tn' <: Sn for the Xi.
5745 * member exists 4898 // Currently, we only handle constraints where
5746 */ 4899 // the Ti' is one of the Xi'. If there are multiple
5747 ExecutableElement lookupMember(ClassElement classElt, String memberName) { 4900 // constraints on some Xi, we choose the lower of the
5748 ExecutableElement element = _lookupMemberInClass(classElt, memberName); 4901 // two (if it exists).
5749 if (element != null) { 4902 bool permute(List<DartType> permutedArgs) {
5750 return element; 4903 if (permutedArgs == null) {
5751 } 4904 return false;
5752 return lookupInheritance(classElt, memberName); 4905 }
5753 } 4906 List<TypeParameterElement> ps = t1.typeParameters;
5754 4907 List<DartType> ts = ps.map((p) => p.type).toList();
5755 /** 4908 for (int i = 0; i < permutedArgs.length; i++) {
5756 * Given some [InterfaceType] and some member name, this returns the 4909 DartType tVar = permutedArgs[i];
5757 * [FunctionType] of the [ExecutableElement] that the 4910 DartType tActual = tArgs2[i];
5758 * class either declares itself, or inherits, that has the member name, if no member is inherited 4911 int index = ts.indexOf(tVar);
5759 * `null` is returned. The returned [FunctionType] has all type 4912 if (index >= 0 && _typeSystem.isSubtypeOf(tActual, actuals[index])) {
5760 * parameters substituted with corresponding type arguments from the given [In terfaceType]. 4913 actuals[index] = tActual;
5761 * 4914 }
5762 * @param interfaceType the interface type to query 4915 }
5763 * @param memberName the name of the executable element to find and return 4916 return actuals.any((x) => !x.isDynamic);
5764 * @return the member's function type, or `null` if no such member exists 4917 }
5765 */ 4918
5766 FunctionType lookupMemberType( 4919 // Look for the first supertype of t1 with the same class name as t2.
5767 InterfaceType interfaceType, String memberName) { 4920 bool match(InterfaceType t1, Set<Element> visited) {
5768 ExecutableElement iteratorMember = 4921 if (t1.element == t2.element) {
5769 lookupMember(interfaceType.element, memberName); 4922 return permute(t1.typeArguments);
5770 if (iteratorMember == null) { 4923 }
4924
4925 if (t1 == _typeProvider.objectType) {
4926 return false;
4927 }
4928
4929 Element element = t1.element;
4930 if (visited == null) {
4931 visited = new HashSet<Element>();
4932 }
4933 if (element == null || !visited.add(element)) {
4934 return false;
4935 }
4936 try {
4937 if (match(t1.superclass, visited)) {
4938 return true;
4939 }
4940
4941 List<InterfaceType> mixins = t1.mixins;
4942 int mixinLength = mixins.length;
4943 for (int i = 0; i < mixinLength; i++) {
4944 if (match(mixins[i], visited)) {
4945 return true;
4946 }
4947 }
4948
4949 List<InterfaceType> interfaces = t1.interfaces;
4950 int interfaceLength = interfaces.length;
4951 for (int j = 0; j < interfaceLength; j++) {
4952 if (match(interfaces[j], visited)) {
4953 return true;
4954 }
4955 }
4956 } finally {
4957 visited.remove(element);
4958 }
4959 return false;
4960 }
4961
4962 // We have that t1 = T1<dynamic, ..., dynamic>.
4963 // To match t1 against t2, we use the uninstantiated version
4964 // of t1, essentially treating it as an instantiation with
4965 // fresh variables, and solve for the variables.
4966 // t1.element.type will be of the form T1<X0, ..., Xn>
4967 if (!match(t1.element.type, null)) {
5771 return null; 4968 return null;
5772 } 4969 }
5773 return substituteTypeArgumentsInMemberFromInheritance( 4970 DartType newT1 = t1.element.type.instantiate(actuals);
5774 iteratorMember.type, memberName, interfaceType); 4971 // If we found a solution, return it.
5775 } 4972 if (_typeSystem.isSubtypeOf(newT1, t2)) {
5776 4973 return actuals;
5777 /** 4974 }
5778 * Determine the set of methods which is overridden by the given class member. If no member is 4975 return null;
5779 * inherited, an empty list is returned. If one of the inherited members is a 4976 }
5780 * [MultiplyInheritedExecutableElement], then it is expanded into its constitu ent inherited 4977
5781 * elements. 4978 /**
5782 * 4979 * Clear the type information assocated with [node].
5783 * @param classElt the class to query 4980 */
5784 * @param memberName the name of the class member to query 4981 static void clearType(AstNode node) {
5785 * @return a list of overridden methods 4982 node?.setProperty(_typeProperty, null);
5786 */ 4983 }
5787 List<ExecutableElement> lookupOverrides( 4984
5788 ClassElement classElt, String memberName) { 4985 /**
5789 List<ExecutableElement> result = new List<ExecutableElement>(); 4986 * Look for contextual type information attached to [node]. Returns
5790 if (memberName == null || memberName.isEmpty) { 4987 * the type if found, otherwise null.
5791 return result; 4988 *
5792 } 4989 * If [node] has a contextual union type like `T | Future<T>` this will be
5793 List<MemberMap> interfaceMaps = 4990 * returned. You can use [getType] if you prefer to only get the `T`.
5794 _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>()); 4991 */
5795 if (interfaceMaps != null) { 4992 static DartType getContext(AstNode node) => node?.getProperty(_typeProperty);
5796 for (MemberMap interfaceMap in interfaceMaps) { 4993
5797 ExecutableElement overriddenElement = interfaceMap.get(memberName); 4994 /**
5798 if (overriddenElement != null) { 4995 * Look for a single contextual type attached to [node], and returns the type
5799 if (overriddenElement is MultiplyInheritedExecutableElement) { 4996 * if found, otherwise null.
5800 MultiplyInheritedExecutableElement multiplyInheritedElement = 4997 *
5801 overriddenElement; 4998 * If [node] has a contextual union type like `T | Future<T>` this will
5802 for (ExecutableElement element 4999 * simplify it to only return `T`. If the caller can handle a union type,
5803 in multiplyInheritedElement.inheritedElements) { 5000 * [getContext] should be used instead.
5804 result.add(element); 5001 */
5805 } 5002 static DartType getType(AstNode node) {
5806 } else { 5003 DartType t = getContext(node);
5807 result.add(overriddenElement); 5004 if (t is FutureUnionType) {
5808 } 5005 return t.type;
5809 } 5006 }
5810 } 5007 return t;
5811 } 5008 }
5812 return result; 5009
5813 } 5010 /**
5814 5011 * Like [getContext] but expands a union type into a list of types.
5815 /** 5012 */
5816 * This method takes some inherited [FunctionType], and resolves all the param eterized types 5013 static Iterable<DartType> getTypes(AstNode node) {
5817 * in the function type, dependent on the class in which it is being overridde n. 5014 DartType t = getContext(node);
5818 * 5015 if (t == null) {
5819 * @param baseFunctionType the function type that is being overridden 5016 return DartType.EMPTY_LIST;
5820 * @param memberName the name of the member, this is used to lookup the inheri tance path of the 5017 }
5821 * override 5018 if (t is FutureUnionType) {
5822 * @param definingType the type that is overriding the member 5019 return t.types;
5823 * @return the passed function type with any parameterized types substituted 5020 }
5824 */ 5021 return <DartType>[t];
5825 FunctionType substituteTypeArgumentsInMemberFromInheritance( 5022 }
5826 FunctionType baseFunctionType, 5023
5827 String memberName, 5024 /**
5828 InterfaceType definingType) { 5025 * Attach contextual type information [type] to [node] for use during
5829 // if the baseFunctionType is null, or does not have any parameters, 5026 * inference.
5830 // return it. 5027 */
5831 if (baseFunctionType == null || 5028 static void setType(AstNode node, DartType type) {
5832 baseFunctionType.typeArguments.length == 0) { 5029 if (type == null || type.isDynamic) {
5833 return baseFunctionType; 5030 clearType(node);
5834 }
5835 // First, generate the path from the defining type to the overridden member
5836 Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>();
5837 _computeInheritancePath(inheritancePath, definingType, memberName);
5838 if (inheritancePath == null || inheritancePath.isEmpty) {
5839 // TODO(jwren) log analysis engine error
5840 return baseFunctionType;
5841 }
5842 FunctionType functionTypeToReturn = baseFunctionType;
5843 // loop backward through the list substituting as we go:
5844 while (!inheritancePath.isEmpty) {
5845 InterfaceType lastType = inheritancePath.removeLast();
5846 List<DartType> parameterTypes = lastType.element.type.typeArguments;
5847 List<DartType> argumentTypes = lastType.typeArguments;
5848 functionTypeToReturn =
5849 functionTypeToReturn.substitute2(argumentTypes, parameterTypes);
5850 }
5851 return functionTypeToReturn;
5852 }
5853
5854 /**
5855 * Compute and return a mapping between the set of all string names of the mem bers inherited from
5856 * the passed [ClassElement] superclass hierarchy, and the associated
5857 * [ExecutableElement].
5858 *
5859 * @param classElt the class element to query
5860 * @param visitedClasses a set of visited classes passed back into this method when it calls
5861 * itself recursively
5862 * @return a mapping between the set of all string names of the members inheri ted from the passed
5863 * [ClassElement] superclass hierarchy, and the associated [Executable Element]
5864 */
5865 MemberMap _computeClassChainLookupMap(
5866 ClassElement classElt, HashSet<ClassElement> visitedClasses) {
5867 MemberMap resultMap = _classLookup[classElt];
5868 if (resultMap != null) {
5869 return resultMap;
5870 } else { 5031 } else {
5871 resultMap = new MemberMap(); 5032 node?.setProperty(_typeProperty, type);
5872 } 5033 }
5873 ClassElement superclassElt = null; 5034 }
5874 InterfaceType supertype = classElt.supertype; 5035
5875 if (supertype != null) { 5036 /**
5876 superclassElt = supertype.element; 5037 * Attach contextual type information [type] to [node] for use during
5877 } else { 5038 * inference.
5878 // classElt is Object 5039 */
5879 _classLookup[classElt] = resultMap; 5040 static void setTypeFromNode(AstNode innerNode, AstNode outerNode) {
5880 return resultMap; 5041 setType(innerNode, getContext(outerNode));
5881 }
5882 if (superclassElt != null) {
5883 if (!visitedClasses.contains(superclassElt)) {
5884 visitedClasses.add(superclassElt);
5885 try {
5886 resultMap = new MemberMap.from(
5887 _computeClassChainLookupMap(superclassElt, visitedClasses));
5888 //
5889 // Substitute the super types down the hierarchy.
5890 //
5891 _substituteTypeParametersDownHierarchy(supertype, resultMap);
5892 //
5893 // Include the members from the superclass in the resultMap.
5894 //
5895 _recordMapWithClassMembers(resultMap, supertype, false);
5896 } finally {
5897 visitedClasses.remove(superclassElt);
5898 }
5899 } else {
5900 // This case happens only when the superclass was previously visited and
5901 // not in the lookup, meaning this is meant to shorten the compute for
5902 // recursive cases.
5903 _classLookup[superclassElt] = resultMap;
5904 return resultMap;
5905 }
5906 }
5907 //
5908 // Include the members from the mixins in the resultMap. If there are
5909 // multiple mixins, visit them in the order listed so that methods in later
5910 // mixins will overwrite identically-named methods in earlier mixins.
5911 //
5912 List<InterfaceType> mixins = classElt.mixins;
5913 for (InterfaceType mixin in mixins) {
5914 ClassElement mixinElement = mixin.element;
5915 if (mixinElement != null) {
5916 if (!visitedClasses.contains(mixinElement)) {
5917 visitedClasses.add(mixinElement);
5918 try {
5919 MemberMap map = new MemberMap.from(
5920 _computeClassChainLookupMap(mixinElement, visitedClasses));
5921 //
5922 // Substitute the super types down the hierarchy.
5923 //
5924 _substituteTypeParametersDownHierarchy(mixin, map);
5925 //
5926 // Include the members from the superclass in the resultMap.
5927 //
5928 _recordMapWithClassMembers(map, mixin, false);
5929 //
5930 // Add the members from map into result map.
5931 //
5932 for (int j = 0; j < map.size; j++) {
5933 String key = map.getKey(j);
5934 ExecutableElement value = map.getValue(j);
5935 if (key != null) {
5936 ClassElement definingClass = value
5937 .getAncestor((Element element) => element is ClassElement);
5938 if (!definingClass.type.isObject) {
5939 ExecutableElement existingValue = resultMap.get(key);
5940 if (existingValue == null ||
5941 (existingValue != null && !_isAbstract(value))) {
5942 resultMap.put(key, value);
5943 }
5944 }
5945 }
5946 }
5947 } finally {
5948 visitedClasses.remove(mixinElement);
5949 }
5950 } else {
5951 // This case happens only when the superclass was previously visited
5952 // and not in the lookup, meaning this is meant to shorten the compute
5953 // for recursive cases.
5954 _classLookup[mixinElement] = resultMap;
5955 return resultMap;
5956 }
5957 }
5958 }
5959 _classLookup[classElt] = resultMap;
5960 return resultMap;
5961 }
5962
5963 /**
5964 * Compute and return the inheritance path given the context of a type and a m ember that is
5965 * overridden in the inheritance path (for which the type is in the path).
5966 *
5967 * @param chain the inheritance path that is built up as this method calls its elf recursively,
5968 * when this method is called an empty [LinkedList] should be provide d
5969 * @param currentType the current type in the inheritance path
5970 * @param memberName the name of the member that is being looked up the inheri tance path
5971 */
5972 void _computeInheritancePath(Queue<InterfaceType> chain,
5973 InterfaceType currentType, String memberName) {
5974 // TODO (jwren) create a public version of this method which doesn't require
5975 // the initial chain to be provided, then provided tests for this
5976 // functionality in InheritanceManagerTest
5977 chain.add(currentType);
5978 ClassElement classElt = currentType.element;
5979 InterfaceType supertype = classElt.supertype;
5980 // Base case- reached Object
5981 if (supertype == null) {
5982 // Looked up the chain all the way to Object, return null.
5983 // This should never happen.
5984 return;
5985 }
5986 // If we are done, return the chain
5987 // We are not done if this is the first recursive call on this method.
5988 if (chain.length != 1) {
5989 // We are done however if the member is in this classElt
5990 if (_lookupMemberInClass(classElt, memberName) != null) {
5991 return;
5992 }
5993 }
5994 // Mixins- note that mixins call lookupMemberInClass, not lookupMember
5995 List<InterfaceType> mixins = classElt.mixins;
5996 for (int i = mixins.length - 1; i >= 0; i--) {
5997 ClassElement mixinElement = mixins[i].element;
5998 if (mixinElement != null) {
5999 ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName);
6000 if (elt != null) {
6001 // this is equivalent (but faster than) calling this method
6002 // recursively
6003 // (return computeInheritancePath(chain, mixins[i], memberName);)
6004 chain.add(mixins[i]);
6005 return;
6006 }
6007 }
6008 }
6009 // Superclass
6010 ClassElement superclassElt = supertype.element;
6011 if (lookupMember(superclassElt, memberName) != null) {
6012 _computeInheritancePath(chain, supertype, memberName);
6013 return;
6014 }
6015 // Interfaces
6016 List<InterfaceType> interfaces = classElt.interfaces;
6017 for (InterfaceType interfaceType in interfaces) {
6018 ClassElement interfaceElement = interfaceType.element;
6019 if (interfaceElement != null &&
6020 lookupMember(interfaceElement, memberName) != null) {
6021 _computeInheritancePath(chain, interfaceType, memberName);
6022 return;
6023 }
6024 }
6025 }
6026
6027 /**
6028 * Compute and return a mapping between the set of all string names of the mem bers inherited from
6029 * the passed [ClassElement] interface hierarchy, and the associated
6030 * [ExecutableElement].
6031 *
6032 * @param classElt the class element to query
6033 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
6034 * itself recursively
6035 * @return a mapping between the set of all string names of the members inheri ted from the passed
6036 * [ClassElement] interface hierarchy, and the associated [ExecutableE lement]
6037 */
6038 MemberMap _computeInterfaceLookupMap(
6039 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
6040 MemberMap resultMap = _interfaceLookup[classElt];
6041 if (resultMap != null) {
6042 return resultMap;
6043 }
6044 List<MemberMap> lookupMaps =
6045 _gatherInterfaceLookupMaps(classElt, visitedInterfaces);
6046 if (lookupMaps == null) {
6047 resultMap = new MemberMap();
6048 } else {
6049 HashMap<String, List<ExecutableElement>> unionMap =
6050 _unionInterfaceLookupMaps(lookupMaps);
6051 resultMap = _resolveInheritanceLookup(classElt, unionMap);
6052 }
6053 _interfaceLookup[classElt] = resultMap;
6054 return resultMap;
6055 }
6056
6057 /**
6058 * Collect a list of interface lookup maps whose elements correspond to all of the classes
6059 * directly above [classElt] in the class hierarchy (the direct superclass if any, all
6060 * mixins, and all direct superinterfaces). Each item in the list is the inter face lookup map
6061 * returned by [computeInterfaceLookupMap] for the corresponding super, except with type
6062 * parameters appropriately substituted.
6063 *
6064 * @param classElt the class element to query
6065 * @param visitedInterfaces a set of visited classes passed back into this met hod when it calls
6066 * itself recursively
6067 * @return `null` if there was a problem (such as a loop in the class hierarch y) or if there
6068 * are no classes above this one in the class hierarchy. Otherwise, a list of interface
6069 * lookup maps.
6070 */
6071 List<MemberMap> _gatherInterfaceLookupMaps(
6072 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) {
6073 InterfaceType supertype = classElt.supertype;
6074 ClassElement superclassElement =
6075 supertype != null ? supertype.element : null;
6076 List<InterfaceType> mixins = classElt.mixins;
6077 List<InterfaceType> interfaces = classElt.interfaces;
6078 // Recursively collect the list of mappings from all of the interface types
6079 List<MemberMap> lookupMaps = new List<MemberMap>();
6080 //
6081 // Superclass element
6082 //
6083 if (superclassElement != null) {
6084 if (!visitedInterfaces.contains(superclassElement)) {
6085 try {
6086 visitedInterfaces.add(superclassElement);
6087 //
6088 // Recursively compute the map for the super type.
6089 //
6090 MemberMap map =
6091 _computeInterfaceLookupMap(superclassElement, visitedInterfaces);
6092 map = new MemberMap.from(map);
6093 //
6094 // Substitute the super type down the hierarchy.
6095 //
6096 _substituteTypeParametersDownHierarchy(supertype, map);
6097 //
6098 // Add any members from the super type into the map as well.
6099 //
6100 _recordMapWithClassMembers(map, supertype, true);
6101 lookupMaps.add(map);
6102 } finally {
6103 visitedInterfaces.remove(superclassElement);
6104 }
6105 } else {
6106 return null;
6107 }
6108 }
6109 //
6110 // Mixin elements
6111 //
6112 for (int i = mixins.length - 1; i >= 0; i--) {
6113 InterfaceType mixinType = mixins[i];
6114 ClassElement mixinElement = mixinType.element;
6115 if (mixinElement != null) {
6116 if (!visitedInterfaces.contains(mixinElement)) {
6117 try {
6118 visitedInterfaces.add(mixinElement);
6119 //
6120 // Recursively compute the map for the mixin.
6121 //
6122 MemberMap map =
6123 _computeInterfaceLookupMap(mixinElement, visitedInterfaces);
6124 map = new MemberMap.from(map);
6125 //
6126 // Substitute the mixin type down the hierarchy.
6127 //
6128 _substituteTypeParametersDownHierarchy(mixinType, map);
6129 //
6130 // Add any members from the mixin type into the map as well.
6131 //
6132 _recordMapWithClassMembers(map, mixinType, true);
6133 lookupMaps.add(map);
6134 } finally {
6135 visitedInterfaces.remove(mixinElement);
6136 }
6137 } else {
6138 return null;
6139 }
6140 }
6141 }
6142 //
6143 // Interface elements
6144 //
6145 for (InterfaceType interfaceType in interfaces) {
6146 ClassElement interfaceElement = interfaceType.element;
6147 if (interfaceElement != null) {
6148 if (!visitedInterfaces.contains(interfaceElement)) {
6149 try {
6150 visitedInterfaces.add(interfaceElement);
6151 //
6152 // Recursively compute the map for the interfaces.
6153 //
6154 MemberMap map =
6155 _computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
6156 map = new MemberMap.from(map);
6157 //
6158 // Substitute the supertypes down the hierarchy
6159 //
6160 _substituteTypeParametersDownHierarchy(interfaceType, map);
6161 //
6162 // And add any members from the interface into the map as well.
6163 //
6164 _recordMapWithClassMembers(map, interfaceType, true);
6165 lookupMaps.add(map);
6166 } finally {
6167 visitedInterfaces.remove(interfaceElement);
6168 }
6169 } else {
6170 return null;
6171 }
6172 }
6173 }
6174 if (lookupMaps.length == 0) {
6175 return null;
6176 }
6177 return lookupMaps;
6178 }
6179
6180 /**
6181 * Given some [ClassElement], this method finds and returns the [ExecutableEle ment] of
6182 * the passed name in the class element. Static members, members in super type s and members not
6183 * accessible from the current library are not considered.
6184 *
6185 * @param classElt the class element to query
6186 * @param memberName the name of the member to lookup in the class
6187 * @return the found [ExecutableElement], or `null` if no such member was foun d
6188 */
6189 ExecutableElement _lookupMemberInClass(
6190 ClassElement classElt, String memberName) {
6191 List<MethodElement> methods = classElt.methods;
6192 for (MethodElement method in methods) {
6193 if (memberName == method.name &&
6194 method.isAccessibleIn(_library) &&
6195 !method.isStatic) {
6196 return method;
6197 }
6198 }
6199 List<PropertyAccessorElement> accessors = classElt.accessors;
6200 for (PropertyAccessorElement accessor in accessors) {
6201 if (memberName == accessor.name &&
6202 accessor.isAccessibleIn(_library) &&
6203 !accessor.isStatic) {
6204 return accessor;
6205 }
6206 }
6207 return null;
6208 }
6209
6210 /**
6211 * Record the passed map with the set of all members (methods, getters and set ters) in the type
6212 * into the passed map.
6213 *
6214 * @param map some non-`null` map to put the methods and accessors from the pa ssed
6215 * [ClassElement] into
6216 * @param type the type that will be recorded into the passed map
6217 * @param doIncludeAbstract `true` if abstract members will be put into the ma p
6218 */
6219 void _recordMapWithClassMembers(
6220 MemberMap map, InterfaceType type, bool doIncludeAbstract) {
6221 List<MethodElement> methods = type.methods;
6222 for (MethodElement method in methods) {
6223 if (method.isAccessibleIn(_library) &&
6224 !method.isStatic &&
6225 (doIncludeAbstract || !method.isAbstract)) {
6226 map.put(method.name, method);
6227 }
6228 }
6229 List<PropertyAccessorElement> accessors = type.accessors;
6230 for (PropertyAccessorElement accessor in accessors) {
6231 if (accessor.isAccessibleIn(_library) &&
6232 !accessor.isStatic &&
6233 (doIncludeAbstract || !accessor.isAbstract)) {
6234 map.put(accessor.name, accessor);
6235 }
6236 }
6237 }
6238
6239 /**
6240 * This method is used to report errors on when they are found computing inher itance information.
6241 * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where thes e generated
6242 * error codes are reported back into the analysis engine.
6243 *
6244 * @param classElt the location of the source for which the exception occurred
6245 * @param offset the offset of the location of the error
6246 * @param length the length of the location of the error
6247 * @param errorCode the error code to be associated with this error
6248 * @param arguments the arguments used to build the error message
6249 */
6250 void _reportError(ClassElement classElt, int offset, int length,
6251 ErrorCode errorCode, List<Object> arguments) {
6252 HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt];
6253 if (errorSet == null) {
6254 errorSet = new HashSet<AnalysisError>();
6255 _errorsInClassElement[classElt] = errorSet;
6256 }
6257 errorSet.add(new AnalysisError(
6258 classElt.source, offset, length, errorCode, arguments));
6259 }
6260
6261 /**
6262 * Given the set of methods defined by classes above [classElt] in the class h ierarchy,
6263 * apply the appropriate inheritance rules to determine those methods inherite d by or overridden
6264 * by [classElt]. Also report static warnings
6265 * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and
6266 * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if ap propriate.
6267 *
6268 * @param classElt the class element to query.
6269 * @param unionMap a mapping from method name to the set of unique (in terms o f signature) methods
6270 * defined in superclasses of [classElt].
6271 * @return the inheritance lookup map for [classElt].
6272 */
6273 MemberMap _resolveInheritanceLookup(ClassElement classElt,
6274 HashMap<String, List<ExecutableElement>> unionMap) {
6275 MemberMap resultMap = new MemberMap();
6276 unionMap.forEach((String key, List<ExecutableElement> list) {
6277 int numOfEltsWithMatchingNames = list.length;
6278 if (numOfEltsWithMatchingNames == 1) {
6279 //
6280 // Example: class A inherits only 1 method named 'm'.
6281 // Since it is the only such method, it is inherited.
6282 // Another example: class A inherits 2 methods named 'm' from 2
6283 // different interfaces, but they both have the same signature, so it is
6284 // the method inherited.
6285 //
6286 resultMap.put(key, list[0]);
6287 } else {
6288 //
6289 // Then numOfEltsWithMatchingNames > 1, check for the warning cases.
6290 //
6291 bool allMethods = true;
6292 bool allSetters = true;
6293 bool allGetters = true;
6294 for (ExecutableElement executableElement in list) {
6295 if (executableElement is PropertyAccessorElement) {
6296 allMethods = false;
6297 if (executableElement.isSetter) {
6298 allGetters = false;
6299 } else {
6300 allSetters = false;
6301 }
6302 } else {
6303 allGetters = false;
6304 allSetters = false;
6305 }
6306 }
6307 //
6308 // If there isn't a mixture of methods with getters, then continue,
6309 // otherwise create a warning.
6310 //
6311 if (allMethods || allGetters || allSetters) {
6312 //
6313 // Compute the element whose type is the subtype of all of the other
6314 // types.
6315 //
6316 List<ExecutableElement> elements = new List.from(list);
6317 List<FunctionType> executableElementTypes =
6318 new List<FunctionType>(numOfEltsWithMatchingNames);
6319 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
6320 executableElementTypes[i] = elements[i].type;
6321 }
6322 List<int> subtypesOfAllOtherTypesIndexes = new List<int>();
6323 for (int i = 0; i < numOfEltsWithMatchingNames; i++) {
6324 FunctionType subtype = executableElementTypes[i];
6325 if (subtype == null) {
6326 continue;
6327 }
6328 bool subtypeOfAllTypes = true;
6329 TypeSystem typeSystem = _library.context.typeSystem;
6330 for (int j = 0;
6331 j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
6332 j++) {
6333 if (i != j) {
6334 if (!typeSystem.isSubtypeOf(
6335 subtype, executableElementTypes[j])) {
6336 subtypeOfAllTypes = false;
6337 break;
6338 }
6339 }
6340 }
6341 if (subtypeOfAllTypes) {
6342 subtypesOfAllOtherTypesIndexes.add(i);
6343 }
6344 }
6345 //
6346 // The following is split into three cases determined by the number of
6347 // elements in subtypesOfAllOtherTypes
6348 //
6349 if (subtypesOfAllOtherTypesIndexes.length == 1) {
6350 //
6351 // Example: class A inherited only 2 method named 'm'.
6352 // One has the function type '() -> dynamic' and one has the
6353 // function type '([int]) -> dynamic'. Since the second method is a
6354 // subtype of all the others, it is the inherited method.
6355 // Tests: InheritanceManagerTest.
6356 // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_*
6357 //
6358 resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]);
6359 } else {
6360 if (subtypesOfAllOtherTypesIndexes.isEmpty) {
6361 //
6362 // Determine if the current class has a method or accessor with
6363 // the member name, if it does then then this class does not
6364 // "inherit" from any of the supertypes. See issue 16134.
6365 //
6366 bool classHasMember = false;
6367 if (allMethods) {
6368 classHasMember = classElt.getMethod(key) != null;
6369 } else {
6370 List<PropertyAccessorElement> accessors = classElt.accessors;
6371 for (int i = 0; i < accessors.length; i++) {
6372 if (accessors[i].name == key) {
6373 classHasMember = true;
6374 }
6375 }
6376 }
6377 //
6378 // Example: class A inherited only 2 method named 'm'.
6379 // One has the function type '() -> int' and one has the function
6380 // type '() -> String'. Since neither is a subtype of the other,
6381 // we create a warning, and have this class inherit nothing.
6382 //
6383 if (!classHasMember) {
6384 String firstTwoFuntionTypesStr =
6385 "${executableElementTypes[0]}, ${executableElementTypes[1]}" ;
6386 _reportError(
6387 classElt,
6388 classElt.nameOffset,
6389 classElt.nameLength,
6390 StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE,
6391 [key, firstTwoFuntionTypesStr]);
6392 }
6393 } else {
6394 //
6395 // Example: class A inherits 2 methods named 'm'.
6396 // One has the function type '(int) -> dynamic' and one has the
6397 // function type '(num) -> dynamic'. Since they are both a subtype
6398 // of the other, a synthetic function '(dynamic) -> dynamic' is
6399 // inherited.
6400 // Tests: test_getMapOfMembersInheritedFromInterfaces_
6401 // union_multipleSubtypes_*
6402 //
6403 List<ExecutableElement> elementArrayToMerge = new List<
6404 ExecutableElement>(subtypesOfAllOtherTypesIndexes.length);
6405 for (int i = 0; i < elementArrayToMerge.length; i++) {
6406 elementArrayToMerge[i] =
6407 elements[subtypesOfAllOtherTypesIndexes[i]];
6408 }
6409 ExecutableElement mergedExecutableElement =
6410 _computeMergedExecutableElement(elementArrayToMerge);
6411 resultMap.put(key, mergedExecutableElement);
6412 }
6413 }
6414 } else {
6415 _reportError(
6416 classElt,
6417 classElt.nameOffset,
6418 classElt.nameLength,
6419 StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHO D,
6420 [key]);
6421 }
6422 }
6423 });
6424 return resultMap;
6425 }
6426
6427 /**
6428 * Loop through all of the members in some [MemberMap], performing type parame ter
6429 * substitutions using a passed supertype.
6430 *
6431 * @param superType the supertype to substitute into the members of the [Membe rMap]
6432 * @param map the MemberMap to perform the substitutions on
6433 */
6434 void _substituteTypeParametersDownHierarchy(
6435 InterfaceType superType, MemberMap map) {
6436 for (int i = 0; i < map.size; i++) {
6437 ExecutableElement executableElement = map.getValue(i);
6438 if (executableElement is MethodMember) {
6439 executableElement =
6440 MethodMember.from(executableElement as MethodMember, superType);
6441 map.setValue(i, executableElement);
6442 } else if (executableElement is PropertyAccessorMember) {
6443 executableElement = PropertyAccessorMember.from(
6444 executableElement as PropertyAccessorMember, superType);
6445 map.setValue(i, executableElement);
6446 }
6447 }
6448 }
6449
6450 /**
6451 * Union all of the [lookupMaps] together into a single map, grouping the Exec utableElements
6452 * into a list where none of the elements are equal where equality is determin ed by having equal
6453 * function types. (We also take note too of the kind of the element: ()->int and () -> int may
6454 * not be equal if one is a getter and the other is a method.)
6455 *
6456 * @param lookupMaps the maps to be unioned together.
6457 * @return the resulting union map.
6458 */
6459 HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps(
6460 List<MemberMap> lookupMaps) {
6461 HashMap<String, List<ExecutableElement>> unionMap =
6462 new HashMap<String, List<ExecutableElement>>();
6463 for (MemberMap lookupMap in lookupMaps) {
6464 int lookupMapSize = lookupMap.size;
6465 for (int i = 0; i < lookupMapSize; i++) {
6466 // Get the string key, if null, break.
6467 String key = lookupMap.getKey(i);
6468 if (key == null) {
6469 break;
6470 }
6471 // Get the list value out of the unionMap
6472 List<ExecutableElement> list = unionMap[key];
6473 // If we haven't created such a map for this key yet, do create it and
6474 // put the list entry into the unionMap.
6475 if (list == null) {
6476 list = new List<ExecutableElement>();
6477 unionMap[key] = list;
6478 }
6479 // Fetch the entry out of this lookupMap
6480 ExecutableElement newExecutableElementEntry = lookupMap.getValue(i);
6481 if (list.isEmpty) {
6482 // If the list is empty, just the new value
6483 list.add(newExecutableElementEntry);
6484 } else {
6485 // Otherwise, only add the newExecutableElementEntry if it isn't
6486 // already in the list, this covers situation where a class inherits
6487 // two methods (or two getters) that are identical.
6488 bool alreadyInList = false;
6489 bool isMethod1 = newExecutableElementEntry is MethodElement;
6490 for (ExecutableElement executableElementInList in list) {
6491 bool isMethod2 = executableElementInList is MethodElement;
6492 if (isMethod1 == isMethod2 &&
6493 executableElementInList.type ==
6494 newExecutableElementEntry.type) {
6495 alreadyInList = true;
6496 break;
6497 }
6498 }
6499 if (!alreadyInList) {
6500 list.add(newExecutableElementEntry);
6501 }
6502 }
6503 }
6504 }
6505 return unionMap;
6506 }
6507
6508 /**
6509 * Given some array of [ExecutableElement]s, this method creates a synthetic e lement as
6510 * described in 8.1.1:
6511 *
6512 * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional pa rameters of a
6513 * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote t he number of
6514 * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denot e the set of all
6515 * named parameters of the <i>m<sub>1</sub>, &hellip;, m<sub>k</sub></i>. Then let
6516 * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i>
6517 * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <= i <= k.</i>
6518 * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameter s of type
6519 * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, name d parameters
6520 * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>.
6521 *
6522 */
6523 static ExecutableElement _computeMergedExecutableElement(
6524 List<ExecutableElement> elementArrayToMerge) {
6525 int h = _getNumOfPositionalParameters(elementArrayToMerge[0]);
6526 int r = _getNumOfRequiredParameters(elementArrayToMerge[0]);
6527 Set<String> namedParametersList = new HashSet<String>();
6528 for (int i = 1; i < elementArrayToMerge.length; i++) {
6529 ExecutableElement element = elementArrayToMerge[i];
6530 int numOfPositionalParams = _getNumOfPositionalParameters(element);
6531 if (h < numOfPositionalParams) {
6532 h = numOfPositionalParams;
6533 }
6534 int numOfRequiredParams = _getNumOfRequiredParameters(element);
6535 if (r > numOfRequiredParams) {
6536 r = numOfRequiredParams;
6537 }
6538 namedParametersList.addAll(_getNamedParameterNames(element));
6539 }
6540 return _createSyntheticExecutableElement(
6541 elementArrayToMerge,
6542 elementArrayToMerge[0].displayName,
6543 r,
6544 h - r,
6545 new List.from(namedParametersList));
6546 }
6547
6548 /**
6549 * Used by [computeMergedExecutableElement] to actually create the
6550 * synthetic element.
6551 *
6552 * @param elementArrayToMerge the array used to create the synthetic element
6553 * @param name the name of the method, getter or setter
6554 * @param numOfRequiredParameters the number of required parameters
6555 * @param numOfPositionalParameters the number of positional parameters
6556 * @param namedParameters the list of [String]s that are the named parameters
6557 * @return the created synthetic element
6558 */
6559 static ExecutableElement _createSyntheticExecutableElement(
6560 List<ExecutableElement> elementArrayToMerge,
6561 String name,
6562 int numOfRequiredParameters,
6563 int numOfPositionalParameters,
6564 List<String> namedParameters) {
6565 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
6566 SimpleIdentifier nameIdentifier = new SimpleIdentifier(
6567 new sc.StringToken(sc.TokenType.IDENTIFIER, name, 0));
6568 ExecutableElementImpl executable;
6569 if (elementArrayToMerge[0] is MethodElement) {
6570 MultiplyInheritedMethodElementImpl unionedMethod =
6571 new MultiplyInheritedMethodElementImpl(nameIdentifier);
6572 unionedMethod.inheritedElements = elementArrayToMerge;
6573 executable = unionedMethod;
6574 } else {
6575 MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor =
6576 new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier);
6577 unionedPropertyAccessor.getter =
6578 (elementArrayToMerge[0] as PropertyAccessorElement).isGetter;
6579 unionedPropertyAccessor.setter =
6580 (elementArrayToMerge[0] as PropertyAccessorElement).isSetter;
6581 unionedPropertyAccessor.inheritedElements = elementArrayToMerge;
6582 executable = unionedPropertyAccessor;
6583 }
6584 int numOfParameters = numOfRequiredParameters +
6585 numOfPositionalParameters +
6586 namedParameters.length;
6587 List<ParameterElement> parameters =
6588 new List<ParameterElement>(numOfParameters);
6589 int i = 0;
6590 for (int j = 0; j < numOfRequiredParameters; j++, i++) {
6591 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
6592 parameter.type = dynamicType;
6593 parameter.parameterKind = ParameterKind.REQUIRED;
6594 parameters[i] = parameter;
6595 }
6596 for (int k = 0; k < numOfPositionalParameters; k++, i++) {
6597 ParameterElementImpl parameter = new ParameterElementImpl("", 0);
6598 parameter.type = dynamicType;
6599 parameter.parameterKind = ParameterKind.POSITIONAL;
6600 parameters[i] = parameter;
6601 }
6602 for (int m = 0; m < namedParameters.length; m++, i++) {
6603 ParameterElementImpl parameter =
6604 new ParameterElementImpl(namedParameters[m], 0);
6605 parameter.type = dynamicType;
6606 parameter.parameterKind = ParameterKind.NAMED;
6607 parameters[i] = parameter;
6608 }
6609 executable.returnType = dynamicType;
6610 executable.parameters = parameters;
6611 FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
6612 executable.type = methodType;
6613 return executable;
6614 }
6615
6616 /**
6617 * Given some [ExecutableElement], return the list of named parameters.
6618 */
6619 static List<String> _getNamedParameterNames(
6620 ExecutableElement executableElement) {
6621 List<String> namedParameterNames = new List<String>();
6622 List<ParameterElement> parameters = executableElement.parameters;
6623 for (int i = 0; i < parameters.length; i++) {
6624 ParameterElement parameterElement = parameters[i];
6625 if (parameterElement.parameterKind == ParameterKind.NAMED) {
6626 namedParameterNames.add(parameterElement.name);
6627 }
6628 }
6629 return namedParameterNames;
6630 }
6631
6632 /**
6633 * Given some [ExecutableElement] return the number of parameters of the speci fied kind.
6634 */
6635 static int _getNumOfParameters(
6636 ExecutableElement executableElement, ParameterKind parameterKind) {
6637 int parameterCount = 0;
6638 List<ParameterElement> parameters = executableElement.parameters;
6639 for (int i = 0; i < parameters.length; i++) {
6640 ParameterElement parameterElement = parameters[i];
6641 if (parameterElement.parameterKind == parameterKind) {
6642 parameterCount++;
6643 }
6644 }
6645 return parameterCount;
6646 }
6647
6648 /**
6649 * Given some [ExecutableElement] return the number of positional parameters.
6650 *
6651 * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSI TIONAL].
6652 */
6653 static int _getNumOfPositionalParameters(
6654 ExecutableElement executableElement) =>
6655 _getNumOfParameters(executableElement, ParameterKind.REQUIRED) +
6656 _getNumOfParameters(executableElement, ParameterKind.POSITIONAL);
6657
6658 /**
6659 * Given some [ExecutableElement] return the number of required parameters.
6660 */
6661 static int _getNumOfRequiredParameters(ExecutableElement executableElement) =>
6662 _getNumOfParameters(executableElement, ParameterKind.REQUIRED);
6663
6664 /**
6665 * Given some [ExecutableElement] returns `true` if it is an abstract member o f a
6666 * class.
6667 *
6668 * @param executableElement some [ExecutableElement] to evaluate
6669 * @return `true` if the given element is an abstract member of a class
6670 */
6671 static bool _isAbstract(ExecutableElement executableElement) {
6672 if (executableElement is MethodElement) {
6673 return executableElement.isAbstract;
6674 } else if (executableElement is PropertyAccessorElement) {
6675 return executableElement.isAbstract;
6676 }
6677 return false;
6678 } 5042 }
6679 } 5043 }
6680 5044
6681 /** 5045 /**
6682 * This enum holds one of four states of a field initialization state through a constructor 5046 * The four states of a field initialization state through a constructor
6683 * signature, not initialized, initialized in the field declaration, initialized in the field 5047 * signature, not initialized, initialized in the field declaration, initialized
6684 * formal, and finally, initialized in the initializers list. 5048 * in the field formal, and finally, initialized in the initializers list.
6685 */ 5049 */
6686 class INIT_STATE extends Enum<INIT_STATE> { 5050 class INIT_STATE implements Comparable<INIT_STATE> {
6687 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0); 5051 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0);
6688 5052
6689 static const INIT_STATE INIT_IN_DECLARATION = 5053 static const INIT_STATE INIT_IN_DECLARATION =
6690 const INIT_STATE('INIT_IN_DECLARATION', 1); 5054 const INIT_STATE('INIT_IN_DECLARATION', 1);
6691 5055
6692 static const INIT_STATE INIT_IN_FIELD_FORMAL = 5056 static const INIT_STATE INIT_IN_FIELD_FORMAL =
6693 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2); 5057 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2);
6694 5058
6695 static const INIT_STATE INIT_IN_INITIALIZERS = 5059 static const INIT_STATE INIT_IN_INITIALIZERS =
6696 const INIT_STATE('INIT_IN_INITIALIZERS', 3); 5060 const INIT_STATE('INIT_IN_INITIALIZERS', 3);
6697 5061
6698 static const List<INIT_STATE> values = const [ 5062 static const List<INIT_STATE> values = const [
6699 NOT_INIT, 5063 NOT_INIT,
6700 INIT_IN_DECLARATION, 5064 INIT_IN_DECLARATION,
6701 INIT_IN_FIELD_FORMAL, 5065 INIT_IN_FIELD_FORMAL,
6702 INIT_IN_INITIALIZERS 5066 INIT_IN_INITIALIZERS
6703 ]; 5067 ];
6704 5068
6705 const INIT_STATE(String name, int ordinal) : super(name, ordinal); 5069 /**
5070 * The name of this init state.
5071 */
5072 final String name;
5073
5074 /**
5075 * The ordinal value of the init state.
5076 */
5077 final int ordinal;
5078
5079 const INIT_STATE(this.name, this.ordinal);
5080
5081 @override
5082 int get hashCode => ordinal;
5083
5084 @override
5085 int compareTo(INIT_STATE other) => ordinal - other.ordinal;
5086
5087 @override
5088 String toString() => name;
6706 } 5089 }
6707 5090
6708 /** 5091 /**
6709 * Instances of the class `LabelScope` represent a scope in which a single label is defined. 5092 * An AST visitor that is used to re-resolve the initializers of instance
5093 * fields. Although this class is an AST visitor, clients are expected to use
5094 * the method [resolveCompilationUnit] to run it over a compilation unit.
6710 */ 5095 */
6711 class LabelScope { 5096 class InstanceFieldResolverVisitor extends ResolverVisitor {
6712 /** 5097 /**
6713 * The label scope enclosing this label scope. 5098 * Initialize a newly created visitor to resolve the nodes in an AST node.
6714 */ 5099 *
6715 final LabelScope _outerScope; 5100 * The [definingLibrary] is the element for the library containing the node
6716 5101 * being visited. The [source] is the source representing the compilation unit
6717 /** 5102 * containing the node being visited. The [typeProvider] is the object used to
6718 * The label defined in this scope. 5103 * access the types from the core library. The [errorListener] is the error
6719 */ 5104 * listener that will be informed of any errors that are found during
6720 final String _label; 5105 * resolution. The [nameScope] is the scope used to resolve identifiers in the
6721 5106 * node that will first be visited. If `null` or unspecified, a new
6722 /** 5107 * [LibraryScope] will be created based on the [definingLibrary].
6723 * The element to which the label resolves. 5108 */
6724 */ 5109 InstanceFieldResolverVisitor(LibraryElement definingLibrary, Source source,
6725 final LabelElement element; 5110 TypeProvider typeProvider, AnalysisErrorListener errorListener,
6726 5111 {Scope nameScope})
6727 /** 5112 : super(definingLibrary, source, typeProvider, errorListener,
6728 * The AST node to which the label resolves. 5113 nameScope: nameScope);
6729 */ 5114
6730 final AstNode node; 5115 /**
6731 5116 * Resolve the instance fields in the given compilation unit [node].
6732 /** 5117 */
6733 * Initialize a newly created scope to represent the label [_label]. 5118 void resolveCompilationUnit(CompilationUnit node) {
6734 * [_outerScope] is the scope enclosing the new label scope. [node] is the 5119 _overrideManager.enterScope();
6735 * AST node the label resolves to. [element] is the element the label
6736 * resolves to.
6737 */
6738 LabelScope(this._outerScope, this._label, this.node, this.element);
6739
6740 /**
6741 * Return the LabelScope which defines [targetLabel], or `null` if it is not
6742 * defined in this scope.
6743 */
6744 LabelScope lookup(String targetLabel) {
6745 if (_label == targetLabel) {
6746 return this;
6747 } else if (_outerScope != null) {
6748 return _outerScope.lookup(targetLabel);
6749 } else {
6750 return null;
6751 }
6752 }
6753 }
6754
6755 /**
6756 * Instances of the class `Library` represent the data about a single library du ring the
6757 * resolution of some (possibly different) library. They are not intended to be used except during
6758 * the resolution process.
6759 */
6760 class Library {
6761 /**
6762 * An empty list that can be used to initialize lists of libraries.
6763 */
6764 static const List<Library> _EMPTY_ARRAY = const <Library>[];
6765
6766 /**
6767 * The prefix of a URI using the dart-ext scheme to reference a native code li brary.
6768 */
6769 static String _DART_EXT_SCHEME = "dart-ext:";
6770
6771 /**
6772 * The analysis context in which this library is being analyzed.
6773 */
6774 final InternalAnalysisContext _analysisContext;
6775
6776 /**
6777 * The inheritance manager which is used for this member lookups in this libra ry.
6778 */
6779 InheritanceManager _inheritanceManager;
6780
6781 /**
6782 * The listener to which analysis errors will be reported.
6783 */
6784 final AnalysisErrorListener errorListener;
6785
6786 /**
6787 * The source specifying the defining compilation unit of this library.
6788 */
6789 final Source librarySource;
6790
6791 /**
6792 * The library element representing this library.
6793 */
6794 LibraryElementImpl _libraryElement;
6795
6796 /**
6797 * A list containing all of the libraries that are imported into this library.
6798 */
6799 List<Library> _importedLibraries = _EMPTY_ARRAY;
6800
6801 /**
6802 * A table mapping URI-based directive to the actual URI value.
6803 */
6804 HashMap<UriBasedDirective, String> _directiveUris =
6805 new HashMap<UriBasedDirective, String>();
6806
6807 /**
6808 * A flag indicating whether this library explicitly imports core.
6809 */
6810 bool explicitlyImportsCore = false;
6811
6812 /**
6813 * A list containing all of the libraries that are exported from this library.
6814 */
6815 List<Library> _exportedLibraries = _EMPTY_ARRAY;
6816
6817 /**
6818 * A table mapping the sources for the compilation units in this library to th eir corresponding
6819 * AST structures.
6820 */
6821 HashMap<Source, CompilationUnit> _astMap =
6822 new HashMap<Source, CompilationUnit>();
6823
6824 /**
6825 * The library scope used when resolving elements within this library's compil ation units.
6826 */
6827 LibraryScope _libraryScope;
6828
6829 /**
6830 * Initialize a newly created data holder that can maintain the data associate d with a library.
6831 *
6832 * @param analysisContext the analysis context in which this library is being analyzed
6833 * @param errorListener the listener to which analysis errors will be reported
6834 * @param librarySource the source specifying the defining compilation unit of this library
6835 */
6836 Library(this._analysisContext, this.errorListener, this.librarySource) {
6837 this._libraryElement =
6838 _analysisContext.getLibraryElement(librarySource) as LibraryElementImpl;
6839 }
6840
6841 /**
6842 * Return an array of the [CompilationUnit]s that make up the library. The fir st unit is
6843 * always the defining unit.
6844 *
6845 * @return an array of the [CompilationUnit]s that make up the library. The fi rst unit is
6846 * always the defining unit
6847 */
6848 List<CompilationUnit> get compilationUnits {
6849 List<CompilationUnit> unitArrayList = new List<CompilationUnit>();
6850 unitArrayList.add(definingCompilationUnit);
6851 for (Source source in _astMap.keys.toSet()) {
6852 if (librarySource != source) {
6853 unitArrayList.add(getAST(source));
6854 }
6855 }
6856 return unitArrayList;
6857 }
6858
6859 /**
6860 * Return a collection containing the sources for the compilation units in thi s library, including
6861 * the defining compilation unit.
6862 *
6863 * @return the sources for the compilation units in this library
6864 */
6865 Set<Source> get compilationUnitSources => _astMap.keys.toSet();
6866
6867 /**
6868 * Return the AST structure associated with the defining compilation unit for this library.
6869 *
6870 * @return the AST structure associated with the defining compilation unit for this library
6871 * @throws AnalysisException if an AST structure could not be created for the defining compilation
6872 * unit
6873 */
6874 CompilationUnit get definingCompilationUnit => getAST(librarySource);
6875
6876 /**
6877 * Set the libraries that are exported by this library to be those in the give n array.
6878 *
6879 * @param exportedLibraries the libraries that are exported by this library
6880 */
6881 void set exportedLibraries(List<Library> exportedLibraries) {
6882 this._exportedLibraries = exportedLibraries;
6883 }
6884
6885 /**
6886 * Return an array containing the libraries that are exported from this librar y.
6887 *
6888 * @return an array containing the libraries that are exported from this libra ry
6889 */
6890 List<Library> get exports => _exportedLibraries;
6891
6892 /**
6893 * Set the libraries that are imported into this library to be those in the gi ven array.
6894 *
6895 * @param importedLibraries the libraries that are imported into this library
6896 */
6897 void set importedLibraries(List<Library> importedLibraries) {
6898 this._importedLibraries = importedLibraries;
6899 }
6900
6901 /**
6902 * Return an array containing the libraries that are imported into this librar y.
6903 *
6904 * @return an array containing the libraries that are imported into this libra ry
6905 */
6906 List<Library> get imports => _importedLibraries;
6907
6908 /**
6909 * Return an array containing the libraries that are either imported or export ed from this
6910 * library.
6911 *
6912 * @return the libraries that are either imported or exported from this librar y
6913 */
6914 List<Library> get importsAndExports {
6915 HashSet<Library> libraries = new HashSet<Library>();
6916 for (Library library in _importedLibraries) {
6917 libraries.add(library);
6918 }
6919 for (Library library in _exportedLibraries) {
6920 libraries.add(library);
6921 }
6922 return new List.from(libraries);
6923 }
6924
6925 /**
6926 * Return the inheritance manager for this library.
6927 *
6928 * @return the inheritance manager for this library
6929 */
6930 InheritanceManager get inheritanceManager {
6931 if (_inheritanceManager == null) {
6932 return _inheritanceManager = new InheritanceManager(_libraryElement);
6933 }
6934 return _inheritanceManager;
6935 }
6936
6937 /**
6938 * Return the library element representing this library, creating it if necess ary.
6939 *
6940 * @return the library element representing this library
6941 */
6942 LibraryElementImpl get libraryElement {
6943 if (_libraryElement == null) {
6944 try {
6945 _libraryElement = _analysisContext.computeLibraryElement(librarySource)
6946 as LibraryElementImpl;
6947 } on AnalysisException catch (exception, stackTrace) {
6948 AnalysisEngine.instance.logger.logError(
6949 "Could not compute library element for ${librarySource.fullName}",
6950 new CaughtException(exception, stackTrace));
6951 }
6952 }
6953 return _libraryElement;
6954 }
6955
6956 /**
6957 * Set the library element representing this library to the given library elem ent.
6958 *
6959 * @param libraryElement the library element representing this library
6960 */
6961 void set libraryElement(LibraryElementImpl libraryElement) {
6962 this._libraryElement = libraryElement;
6963 if (_inheritanceManager != null) {
6964 _inheritanceManager.libraryElement = libraryElement;
6965 }
6966 }
6967
6968 /**
6969 * Return the library scope used when resolving elements within this library's compilation units.
6970 *
6971 * @return the library scope used when resolving elements within this library' s compilation units
6972 */
6973 LibraryScope get libraryScope {
6974 if (_libraryScope == null) {
6975 _libraryScope = new LibraryScope(_libraryElement, errorListener);
6976 }
6977 return _libraryScope;
6978 }
6979
6980 /**
6981 * Return the AST structure associated with the given source.
6982 *
6983 * @param source the source representing the compilation unit whose AST is to be returned
6984 * @return the AST structure associated with the given source
6985 * @throws AnalysisException if an AST structure could not be created for the compilation unit
6986 */
6987 CompilationUnit getAST(Source source) {
6988 CompilationUnit unit = _astMap[source];
6989 if (unit == null) {
6990 unit = _analysisContext.computeResolvableCompilationUnit(source);
6991 _astMap[source] = unit;
6992 }
6993 return unit;
6994 }
6995
6996 /**
6997 * Return the result of resolving the URI of the given URI-based directive aga inst the URI of the
6998 * library, or `null` if the URI is not valid. If the URI is not valid, report the error.
6999 *
7000 * @param directive the directive which URI should be resolved
7001 * @return the result of resolving the URI against the URI of the library
7002 */
7003 Source getSource(UriBasedDirective directive) {
7004 StringLiteral uriLiteral = directive.uri;
7005 if (uriLiteral is StringInterpolation) {
7006 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
7007 uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION));
7008 return null;
7009 }
7010 String uriContent = uriLiteral.stringValue.trim();
7011 _directiveUris[directive] = uriContent;
7012 uriContent = Uri.encodeFull(uriContent);
7013 if (directive is ImportDirective &&
7014 uriContent.startsWith(_DART_EXT_SCHEME)) {
7015 _libraryElement.hasExtUri = true;
7016 return null;
7017 }
7018 try { 5120 try {
7019 parseUriWithException(uriContent); 5121 NodeList<CompilationUnitMember> declarations = node.declarations;
7020 Source source = 5122 int declarationCount = declarations.length;
7021 _analysisContext.sourceFactory.resolveUri(librarySource, uriContent); 5123 for (int i = 0; i < declarationCount; i++) {
7022 if (!_analysisContext.exists(source)) { 5124 CompilationUnitMember declaration = declarations[i];
7023 errorListener.onError(new AnalysisError( 5125 if (declaration is ClassDeclaration) {
7024 librarySource, 5126 _resolveClassDeclaration(declaration);
7025 uriLiteral.offset, 5127 }
7026 uriLiteral.length, 5128 }
7027 CompileTimeErrorCode.URI_DOES_NOT_EXIST, 5129 } finally {
7028 [uriContent])); 5130 _overrideManager.exitScope();
7029 } 5131 }
7030 return source; 5132 }
7031 } on URISyntaxException { 5133
7032 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, 5134 /**
7033 uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent])); 5135 * Resolve the instance fields in the given class declaration [node].
7034 } 5136 */
7035 return null; 5137 void _resolveClassDeclaration(ClassDeclaration node) {
7036 } 5138 _enclosingClassDeclaration = node;
7037 5139 ClassElement outerType = enclosingClass;
7038 /** 5140 Scope outerScope = nameScope;
7039 * Returns the URI value of the given directive. 5141 try {
7040 */ 5142 enclosingClass = node.element;
7041 String getUri(UriBasedDirective directive) => _directiveUris[directive]; 5143 typeAnalyzer.thisType = enclosingClass?.type;
7042 5144 if (enclosingClass == null) {
7043 /** 5145 AnalysisEngine.instance.logger.logInformation(
7044 * Set the AST structure associated with the defining compilation unit for thi s library to the 5146 "Missing element for class declaration ${node.name.name} in ${defini ngLibrary.source.fullName}",
7045 * given AST structure. 5147 new CaughtException(new AnalysisException(), null));
7046 * 5148 // Don't try to re-resolve the initializers if we cannot set up the
7047 * @param unit the AST structure associated with the defining compilation unit for this library 5149 // right name scope for resolution.
7048 */ 5150 } else {
7049 void setDefiningCompilationUnit(CompilationUnit unit) { 5151 nameScope = new ClassScope(nameScope, enclosingClass);
7050 _astMap[librarySource] = unit; 5152 NodeList<ClassMember> members = node.members;
7051 } 5153 int length = members.length;
7052 5154 for (int i = 0; i < length; i++) {
7053 @override 5155 ClassMember member = members[i];
7054 String toString() => librarySource.shortName; 5156 if (member is FieldDeclaration) {
7055 } 5157 _resolveFieldDeclaration(member);
7056
7057 /**
7058 * Instances of the class `LibraryElementBuilder` build an element model for a s ingle library.
7059 */
7060 class LibraryElementBuilder {
7061 /**
7062 * The analysis context in which the element model will be built.
7063 */
7064 final InternalAnalysisContext _analysisContext;
7065
7066 /**
7067 * The listener to which errors will be reported.
7068 */
7069 final AnalysisErrorListener _errorListener;
7070
7071 /**
7072 * Initialize a newly created library element builder.
7073 *
7074 * @param analysisContext the analysis context in which the element model will be built
7075 * @param errorListener the listener to which errors will be reported
7076 */
7077 LibraryElementBuilder(this._analysisContext, this._errorListener);
7078
7079 /**
7080 * Build the library element for the given library.
7081 *
7082 * @param library the library for which an element model is to be built
7083 * @return the library element that was built
7084 * @throws AnalysisException if the analysis could not be performed
7085 */
7086 LibraryElementImpl buildLibrary(Library library) {
7087 CompilationUnitBuilder builder = new CompilationUnitBuilder();
7088 Source librarySource = library.librarySource;
7089 CompilationUnit definingCompilationUnit = library.definingCompilationUnit;
7090 CompilationUnitElementImpl definingCompilationUnitElement = builder
7091 .buildCompilationUnit(
7092 librarySource, definingCompilationUnit, librarySource);
7093 NodeList<Directive> directives = definingCompilationUnit.directives;
7094 LibraryDirective libraryDirective = null;
7095 LibraryIdentifier libraryNameNode = null;
7096 bool hasPartDirective = false;
7097 FunctionElement entryPoint =
7098 _findEntryPoint(definingCompilationUnitElement);
7099 List<Directive> directivesToResolve = new List<Directive>();
7100 List<CompilationUnitElementImpl> sourcedCompilationUnits =
7101 new List<CompilationUnitElementImpl>();
7102 for (Directive directive in directives) {
7103 //
7104 // We do not build the elements representing the import and export
7105 // directives at this point. That is not done until we get to
7106 // LibraryResolver.buildDirectiveModels() because we need the
7107 // LibraryElements for the referenced libraries, which might not exist at
7108 // this point (due to the possibility of circular references).
7109 //
7110 if (directive is LibraryDirective) {
7111 if (libraryNameNode == null) {
7112 libraryDirective = directive;
7113 libraryNameNode = directive.name;
7114 directivesToResolve.add(directive);
7115 }
7116 } else if (directive is PartDirective) {
7117 PartDirective partDirective = directive;
7118 StringLiteral partUri = partDirective.uri;
7119 Source partSource = partDirective.source;
7120 if (_analysisContext.exists(partSource)) {
7121 hasPartDirective = true;
7122 CompilationUnit partUnit = library.getAST(partSource);
7123 CompilationUnitElementImpl part =
7124 builder.buildCompilationUnit(partSource, partUnit, librarySource);
7125 part.uriOffset = partUri.offset;
7126 part.uriEnd = partUri.end;
7127 part.uri = partDirective.uriContent;
7128 //
7129 // Validate that the part contains a part-of directive with the same
7130 // name as the library.
7131 //
7132 String partLibraryName =
7133 _getPartLibraryName(partSource, partUnit, directivesToResolve);
7134 if (partLibraryName == null) {
7135 _errorListener.onError(new AnalysisError(
7136 librarySource,
7137 partUri.offset,
7138 partUri.length,
7139 CompileTimeErrorCode.PART_OF_NON_PART,
7140 [partUri.toSource()]));
7141 } else if (libraryNameNode == null) {
7142 // TODO(brianwilkerson) Collect the names declared by the part.
7143 // If they are all the same then we can use that name as the
7144 // inferred name of the library and present it in a quick-fix.
7145 // partLibraryNames.add(partLibraryName);
7146 } else if (libraryNameNode.name != partLibraryName) {
7147 _errorListener.onError(new AnalysisError(
7148 librarySource,
7149 partUri.offset,
7150 partUri.length,
7151 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
7152 [libraryNameNode.name, partLibraryName]));
7153 } 5158 }
7154 if (entryPoint == null) { 5159 }
7155 entryPoint = _findEntryPoint(part); 5160 }
5161 } finally {
5162 nameScope = outerScope;
5163 typeAnalyzer.thisType = outerType?.type;
5164 enclosingClass = outerType;
5165 _enclosingClassDeclaration = null;
5166 }
5167 }
5168
5169 /**
5170 * Resolve the instance fields in the given field declaration [node].
5171 */
5172 void _resolveFieldDeclaration(FieldDeclaration node) {
5173 if (!node.isStatic) {
5174 for (VariableDeclaration field in node.fields.variables) {
5175 if (field.initializer != null) {
5176 field.initializer.accept(this);
5177 FieldElement fieldElement = field.name.staticElement;
5178 if (fieldElement.initializer != null) {
5179 (fieldElement.initializer as ExecutableElementImpl).returnType =
5180 field.initializer.staticType;
7156 } 5181 }
7157 directive.element = part; 5182 }
7158 sourcedCompilationUnits.add(part); 5183 }
7159 } 5184 }
7160 }
7161 }
7162 if (hasPartDirective && libraryNameNode == null) {
7163 _errorListener.onError(new AnalysisError(librarySource, 0, 0,
7164 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
7165 }
7166 //
7167 // Create and populate the library element.
7168 //
7169 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
7170 _analysisContext.getContextFor(librarySource), libraryNameNode);
7171 _setDocRange(libraryElement, libraryDirective);
7172 libraryElement.definingCompilationUnit = definingCompilationUnitElement;
7173 if (entryPoint != null) {
7174 libraryElement.entryPoint = entryPoint;
7175 }
7176 int sourcedUnitCount = sourcedCompilationUnits.length;
7177 libraryElement.parts = sourcedCompilationUnits;
7178 for (Directive directive in directivesToResolve) {
7179 directive.element = libraryElement;
7180 }
7181 library.libraryElement = libraryElement;
7182 if (sourcedUnitCount > 0) {
7183 _patchTopLevelAccessors(libraryElement);
7184 }
7185 return libraryElement;
7186 }
7187
7188 /**
7189 * Build the library element for the given library. The resulting element is
7190 * stored in the [ResolvableLibrary] structure.
7191 *
7192 * @param library the library for which an element model is to be built
7193 * @throws AnalysisException if the analysis could not be performed
7194 */
7195 void buildLibrary2(ResolvableLibrary library) {
7196 CompilationUnitBuilder builder = new CompilationUnitBuilder();
7197 Source librarySource = library.librarySource;
7198 CompilationUnit definingCompilationUnit = library.definingCompilationUnit;
7199 CompilationUnitElementImpl definingCompilationUnitElement = builder
7200 .buildCompilationUnit(
7201 librarySource, definingCompilationUnit, librarySource);
7202 NodeList<Directive> directives = definingCompilationUnit.directives;
7203 LibraryDirective libraryDirective = null;
7204 LibraryIdentifier libraryNameNode = null;
7205 bool hasPartDirective = false;
7206 FunctionElement entryPoint =
7207 _findEntryPoint(definingCompilationUnitElement);
7208 List<Directive> directivesToResolve = new List<Directive>();
7209 List<CompilationUnitElementImpl> sourcedCompilationUnits =
7210 new List<CompilationUnitElementImpl>();
7211 for (Directive directive in directives) {
7212 //
7213 // We do not build the elements representing the import and export
7214 // directives at this point. That is not done until we get to
7215 // LibraryResolver.buildDirectiveModels() because we need the
7216 // LibraryElements for the referenced libraries, which might not exist at
7217 // this point (due to the possibility of circular references).
7218 //
7219 if (directive is LibraryDirective) {
7220 if (libraryNameNode == null) {
7221 libraryDirective = directive;
7222 libraryNameNode = directive.name;
7223 directivesToResolve.add(directive);
7224 }
7225 } else if (directive is PartDirective) {
7226 PartDirective partDirective = directive;
7227 StringLiteral partUri = partDirective.uri;
7228 Source partSource = partDirective.source;
7229 if (_analysisContext.exists(partSource)) {
7230 hasPartDirective = true;
7231 CompilationUnit partUnit = library.getAST(partSource);
7232 if (partUnit != null) {
7233 CompilationUnitElementImpl part = builder.buildCompilationUnit(
7234 partSource, partUnit, librarySource);
7235 part.uriOffset = partUri.offset;
7236 part.uriEnd = partUri.end;
7237 part.uri = partDirective.uriContent;
7238 //
7239 // Validate that the part contains a part-of directive with the same
7240 // name as the library.
7241 //
7242 String partLibraryName =
7243 _getPartLibraryName(partSource, partUnit, directivesToResolve);
7244 if (partLibraryName == null) {
7245 _errorListener.onError(new AnalysisError(
7246 librarySource,
7247 partUri.offset,
7248 partUri.length,
7249 CompileTimeErrorCode.PART_OF_NON_PART,
7250 [partUri.toSource()]));
7251 } else if (libraryNameNode == null) {
7252 // TODO(brianwilkerson) Collect the names declared by the part.
7253 // If they are all the same then we can use that name as the
7254 // inferred name of the library and present it in a quick-fix.
7255 // partLibraryNames.add(partLibraryName);
7256 } else if (libraryNameNode.name != partLibraryName) {
7257 _errorListener.onError(new AnalysisError(
7258 librarySource,
7259 partUri.offset,
7260 partUri.length,
7261 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY,
7262 [libraryNameNode.name, partLibraryName]));
7263 }
7264 if (entryPoint == null) {
7265 entryPoint = _findEntryPoint(part);
7266 }
7267 directive.element = part;
7268 sourcedCompilationUnits.add(part);
7269 }
7270 }
7271 }
7272 }
7273 if (hasPartDirective && libraryNameNode == null) {
7274 _errorListener.onError(new AnalysisError(librarySource, 0, 0,
7275 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART));
7276 }
7277 //
7278 // Create and populate the library element.
7279 //
7280 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
7281 _analysisContext.getContextFor(librarySource), libraryNameNode);
7282 _setDocRange(libraryElement, libraryDirective);
7283 libraryElement.definingCompilationUnit = definingCompilationUnitElement;
7284 if (entryPoint != null) {
7285 libraryElement.entryPoint = entryPoint;
7286 }
7287 int sourcedUnitCount = sourcedCompilationUnits.length;
7288 libraryElement.parts = sourcedCompilationUnits;
7289 for (Directive directive in directivesToResolve) {
7290 directive.element = libraryElement;
7291 }
7292 library.libraryElement = libraryElement;
7293 if (sourcedUnitCount > 0) {
7294 _patchTopLevelAccessors(libraryElement);
7295 }
7296 }
7297
7298 /**
7299 * Add all of the non-synthetic getters and setters defined in the given compi lation unit that
7300 * have no corresponding accessor to one of the given collections.
7301 *
7302 * @param getters the map to which getters are to be added
7303 * @param setters the list to which setters are to be added
7304 * @param unit the compilation unit defining the accessors that are potentiall y being added
7305 */
7306 void _collectAccessors(HashMap<String, PropertyAccessorElement> getters,
7307 List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
7308 for (PropertyAccessorElement accessor in unit.accessors) {
7309 if (accessor.isGetter) {
7310 if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
7311 getters[accessor.displayName] = accessor;
7312 }
7313 } else {
7314 if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
7315 setters.add(accessor);
7316 }
7317 }
7318 }
7319 }
7320
7321 /**
7322 * Search the top-level functions defined in the given compilation unit for th e entry point.
7323 *
7324 * @param element the compilation unit to be searched
7325 * @return the entry point that was found, or `null` if the compilation unit d oes not define
7326 * an entry point
7327 */
7328 FunctionElement _findEntryPoint(CompilationUnitElementImpl element) {
7329 for (FunctionElement function in element.functions) {
7330 if (function.isEntryPoint) {
7331 return function;
7332 }
7333 }
7334 return null;
7335 }
7336
7337 /**
7338 * Return the name of the library that the given part is declared to be a part of, or `null`
7339 * if the part does not contain a part-of directive.
7340 *
7341 * @param partSource the source representing the part
7342 * @param partUnit the AST structure of the part
7343 * @param directivesToResolve a list of directives that should be resolved to the library being
7344 * built
7345 * @return the name of the library that the given part is declared to be a par t of
7346 */
7347 String _getPartLibraryName(Source partSource, CompilationUnit partUnit,
7348 List<Directive> directivesToResolve) {
7349 for (Directive directive in partUnit.directives) {
7350 if (directive is PartOfDirective) {
7351 directivesToResolve.add(directive);
7352 LibraryIdentifier libraryName = directive.libraryName;
7353 if (libraryName != null) {
7354 return libraryName.name;
7355 }
7356 }
7357 }
7358 return null;
7359 }
7360
7361 /**
7362 * Look through all of the compilation units defined for the given library, lo oking for getters
7363 * and setters that are defined in different compilation units but that have t he same names. If
7364 * any are found, make sure that they have the same variable element.
7365 *
7366 * @param libraryElement the library defining the compilation units to be proc essed
7367 */
7368 void _patchTopLevelAccessors(LibraryElementImpl libraryElement) {
7369 HashMap<String, PropertyAccessorElement> getters =
7370 new HashMap<String, PropertyAccessorElement>();
7371 List<PropertyAccessorElement> setters = new List<PropertyAccessorElement>();
7372 _collectAccessors(getters, setters, libraryElement.definingCompilationUnit);
7373 for (CompilationUnitElement unit in libraryElement.parts) {
7374 _collectAccessors(getters, setters, unit);
7375 }
7376 for (PropertyAccessorElement setter in setters) {
7377 PropertyAccessorElement getter = getters[setter.displayName];
7378 if (getter != null) {
7379 PropertyInducingElementImpl variable =
7380 getter.variable as PropertyInducingElementImpl;
7381 variable.setter = setter;
7382 (setter as PropertyAccessorElementImpl).variable = variable;
7383 }
7384 }
7385 }
7386
7387 /**
7388 * If the given [node] has a documentation comment, remember its range
7389 * into the given [element].
7390 */
7391 void _setDocRange(ElementImpl element, LibraryDirective node) {
7392 if (node != null) {
7393 Comment comment = node.documentationComment;
7394 if (comment != null && comment.isDocumentation) {
7395 element.setDocRange(comment.offset, comment.length);
7396 }
7397 }
7398 }
7399 }
7400
7401 /**
7402 * Instances of the class `LibraryImportScope` represent the scope containing al l of the names
7403 * available from imported libraries.
7404 */
7405 class LibraryImportScope extends Scope {
7406 /**
7407 * The element representing the library in which this scope is enclosed.
7408 */
7409 final LibraryElement _definingLibrary;
7410
7411 /**
7412 * The listener that is to be informed when an error is encountered.
7413 */
7414 final AnalysisErrorListener errorListener;
7415
7416 /**
7417 * A list of the namespaces representing the names that are available in this scope from imported
7418 * libraries.
7419 */
7420 List<Namespace> _importedNamespaces;
7421
7422 /**
7423 * Initialize a newly created scope representing the names imported into the g iven library.
7424 *
7425 * @param definingLibrary the element representing the library that imports th e names defined in
7426 * this scope
7427 * @param errorListener the listener that is to be informed when an error is e ncountered
7428 */
7429 LibraryImportScope(this._definingLibrary, this.errorListener) {
7430 _createImportedNamespaces();
7431 }
7432
7433 @override
7434 void define(Element element) {
7435 if (!Scope.isPrivateName(element.displayName)) {
7436 super.define(element);
7437 }
7438 }
7439
7440 @override
7441 Source getSource(AstNode node) {
7442 Source source = super.getSource(node);
7443 if (source == null) {
7444 source = _definingLibrary.definingCompilationUnit.source;
7445 }
7446 return source;
7447 }
7448
7449 @override
7450 Element internalLookup(
7451 Identifier identifier, String name, LibraryElement referencingLibrary) {
7452 Element foundElement = localLookup(name, referencingLibrary);
7453 if (foundElement != null) {
7454 return foundElement;
7455 }
7456 for (int i = 0; i < _importedNamespaces.length; i++) {
7457 Namespace nameSpace = _importedNamespaces[i];
7458 Element element = nameSpace.get(name);
7459 if (element != null) {
7460 if (foundElement == null) {
7461 foundElement = element;
7462 } else if (!identical(foundElement, element)) {
7463 foundElement = MultiplyDefinedElementImpl.fromElements(
7464 _definingLibrary.context, foundElement, element);
7465 }
7466 }
7467 }
7468 if (foundElement is MultiplyDefinedElementImpl) {
7469 foundElement = _removeSdkElements(
7470 identifier, name, foundElement as MultiplyDefinedElementImpl);
7471 }
7472 if (foundElement is MultiplyDefinedElementImpl) {
7473 String foundEltName = foundElement.displayName;
7474 List<Element> conflictingMembers = foundElement.conflictingElements;
7475 int count = conflictingMembers.length;
7476 List<String> libraryNames = new List<String>(count);
7477 for (int i = 0; i < count; i++) {
7478 libraryNames[i] = _getLibraryName(conflictingMembers[i]);
7479 }
7480 libraryNames.sort();
7481 errorListener.onError(new AnalysisError(
7482 getSource(identifier),
7483 identifier.offset,
7484 identifier.length,
7485 StaticWarningCode.AMBIGUOUS_IMPORT, [
7486 foundEltName,
7487 StringUtilities.printListOfQuotedNames(libraryNames)
7488 ]));
7489 return foundElement;
7490 }
7491 if (foundElement != null) {
7492 defineNameWithoutChecking(name, foundElement);
7493 }
7494 return foundElement;
7495 }
7496
7497 /**
7498 * Create all of the namespaces associated with the libraries imported into th is library. The
7499 * names are not added to this scope, but are stored for later reference.
7500 *
7501 * @param definingLibrary the element representing the library that imports th e libraries for
7502 * which namespaces will be created
7503 */
7504 void _createImportedNamespaces() {
7505 NamespaceBuilder builder = new NamespaceBuilder();
7506 List<ImportElement> imports = _definingLibrary.imports;
7507 int count = imports.length;
7508 _importedNamespaces = new List<Namespace>(count);
7509 for (int i = 0; i < count; i++) {
7510 _importedNamespaces[i] =
7511 builder.createImportNamespaceForDirective(imports[i]);
7512 }
7513 }
7514
7515 /**
7516 * Returns the name of the library that defines given element.
7517 *
7518 * @param element the element to get library name
7519 * @return the name of the library that defines given element
7520 */
7521 String _getLibraryName(Element element) {
7522 if (element == null) {
7523 return StringUtilities.EMPTY;
7524 }
7525 LibraryElement library = element.library;
7526 if (library == null) {
7527 return StringUtilities.EMPTY;
7528 }
7529 List<ImportElement> imports = _definingLibrary.imports;
7530 int count = imports.length;
7531 for (int i = 0; i < count; i++) {
7532 if (identical(imports[i].importedLibrary, library)) {
7533 return library.definingCompilationUnit.displayName;
7534 }
7535 }
7536 List<String> indirectSources = new List<String>();
7537 for (int i = 0; i < count; i++) {
7538 LibraryElement importedLibrary = imports[i].importedLibrary;
7539 if (importedLibrary != null) {
7540 for (LibraryElement exportedLibrary
7541 in importedLibrary.exportedLibraries) {
7542 if (identical(exportedLibrary, library)) {
7543 indirectSources
7544 .add(importedLibrary.definingCompilationUnit.displayName);
7545 }
7546 }
7547 }
7548 }
7549 int indirectCount = indirectSources.length;
7550 StringBuffer buffer = new StringBuffer();
7551 buffer.write(library.definingCompilationUnit.displayName);
7552 if (indirectCount > 0) {
7553 buffer.write(" (via ");
7554 if (indirectCount > 1) {
7555 indirectSources.sort();
7556 buffer.write(StringUtilities.printListOfQuotedNames(indirectSources));
7557 } else {
7558 buffer.write(indirectSources[0]);
7559 }
7560 buffer.write(")");
7561 }
7562 return buffer.toString();
7563 }
7564
7565 /**
7566 * Given a collection of elements (captured by the [foundElement]) that the
7567 * [identifier] (with the given [name]) resolved to, remove from the list all
7568 * of the names defined in the SDK and return the element(s) that remain.
7569 */
7570 Element _removeSdkElements(Identifier identifier, String name,
7571 MultiplyDefinedElementImpl foundElement) {
7572 List<Element> conflictingElements = foundElement.conflictingElements;
7573 List<Element> nonSdkElements = new List<Element>();
7574 Element sdkElement = null;
7575 for (Element member in conflictingElements) {
7576 if (member.library.isInSdk) {
7577 sdkElement = member;
7578 } else {
7579 nonSdkElements.add(member);
7580 }
7581 }
7582 if (sdkElement != null && nonSdkElements.length > 0) {
7583 String sdkLibName = _getLibraryName(sdkElement);
7584 String otherLibName = _getLibraryName(nonSdkElements[0]);
7585 errorListener.onError(new AnalysisError(
7586 getSource(identifier),
7587 identifier.offset,
7588 identifier.length,
7589 StaticWarningCode.CONFLICTING_DART_IMPORT,
7590 [name, sdkLibName, otherLibName]));
7591 }
7592 if (nonSdkElements.length == conflictingElements.length) {
7593 // None of the members were removed
7594 return foundElement;
7595 } else if (nonSdkElements.length == 1) {
7596 // All but one member was removed
7597 return nonSdkElements[0];
7598 } else if (nonSdkElements.length == 0) {
7599 // All members were removed
7600 AnalysisEngine.instance.logger
7601 .logInformation("Multiply defined SDK element: $foundElement");
7602 return foundElement;
7603 }
7604 return new MultiplyDefinedElementImpl(
7605 _definingLibrary.context, nonSdkElements);
7606 }
7607 }
7608
7609 /**
7610 * Instances of the class `LibraryResolver` are used to resolve one or more mutu ally dependent
7611 * libraries within a single context.
7612 */
7613 class LibraryResolver {
7614 /**
7615 * The analysis context in which the libraries are being analyzed.
7616 */
7617 final InternalAnalysisContext analysisContext;
7618
7619 /**
7620 * The listener to which analysis errors will be reported, this error listener is either
7621 * references [recordingErrorListener], or it unions the passed
7622 * [AnalysisErrorListener] with the [recordingErrorListener].
7623 */
7624 RecordingErrorListener _errorListener;
7625
7626 /**
7627 * A source object representing the core library (dart:core).
7628 */
7629 Source _coreLibrarySource;
7630
7631 /**
7632 * A Source object representing the async library (dart:async).
7633 */
7634 Source _asyncLibrarySource;
7635
7636 /**
7637 * The object representing the core library.
7638 */
7639 Library _coreLibrary;
7640
7641 /**
7642 * The object representing the async library.
7643 */
7644 Library _asyncLibrary;
7645
7646 /**
7647 * The object used to access the types from the core library.
7648 */
7649 TypeProvider _typeProvider;
7650
7651 /**
7652 * The type system in use for the library
7653 */
7654 TypeSystem _typeSystem;
7655
7656 /**
7657 * A table mapping library sources to the information being maintained for tho se libraries.
7658 */
7659 HashMap<Source, Library> _libraryMap = new HashMap<Source, Library>();
7660
7661 /**
7662 * A collection containing the libraries that are being resolved together.
7663 */
7664 Set<Library> _librariesInCycles;
7665
7666 /**
7667 * Initialize a newly created library resolver to resolve libraries within the given context.
7668 *
7669 * @param analysisContext the analysis context in which the library is being a nalyzed
7670 */
7671 LibraryResolver(this.analysisContext) {
7672 this._errorListener = new RecordingErrorListener();
7673 _coreLibrarySource =
7674 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE);
7675 _asyncLibrarySource =
7676 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC);
7677 }
7678
7679 /**
7680 * Return the listener to which analysis errors will be reported.
7681 *
7682 * @return the listener to which analysis errors will be reported
7683 */
7684 RecordingErrorListener get errorListener => _errorListener;
7685
7686 /**
7687 * Return an array containing information about all of the libraries that were resolved.
7688 *
7689 * @return an array containing the libraries that were resolved
7690 */
7691 Set<Library> get resolvedLibraries => _librariesInCycles;
7692
7693 /**
7694 * The object used to access the types from the core library.
7695 */
7696 TypeProvider get typeProvider => _typeProvider;
7697
7698 /**
7699 * The type system in use.
7700 */
7701 TypeSystem get typeSystem => _typeSystem;
7702
7703 /**
7704 * Create an object to represent the information about the library defined by the compilation unit
7705 * with the given source.
7706 *
7707 * @param librarySource the source of the library's defining compilation unit
7708 * @return the library object that was created
7709 * @throws AnalysisException if the library source is not valid
7710 */
7711 Library createLibrary(Source librarySource) {
7712 Library library =
7713 new Library(analysisContext, _errorListener, librarySource);
7714 _libraryMap[librarySource] = library;
7715 return library;
7716 }
7717
7718 /**
7719 * Resolve the library specified by the given source in the given context. The library is assumed
7720 * to be embedded in the given source.
7721 *
7722 * @param librarySource the source specifying the defining compilation unit of the library to be
7723 * resolved
7724 * @param unit the compilation unit representing the embedded library
7725 * @param fullAnalysis `true` if a full analysis should be performed
7726 * @return the element representing the resolved library
7727 * @throws AnalysisException if the library could not be resolved for some rea son
7728 */
7729 LibraryElement resolveEmbeddedLibrary(
7730 Source librarySource, CompilationUnit unit, bool fullAnalysis) {
7731 //
7732 // Create the objects representing the library being resolved and the core
7733 // library.
7734 //
7735 Library targetLibrary = _createLibraryWithUnit(librarySource, unit);
7736 _coreLibrary = _libraryMap[_coreLibrarySource];
7737 if (_coreLibrary == null) {
7738 // This will only happen if the library being analyzed is the core
7739 // library.
7740 _coreLibrary = createLibrary(_coreLibrarySource);
7741 if (_coreLibrary == null) {
7742 LibraryResolver2.missingCoreLibrary(
7743 analysisContext, _coreLibrarySource);
7744 }
7745 }
7746 _asyncLibrary = _libraryMap[_asyncLibrarySource];
7747 if (_asyncLibrary == null) {
7748 // This will only happen if the library being analyzed is the async
7749 // library.
7750 _asyncLibrary = createLibrary(_asyncLibrarySource);
7751 if (_asyncLibrary == null) {
7752 LibraryResolver2.missingAsyncLibrary(
7753 analysisContext, _asyncLibrarySource);
7754 }
7755 }
7756 //
7757 // Compute the set of libraries that need to be resolved together.
7758 //
7759 _computeEmbeddedLibraryDependencies(targetLibrary, unit);
7760 _librariesInCycles = _computeLibrariesInCycles(targetLibrary);
7761 //
7762 // Build the element models representing the libraries being resolved.
7763 // This is done in three steps:
7764 //
7765 // 1. Build the basic element models without making any connections
7766 // between elements other than the basic parent/child relationships.
7767 // This includes building the elements representing the libraries.
7768 // 2. Build the elements for the import and export directives. This
7769 // requires that we have the elements built for the referenced
7770 // libraries, but because of the possibility of circular references
7771 // needs to happen after all of the library elements have been created.
7772 // 3. Build the rest of the type model by connecting superclasses, mixins,
7773 // and interfaces. This requires that we be able to compute the names
7774 // visible in the libraries being resolved, which in turn requires that
7775 // we have resolved the import directives.
7776 //
7777 _buildElementModels();
7778 LibraryElement coreElement = _coreLibrary.libraryElement;
7779 if (coreElement == null) {
7780 throw new AnalysisException("Could not resolve dart:core");
7781 }
7782 LibraryElement asyncElement = _asyncLibrary.libraryElement;
7783 if (asyncElement == null) {
7784 throw new AnalysisException("Could not resolve dart:async");
7785 }
7786 _buildDirectiveModels();
7787 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
7788 _typeSystem = TypeSystem.create(analysisContext);
7789 _buildTypeHierarchies();
7790 //
7791 // Perform resolution and type analysis.
7792 //
7793 // TODO(brianwilkerson) Decide whether we want to resolve all of the
7794 // libraries or whether we want to only resolve the target library.
7795 // The advantage to resolving everything is that we have already done part
7796 // of the work so we'll avoid duplicated effort. The disadvantage of
7797 // resolving everything is that we might do extra work that we don't
7798 // really care about. Another possibility is to add a parameter to this
7799 // method and punt the decision to the clients.
7800 //
7801 //if (analyzeAll) {
7802 resolveReferencesAndTypes();
7803 //} else {
7804 // resolveReferencesAndTypes(targetLibrary);
7805 //}
7806 _performConstantEvaluation();
7807 return targetLibrary.libraryElement;
7808 }
7809
7810 /**
7811 * Resolve the library specified by the given source in the given context.
7812 *
7813 * Note that because Dart allows circular imports between libraries, it is pos sible that more than
7814 * one library will need to be resolved. In such cases the error listener can receive errors from
7815 * multiple libraries.
7816 *
7817 * @param librarySource the source specifying the defining compilation unit of the library to be
7818 * resolved
7819 * @param fullAnalysis `true` if a full analysis should be performed
7820 * @return the element representing the resolved library
7821 * @throws AnalysisException if the library could not be resolved for some rea son
7822 */
7823 LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) {
7824 //
7825 // Create the object representing the library being resolved and compute
7826 // the dependency relationship. Note that all libraries depend implicitly
7827 // on core, and we inject an ersatz dependency on async, so once this is
7828 // done the core and async library elements will have been created.
7829 //
7830 Library targetLibrary = createLibrary(librarySource);
7831 _computeLibraryDependencies(targetLibrary);
7832 _coreLibrary = _libraryMap[_coreLibrarySource];
7833 _asyncLibrary = _libraryMap[_asyncLibrarySource];
7834 //
7835 // Compute the set of libraries that need to be resolved together.
7836 //
7837 _librariesInCycles = _computeLibrariesInCycles(targetLibrary);
7838 //
7839 // Build the element models representing the libraries being resolved.
7840 // This is done in three steps:
7841 //
7842 // 1. Build the basic element models without making any connections
7843 // between elements other than the basic parent/child relationships.
7844 // This includes building the elements representing the libraries, but
7845 // excludes members defined in enums.
7846 // 2. Build the elements for the import and export directives. This
7847 // requires that we have the elements built for the referenced
7848 // libraries, but because of the possibility of circular references
7849 // needs to happen after all of the library elements have been created.
7850 // 3. Build the members in enum declarations.
7851 // 4. Build the rest of the type model by connecting superclasses, mixins,
7852 // and interfaces. This requires that we be able to compute the names
7853 // visible in the libraries being resolved, which in turn requires that
7854 // we have resolved the import directives.
7855 //
7856 _buildElementModels();
7857 LibraryElement coreElement = _coreLibrary.libraryElement;
7858 if (coreElement == null) {
7859 throw new AnalysisException("Could not resolve dart:core");
7860 }
7861 LibraryElement asyncElement = _asyncLibrary.libraryElement;
7862 if (asyncElement == null) {
7863 throw new AnalysisException("Could not resolve dart:async");
7864 }
7865 _buildDirectiveModels();
7866 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
7867 _typeSystem = TypeSystem.create(analysisContext);
7868 _buildEnumMembers();
7869 _buildTypeHierarchies();
7870 //
7871 // Perform resolution and type analysis.
7872 //
7873 // TODO(brianwilkerson) Decide whether we want to resolve all of the
7874 // libraries or whether we want to only resolve the target library. The
7875 // advantage to resolving everything is that we have already done part of
7876 // the work so we'll avoid duplicated effort. The disadvantage of
7877 // resolving everything is that we might do extra work that we don't
7878 // really care about. Another possibility is to add a parameter to this
7879 // method and punt the decision to the clients.
7880 //
7881 //if (analyzeAll) {
7882 resolveReferencesAndTypes();
7883 //} else {
7884 // resolveReferencesAndTypes(targetLibrary);
7885 //}
7886 _performConstantEvaluation();
7887 return targetLibrary.libraryElement;
7888 }
7889
7890 /**
7891 * Resolve the identifiers and perform type analysis in the libraries in the c urrent cycle.
7892 *
7893 * @throws AnalysisException if any of the identifiers could not be resolved o r if any of the
7894 * libraries could not have their types analyzed
7895 */
7896 void resolveReferencesAndTypes() {
7897 for (Library library in _librariesInCycles) {
7898 _resolveReferencesAndTypesInLibrary(library);
7899 }
7900 }
7901
7902 /**
7903 * Add a dependency to the given map from the referencing library to the refer enced library.
7904 *
7905 * @param dependencyMap the map to which the dependency is to be added
7906 * @param referencingLibrary the library that references the referenced librar y
7907 * @param referencedLibrary the library referenced by the referencing library
7908 */
7909 void _addDependencyToMap(HashMap<Library, List<Library>> dependencyMap,
7910 Library referencingLibrary, Library referencedLibrary) {
7911 List<Library> dependentLibraries = dependencyMap[referencedLibrary];
7912 if (dependentLibraries == null) {
7913 dependentLibraries = new List<Library>();
7914 dependencyMap[referencedLibrary] = dependentLibraries;
7915 }
7916 dependentLibraries.add(referencingLibrary);
7917 }
7918
7919 /**
7920 * Given a library that is part of a cycle that includes the root library, add to the given set of
7921 * libraries all of the libraries reachable from the root library that are als o included in the
7922 * cycle.
7923 *
7924 * @param library the library to be added to the collection of libraries in cy cles
7925 * @param librariesInCycle a collection of the libraries that are in the cycle
7926 * @param dependencyMap a table mapping libraries to the collection of librari es from which those
7927 * libraries are referenced
7928 */
7929 void _addLibrariesInCycle(Library library, Set<Library> librariesInCycle,
7930 HashMap<Library, List<Library>> dependencyMap) {
7931 if (librariesInCycle.add(library)) {
7932 List<Library> dependentLibraries = dependencyMap[library];
7933 if (dependentLibraries != null) {
7934 for (Library dependentLibrary in dependentLibraries) {
7935 _addLibrariesInCycle(
7936 dependentLibrary, librariesInCycle, dependencyMap);
7937 }
7938 }
7939 }
7940 }
7941
7942 /**
7943 * Add the given library, and all libraries reachable from it that have not al ready been visited,
7944 * to the given dependency map.
7945 *
7946 * @param library the library currently being added to the dependency map
7947 * @param dependencyMap the dependency map being computed
7948 * @param visitedLibraries the libraries that have already been visited, used to prevent infinite
7949 * recursion
7950 */
7951 void _addToDependencyMap(
7952 Library library,
7953 HashMap<Library, List<Library>> dependencyMap,
7954 Set<Library> visitedLibraries) {
7955 if (visitedLibraries.add(library)) {
7956 bool asyncFound = false;
7957 for (Library referencedLibrary in library.importsAndExports) {
7958 _addDependencyToMap(dependencyMap, library, referencedLibrary);
7959 _addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries);
7960 if (identical(referencedLibrary, _asyncLibrary)) {
7961 asyncFound = true;
7962 }
7963 }
7964 if (!library.explicitlyImportsCore && !identical(library, _coreLibrary)) {
7965 _addDependencyToMap(dependencyMap, library, _coreLibrary);
7966 }
7967 if (!asyncFound && !identical(library, _asyncLibrary)) {
7968 _addDependencyToMap(dependencyMap, library, _asyncLibrary);
7969 _addToDependencyMap(_asyncLibrary, dependencyMap, visitedLibraries);
7970 }
7971 }
7972 }
7973
7974 /**
7975 * Build the element model representing the combinators declared by the given directive.
7976 *
7977 * @param directive the directive that declares the combinators
7978 * @return an array containing the import combinators that were built
7979 */
7980 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) {
7981 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>();
7982 for (Combinator combinator in directive.combinators) {
7983 if (combinator is HideCombinator) {
7984 HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
7985 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames);
7986 combinators.add(hide);
7987 } else {
7988 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
7989 show.offset = combinator.offset;
7990 show.end = combinator.end;
7991 show.shownNames =
7992 _getIdentifiers((combinator as ShowCombinator).shownNames);
7993 combinators.add(show);
7994 }
7995 }
7996 return combinators;
7997 }
7998
7999 /**
8000 * Every library now has a corresponding [LibraryElement], so it is now possib le to resolve
8001 * the import and export directives.
8002 *
8003 * @throws AnalysisException if the defining compilation unit for any of the l ibraries could not
8004 * be accessed
8005 */
8006 void _buildDirectiveModels() {
8007 for (Library library in _librariesInCycles) {
8008 HashMap<String, PrefixElementImpl> nameToPrefixMap =
8009 new HashMap<String, PrefixElementImpl>();
8010 List<ImportElement> imports = new List<ImportElement>();
8011 List<ExportElement> exports = new List<ExportElement>();
8012 for (Directive directive in library.definingCompilationUnit.directives) {
8013 if (directive is ImportDirective) {
8014 ImportDirective importDirective = directive;
8015 String uriContent = importDirective.uriContent;
8016 if (DartUriResolver.isDartExtUri(uriContent)) {
8017 library.libraryElement.hasExtUri = true;
8018 }
8019 Source importedSource = importDirective.source;
8020 if (importedSource != null) {
8021 // The imported source will be null if the URI in the import
8022 // directive was invalid.
8023 Library importedLibrary = _libraryMap[importedSource];
8024 if (importedLibrary != null) {
8025 ImportElementImpl importElement =
8026 new ImportElementImpl(directive.offset);
8027 StringLiteral uriLiteral = importDirective.uri;
8028 importElement.uriOffset = uriLiteral.offset;
8029 importElement.uriEnd = uriLiteral.end;
8030 importElement.uri = uriContent;
8031 importElement.deferred = importDirective.deferredKeyword != null;
8032 importElement.combinators = _buildCombinators(importDirective);
8033 LibraryElement importedLibraryElement =
8034 importedLibrary.libraryElement;
8035 if (importedLibraryElement != null) {
8036 importElement.importedLibrary = importedLibraryElement;
8037 }
8038 SimpleIdentifier prefixNode = directive.prefix;
8039 if (prefixNode != null) {
8040 importElement.prefixOffset = prefixNode.offset;
8041 String prefixName = prefixNode.name;
8042 PrefixElementImpl prefix = nameToPrefixMap[prefixName];
8043 if (prefix == null) {
8044 prefix = new PrefixElementImpl.forNode(prefixNode);
8045 nameToPrefixMap[prefixName] = prefix;
8046 }
8047 importElement.prefix = prefix;
8048 prefixNode.staticElement = prefix;
8049 }
8050 directive.element = importElement;
8051 imports.add(importElement);
8052 if (analysisContext.computeKindOf(importedSource) !=
8053 SourceKind.LIBRARY) {
8054 ErrorCode errorCode = (importElement.isDeferred
8055 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
8056 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
8057 _errorListener.onError(new AnalysisError(
8058 library.librarySource,
8059 uriLiteral.offset,
8060 uriLiteral.length,
8061 errorCode,
8062 [uriLiteral.toSource()]));
8063 }
8064 }
8065 }
8066 } else if (directive is ExportDirective) {
8067 ExportDirective exportDirective = directive;
8068 Source exportedSource = exportDirective.source;
8069 if (exportedSource != null) {
8070 // The exported source will be null if the URI in the export
8071 // directive was invalid.
8072 Library exportedLibrary = _libraryMap[exportedSource];
8073 if (exportedLibrary != null) {
8074 ExportElementImpl exportElement =
8075 new ExportElementImpl(directive.offset);
8076 StringLiteral uriLiteral = exportDirective.uri;
8077 exportElement.uriOffset = uriLiteral.offset;
8078 exportElement.uriEnd = uriLiteral.end;
8079 exportElement.uri = exportDirective.uriContent;
8080 exportElement.combinators = _buildCombinators(exportDirective);
8081 LibraryElement exportedLibraryElement =
8082 exportedLibrary.libraryElement;
8083 if (exportedLibraryElement != null) {
8084 exportElement.exportedLibrary = exportedLibraryElement;
8085 }
8086 directive.element = exportElement;
8087 exports.add(exportElement);
8088 if (analysisContext.computeKindOf(exportedSource) !=
8089 SourceKind.LIBRARY) {
8090 _errorListener.onError(new AnalysisError(
8091 library.librarySource,
8092 uriLiteral.offset,
8093 uriLiteral.length,
8094 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
8095 [uriLiteral.toSource()]));
8096 }
8097 }
8098 }
8099 }
8100 }
8101 Source librarySource = library.librarySource;
8102 if (!library.explicitlyImportsCore &&
8103 _coreLibrarySource != librarySource) {
8104 ImportElementImpl importElement = new ImportElementImpl(-1);
8105 importElement.importedLibrary = _coreLibrary.libraryElement;
8106 importElement.synthetic = true;
8107 imports.add(importElement);
8108 }
8109 LibraryElementImpl libraryElement = library.libraryElement;
8110 libraryElement.imports = imports;
8111 libraryElement.exports = exports;
8112 if (libraryElement.entryPoint == null) {
8113 Namespace namespace = new NamespaceBuilder()
8114 .createExportNamespaceForLibrary(libraryElement);
8115 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME);
8116 if (element is FunctionElement) {
8117 libraryElement.entryPoint = element;
8118 }
8119 }
8120 }
8121 }
8122
8123 /**
8124 * Build element models for all of the libraries in the current cycle.
8125 *
8126 * @throws AnalysisException if any of the element models cannot be built
8127 */
8128 void _buildElementModels() {
8129 for (Library library in _librariesInCycles) {
8130 LibraryElementBuilder builder =
8131 new LibraryElementBuilder(analysisContext, errorListener);
8132 LibraryElementImpl libraryElement = builder.buildLibrary(library);
8133 library.libraryElement = libraryElement;
8134 }
8135 }
8136
8137 /**
8138 * Build the members in enum declarations. This cannot be done while building the rest of the
8139 * element model because it depends on being able to access core types, which cannot happen until
8140 * the rest of the element model has been built (when resolving the core libra ry).
8141 *
8142 * @throws AnalysisException if any of the enum members could not be built
8143 */
8144 void _buildEnumMembers() {
8145 PerformanceStatistics.resolve.makeCurrentWhile(() {
8146 for (Library library in _librariesInCycles) {
8147 for (Source source in library.compilationUnitSources) {
8148 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider);
8149 library.getAST(source).accept(builder);
8150 }
8151 }
8152 });
8153 }
8154
8155 /**
8156 * Resolve the type hierarchy across all of the types declared in the librarie s in the current
8157 * cycle.
8158 *
8159 * @throws AnalysisException if any of the type hierarchies could not be resol ved
8160 */
8161 void _buildTypeHierarchies() {
8162 PerformanceStatistics.resolve.makeCurrentWhile(() {
8163 for (Library library in _librariesInCycles) {
8164 for (Source source in library.compilationUnitSources) {
8165 TypeResolverVisitorFactory typeResolverVisitorFactory =
8166 analysisContext.typeResolverVisitorFactory;
8167 TypeResolverVisitor visitor = (typeResolverVisitorFactory == null)
8168 ? new TypeResolverVisitor(library.libraryElement, source,
8169 _typeProvider, library.errorListener,
8170 nameScope: library.libraryScope)
8171 : typeResolverVisitorFactory(library, source, _typeProvider);
8172 library.getAST(source).accept(visitor);
8173 }
8174 }
8175 });
8176 }
8177
8178 /**
8179 * Compute a dependency map of libraries reachable from the given library. A d ependency map is a
8180 * table that maps individual libraries to a list of the libraries that either import or export
8181 * those libraries.
8182 *
8183 * This map is used to compute all of the libraries involved in a cycle that i nclude the root
8184 * library. Given that we only add libraries that are reachable from the root library, when we
8185 * work backward we are guaranteed to only get libraries in the cycle.
8186 *
8187 * @param library the library currently being added to the dependency map
8188 */
8189 HashMap<Library, List<Library>> _computeDependencyMap(Library library) {
8190 HashMap<Library, List<Library>> dependencyMap =
8191 new HashMap<Library, List<Library>>();
8192 _addToDependencyMap(library, dependencyMap, new HashSet<Library>());
8193 return dependencyMap;
8194 }
8195
8196 /**
8197 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8198 * class [Library] to represent them, and record the references in the library objects.
8199 *
8200 * @param library the library to be processed to find libraries that have not yet been traversed
8201 * @throws AnalysisException if some portion of the library graph could not be traversed
8202 */
8203 void _computeEmbeddedLibraryDependencies(
8204 Library library, CompilationUnit unit) {
8205 Source librarySource = library.librarySource;
8206 HashSet<Source> exportedSources = new HashSet<Source>();
8207 HashSet<Source> importedSources = new HashSet<Source>();
8208 for (Directive directive in unit.directives) {
8209 if (directive is ExportDirective) {
8210 Source exportSource = _resolveSource(librarySource, directive);
8211 if (exportSource != null) {
8212 exportedSources.add(exportSource);
8213 }
8214 } else if (directive is ImportDirective) {
8215 Source importSource = _resolveSource(librarySource, directive);
8216 if (importSource != null) {
8217 importedSources.add(importSource);
8218 }
8219 }
8220 }
8221 _computeLibraryDependenciesFromDirectives(library,
8222 new List.from(importedSources), new List.from(exportedSources));
8223 }
8224
8225 /**
8226 * Return a collection containing all of the libraries reachable from the give n library that are
8227 * contained in a cycle that includes the given library.
8228 *
8229 * @param library the library that must be included in any cycles whose member s are to be returned
8230 * @return all of the libraries referenced by the given library that have a ci rcular reference
8231 * back to the given library
8232 */
8233 Set<Library> _computeLibrariesInCycles(Library library) {
8234 HashMap<Library, List<Library>> dependencyMap =
8235 _computeDependencyMap(library);
8236 Set<Library> librariesInCycle = new HashSet<Library>();
8237 _addLibrariesInCycle(library, librariesInCycle, dependencyMap);
8238 return librariesInCycle;
8239 }
8240
8241 /**
8242 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8243 * class [Library] to represent them, and record the references in the library objects.
8244 *
8245 * @param library the library to be processed to find libraries that have not yet been traversed
8246 * @throws AnalysisException if some portion of the library graph could not be traversed
8247 */
8248 void _computeLibraryDependencies(Library library) {
8249 Source librarySource = library.librarySource;
8250 _computeLibraryDependenciesFromDirectives(
8251 library,
8252 analysisContext.computeImportedLibraries(librarySource),
8253 analysisContext.computeExportedLibraries(librarySource));
8254 }
8255
8256 /**
8257 * Recursively traverse the libraries reachable from the given library, creati ng instances of the
8258 * class [Library] to represent them, and record the references in the library objects.
8259 *
8260 * @param library the library to be processed to find libraries that have not yet been traversed
8261 * @param importedSources an array containing the sources that are imported in to the given library
8262 * @param exportedSources an array containing the sources that are exported fr om the given library
8263 * @throws AnalysisException if some portion of the library graph could not be traversed
8264 */
8265 void _computeLibraryDependenciesFromDirectives(Library library,
8266 List<Source> importedSources, List<Source> exportedSources) {
8267 List<Library> importedLibraries = new List<Library>();
8268 bool explicitlyImportsCore = false;
8269 bool importsAsync = false;
8270 for (Source importedSource in importedSources) {
8271 if (importedSource == _coreLibrarySource) {
8272 explicitlyImportsCore = true;
8273 }
8274 if (importedSource == _asyncLibrarySource) {
8275 importsAsync = true;
8276 }
8277 Library importedLibrary = _libraryMap[importedSource];
8278 if (importedLibrary == null) {
8279 importedLibrary = _createLibraryOrNull(importedSource);
8280 if (importedLibrary != null) {
8281 _computeLibraryDependencies(importedLibrary);
8282 }
8283 }
8284 if (importedLibrary != null) {
8285 importedLibraries.add(importedLibrary);
8286 }
8287 }
8288 library.importedLibraries = importedLibraries;
8289 List<Library> exportedLibraries = new List<Library>();
8290 for (Source exportedSource in exportedSources) {
8291 Library exportedLibrary = _libraryMap[exportedSource];
8292 if (exportedLibrary == null) {
8293 exportedLibrary = _createLibraryOrNull(exportedSource);
8294 if (exportedLibrary != null) {
8295 _computeLibraryDependencies(exportedLibrary);
8296 }
8297 }
8298 if (exportedLibrary != null) {
8299 exportedLibraries.add(exportedLibrary);
8300 }
8301 }
8302 library.exportedLibraries = exportedLibraries;
8303 library.explicitlyImportsCore = explicitlyImportsCore;
8304 if (!explicitlyImportsCore && _coreLibrarySource != library.librarySource) {
8305 Library importedLibrary = _libraryMap[_coreLibrarySource];
8306 if (importedLibrary == null) {
8307 importedLibrary = _createLibraryOrNull(_coreLibrarySource);
8308 if (importedLibrary != null) {
8309 _computeLibraryDependencies(importedLibrary);
8310 }
8311 }
8312 }
8313 if (!importsAsync && _asyncLibrarySource != library.librarySource) {
8314 Library importedLibrary = _libraryMap[_asyncLibrarySource];
8315 if (importedLibrary == null) {
8316 importedLibrary = _createLibraryOrNull(_asyncLibrarySource);
8317 if (importedLibrary != null) {
8318 _computeLibraryDependencies(importedLibrary);
8319 }
8320 }
8321 }
8322 }
8323
8324 /**
8325 * Create an object to represent the information about the library defined by the compilation unit
8326 * with the given source. Return the library object that was created, or `null ` if the
8327 * source is not valid.
8328 *
8329 * @param librarySource the source of the library's defining compilation unit
8330 * @return the library object that was created
8331 */
8332 Library _createLibraryOrNull(Source librarySource) {
8333 if (!analysisContext.exists(librarySource)) {
8334 return null;
8335 }
8336 Library library =
8337 new Library(analysisContext, _errorListener, librarySource);
8338 _libraryMap[librarySource] = library;
8339 return library;
8340 }
8341
8342 /**
8343 * Create an object to represent the information about the library defined by the compilation unit
8344 * with the given source.
8345 *
8346 * @param librarySource the source of the library's defining compilation unit
8347 * @param unit the compilation unit that defines the library
8348 * @return the library object that was created
8349 * @throws AnalysisException if the library source is not valid
8350 */
8351 Library _createLibraryWithUnit(Source librarySource, CompilationUnit unit) {
8352 Library library =
8353 new Library(analysisContext, _errorListener, librarySource);
8354 library.setDefiningCompilationUnit(unit);
8355 _libraryMap[librarySource] = library;
8356 return library;
8357 }
8358
8359 /**
8360 * Return an array containing the lexical identifiers associated with the node s in the given list.
8361 *
8362 * @param names the AST nodes representing the identifiers
8363 * @return the lexical identifiers associated with the nodes in the list
8364 */
8365 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) {
8366 int count = names.length;
8367 List<String> identifiers = new List<String>(count);
8368 for (int i = 0; i < count; i++) {
8369 identifiers[i] = names[i].name;
8370 }
8371 return identifiers;
8372 }
8373
8374 /**
8375 * Compute a value for all of the constants in the libraries being analyzed.
8376 */
8377 void _performConstantEvaluation() {
8378 PerformanceStatistics.resolve.makeCurrentWhile(() {
8379 ConstantValueComputer computer = new ConstantValueComputer(
8380 analysisContext,
8381 _typeProvider,
8382 analysisContext.declaredVariables,
8383 null,
8384 _typeSystem);
8385 for (Library library in _librariesInCycles) {
8386 for (Source source in library.compilationUnitSources) {
8387 try {
8388 CompilationUnit unit = library.getAST(source);
8389 if (unit != null) {
8390 computer.add(unit, source, library.librarySource);
8391 }
8392 } on AnalysisException catch (exception, stackTrace) {
8393 AnalysisEngine.instance.logger.logError(
8394 "Internal Error: Could not access AST for ${source.fullName} dur ing constant evaluation",
8395 new CaughtException(exception, stackTrace));
8396 }
8397 }
8398 }
8399 computer.computeValues();
8400 // As a temporary workaround for issue 21572, run ConstantVerifier now.
8401 // TODO(paulberry): remove this workaround once issue 21572 is fixed.
8402 for (Library library in _librariesInCycles) {
8403 for (Source source in library.compilationUnitSources) {
8404 try {
8405 CompilationUnit unit = library.getAST(source);
8406 ErrorReporter errorReporter =
8407 new ErrorReporter(_errorListener, source);
8408 ConstantVerifier constantVerifier = new ConstantVerifier(
8409 errorReporter,
8410 library.libraryElement,
8411 _typeProvider,
8412 analysisContext.declaredVariables);
8413 unit.accept(constantVerifier);
8414 } on AnalysisException catch (exception, stackTrace) {
8415 AnalysisEngine.instance.logger.logError(
8416 "Internal Error: Could not access AST for ${source.fullName} "
8417 "during constant verification",
8418 new CaughtException(exception, stackTrace));
8419 }
8420 }
8421 }
8422 });
8423 }
8424
8425 /**
8426 * Resolve the identifiers and perform type analysis in the given library.
8427 *
8428 * @param library the library to be resolved
8429 * @throws AnalysisException if any of the identifiers could not be resolved o r if the types in
8430 * the library cannot be analyzed
8431 */
8432 void _resolveReferencesAndTypesInLibrary(Library library) {
8433 PerformanceStatistics.resolve.makeCurrentWhile(() {
8434 for (Source source in library.compilationUnitSources) {
8435 CompilationUnit ast = library.getAST(source);
8436 ast.accept(new VariableResolverVisitor(library.libraryElement, source,
8437 _typeProvider, library.errorListener,
8438 nameScope: library.libraryScope));
8439 ResolverVisitorFactory visitorFactory =
8440 analysisContext.resolverVisitorFactory;
8441 ResolverVisitor visitor = visitorFactory != null
8442 ? visitorFactory(library, source, _typeProvider)
8443 : new ResolverVisitor(library.libraryElement, source, _typeProvider,
8444 library.errorListener,
8445 nameScope: library.libraryScope,
8446 inheritanceManager: library.inheritanceManager);
8447 ast.accept(visitor);
8448 }
8449 });
8450 }
8451
8452 /**
8453 * Return the result of resolving the URI of the given URI-based directive aga inst the URI of the
8454 * given library, or `null` if the URI is not valid.
8455 *
8456 * @param librarySource the source representing the library containing the dir ective
8457 * @param directive the directive which URI should be resolved
8458 * @return the result of resolving the URI against the URI of the library
8459 */
8460 Source _resolveSource(Source librarySource, UriBasedDirective directive) {
8461 StringLiteral uriLiteral = directive.uri;
8462 if (uriLiteral is StringInterpolation) {
8463 return null;
8464 }
8465 String uriContent = uriLiteral.stringValue.trim();
8466 if (uriContent == null || uriContent.isEmpty) {
8467 return null;
8468 }
8469 uriContent = Uri.encodeFull(uriContent);
8470 return analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
8471 }
8472 }
8473
8474 /**
8475 * Instances of the class `LibraryResolver` are used to resolve one or more mutu ally dependent
8476 * libraries within a single context.
8477 */
8478 class LibraryResolver2 {
8479 /**
8480 * The analysis context in which the libraries are being analyzed.
8481 */
8482 final InternalAnalysisContext analysisContext;
8483
8484 /**
8485 * The listener to which analysis errors will be reported, this error listener is either
8486 * references [recordingErrorListener], or it unions the passed
8487 * [AnalysisErrorListener] with the [recordingErrorListener].
8488 */
8489 RecordingErrorListener _errorListener;
8490
8491 /**
8492 * A source object representing the core library (dart:core).
8493 */
8494 Source _coreLibrarySource;
8495
8496 /**
8497 * A source object representing the async library (dart:async).
8498 */
8499 Source _asyncLibrarySource;
8500
8501 /**
8502 * The object representing the core library.
8503 */
8504 ResolvableLibrary _coreLibrary;
8505
8506 /**
8507 * The object representing the async library.
8508 */
8509 ResolvableLibrary _asyncLibrary;
8510
8511 /**
8512 * The object used to access the types from the core library.
8513 */
8514 TypeProvider _typeProvider;
8515
8516 /**
8517 * The type system in use for the library
8518 */
8519 TypeSystem _typeSystem;
8520
8521 /**
8522 * A table mapping library sources to the information being maintained for tho se libraries.
8523 */
8524 HashMap<Source, ResolvableLibrary> _libraryMap =
8525 new HashMap<Source, ResolvableLibrary>();
8526
8527 /**
8528 * A collection containing the libraries that are being resolved together.
8529 */
8530 List<ResolvableLibrary> _librariesInCycle;
8531
8532 /**
8533 * Initialize a newly created library resolver to resolve libraries within the given context.
8534 *
8535 * @param analysisContext the analysis context in which the library is being a nalyzed
8536 */
8537 LibraryResolver2(this.analysisContext) {
8538 this._errorListener = new RecordingErrorListener();
8539 _coreLibrarySource =
8540 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE);
8541 _asyncLibrarySource =
8542 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC);
8543 }
8544
8545 /**
8546 * Return the listener to which analysis errors will be reported.
8547 *
8548 * @return the listener to which analysis errors will be reported
8549 */
8550 RecordingErrorListener get errorListener => _errorListener;
8551
8552 /**
8553 * Return an array containing information about all of the libraries that were resolved.
8554 *
8555 * @return an array containing the libraries that were resolved
8556 */
8557 List<ResolvableLibrary> get resolvedLibraries => _librariesInCycle;
8558
8559 /**
8560 * Resolve the library specified by the given source in the given context.
8561 *
8562 * Note that because Dart allows circular imports between libraries, it is pos sible that more than
8563 * one library will need to be resolved. In such cases the error listener can receive errors from
8564 * multiple libraries.
8565 *
8566 * @param librarySource the source specifying the defining compilation unit of the library to be
8567 * resolved
8568 * @param fullAnalysis `true` if a full analysis should be performed
8569 * @return the element representing the resolved library
8570 * @throws AnalysisException if the library could not be resolved for some rea son
8571 */
8572 LibraryElement resolveLibrary(
8573 Source librarySource, List<ResolvableLibrary> librariesInCycle) {
8574 //
8575 // Build the map of libraries that are known.
8576 //
8577 this._librariesInCycle = librariesInCycle;
8578 _libraryMap = _buildLibraryMap();
8579 ResolvableLibrary targetLibrary = _libraryMap[librarySource];
8580 _coreLibrary = _libraryMap[_coreLibrarySource];
8581 _asyncLibrary = _libraryMap[_asyncLibrarySource];
8582 //
8583 // Build the element models representing the libraries being resolved.
8584 // This is done in three steps:
8585 //
8586 // 1. Build the basic element models without making any connections
8587 // between elements other than the basic parent/child relationships.
8588 // This includes building the elements representing the libraries, but
8589 // excludes members defined in enums.
8590 // 2. Build the elements for the import and export directives. This
8591 // requires that we have the elements built for the referenced
8592 // libraries, but because of the possibility of circular references
8593 // needs to happen after all of the library elements have been created.
8594 // 3. Build the members in enum declarations.
8595 // 4. Build the rest of the type model by connecting superclasses, mixins,
8596 // and interfaces. This requires that we be able to compute the names
8597 // visible in the libraries being resolved, which in turn requires that
8598 // we have resolved the import directives.
8599 //
8600 _buildElementModels();
8601 LibraryElement coreElement = _coreLibrary.libraryElement;
8602 if (coreElement == null) {
8603 missingCoreLibrary(analysisContext, _coreLibrarySource);
8604 }
8605 LibraryElement asyncElement = _asyncLibrary.libraryElement;
8606 if (asyncElement == null) {
8607 missingAsyncLibrary(analysisContext, _asyncLibrarySource);
8608 }
8609 _buildDirectiveModels();
8610 _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
8611 _typeSystem = TypeSystem.create(analysisContext);
8612 _buildEnumMembers();
8613 _buildTypeHierarchies();
8614 //
8615 // Perform resolution and type analysis.
8616 //
8617 // TODO(brianwilkerson) Decide whether we want to resolve all of the
8618 // libraries or whether we want to only resolve the target library. The
8619 // advantage to resolving everything is that we have already done part of
8620 // the work so we'll avoid duplicated effort. The disadvantage of
8621 // resolving everything is that we might do extra work that we don't
8622 // really care about. Another possibility is to add a parameter to this
8623 // method and punt the decision to the clients.
8624 //
8625 //if (analyzeAll) {
8626 _resolveReferencesAndTypes();
8627 //} else {
8628 // resolveReferencesAndTypes(targetLibrary);
8629 //}
8630 _performConstantEvaluation();
8631 return targetLibrary.libraryElement;
8632 }
8633
8634 /**
8635 * Build the element model representing the combinators declared by the given directive.
8636 *
8637 * @param directive the directive that declares the combinators
8638 * @return an array containing the import combinators that were built
8639 */
8640 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) {
8641 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>();
8642 for (Combinator combinator in directive.combinators) {
8643 if (combinator is HideCombinator) {
8644 HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
8645 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames);
8646 combinators.add(hide);
8647 } else {
8648 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
8649 show.offset = combinator.offset;
8650 show.end = combinator.end;
8651 show.shownNames =
8652 _getIdentifiers((combinator as ShowCombinator).shownNames);
8653 combinators.add(show);
8654 }
8655 }
8656 return combinators;
8657 }
8658
8659 /**
8660 * Every library now has a corresponding [LibraryElement], so it is now possib le to resolve
8661 * the import and export directives.
8662 *
8663 * @throws AnalysisException if the defining compilation unit for any of the l ibraries could not
8664 * be accessed
8665 */
8666 void _buildDirectiveModels() {
8667 for (ResolvableLibrary library in _librariesInCycle) {
8668 HashMap<String, PrefixElementImpl> nameToPrefixMap =
8669 new HashMap<String, PrefixElementImpl>();
8670 List<ImportElement> imports = new List<ImportElement>();
8671 List<ExportElement> exports = new List<ExportElement>();
8672 for (Directive directive in library.definingCompilationUnit.directives) {
8673 if (directive is ImportDirective) {
8674 ImportDirective importDirective = directive;
8675 String uriContent = importDirective.uriContent;
8676 if (DartUriResolver.isDartExtUri(uriContent)) {
8677 library.libraryElement.hasExtUri = true;
8678 }
8679 Source importedSource = importDirective.source;
8680 if (importedSource != null &&
8681 analysisContext.exists(importedSource)) {
8682 // The imported source will be null if the URI in the import
8683 // directive was invalid.
8684 ResolvableLibrary importedLibrary = _libraryMap[importedSource];
8685 if (importedLibrary != null) {
8686 ImportElementImpl importElement =
8687 new ImportElementImpl(directive.offset);
8688 StringLiteral uriLiteral = importDirective.uri;
8689 if (uriLiteral != null) {
8690 importElement.uriOffset = uriLiteral.offset;
8691 importElement.uriEnd = uriLiteral.end;
8692 }
8693 importElement.uri = uriContent;
8694 importElement.deferred = importDirective.deferredKeyword != null;
8695 importElement.combinators = _buildCombinators(importDirective);
8696 LibraryElement importedLibraryElement =
8697 importedLibrary.libraryElement;
8698 if (importedLibraryElement != null) {
8699 importElement.importedLibrary = importedLibraryElement;
8700 }
8701 SimpleIdentifier prefixNode = directive.prefix;
8702 if (prefixNode != null) {
8703 importElement.prefixOffset = prefixNode.offset;
8704 String prefixName = prefixNode.name;
8705 PrefixElementImpl prefix = nameToPrefixMap[prefixName];
8706 if (prefix == null) {
8707 prefix = new PrefixElementImpl.forNode(prefixNode);
8708 nameToPrefixMap[prefixName] = prefix;
8709 }
8710 importElement.prefix = prefix;
8711 prefixNode.staticElement = prefix;
8712 }
8713 directive.element = importElement;
8714 imports.add(importElement);
8715 if (analysisContext.computeKindOf(importedSource) !=
8716 SourceKind.LIBRARY) {
8717 ErrorCode errorCode = (importElement.isDeferred
8718 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
8719 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY);
8720 _errorListener.onError(new AnalysisError(
8721 library.librarySource,
8722 uriLiteral.offset,
8723 uriLiteral.length,
8724 errorCode,
8725 [uriLiteral.toSource()]));
8726 }
8727 }
8728 }
8729 } else if (directive is ExportDirective) {
8730 ExportDirective exportDirective = directive;
8731 Source exportedSource = exportDirective.source;
8732 if (exportedSource != null &&
8733 analysisContext.exists(exportedSource)) {
8734 // The exported source will be null if the URI in the export
8735 // directive was invalid.
8736 ResolvableLibrary exportedLibrary = _libraryMap[exportedSource];
8737 if (exportedLibrary != null) {
8738 ExportElementImpl exportElement =
8739 new ExportElementImpl(directive.offset);
8740 StringLiteral uriLiteral = exportDirective.uri;
8741 if (uriLiteral != null) {
8742 exportElement.uriOffset = uriLiteral.offset;
8743 exportElement.uriEnd = uriLiteral.end;
8744 }
8745 exportElement.uri = exportDirective.uriContent;
8746 exportElement.combinators = _buildCombinators(exportDirective);
8747 LibraryElement exportedLibraryElement =
8748 exportedLibrary.libraryElement;
8749 if (exportedLibraryElement != null) {
8750 exportElement.exportedLibrary = exportedLibraryElement;
8751 }
8752 directive.element = exportElement;
8753 exports.add(exportElement);
8754 if (analysisContext.computeKindOf(exportedSource) !=
8755 SourceKind.LIBRARY) {
8756 _errorListener.onError(new AnalysisError(
8757 library.librarySource,
8758 uriLiteral.offset,
8759 uriLiteral.length,
8760 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
8761 [uriLiteral.toSource()]));
8762 }
8763 }
8764 }
8765 }
8766 }
8767 Source librarySource = library.librarySource;
8768 if (!library.explicitlyImportsCore &&
8769 _coreLibrarySource != librarySource) {
8770 ImportElementImpl importElement = new ImportElementImpl(-1);
8771 importElement.importedLibrary = _coreLibrary.libraryElement;
8772 importElement.synthetic = true;
8773 imports.add(importElement);
8774 }
8775 LibraryElementImpl libraryElement = library.libraryElement;
8776 libraryElement.imports = imports;
8777 libraryElement.exports = exports;
8778 if (libraryElement.entryPoint == null) {
8779 Namespace namespace = new NamespaceBuilder()
8780 .createExportNamespaceForLibrary(libraryElement);
8781 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME);
8782 if (element is FunctionElement) {
8783 libraryElement.entryPoint = element;
8784 }
8785 }
8786 }
8787 }
8788
8789 /**
8790 * Build element models for all of the libraries in the current cycle.
8791 *
8792 * @throws AnalysisException if any of the element models cannot be built
8793 */
8794 void _buildElementModels() {
8795 for (ResolvableLibrary library in _librariesInCycle) {
8796 LibraryElementBuilder builder =
8797 new LibraryElementBuilder(analysisContext, errorListener);
8798 builder.buildLibrary2(library);
8799 }
8800 }
8801
8802 /**
8803 * Build the members in enum declarations. This cannot be done while building the rest of the
8804 * element model because it depends on being able to access core types, which cannot happen until
8805 * the rest of the element model has been built (when resolving the core libra ry).
8806 *
8807 * @throws AnalysisException if any of the enum members could not be built
8808 */
8809 void _buildEnumMembers() {
8810 PerformanceStatistics.resolve.makeCurrentWhile(() {
8811 for (ResolvableLibrary library in _librariesInCycle) {
8812 for (Source source in library.compilationUnitSources) {
8813 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider);
8814 library.getAST(source).accept(builder);
8815 }
8816 }
8817 });
8818 }
8819
8820 HashMap<Source, ResolvableLibrary> _buildLibraryMap() {
8821 HashMap<Source, ResolvableLibrary> libraryMap =
8822 new HashMap<Source, ResolvableLibrary>();
8823 int libraryCount = _librariesInCycle.length;
8824 for (int i = 0; i < libraryCount; i++) {
8825 ResolvableLibrary library = _librariesInCycle[i];
8826 library.errorListener = _errorListener;
8827 libraryMap[library.librarySource] = library;
8828 List<ResolvableLibrary> dependencies = library.importsAndExports;
8829 int dependencyCount = dependencies.length;
8830 for (int j = 0; j < dependencyCount; j++) {
8831 ResolvableLibrary dependency = dependencies[j];
8832 //dependency.setErrorListener(errorListener);
8833 libraryMap[dependency.librarySource] = dependency;
8834 }
8835 }
8836 return libraryMap;
8837 }
8838
8839 /**
8840 * Resolve the type hierarchy across all of the types declared in the librarie s in the current
8841 * cycle.
8842 *
8843 * @throws AnalysisException if any of the type hierarchies could not be resol ved
8844 */
8845 void _buildTypeHierarchies() {
8846 PerformanceStatistics.resolve.makeCurrentWhile(() {
8847 for (ResolvableLibrary library in _librariesInCycle) {
8848 for (ResolvableCompilationUnit unit
8849 in library.resolvableCompilationUnits) {
8850 Source source = unit.source;
8851 CompilationUnit ast = unit.compilationUnit;
8852 TypeResolverVisitor visitor = new TypeResolverVisitor(
8853 library.libraryElement,
8854 source,
8855 _typeProvider,
8856 library.libraryScope.errorListener,
8857 nameScope: library.libraryScope);
8858 ast.accept(visitor);
8859 }
8860 }
8861 });
8862 }
8863
8864 /**
8865 * Return an array containing the lexical identifiers associated with the node s in the given list.
8866 *
8867 * @param names the AST nodes representing the identifiers
8868 * @return the lexical identifiers associated with the nodes in the list
8869 */
8870 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) {
8871 int count = names.length;
8872 List<String> identifiers = new List<String>(count);
8873 for (int i = 0; i < count; i++) {
8874 identifiers[i] = names[i].name;
8875 }
8876 return identifiers;
8877 }
8878
8879 /**
8880 * Compute a value for all of the constants in the libraries being analyzed.
8881 */
8882 void _performConstantEvaluation() {
8883 PerformanceStatistics.resolve.makeCurrentWhile(() {
8884 ConstantValueComputer computer = new ConstantValueComputer(
8885 analysisContext,
8886 _typeProvider,
8887 analysisContext.declaredVariables,
8888 null,
8889 _typeSystem);
8890 for (ResolvableLibrary library in _librariesInCycle) {
8891 for (ResolvableCompilationUnit unit
8892 in library.resolvableCompilationUnits) {
8893 CompilationUnit ast = unit.compilationUnit;
8894 if (ast != null) {
8895 computer.add(ast, unit.source, library.librarySource);
8896 }
8897 }
8898 }
8899 computer.computeValues();
8900 // As a temporary workaround for issue 21572, run ConstantVerifier now.
8901 // TODO(paulberry): remove this workaround once issue 21572 is fixed.
8902 for (ResolvableLibrary library in _librariesInCycle) {
8903 for (ResolvableCompilationUnit unit
8904 in library.resolvableCompilationUnits) {
8905 CompilationUnit ast = unit.compilationUnit;
8906 ErrorReporter errorReporter =
8907 new ErrorReporter(_errorListener, unit.source);
8908 ConstantVerifier constantVerifier = new ConstantVerifier(
8909 errorReporter,
8910 library.libraryElement,
8911 _typeProvider,
8912 analysisContext.declaredVariables);
8913 ast.accept(constantVerifier);
8914 }
8915 }
8916 });
8917 }
8918
8919 /**
8920 * Resolve the identifiers and perform type analysis in the libraries in the c urrent cycle.
8921 *
8922 * @throws AnalysisException if any of the identifiers could not be resolved o r if any of the
8923 * libraries could not have their types analyzed
8924 */
8925 void _resolveReferencesAndTypes() {
8926 for (ResolvableLibrary library in _librariesInCycle) {
8927 _resolveReferencesAndTypesInLibrary(library);
8928 }
8929 }
8930
8931 /**
8932 * Resolve the identifiers and perform type analysis in the given library.
8933 *
8934 * @param library the library to be resolved
8935 * @throws AnalysisException if any of the identifiers could not be resolved o r if the types in
8936 * the library cannot be analyzed
8937 */
8938 void _resolveReferencesAndTypesInLibrary(ResolvableLibrary library) {
8939 PerformanceStatistics.resolve.makeCurrentWhile(() {
8940 for (ResolvableCompilationUnit unit
8941 in library.resolvableCompilationUnits) {
8942 Source source = unit.source;
8943 CompilationUnit ast = unit.compilationUnit;
8944 ast.accept(new VariableResolverVisitor(library.libraryElement, source,
8945 _typeProvider, library.libraryScope.errorListener,
8946 nameScope: library.libraryScope));
8947 ResolverVisitor visitor = new ResolverVisitor(library.libraryElement,
8948 source, _typeProvider, library._libraryScope.errorListener,
8949 nameScope: library._libraryScope,
8950 inheritanceManager: library.inheritanceManager);
8951 ast.accept(visitor);
8952 }
8953 });
8954 }
8955
8956 /**
8957 * Report that the async library could not be resolved in the given
8958 * [analysisContext] and throw an exception. [asyncLibrarySource] is the sour ce
8959 * representing the async library.
8960 */
8961 static void missingAsyncLibrary(
8962 AnalysisContext analysisContext, Source asyncLibrarySource) {
8963 throw new AnalysisException("Could not resolve dart:async");
8964 }
8965
8966 /**
8967 * Report that the core library could not be resolved in the given analysis co ntext and throw an
8968 * exception.
8969 *
8970 * @param analysisContext the analysis context in which the failure occurred
8971 * @param coreLibrarySource the source representing the core library
8972 * @throws AnalysisException always
8973 */
8974 static void missingCoreLibrary(
8975 AnalysisContext analysisContext, Source coreLibrarySource) {
8976 throw new AnalysisException("Could not resolve dart:core");
8977 }
8978 }
8979
8980 /**
8981 * Instances of the class `LibraryScope` implement a scope containing all of the names defined
8982 * in a given library.
8983 */
8984 class LibraryScope extends EnclosedScope {
8985 /**
8986 * Initialize a newly created scope representing the names defined in the give n library.
8987 *
8988 * @param definingLibrary the element representing the library represented by this scope
8989 * @param errorListener the listener that is to be informed when an error is e ncountered
8990 */
8991 LibraryScope(
8992 LibraryElement definingLibrary, AnalysisErrorListener errorListener)
8993 : super(new LibraryImportScope(definingLibrary, errorListener)) {
8994 _defineTopLevelNames(definingLibrary);
8995 }
8996
8997 @override
8998 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) {
8999 if (existing is PrefixElement) {
9000 // TODO(scheglov) consider providing actual 'nameOffset' from the
9001 // synthetic accessor
9002 int offset = duplicate.nameOffset;
9003 if (duplicate is PropertyAccessorElement) {
9004 PropertyAccessorElement accessor = duplicate;
9005 if (accessor.isSynthetic) {
9006 offset = accessor.variable.nameOffset;
9007 }
9008 }
9009 return new AnalysisError(
9010 duplicate.source,
9011 offset,
9012 duplicate.nameLength,
9013 CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
9014 [existing.displayName]);
9015 }
9016 return super.getErrorForDuplicate(existing, duplicate);
9017 }
9018
9019 /**
9020 * Add to this scope all of the public top-level names that are defined in the given compilation
9021 * unit.
9022 *
9023 * @param compilationUnit the compilation unit defining the top-level names to be added to this
9024 * scope
9025 */
9026 void _defineLocalNames(CompilationUnitElement compilationUnit) {
9027 for (PropertyAccessorElement element in compilationUnit.accessors) {
9028 define(element);
9029 }
9030 for (ClassElement element in compilationUnit.enums) {
9031 define(element);
9032 }
9033 for (FunctionElement element in compilationUnit.functions) {
9034 define(element);
9035 }
9036 for (FunctionTypeAliasElement element
9037 in compilationUnit.functionTypeAliases) {
9038 define(element);
9039 }
9040 for (ClassElement element in compilationUnit.types) {
9041 define(element);
9042 }
9043 }
9044
9045 /**
9046 * Add to this scope all of the names that are explicitly defined in the given library.
9047 *
9048 * @param definingLibrary the element representing the library that defines th e names in this
9049 * scope
9050 */
9051 void _defineTopLevelNames(LibraryElement definingLibrary) {
9052 for (PrefixElement prefix in definingLibrary.prefixes) {
9053 define(prefix);
9054 }
9055 _defineLocalNames(definingLibrary.definingCompilationUnit);
9056 for (CompilationUnitElement compilationUnit in definingLibrary.parts) {
9057 _defineLocalNames(compilationUnit);
9058 }
9059 }
9060 }
9061
9062 /**
9063 * This class is used to replace uses of `HashMap<String, ExecutableElement>`
9064 * which are not as performant as this class.
9065 */
9066 class MemberMap {
9067 /**
9068 * The current size of this map.
9069 */
9070 int _size = 0;
9071
9072 /**
9073 * The array of keys.
9074 */
9075 List<String> _keys;
9076
9077 /**
9078 * The array of ExecutableElement values.
9079 */
9080 List<ExecutableElement> _values;
9081
9082 /**
9083 * Initialize a newly created member map to have the given [initialCapacity].
9084 * The map will grow if needed.
9085 */
9086 MemberMap([int initialCapacity = 10]) {
9087 _initArrays(initialCapacity);
9088 }
9089
9090 /**
9091 * This constructor takes an initial capacity of the map.
9092 *
9093 * @param initialCapacity the initial capacity
9094 */
9095 @deprecated // Use new MemberMap(initialCapacity)
9096 MemberMap.con1(int initialCapacity) {
9097 _initArrays(initialCapacity);
9098 }
9099
9100 /**
9101 * Copy constructor.
9102 */
9103 @deprecated // Use new MemberMap.from(memberMap)
9104 MemberMap.con2(MemberMap memberMap) {
9105 _initArrays(memberMap._size + 5);
9106 for (int i = 0; i < memberMap._size; i++) {
9107 _keys[i] = memberMap._keys[i];
9108 _values[i] = memberMap._values[i];
9109 }
9110 _size = memberMap._size;
9111 }
9112
9113 /**
9114 * Initialize a newly created member map to contain the same members as the
9115 * given [memberMap].
9116 */
9117 MemberMap.from(MemberMap memberMap) {
9118 _initArrays(memberMap._size + 5);
9119 for (int i = 0; i < memberMap._size; i++) {
9120 _keys[i] = memberMap._keys[i];
9121 _values[i] = memberMap._values[i];
9122 }
9123 _size = memberMap._size;
9124 }
9125
9126 /**
9127 * The size of the map.
9128 *
9129 * @return the size of the map.
9130 */
9131 int get size => _size;
9132
9133 /**
9134 * Given some key, return the ExecutableElement value from the map, if the key does not exist in
9135 * the map, `null` is returned.
9136 *
9137 * @param key some key to look up in the map
9138 * @return the associated ExecutableElement value from the map, if the key doe s not exist in the
9139 * map, `null` is returned
9140 */
9141 ExecutableElement get(String key) {
9142 for (int i = 0; i < _size; i++) {
9143 if (_keys[i] != null && _keys[i] == key) {
9144 return _values[i];
9145 }
9146 }
9147 return null;
9148 }
9149
9150 /**
9151 * Get and return the key at the specified location. If the key/value pair has been removed from
9152 * the set, then `null` is returned.
9153 *
9154 * @param i some non-zero value less than size
9155 * @return the key at the passed index
9156 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
9157 * zero or greater than or equal to the capacity of the arrays
9158 */
9159 String getKey(int i) => _keys[i];
9160
9161 /**
9162 * Get and return the ExecutableElement at the specified location. If the key/ value pair has been
9163 * removed from the set, then then `null` is returned.
9164 *
9165 * @param i some non-zero value less than size
9166 * @return the key at the passed index
9167 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe d index is less than
9168 * zero or greater than or equal to the capacity of the arrays
9169 */
9170 ExecutableElement getValue(int i) => _values[i];
9171
9172 /**
9173 * Given some key/value pair, store the pair in the map. If the key exists alr eady, then the new
9174 * value overrides the old value.
9175 *
9176 * @param key the key to store in the map
9177 * @param value the ExecutableElement value to store in the map
9178 */
9179 void put(String key, ExecutableElement value) {
9180 // If we already have a value with this key, override the value
9181 for (int i = 0; i < _size; i++) {
9182 if (_keys[i] != null && _keys[i] == key) {
9183 _values[i] = value;
9184 return;
9185 }
9186 }
9187 // If needed, double the size of our arrays and copy values over in both
9188 // arrays
9189 if (_size == _keys.length) {
9190 int newArrayLength = _size * 2;
9191 List<String> keys_new_array = new List<String>(newArrayLength);
9192 List<ExecutableElement> values_new_array =
9193 new List<ExecutableElement>(newArrayLength);
9194 for (int i = 0; i < _size; i++) {
9195 keys_new_array[i] = _keys[i];
9196 }
9197 for (int i = 0; i < _size; i++) {
9198 values_new_array[i] = _values[i];
9199 }
9200 _keys = keys_new_array;
9201 _values = values_new_array;
9202 }
9203 // Put new value at end of array
9204 _keys[_size] = key;
9205 _values[_size] = value;
9206 _size++;
9207 }
9208
9209 /**
9210 * Given some [String] key, this method replaces the associated key and value pair with
9211 * `null`. The size is not decremented with this call, instead it is expected that the users
9212 * check for `null`.
9213 *
9214 * @param key the key of the key/value pair to remove from the map
9215 */
9216 void remove(String key) {
9217 for (int i = 0; i < _size; i++) {
9218 if (_keys[i] == key) {
9219 _keys[i] = null;
9220 _values[i] = null;
9221 return;
9222 }
9223 }
9224 }
9225
9226 /**
9227 * Sets the ExecutableElement at the specified location.
9228 *
9229 * @param i some non-zero value less than size
9230 * @param value the ExecutableElement value to store in the map
9231 */
9232 void setValue(int i, ExecutableElement value) {
9233 _values[i] = value;
9234 }
9235
9236 /**
9237 * Initializes [keys] and [values].
9238 */
9239 void _initArrays(int initialCapacity) {
9240 _keys = new List<String>(initialCapacity);
9241 _values = new List<ExecutableElement>(initialCapacity);
9242 }
9243 }
9244
9245 /**
9246 * Instances of the class `Namespace` implement a mapping of identifiers to the elements
9247 * represented by those identifiers. Namespaces are the building blocks for scop es.
9248 */
9249 class Namespace {
9250 /**
9251 * An empty namespace.
9252 */
9253 static Namespace EMPTY = new Namespace(new HashMap<String, Element>());
9254
9255 /**
9256 * A table mapping names that are defined in this namespace to the element rep resenting the thing
9257 * declared with that name.
9258 */
9259 final HashMap<String, Element> _definedNames;
9260
9261 /**
9262 * Initialize a newly created namespace to have the given defined names.
9263 *
9264 * @param definedNames the mapping from names that are defined in this namespa ce to the
9265 * corresponding elements
9266 */
9267 Namespace(this._definedNames);
9268
9269 /**
9270 * Return a table containing the same mappings as those defined by this namesp ace.
9271 *
9272 * @return a table containing the same mappings as those defined by this names pace
9273 */
9274 Map<String, Element> get definedNames => _definedNames;
9275
9276 /**
9277 * Return the element in this namespace that is available to the containing sc ope using the given
9278 * name.
9279 *
9280 * @param name the name used to reference the
9281 * @return the element represented by the given identifier
9282 */
9283 Element get(String name) => _definedNames[name];
9284 }
9285
9286 /**
9287 * Instances of the class `NamespaceBuilder` are used to build a `Namespace`. Na mespace
9288 * builders are thread-safe and re-usable.
9289 */
9290 class NamespaceBuilder {
9291 /**
9292 * Create a namespace representing the export namespace of the given [ExportEl ement].
9293 *
9294 * @param element the export element whose export namespace is to be created
9295 * @return the export namespace that was created
9296 */
9297 Namespace createExportNamespaceForDirective(ExportElement element) {
9298 LibraryElement exportedLibrary = element.exportedLibrary;
9299 if (exportedLibrary == null) {
9300 //
9301 // The exported library will be null if the URI does not reference a valid
9302 // library.
9303 //
9304 return Namespace.EMPTY;
9305 }
9306 HashMap<String, Element> definedNames =
9307 _createExportMapping(exportedLibrary, new HashSet<LibraryElement>());
9308 definedNames = _applyCombinators(definedNames, element.combinators);
9309 return new Namespace(definedNames);
9310 }
9311
9312 /**
9313 * Create a namespace representing the export namespace of the given library.
9314 *
9315 * @param library the library whose export namespace is to be created
9316 * @return the export namespace that was created
9317 */
9318 Namespace createExportNamespaceForLibrary(LibraryElement library) =>
9319 new Namespace(
9320 _createExportMapping(library, new HashSet<LibraryElement>()));
9321
9322 /**
9323 * Create a namespace representing the import namespace of the given library.
9324 *
9325 * @param library the library whose import namespace is to be created
9326 * @return the import namespace that was created
9327 */
9328 Namespace createImportNamespaceForDirective(ImportElement element) {
9329 LibraryElement importedLibrary = element.importedLibrary;
9330 if (importedLibrary == null) {
9331 //
9332 // The imported library will be null if the URI does not reference a valid
9333 // library.
9334 //
9335 return Namespace.EMPTY;
9336 }
9337 HashMap<String, Element> definedNames =
9338 _createExportMapping(importedLibrary, new HashSet<LibraryElement>());
9339 definedNames = _applyCombinators(definedNames, element.combinators);
9340 definedNames = _applyPrefix(definedNames, element.prefix);
9341 return new Namespace(definedNames);
9342 }
9343
9344 /**
9345 * Create a namespace representing the public namespace of the given library.
9346 *
9347 * @param library the library whose public namespace is to be created
9348 * @return the public namespace that was created
9349 */
9350 Namespace createPublicNamespaceForLibrary(LibraryElement library) {
9351 HashMap<String, Element> definedNames = new HashMap<String, Element>();
9352 _addPublicNames(definedNames, library.definingCompilationUnit);
9353 for (CompilationUnitElement compilationUnit in library.parts) {
9354 _addPublicNames(definedNames, compilationUnit);
9355 }
9356 return new Namespace(definedNames);
9357 }
9358
9359 /**
9360 * Add all of the names in the given namespace to the given mapping table.
9361 *
9362 * @param definedNames the mapping table to which the names in the given names pace are to be added
9363 * @param namespace the namespace containing the names to be added to this nam espace
9364 */
9365 void _addAllFromNamespace(
9366 Map<String, Element> definedNames, Namespace namespace) {
9367 if (namespace != null) {
9368 definedNames.addAll(namespace.definedNames);
9369 }
9370 }
9371
9372 /**
9373 * Add the given element to the given mapping table if it has a publicly visib le name.
9374 *
9375 * @param definedNames the mapping table to which the public name is to be add ed
9376 * @param element the element to be added
9377 */
9378 void _addIfPublic(Map<String, Element> definedNames, Element element) {
9379 String name = element.name;
9380 if (name != null && !Scope.isPrivateName(name)) {
9381 definedNames[name] = element;
9382 }
9383 }
9384
9385 /**
9386 * Add to the given mapping table all of the public top-level names that are d efined in the given
9387 * compilation unit.
9388 *
9389 * @param definedNames the mapping table to which the public names are to be a dded
9390 * @param compilationUnit the compilation unit defining the top-level names to be added to this
9391 * namespace
9392 */
9393 void _addPublicNames(Map<String, Element> definedNames,
9394 CompilationUnitElement compilationUnit) {
9395 for (PropertyAccessorElement element in compilationUnit.accessors) {
9396 _addIfPublic(definedNames, element);
9397 }
9398 for (ClassElement element in compilationUnit.enums) {
9399 _addIfPublic(definedNames, element);
9400 }
9401 for (FunctionElement element in compilationUnit.functions) {
9402 _addIfPublic(definedNames, element);
9403 }
9404 for (FunctionTypeAliasElement element
9405 in compilationUnit.functionTypeAliases) {
9406 _addIfPublic(definedNames, element);
9407 }
9408 for (ClassElement element in compilationUnit.types) {
9409 _addIfPublic(definedNames, element);
9410 }
9411 }
9412
9413 /**
9414 * Apply the given combinators to all of the names in the given mapping table.
9415 *
9416 * @param definedNames the mapping table to which the namespace operations are to be applied
9417 * @param combinators the combinators to be applied
9418 */
9419 HashMap<String, Element> _applyCombinators(
9420 HashMap<String, Element> definedNames,
9421 List<NamespaceCombinator> combinators) {
9422 for (NamespaceCombinator combinator in combinators) {
9423 if (combinator is HideElementCombinator) {
9424 definedNames = _hide(definedNames, combinator.hiddenNames);
9425 } else if (combinator is ShowElementCombinator) {
9426 definedNames = _show(definedNames, combinator.shownNames);
9427 } else {
9428 // Internal error.
9429 AnalysisEngine.instance.logger
9430 .logError("Unknown type of combinator: ${combinator.runtimeType}");
9431 }
9432 }
9433 return definedNames;
9434 }
9435
9436 /**
9437 * Apply the given prefix to all of the names in the table of defined names.
9438 *
9439 * @param definedNames the names that were defined before this operation
9440 * @param prefixElement the element defining the prefix to be added to the nam es
9441 */
9442 HashMap<String, Element> _applyPrefix(
9443 HashMap<String, Element> definedNames, PrefixElement prefixElement) {
9444 if (prefixElement != null) {
9445 String prefix = prefixElement.name;
9446 HashMap<String, Element> newNames = new HashMap<String, Element>();
9447 definedNames.forEach((String name, Element element) {
9448 newNames["$prefix.$name"] = element;
9449 });
9450 return newNames;
9451 } else {
9452 return definedNames;
9453 }
9454 }
9455
9456 /**
9457 * Create a mapping table representing the export namespace of the given libra ry.
9458 *
9459 * @param library the library whose public namespace is to be created
9460 * @param visitedElements a set of libraries that do not need to be visited wh en processing the
9461 * export directives of the given library because all of the names de fined by them will
9462 * be added by another library
9463 * @return the mapping table that was created
9464 */
9465 HashMap<String, Element> _createExportMapping(
9466 LibraryElement library, HashSet<LibraryElement> visitedElements) {
9467 // Check if the export namespace has been already computed.
9468 {
9469 Namespace exportNamespace = library.exportNamespace;
9470 if (exportNamespace != null) {
9471 return exportNamespace.definedNames;
9472 }
9473 }
9474 // TODO(scheglov) Remove this after switching to the new task model.
9475 visitedElements.add(library);
9476 try {
9477 HashMap<String, Element> definedNames = new HashMap<String, Element>();
9478 for (ExportElement element in library.exports) {
9479 LibraryElement exportedLibrary = element.exportedLibrary;
9480 if (exportedLibrary != null &&
9481 !visitedElements.contains(exportedLibrary)) {
9482 //
9483 // The exported library will be null if the URI does not reference a
9484 // valid library.
9485 //
9486 HashMap<String, Element> exportedNames =
9487 _createExportMapping(exportedLibrary, visitedElements);
9488 exportedNames = _applyCombinators(exportedNames, element.combinators);
9489 definedNames.addAll(exportedNames);
9490 }
9491 }
9492 _addAllFromNamespace(
9493 definedNames,
9494 (library.context as InternalAnalysisContext)
9495 .getPublicNamespace(library));
9496 return definedNames;
9497 } finally {
9498 visitedElements.remove(library);
9499 }
9500 }
9501
9502 /**
9503 * Return a new map of names which has all the names from [definedNames]
9504 * with exception of [hiddenNames].
9505 */
9506 Map<String, Element> _hide(
9507 HashMap<String, Element> definedNames, List<String> hiddenNames) {
9508 HashMap<String, Element> newNames =
9509 new HashMap<String, Element>.from(definedNames);
9510 for (String name in hiddenNames) {
9511 newNames.remove(name);
9512 newNames.remove("$name=");
9513 }
9514 return newNames;
9515 }
9516
9517 /**
9518 * Return a new map of names which has only [shownNames] from [definedNames].
9519 */
9520 HashMap<String, Element> _show(
9521 HashMap<String, Element> definedNames, List<String> shownNames) {
9522 HashMap<String, Element> newNames = new HashMap<String, Element>();
9523 for (String name in shownNames) {
9524 Element element = definedNames[name];
9525 if (element != null) {
9526 newNames[name] = element;
9527 }
9528 String setterName = "$name=";
9529 element = definedNames[setterName];
9530 if (element != null) {
9531 newNames[setterName] = element;
9532 }
9533 }
9534 return newNames;
9535 } 5185 }
9536 } 5186 }
9537 5187
9538 /** 5188 /**
9539 * Instances of the class `OverrideVerifier` visit all of the declarations in a compilation 5189 * Instances of the class `OverrideVerifier` visit all of the declarations in a compilation
9540 * unit to verify that if they have an override annotation it is being used corr ectly. 5190 * unit to verify that if they have an override annotation it is being used corr ectly.
9541 */ 5191 */
9542 class OverrideVerifier extends RecursiveAstVisitor<Object> { 5192 class OverrideVerifier extends RecursiveAstVisitor {
9543 /** 5193 /**
9544 * The error reporter used to report errors. 5194 * The error reporter used to report errors.
9545 */ 5195 */
9546 final ErrorReporter _errorReporter; 5196 final ErrorReporter _errorReporter;
9547 5197
9548 /** 5198 /**
9549 * The inheritance manager used to find overridden methods. 5199 * The inheritance manager used to find overridden methods.
9550 */ 5200 */
9551 final InheritanceManager _manager; 5201 final InheritanceManager _manager;
9552 5202
9553 /** 5203 /**
9554 * Initialize a newly created verifier to look for inappropriate uses of the o verride annotation. 5204 * Initialize a newly created verifier to look for inappropriate uses of the o verride annotation.
9555 * 5205 *
9556 * @param errorReporter the error reporter used to report errors 5206 * @param errorReporter the error reporter used to report errors
9557 * @param manager the inheritance manager used to find overridden methods 5207 * @param manager the inheritance manager used to find overridden methods
9558 */ 5208 */
9559 OverrideVerifier(this._errorReporter, this._manager); 5209 OverrideVerifier(this._errorReporter, this._manager);
9560 5210
9561 @override 5211 @override
9562 Object visitMethodDeclaration(MethodDeclaration node) { 5212 visitFieldDeclaration(FieldDeclaration node) {
5213 for (VariableDeclaration field in node.fields.variables) {
5214 VariableElement fieldElement = field.element;
5215 if (fieldElement is FieldElement && _isOverride(fieldElement)) {
5216 PropertyAccessorElement getter = fieldElement.getter;
5217 PropertyAccessorElement setter = fieldElement.setter;
5218 if (!(getter != null && _getOverriddenMember(getter) != null ||
5219 setter != null && _getOverriddenMember(setter) != null)) {
5220 _errorReporter.reportErrorForNode(
5221 HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD, field.name);
5222 }
5223 }
5224 }
5225 }
5226
5227 @override
5228 visitMethodDeclaration(MethodDeclaration node) {
9563 ExecutableElement element = node.element; 5229 ExecutableElement element = node.element;
9564 if (_isOverride(element)) { 5230 if (_isOverride(element)) {
9565 if (_getOverriddenMember(element) == null) { 5231 if (_getOverriddenMember(element) == null) {
9566 if (element is MethodElement) { 5232 if (element is MethodElement) {
9567 _errorReporter.reportErrorForNode( 5233 _errorReporter.reportErrorForNode(
9568 HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name); 5234 HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name);
9569 } else if (element is PropertyAccessorElement) { 5235 } else if (element is PropertyAccessorElement) {
9570 if (element.isGetter) { 5236 if (element.isGetter) {
9571 _errorReporter.reportErrorForNode( 5237 _errorReporter.reportErrorForNode(
9572 HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER, node.name); 5238 HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER, node.name);
9573 } else { 5239 } else {
9574 _errorReporter.reportErrorForNode( 5240 _errorReporter.reportErrorForNode(
9575 HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER, node.name); 5241 HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER, node.name);
9576 } 5242 }
9577 } 5243 }
9578 } 5244 }
9579 } 5245 }
9580 return super.visitMethodDeclaration(node);
9581 } 5246 }
9582 5247
9583 /** 5248 /**
9584 * Return the member that overrides the given member. 5249 * Return the member that overrides the given member.
9585 * 5250 *
9586 * @param member the member that overrides the returned member 5251 * @param member the member that overrides the returned member
9587 * @return the member that overrides the given member 5252 * @return the member that overrides the given member
9588 */ 5253 */
9589 ExecutableElement _getOverriddenMember(ExecutableElement member) { 5254 ExecutableElement _getOverriddenMember(ExecutableElement member) {
9590 LibraryElement library = member.library; 5255 LibraryElement library = member.library;
(...skipping 17 matching lines...) Expand all
9608 bool _isOverride(Element element) => element != null && element.isOverride; 5273 bool _isOverride(Element element) => element != null && element.isOverride;
9609 } 5274 }
9610 5275
9611 /** 5276 /**
9612 * An AST visitor that is used to resolve the some of the nodes within a single 5277 * An AST visitor that is used to resolve the some of the nodes within a single
9613 * compilation unit. The nodes that are skipped are those that are within 5278 * compilation unit. The nodes that are skipped are those that are within
9614 * function bodies. 5279 * function bodies.
9615 */ 5280 */
9616 class PartialResolverVisitor extends ResolverVisitor { 5281 class PartialResolverVisitor extends ResolverVisitor {
9617 /** 5282 /**
9618 * A flag indicating whether the resolver is being run in strong mode.
9619 */
9620 final bool strongMode;
9621
9622 /**
9623 * The static variables and fields that have an initializer. These are the 5283 * The static variables and fields that have an initializer. These are the
9624 * variables that need to be re-resolved after static variables have their 5284 * variables that need to be re-resolved after static variables have their
9625 * types inferred. A subset of these variables are those whose types should 5285 * types inferred. A subset of these variables are those whose types should
9626 * be inferred. The list will be empty unless the resolver is being run in 5286 * be inferred.
9627 * strong mode. 5287 */
9628 */ 5288 final List<VariableElement> staticVariables = <VariableElement>[];
9629 final List<VariableElement> variablesAndFields = <VariableElement>[];
9630
9631 /**
9632 * A flag indicating whether we should discard errors while resolving the
9633 * initializer for variable declarations. We do this for top-level variables
9634 * and fields because their initializer will be re-resolved at a later time.
9635 */
9636 bool discardErrorsInInitializer = false;
9637 5289
9638 /** 5290 /**
9639 * Initialize a newly created visitor to resolve the nodes in an AST node. 5291 * Initialize a newly created visitor to resolve the nodes in an AST node.
9640 * 5292 *
9641 * The [definingLibrary] is the element for the library containing the node 5293 * The [definingLibrary] is the element for the library containing the node
9642 * being visited. The [source] is the source representing the compilation unit 5294 * being visited. The [source] is the source representing the compilation unit
9643 * containing the node being visited. The [typeProvider] is the object used to 5295 * containing the node being visited. The [typeProvider] is the object used to
9644 * access the types from the core library. The [errorListener] is the error 5296 * access the types from the core library. The [errorListener] is the error
9645 * listener that will be informed of any errors that are found during 5297 * listener that will be informed of any errors that are found during
9646 * resolution. The [nameScope] is the scope used to resolve identifiers in the 5298 * resolution. The [nameScope] is the scope used to resolve identifiers in the
9647 * node that will first be visited. If `null` or unspecified, a new 5299 * node that will first be visited. If `null` or unspecified, a new
9648 * [LibraryScope] will be created based on [definingLibrary] and 5300 * [LibraryScope] will be created based on [definingLibrary] and
9649 * [typeProvider]. The [inheritanceManager] is used to perform inheritance 5301 * [typeProvider]. The [inheritanceManager] is used to perform inheritance
9650 * lookups. If `null` or unspecified, a new [InheritanceManager] will be 5302 * lookups. If `null` or unspecified, a new [InheritanceManager] will be
9651 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to 5303 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to
9652 * create the type analyzer. If `null` or unspecified, a type analyzer of 5304 * create the type analyzer. If `null` or unspecified, a type analyzer of
9653 * type [StaticTypeAnalyzer] will be created. 5305 * type [StaticTypeAnalyzer] will be created.
9654 */ 5306 */
9655 PartialResolverVisitor(LibraryElement definingLibrary, Source source, 5307 PartialResolverVisitor(LibraryElement definingLibrary, Source source,
9656 TypeProvider typeProvider, AnalysisErrorListener errorListener, 5308 TypeProvider typeProvider, AnalysisErrorListener errorListener,
9657 {Scope nameScope, 5309 {Scope nameScope})
9658 InheritanceManager inheritanceManager, 5310 : super(definingLibrary, source, typeProvider, errorListener,
9659 StaticTypeAnalyzerFactory typeAnalyzerFactory}) 5311 nameScope: nameScope);
9660 : strongMode = definingLibrary.context.analysisOptions.strongMode,
9661 super(definingLibrary, source, typeProvider,
9662 new DisablableErrorListener(errorListener));
9663 5312
9664 @override 5313 @override
9665 Object visitBlockFunctionBody(BlockFunctionBody node) { 5314 Object visitBlockFunctionBody(BlockFunctionBody node) {
9666 if (_shouldBeSkipped(node)) { 5315 if (_shouldBeSkipped(node)) {
9667 return null; 5316 return null;
9668 } 5317 }
9669 return super.visitBlockFunctionBody(node); 5318 return super.visitBlockFunctionBody(node);
9670 } 5319 }
9671 5320
9672 @override 5321 @override
9673 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { 5322 Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
9674 if (_shouldBeSkipped(node)) { 5323 if (_shouldBeSkipped(node)) {
9675 return null; 5324 return null;
9676 } 5325 }
9677 return super.visitExpressionFunctionBody(node); 5326 return super.visitExpressionFunctionBody(node);
9678 } 5327 }
9679 5328
9680 @override 5329 @override
9681 Object visitFieldDeclaration(FieldDeclaration node) { 5330 Object visitFieldDeclaration(FieldDeclaration node) {
9682 if (strongMode && node.isStatic) { 5331 if (node.isStatic) {
9683 _addVariables(node.fields.variables); 5332 _addStaticVariables(node.fields.variables);
9684 bool wasDiscarding = discardErrorsInInitializer;
9685 discardErrorsInInitializer = true;
9686 try {
9687 return super.visitFieldDeclaration(node);
9688 } finally {
9689 discardErrorsInInitializer = wasDiscarding;
9690 }
9691 } 5333 }
9692 return super.visitFieldDeclaration(node); 5334 return super.visitFieldDeclaration(node);
9693 } 5335 }
9694 5336
9695 @override 5337 @override
9696 Object visitNode(AstNode node) { 5338 Object visitNode(AstNode node) {
9697 if (discardErrorsInInitializer) {
9698 AstNode parent = node.parent;
9699 if (parent is VariableDeclaration && parent.initializer == node) {
9700 DisablableErrorListener listener = errorListener;
9701 return listener.disableWhile(() => super.visitNode(node));
9702 }
9703 }
9704 return super.visitNode(node); 5339 return super.visitNode(node);
9705 } 5340 }
9706 5341
9707 @override 5342 @override
9708 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { 5343 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
9709 if (strongMode) { 5344 _addStaticVariables(node.variables.variables);
9710 _addVariables(node.variables.variables);
9711 bool wasDiscarding = discardErrorsInInitializer;
9712 discardErrorsInInitializer = true;
9713 try {
9714 return super.visitTopLevelVariableDeclaration(node);
9715 } finally {
9716 discardErrorsInInitializer = wasDiscarding;
9717 }
9718 }
9719 return super.visitTopLevelVariableDeclaration(node); 5345 return super.visitTopLevelVariableDeclaration(node);
9720 } 5346 }
9721 5347
9722 /** 5348 /**
9723 * Add all of the [variables] with initializers to the list of variables whose 5349 * Add all of the [variables] with initializers to the list of variables whose
9724 * type can be inferred. Technically, we only infer the types of variables 5350 * type can be inferred. Technically, we only infer the types of variables
9725 * that do not have a static type, but all variables with initializers 5351 * that do not have a static type, but all variables with initializers
9726 * potentially need to be re-resolved after inference because they might 5352 * potentially need to be re-resolved after inference because they might
9727 * refer to a field whose type was inferred. 5353 * refer to a field whose type was inferred.
9728 */ 5354 */
9729 void _addVariables(NodeList<VariableDeclaration> variables) { 5355 void _addStaticVariables(List<VariableDeclaration> variables) {
9730 for (VariableDeclaration variable in variables) { 5356 int length = variables.length;
9731 if (variable.initializer != null) { 5357 for (int i = 0; i < length; i++) {
9732 variablesAndFields.add(variable.element); 5358 VariableDeclaration variable = variables[i];
5359 if (variable.name.name.isNotEmpty && variable.initializer != null) {
5360 staticVariables.add(variable.element);
9733 } 5361 }
9734 } 5362 }
9735 } 5363 }
9736 5364
9737 /** 5365 /**
9738 * Return `true` if the given function body should be skipped because it is 5366 * Return `true` if the given function body should be skipped because it is
9739 * the body of a top-level function, method or constructor. 5367 * the body of a top-level function, method or constructor.
9740 */ 5368 */
9741 bool _shouldBeSkipped(FunctionBody body) { 5369 bool _shouldBeSkipped(FunctionBody body) {
9742 AstNode parent = body.parent; 5370 AstNode parent = body.parent;
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
9947 // return fullName.replaceAll(r'\', '/'); 5575 // return fullName.replaceAll(r'\', '/');
9948 // } 5576 // }
9949 // } 5577 // }
9950 // return null; 5578 // return null;
9951 // } 5579 // }
9952 } 5580 }
9953 5581
9954 /** 5582 /**
9955 * Kind of the redirecting constructor. 5583 * Kind of the redirecting constructor.
9956 */ 5584 */
9957 class RedirectingConstructorKind extends Enum<RedirectingConstructorKind> { 5585 class RedirectingConstructorKind
5586 implements Comparable<RedirectingConstructorKind> {
9958 static const RedirectingConstructorKind CONST = 5587 static const RedirectingConstructorKind CONST =
9959 const RedirectingConstructorKind('CONST', 0); 5588 const RedirectingConstructorKind('CONST', 0);
9960 5589
9961 static const RedirectingConstructorKind NORMAL = 5590 static const RedirectingConstructorKind NORMAL =
9962 const RedirectingConstructorKind('NORMAL', 1); 5591 const RedirectingConstructorKind('NORMAL', 1);
9963 5592
9964 static const List<RedirectingConstructorKind> values = const [CONST, NORMAL]; 5593 static const List<RedirectingConstructorKind> values = const [CONST, NORMAL];
9965 5594
9966 const RedirectingConstructorKind(String name, int ordinal) 5595 /**
9967 : super(name, ordinal); 5596 * The name of this redirecting constructor kind.
5597 */
5598 final String name;
5599
5600 /**
5601 * The ordinal value of the redirecting constructor kind.
5602 */
5603 final int ordinal;
5604
5605 const RedirectingConstructorKind(this.name, this.ordinal);
5606
5607 @override
5608 int get hashCode => ordinal;
5609
5610 @override
5611 int compareTo(RedirectingConstructorKind other) => ordinal - other.ordinal;
5612
5613 @override
5614 String toString() => name;
9968 } 5615 }
9969 5616
9970 /** 5617 /**
9971 * A `ResolvableLibrary` represents a single library during the resolution of
9972 * some (possibly different) library. They are not intended to be used except
9973 * during the resolution process.
9974 */
9975 class ResolvableLibrary {
9976 /**
9977 * An empty array that can be used to initialize lists of libraries.
9978 */
9979 static List<ResolvableLibrary> _EMPTY_ARRAY = new List<ResolvableLibrary>(0);
9980
9981 /**
9982 * The next artificial hash code.
9983 */
9984 static int _NEXT_HASH_CODE = 0;
9985
9986 /**
9987 * The artifitial hash code for this object.
9988 */
9989 final int _hashCode = _nextHashCode();
9990
9991 /**
9992 * The source specifying the defining compilation unit of this library.
9993 */
9994 final Source librarySource;
9995
9996 /**
9997 * A list containing all of the libraries that are imported into this library.
9998 */
9999 List<ResolvableLibrary> _importedLibraries = _EMPTY_ARRAY;
10000
10001 /**
10002 * A flag indicating whether this library explicitly imports core.
10003 */
10004 bool explicitlyImportsCore = false;
10005
10006 /**
10007 * An array containing all of the libraries that are exported from this librar y.
10008 */
10009 List<ResolvableLibrary> _exportedLibraries = _EMPTY_ARRAY;
10010
10011 /**
10012 * An array containing the compilation units that comprise this library. The
10013 * defining compilation unit is always first.
10014 */
10015 List<ResolvableCompilationUnit> _compilationUnits;
10016
10017 /**
10018 * The library element representing this library.
10019 */
10020 LibraryElementImpl _libraryElement;
10021
10022 /**
10023 * The listener to which analysis errors will be reported.
10024 */
10025 AnalysisErrorListener _errorListener;
10026
10027 /**
10028 * The inheritance manager which is used for member lookups in this library.
10029 */
10030 InheritanceManager _inheritanceManager;
10031
10032 /**
10033 * The library scope used when resolving elements within this library's compil ation units.
10034 */
10035 LibraryScope _libraryScope;
10036
10037 /**
10038 * Initialize a newly created data holder that can maintain the data associate d with a library.
10039 *
10040 * @param librarySource the source specifying the defining compilation unit of this library
10041 * @param errorListener the listener to which analysis errors will be reported
10042 */
10043 ResolvableLibrary(this.librarySource);
10044
10045 /**
10046 * Return an array of the [CompilationUnit]s that make up the library. The fir st unit is
10047 * always the defining unit.
10048 *
10049 * @return an array of the [CompilationUnit]s that make up the library. The fi rst unit is
10050 * always the defining unit
10051 */
10052 List<CompilationUnit> get compilationUnits {
10053 int count = _compilationUnits.length;
10054 List<CompilationUnit> units = new List<CompilationUnit>(count);
10055 for (int i = 0; i < count; i++) {
10056 units[i] = _compilationUnits[i].compilationUnit;
10057 }
10058 return units;
10059 }
10060
10061 /**
10062 * Return an array containing the sources for the compilation units in this li brary, including the
10063 * defining compilation unit.
10064 *
10065 * @return the sources for the compilation units in this library
10066 */
10067 List<Source> get compilationUnitSources {
10068 int count = _compilationUnits.length;
10069 List<Source> sources = new List<Source>(count);
10070 for (int i = 0; i < count; i++) {
10071 sources[i] = _compilationUnits[i].source;
10072 }
10073 return sources;
10074 }
10075
10076 /**
10077 * Return the AST structure associated with the defining compilation unit for this library.
10078 *
10079 * @return the AST structure associated with the defining compilation unit for this library
10080 * @throws AnalysisException if an AST structure could not be created for the defining compilation
10081 * unit
10082 */
10083 CompilationUnit get definingCompilationUnit =>
10084 _compilationUnits[0].compilationUnit;
10085
10086 /**
10087 * Set the listener to which analysis errors will be reported to be the given listener.
10088 *
10089 * @param errorListener the listener to which analysis errors will be reported
10090 */
10091 void set errorListener(AnalysisErrorListener errorListener) {
10092 this._errorListener = errorListener;
10093 }
10094
10095 /**
10096 * Set the libraries that are exported by this library to be those in the give n array.
10097 *
10098 * @param exportedLibraries the libraries that are exported by this library
10099 */
10100 void set exportedLibraries(List<ResolvableLibrary> exportedLibraries) {
10101 this._exportedLibraries = exportedLibraries;
10102 }
10103
10104 /**
10105 * Return an array containing the libraries that are exported from this librar y.
10106 *
10107 * @return an array containing the libraries that are exported from this libra ry
10108 */
10109 List<ResolvableLibrary> get exports => _exportedLibraries;
10110
10111 @override
10112 int get hashCode => _hashCode;
10113
10114 /**
10115 * Set the libraries that are imported into this library to be those in the gi ven array.
10116 *
10117 * @param importedLibraries the libraries that are imported into this library
10118 */
10119 void set importedLibraries(List<ResolvableLibrary> importedLibraries) {
10120 this._importedLibraries = importedLibraries;
10121 }
10122
10123 /**
10124 * Return an array containing the libraries that are imported into this librar y.
10125 *
10126 * @return an array containing the libraries that are imported into this libra ry
10127 */
10128 List<ResolvableLibrary> get imports => _importedLibraries;
10129
10130 /**
10131 * Return an array containing the libraries that are either imported or export ed from this
10132 * library.
10133 *
10134 * @return the libraries that are either imported or exported from this librar y
10135 */
10136 List<ResolvableLibrary> get importsAndExports {
10137 HashSet<ResolvableLibrary> libraries = new HashSet<ResolvableLibrary>();
10138 for (ResolvableLibrary library in _importedLibraries) {
10139 libraries.add(library);
10140 }
10141 for (ResolvableLibrary library in _exportedLibraries) {
10142 libraries.add(library);
10143 }
10144 return new List.from(libraries);
10145 }
10146
10147 /**
10148 * Return the inheritance manager for this library.
10149 *
10150 * @return the inheritance manager for this library
10151 */
10152 InheritanceManager get inheritanceManager {
10153 if (_inheritanceManager == null) {
10154 return _inheritanceManager = new InheritanceManager(_libraryElement);
10155 }
10156 return _inheritanceManager;
10157 }
10158
10159 /**
10160 * Return the library element representing this library, creating it if necess ary.
10161 *
10162 * @return the library element representing this library
10163 */
10164 LibraryElementImpl get libraryElement => _libraryElement;
10165
10166 /**
10167 * Set the library element representing this library to the given library elem ent.
10168 *
10169 * @param libraryElement the library element representing this library
10170 */
10171 void set libraryElement(LibraryElementImpl libraryElement) {
10172 this._libraryElement = libraryElement;
10173 if (_inheritanceManager != null) {
10174 _inheritanceManager.libraryElement = libraryElement;
10175 }
10176 }
10177
10178 /**
10179 * Return the library scope used when resolving elements within this library's compilation units.
10180 *
10181 * @return the library scope used when resolving elements within this library' s compilation units
10182 */
10183 LibraryScope get libraryScope {
10184 if (_libraryScope == null) {
10185 _libraryScope = new LibraryScope(_libraryElement, _errorListener);
10186 }
10187 return _libraryScope;
10188 }
10189
10190 /**
10191 * Return an array containing the compilation units that comprise this library . The defining
10192 * compilation unit is always first.
10193 *
10194 * @return the compilation units that comprise this library
10195 */
10196 List<ResolvableCompilationUnit> get resolvableCompilationUnits =>
10197 _compilationUnits;
10198
10199 /**
10200 * Set the compilation unit in this library to the given compilation units. Th e defining
10201 * compilation unit must be the first element of the array.
10202 *
10203 * @param units the compilation units in this library
10204 */
10205 void set resolvableCompilationUnits(List<ResolvableCompilationUnit> units) {
10206 _compilationUnits = units;
10207 }
10208
10209 /**
10210 * Return the AST structure associated with the given source, or `null` if the source does
10211 * not represent a compilation unit that is included in this library.
10212 *
10213 * @param source the source representing the compilation unit whose AST is to be returned
10214 * @return the AST structure associated with the given source
10215 * @throws AnalysisException if an AST structure could not be created for the compilation unit
10216 */
10217 CompilationUnit getAST(Source source) {
10218 int count = _compilationUnits.length;
10219 for (int i = 0; i < count; i++) {
10220 if (_compilationUnits[i].source == source) {
10221 return _compilationUnits[i].compilationUnit;
10222 }
10223 }
10224 return null;
10225 }
10226
10227 @override
10228 String toString() => librarySource.shortName;
10229
10230 static int _nextHashCode() {
10231 int next = (_NEXT_HASH_CODE + 1) & 0xFFFFFF;
10232 _NEXT_HASH_CODE = next;
10233 return next;
10234 }
10235 }
10236
10237 /**
10238 * The enumeration `ResolverErrorCode` defines the error codes used for errors 5618 * The enumeration `ResolverErrorCode` defines the error codes used for errors
10239 * detected by the resolver. The convention for this class is for the name of 5619 * detected by the resolver. The convention for this class is for the name of
10240 * the error code to indicate the problem that caused the error to be generated 5620 * the error code to indicate the problem that caused the error to be generated
10241 * and for the error message to explain what is wrong and, when appropriate, how 5621 * and for the error message to explain what is wrong and, when appropriate, how
10242 * the problem can be corrected. 5622 * the problem can be corrected.
10243 */ 5623 */
10244 class ResolverErrorCode extends ErrorCode { 5624 class ResolverErrorCode extends ErrorCode {
10245 static const ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER = 5625 static const ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER =
10246 const ResolverErrorCode('BREAK_LABEL_ON_SWITCH_MEMBER', 5626 const ResolverErrorCode('BREAK_LABEL_ON_SWITCH_MEMBER',
10247 "Break label resolves to case or default statement"); 5627 "Break label resolves to case or default statement");
(...skipping 21 matching lines...) Expand all
10269 @override 5649 @override
10270 ErrorType get type => ErrorType.COMPILE_TIME_ERROR; 5650 ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
10271 } 5651 }
10272 5652
10273 /** 5653 /**
10274 * Instances of the class `ResolverVisitor` are used to resolve the nodes within a single 5654 * Instances of the class `ResolverVisitor` are used to resolve the nodes within a single
10275 * compilation unit. 5655 * compilation unit.
10276 */ 5656 */
10277 class ResolverVisitor extends ScopedVisitor { 5657 class ResolverVisitor extends ScopedVisitor {
10278 /** 5658 /**
10279 * The manager for the inheritance mappings.
10280 */
10281 InheritanceManager _inheritanceManager;
10282
10283 /**
10284 * The object used to resolve the element associated with the current node. 5659 * The object used to resolve the element associated with the current node.
10285 */ 5660 */
10286 ElementResolver elementResolver; 5661 ElementResolver elementResolver;
10287 5662
10288 /** 5663 /**
10289 * The object used to compute the type associated with the current node. 5664 * The object used to compute the type associated with the current node.
10290 */ 5665 */
10291 StaticTypeAnalyzer typeAnalyzer; 5666 StaticTypeAnalyzer typeAnalyzer;
10292 5667
10293 /* 5668 /**
10294 * The type system in use during resolution. 5669 * The type system in use during resolution.
10295 */ 5670 */
10296 TypeSystem typeSystem; 5671 TypeSystem typeSystem;
10297 5672
10298 /** 5673 /**
10299 * The class element representing the class containing the current node,
10300 * or `null` if the current node is not contained in a class.
10301 */
10302 ClassElement enclosingClass = null;
10303
10304 /**
10305 * The class declaration representing the class containing the current node, o r `null` if 5674 * The class declaration representing the class containing the current node, o r `null` if
10306 * the current node is not contained in a class. 5675 * the current node is not contained in a class.
10307 */ 5676 */
10308 ClassDeclaration _enclosingClassDeclaration = null; 5677 ClassDeclaration _enclosingClassDeclaration = null;
10309 5678
10310 /** 5679 /**
10311 * The function type alias representing the function type containing the curre nt node, or 5680 * The function type alias representing the function type containing the curre nt node, or
10312 * `null` if the current node is not contained in a function type alias. 5681 * `null` if the current node is not contained in a function type alias.
10313 */ 5682 */
10314 FunctionTypeAlias _enclosingFunctionTypeAlias = null; 5683 FunctionTypeAlias _enclosingFunctionTypeAlias = null;
10315 5684
10316 /** 5685 /**
10317 * The element representing the function containing the current node, or `null ` if the 5686 * The element representing the function containing the current node, or `null ` if the
10318 * current node is not contained in a function. 5687 * current node is not contained in a function.
10319 */ 5688 */
10320 ExecutableElement _enclosingFunction = null; 5689 ExecutableElement _enclosingFunction = null;
10321 5690
10322 /** 5691 InferenceContext inferenceContext = null;
10323 * The [Comment] before a [FunctionDeclaration] or a [MethodDeclaration] that
10324 * cannot be resolved where we visited it, because it should be resolved in th e scope of the body.
10325 */
10326 Comment _commentBeforeFunction = null;
10327 5692
10328 /** 5693 /**
10329 * The object keeping track of which elements have had their types overridden. 5694 * The object keeping track of which elements have had their types overridden.
10330 */ 5695 */
10331 TypeOverrideManager _overrideManager = new TypeOverrideManager(); 5696 TypeOverrideManager _overrideManager = new TypeOverrideManager();
10332 5697
10333 /** 5698 /**
10334 * The object keeping track of which elements have had their types promoted. 5699 * The object keeping track of which elements have had their types promoted.
10335 */ 5700 */
10336 TypePromotionManager _promoteManager = new TypePromotionManager(); 5701 TypePromotionManager _promoteManager = new TypePromotionManager();
10337 5702
10338 /** 5703 /**
10339 * A comment before a function should be resolved in the context of the 5704 * A comment before a function should be resolved in the context of the
10340 * function. But when we incrementally resolve a comment, we don't want to 5705 * function. But when we incrementally resolve a comment, we don't want to
10341 * resolve the whole function. 5706 * resolve the whole function.
10342 * 5707 *
10343 * So, this flag is set to `true`, when just context of the function should 5708 * So, this flag is set to `true`, when just context of the function should
10344 * be built and the comment resolved. 5709 * be built and the comment resolved.
10345 */ 5710 */
10346 bool resolveOnlyCommentInFunctionBody = false; 5711 bool resolveOnlyCommentInFunctionBody = false;
10347 5712
10348 /** 5713 /**
5714 * Body of the function currently being analyzed, if any.
5715 */
5716 FunctionBody _currentFunctionBody;
5717
5718 /**
5719 * Are we running in strong mode or not.
5720 */
5721 bool strongMode;
5722
5723 /**
10349 * Initialize a newly created visitor to resolve the nodes in an AST node. 5724 * Initialize a newly created visitor to resolve the nodes in an AST node.
10350 * 5725 *
10351 * The [definingLibrary] is the element for the library containing the node 5726 * The [definingLibrary] is the element for the library containing the node
10352 * being visited. The [source] is the source representing the compilation unit 5727 * being visited. The [source] is the source representing the compilation unit
10353 * containing the node being visited. The [typeProvider] is the object used to 5728 * containing the node being visited. The [typeProvider] is the object used to
10354 * access the types from the core library. The [errorListener] is the error 5729 * access the types from the core library. The [errorListener] is the error
10355 * listener that will be informed of any errors that are found during 5730 * listener that will be informed of any errors that are found during
10356 * resolution. The [nameScope] is the scope used to resolve identifiers in the 5731 * resolution. The [nameScope] is the scope used to resolve identifiers in the
10357 * node that will first be visited. If `null` or unspecified, a new 5732 * node that will first be visited. If `null` or unspecified, a new
10358 * [LibraryScope] will be created based on [definingLibrary] and 5733 * [LibraryScope] will be created based on [definingLibrary] and
10359 * [typeProvider]. The [inheritanceManager] is used to perform inheritance 5734 * [typeProvider]. The [inheritanceManager] is used to perform inheritance
10360 * lookups. If `null` or unspecified, a new [InheritanceManager] will be 5735 * lookups. If `null` or unspecified, a new [InheritanceManager] will be
10361 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to 5736 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to
10362 * create the type analyzer. If `null` or unspecified, a type analyzer of 5737 * create the type analyzer. If `null` or unspecified, a type analyzer of
10363 * type [StaticTypeAnalyzer] will be created. 5738 * type [StaticTypeAnalyzer] will be created.
10364 */ 5739 */
10365 ResolverVisitor(LibraryElement definingLibrary, Source source, 5740 ResolverVisitor(LibraryElement definingLibrary, Source source,
10366 TypeProvider typeProvider, AnalysisErrorListener errorListener, 5741 TypeProvider typeProvider, AnalysisErrorListener errorListener,
10367 {Scope nameScope, 5742 {Scope nameScope})
10368 InheritanceManager inheritanceManager,
10369 StaticTypeAnalyzerFactory typeAnalyzerFactory})
10370 : super(definingLibrary, source, typeProvider, errorListener, 5743 : super(definingLibrary, source, typeProvider, errorListener,
10371 nameScope: nameScope) { 5744 nameScope: nameScope) {
10372 if (inheritanceManager == null) { 5745 AnalysisOptions options = definingLibrary.context.analysisOptions;
10373 this._inheritanceManager = new InheritanceManager(definingLibrary); 5746 this.strongMode = options.strongMode;
10374 } else {
10375 this._inheritanceManager = inheritanceManager;
10376 }
10377 this.elementResolver = new ElementResolver(this); 5747 this.elementResolver = new ElementResolver(this);
10378 this.typeSystem = definingLibrary.context.typeSystem; 5748 this.typeSystem = definingLibrary.context.typeSystem;
10379 if (typeAnalyzerFactory == null) { 5749 bool strongModeHints = false;
10380 this.typeAnalyzer = new StaticTypeAnalyzer(this); 5750 if (options is AnalysisOptionsImpl) {
10381 } else { 5751 strongModeHints = options.strongModeHints;
10382 this.typeAnalyzer = typeAnalyzerFactory(this);
10383 } 5752 }
5753 this.inferenceContext = new InferenceContext._(
5754 errorReporter, typeProvider, typeSystem, strongModeHints);
5755 this.typeAnalyzer = new StaticTypeAnalyzer(this);
10384 } 5756 }
10385 5757
10386 /** 5758 /**
10387 * Initialize a newly created visitor to resolve the nodes in a compilation un it.
10388 *
10389 * @param library the library containing the compilation unit being resolved
10390 * @param source the source representing the compilation unit being visited
10391 * @param typeProvider the object used to access the types from the core libra ry
10392 *
10393 * Deprecated. Please use unnamed constructor instead.
10394 */
10395 @deprecated
10396 ResolverVisitor.con1(
10397 Library library, Source source, TypeProvider typeProvider,
10398 {StaticTypeAnalyzerFactory typeAnalyzerFactory})
10399 : this(
10400 library.libraryElement, source, typeProvider, library.errorListener,
10401 nameScope: library.libraryScope,
10402 inheritanceManager: library.inheritanceManager,
10403 typeAnalyzerFactory: typeAnalyzerFactory);
10404
10405 /**
10406 * Return the element representing the function containing the current node, o r `null` if 5759 * Return the element representing the function containing the current node, o r `null` if
10407 * the current node is not contained in a function. 5760 * the current node is not contained in a function.
10408 * 5761 *
10409 * @return the element representing the function containing the current node 5762 * @return the element representing the function containing the current node
10410 */ 5763 */
10411 ExecutableElement get enclosingFunction => _enclosingFunction; 5764 ExecutableElement get enclosingFunction => _enclosingFunction;
10412 5765
10413 /** 5766 /**
10414 * Return the object keeping track of which elements have had their types over ridden. 5767 * Return the object keeping track of which elements have had their types over ridden.
10415 * 5768 *
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
10462 } else if (expression is PropertyAccess) { 5815 } else if (expression is PropertyAccess) {
10463 element = expression.propertyName.staticElement; 5816 element = expression.propertyName.staticElement;
10464 } 5817 }
10465 if (element is VariableElement) { 5818 if (element is VariableElement) {
10466 return element; 5819 return element;
10467 } 5820 }
10468 return null; 5821 return null;
10469 } 5822 }
10470 5823
10471 /** 5824 /**
10472 * Return the static element associated with the given expression whose type c an be promoted, or 5825 * Return the static element associated with the given expression whose type
10473 * `null` if there is no element whose type can be promoted. 5826 * can be promoted, or `null` if there is no element whose type can be
10474 * 5827 * promoted.
10475 * @param expression the expression with which the element is associated
10476 * @return the element associated with the given expression
10477 */ 5828 */
10478 VariableElement getPromotionStaticElement(Expression expression) { 5829 VariableElement getPromotionStaticElement(Expression expression) {
10479 while (expression is ParenthesizedExpression) { 5830 expression = expression?.unParenthesized;
10480 expression = (expression as ParenthesizedExpression).expression; 5831 if (expression is SimpleIdentifier) {
10481 } 5832 Element element = expression.staticElement;
10482 if (expression is! SimpleIdentifier) { 5833 if (element is VariableElement) {
10483 return null; 5834 ElementKind kind = element.kind;
10484 } 5835 if (kind == ElementKind.LOCAL_VARIABLE ||
10485 SimpleIdentifier identifier = expression as SimpleIdentifier; 5836 kind == ElementKind.PARAMETER) {
10486 Element element = identifier.staticElement; 5837 return element;
10487 if (element is! VariableElement) { 5838 }
10488 return null; 5839 }
10489 }
10490 ElementKind kind = element.kind;
10491 if (kind == ElementKind.LOCAL_VARIABLE) {
10492 return element as VariableElement;
10493 }
10494 if (kind == ElementKind.PARAMETER) {
10495 return element as VariableElement;
10496 } 5840 }
10497 return null; 5841 return null;
10498 } 5842 }
10499 5843
10500 /** 5844 /**
10501 * Prepares this [ResolverVisitor] to using it for incremental resolution. 5845 * Prepares this [ResolverVisitor] to using it for incremental resolution.
10502 */ 5846 */
10503 void initForIncrementalResolution([Declaration declaration = null]) { 5847 void initForIncrementalResolution() {
10504 if (declaration != null) {
10505 Element element = declaration.element;
10506 if (element is ExecutableElement) {
10507 _enclosingFunction = element;
10508 }
10509 _commentBeforeFunction = declaration.documentationComment;
10510 }
10511 _overrideManager.enterScope(); 5848 _overrideManager.enterScope();
10512 } 5849 }
10513 5850
10514 /** 5851 /**
5852 * Returns true if this method is `Future.then` or an override thereof.
5853 *
5854 * If so we will apply special typing rules in strong mode, to handle the
5855 * implicit union of `S | Future<S>`
5856 */
5857 bool isFutureThen(Element element) {
5858 // If we are a method named then
5859 if (element is MethodElement && element.name == 'then') {
5860 DartType type = element.enclosingElement.type;
5861 // On Future or a subtype, then we're good.
5862 return (type.isDartAsyncFuture || isSubtypeOfFuture(type));
5863 }
5864 return false;
5865 }
5866
5867 /**
5868 * Returns true if this type is any subtype of the built in Future type.
5869 */
5870 bool isSubtypeOfFuture(DartType type) =>
5871 typeSystem.isSubtypeOf(type, typeProvider.futureDynamicType);
5872
5873 /**
5874 * Given a downward inference type [fnType], and the declared
5875 * [typeParameterList] for a function expression, determines if we can enable
5876 * downward inference and if so, returns the function type to use for
5877 * inference.
5878 *
5879 * This will return null if inference is not possible. This happens when
5880 * there is no way we can find a subtype of the function type, given the
5881 * provided type parameter list.
5882 */
5883 FunctionType matchFunctionTypeParameters(
5884 TypeParameterList typeParameterList, FunctionType fnType) {
5885 if (typeParameterList == null) {
5886 if (fnType.typeFormals.isEmpty) {
5887 return fnType;
5888 }
5889
5890 // A non-generic function cannot be a subtype of a generic one.
5891 return null;
5892 }
5893
5894 NodeList<TypeParameter> typeParameters = typeParameterList.typeParameters;
5895 if (fnType.typeFormals.isEmpty) {
5896 // TODO(jmesserly): this is a legal subtype. We don't currently infer
5897 // here, but we could. This is similar to
5898 // StrongTypeSystemImpl.inferFunctionTypeInstantiation, but we don't
5899 // have the FunctionType yet for the current node, so it's not quite
5900 // straightforward to apply.
5901 return null;
5902 }
5903
5904 if (fnType.typeFormals.length != typeParameters.length) {
5905 // A subtype cannot have different number of type formals.
5906 return null;
5907 }
5908
5909 // Same number of type formals. Instantiate the function type so its
5910 // parameter and return type are in terms of the surrounding context.
5911 return fnType.instantiate(typeParameters
5912 .map((TypeParameter t) =>
5913 (t.name.staticElement as TypeParameterElement).type)
5914 .toList());
5915 }
5916
5917 /**
10515 * If it is appropriate to do so, override the current type of the static and propagated elements 5918 * If it is appropriate to do so, override the current type of the static and propagated elements
10516 * associated with the given expression with the given type. Generally speakin g, it is appropriate 5919 * associated with the given expression with the given type. Generally speakin g, it is appropriate
10517 * if the given type is more specific than the current type. 5920 * if the given type is more specific than the current type.
10518 * 5921 *
10519 * @param expression the expression used to access the static and propagated e lements whose types 5922 * @param expression the expression used to access the static and propagated e lements whose types
10520 * might be overridden 5923 * might be overridden
10521 * @param potentialType the potential type of the elements 5924 * @param potentialType the potential type of the elements
10522 * @param allowPrecisionLoss see @{code overrideVariable} docs 5925 * @param allowPrecisionLoss see @{code overrideVariable} docs
10523 */ 5926 */
10524 void overrideExpression(Expression expression, DartType potentialType, 5927 void overrideExpression(Expression expression, DartType potentialType,
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
10596 } 5999 }
10597 return null; 6000 return null;
10598 } 6001 }
10599 6002
10600 /** 6003 /**
10601 * A client is about to resolve a member in the given class declaration. 6004 * A client is about to resolve a member in the given class declaration.
10602 */ 6005 */
10603 void prepareToResolveMembersInClass(ClassDeclaration node) { 6006 void prepareToResolveMembersInClass(ClassDeclaration node) {
10604 _enclosingClassDeclaration = node; 6007 _enclosingClassDeclaration = node;
10605 enclosingClass = node.element; 6008 enclosingClass = node.element;
10606 typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type; 6009 typeAnalyzer.thisType = enclosingClass?.type;
10607 } 6010 }
10608 6011
10609 /** 6012 /**
10610 * If the given [type] is valid, strongly more specific than the 6013 * If the given [type] is valid, strongly more specific than the
10611 * existing static type of the given [expression], record it as a propagated 6014 * existing static type of the given [expression], record it as a propagated
10612 * type of the given [expression]. Otherwise, reset it to `null`. 6015 * type of the given [expression]. Otherwise, reset it to `null`.
10613 * 6016 *
10614 * If [hasOldPropagatedType] is `true` then the existing propagated type 6017 * If [hasOldPropagatedType] is `true` then the existing propagated type
10615 * should also is checked. 6018 * should also is checked.
10616 */ 6019 */
10617 void recordPropagatedTypeIfBetter(Expression expression, DartType type, 6020 void recordPropagatedTypeIfBetter(Expression expression, DartType type,
10618 [bool hasOldPropagatedType = false]) { 6021 [bool hasOldPropagatedType = false]) {
10619 // Ensure that propagated type invalid. 6022 // Ensure that propagated type invalid.
10620 if (type == null || type.isDynamic || type.isBottom) { 6023 if (strongMode || type == null || type.isDynamic || type.isBottom) {
10621 if (!hasOldPropagatedType) { 6024 if (!hasOldPropagatedType) {
10622 expression.propagatedType = null; 6025 expression.propagatedType = null;
10623 } 6026 }
10624 return; 6027 return;
10625 } 6028 }
10626 // Ensure that propagated type is more specific than the static type. 6029 // Ensure that propagated type is more specific than the static type.
10627 DartType staticType = expression.staticType; 6030 DartType staticType = expression.staticType;
10628 if (type == staticType || !type.isMoreSpecificThan(staticType)) { 6031 if (type == staticType || !type.isMoreSpecificThan(staticType)) {
10629 expression.propagatedType = null; 6032 expression.propagatedType = null;
10630 return; 6033 return;
10631 } 6034 }
10632 // Ensure that the new propagated type is more specific than the old one. 6035 // Ensure that the new propagated type is more specific than the old one.
10633 if (hasOldPropagatedType) { 6036 if (hasOldPropagatedType) {
10634 DartType oldPropagatedType = expression.propagatedType; 6037 DartType oldPropagatedType = expression.propagatedType;
10635 if (oldPropagatedType != null && 6038 if (oldPropagatedType != null &&
10636 !type.isMoreSpecificThan(oldPropagatedType)) { 6039 !type.isMoreSpecificThan(oldPropagatedType)) {
10637 return; 6040 return;
10638 } 6041 }
10639 } 6042 }
10640 // OK 6043 // OK
10641 expression.propagatedType = type; 6044 expression.propagatedType = type;
10642 } 6045 }
10643 6046
6047 /**
6048 * Visit the given [comment] if it is not `null`.
6049 */
6050 void safelyVisitComment(Comment comment) {
6051 if (comment != null) {
6052 super.visitComment(comment);
6053 }
6054 }
6055
10644 @override 6056 @override
10645 Object visitAnnotation(Annotation node) { 6057 Object visitAnnotation(Annotation node) {
10646 AstNode parent = node.parent; 6058 AstNode parent = node.parent;
10647 if (identical(parent, _enclosingClassDeclaration) || 6059 if (identical(parent, _enclosingClassDeclaration) ||
10648 identical(parent, _enclosingFunctionTypeAlias)) { 6060 identical(parent, _enclosingFunctionTypeAlias)) {
10649 return null; 6061 return null;
10650 } 6062 }
10651 return super.visitAnnotation(node); 6063 node.name?.accept(this);
6064 node.constructorName?.accept(this);
6065 Element element = node.element;
6066 if (element is ExecutableElement) {
6067 InferenceContext.setType(node.arguments, element.type);
6068 }
6069 node.arguments?.accept(this);
6070 node.accept(elementResolver);
6071 node.accept(typeAnalyzer);
6072 ElementAnnotationImpl elementAnnotationImpl = node.elementAnnotation;
6073 if (elementAnnotationImpl == null) {
6074 // Analyzer ignores annotations on "part of" directives.
6075 assert(parent is PartOfDirective);
6076 } else {
6077 elementAnnotationImpl.annotationAst =
6078 new ConstantAstCloner().cloneNode(node);
6079 }
6080 return null;
10652 } 6081 }
10653 6082
10654 @override 6083 @override
6084 Object visitArgumentList(ArgumentList node) {
6085 DartType callerType = InferenceContext.getType(node);
6086 if (callerType is FunctionType) {
6087 Map<String, DartType> namedParameterTypes =
6088 callerType.namedParameterTypes;
6089 List<DartType> normalParameterTypes = callerType.normalParameterTypes;
6090 List<DartType> optionalParameterTypes = callerType.optionalParameterTypes;
6091 int normalCount = normalParameterTypes.length;
6092 int optionalCount = optionalParameterTypes.length;
6093
6094 NodeList<Expression> arguments = node.arguments;
6095 Iterable<Expression> positional =
6096 arguments.takeWhile((l) => l is! NamedExpression);
6097 Iterable<Expression> required = positional.take(normalCount);
6098 Iterable<Expression> optional =
6099 positional.skip(normalCount).take(optionalCount);
6100 Iterable<Expression> named =
6101 arguments.skipWhile((l) => l is! NamedExpression);
6102
6103 //TODO(leafp): Consider using the parameter elements here instead.
6104 //TODO(leafp): Make sure that the parameter elements are getting
6105 // setup correctly with inference.
6106 int index = 0;
6107 for (Expression argument in required) {
6108 InferenceContext.setType(argument, normalParameterTypes[index++]);
6109 }
6110 index = 0;
6111 for (Expression argument in optional) {
6112 InferenceContext.setType(argument, optionalParameterTypes[index++]);
6113 }
6114
6115 for (Expression argument in named) {
6116 if (argument is NamedExpression) {
6117 DartType type = namedParameterTypes[argument.name.label.name];
6118 if (type != null) {
6119 InferenceContext.setType(argument, type);
6120 }
6121 }
6122 }
6123 }
6124 return super.visitArgumentList(node);
6125 }
6126
6127 @override
10655 Object visitAsExpression(AsExpression node) { 6128 Object visitAsExpression(AsExpression node) {
10656 super.visitAsExpression(node); 6129 super.visitAsExpression(node);
10657 // Since an as-statement doesn't actually change the type, we don't 6130 // Since an as-statement doesn't actually change the type, we don't
10658 // let it affect the propagated type when it would result in a loss 6131 // let it affect the propagated type when it would result in a loss
10659 // of precision. 6132 // of precision.
10660 overrideExpression(node.expression, node.type.type, false, false); 6133 overrideExpression(node.expression, node.type.type, false, false);
10661 return null; 6134 return null;
10662 } 6135 }
10663 6136
10664 @override 6137 @override
10665 Object visitAssertStatement(AssertStatement node) { 6138 Object visitAssertStatement(AssertStatement node) {
10666 super.visitAssertStatement(node); 6139 super.visitAssertStatement(node);
10667 _propagateTrueState(node.condition); 6140 _propagateTrueState(node.condition);
10668 return null; 6141 return null;
10669 } 6142 }
10670 6143
10671 @override 6144 @override
6145 Object visitAssignmentExpression(AssignmentExpression node) {
6146 node.leftHandSide?.accept(this);
6147 TokenType operator = node.operator.type;
6148 if (operator == TokenType.EQ ||
6149 operator == TokenType.QUESTION_QUESTION_EQ) {
6150 InferenceContext.setType(
6151 node.rightHandSide, node.leftHandSide.staticType);
6152 }
6153 node.rightHandSide?.accept(this);
6154 node.accept(elementResolver);
6155 node.accept(typeAnalyzer);
6156 return null;
6157 }
6158
6159 @override
6160 Object visitAwaitExpression(AwaitExpression node) {
6161 DartType contextType = InferenceContext.getContext(node);
6162 if (contextType != null) {
6163 var futureUnion =
6164 FutureUnionType.from(contextType, typeProvider, typeSystem);
6165 InferenceContext.setType(node.expression, futureUnion);
6166 }
6167 return super.visitAwaitExpression(node);
6168 }
6169
6170 @override
10672 Object visitBinaryExpression(BinaryExpression node) { 6171 Object visitBinaryExpression(BinaryExpression node) {
10673 sc.TokenType operatorType = node.operator.type; 6172 TokenType operatorType = node.operator.type;
10674 Expression leftOperand = node.leftOperand; 6173 Expression leftOperand = node.leftOperand;
10675 Expression rightOperand = node.rightOperand; 6174 Expression rightOperand = node.rightOperand;
10676 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) { 6175 if (operatorType == TokenType.AMPERSAND_AMPERSAND) {
10677 safelyVisit(leftOperand); 6176 leftOperand?.accept(this);
10678 if (rightOperand != null) { 6177 if (rightOperand != null) {
10679 _overrideManager.enterScope(); 6178 _overrideManager.enterScope();
10680 try { 6179 try {
10681 _promoteManager.enterScope(); 6180 _promoteManager.enterScope();
10682 try { 6181 try {
10683 _propagateTrueState(leftOperand); 6182 _propagateTrueState(leftOperand);
10684 // Type promotion. 6183 // Type promotion.
10685 _promoteTypes(leftOperand); 6184 _promoteTypes(leftOperand);
10686 _clearTypePromotionsIfPotentiallyMutatedIn(leftOperand); 6185 _clearTypePromotionsIfPotentiallyMutatedIn(leftOperand);
10687 _clearTypePromotionsIfPotentiallyMutatedIn(rightOperand); 6186 _clearTypePromotionsIfPotentiallyMutatedIn(rightOperand);
10688 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( 6187 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10689 rightOperand); 6188 rightOperand);
10690 // Visit right operand. 6189 // Visit right operand.
10691 rightOperand.accept(this); 6190 rightOperand.accept(this);
10692 } finally { 6191 } finally {
10693 _promoteManager.exitScope(); 6192 _promoteManager.exitScope();
10694 } 6193 }
10695 } finally { 6194 } finally {
10696 _overrideManager.exitScope(); 6195 _overrideManager.exitScope();
10697 } 6196 }
10698 } 6197 }
10699 } else if (operatorType == sc.TokenType.BAR_BAR) { 6198 } else if (operatorType == TokenType.BAR_BAR) {
10700 safelyVisit(leftOperand); 6199 leftOperand?.accept(this);
10701 if (rightOperand != null) { 6200 if (rightOperand != null) {
10702 _overrideManager.enterScope(); 6201 _overrideManager.enterScope();
10703 try { 6202 try {
10704 _propagateFalseState(leftOperand); 6203 _propagateFalseState(leftOperand);
10705 rightOperand.accept(this); 6204 rightOperand.accept(this);
10706 } finally { 6205 } finally {
10707 _overrideManager.exitScope(); 6206 _overrideManager.exitScope();
10708 } 6207 }
10709 } 6208 }
10710 } else { 6209 } else {
10711 safelyVisit(leftOperand); 6210 // TODO(leafp): Do downwards inference using the declared type
10712 safelyVisit(rightOperand); 6211 // of the binary operator for other cases.
6212 if (operatorType == TokenType.QUESTION_QUESTION) {
6213 InferenceContext.setTypeFromNode(leftOperand, node);
6214 }
6215 leftOperand?.accept(this);
6216 if (operatorType == TokenType.QUESTION_QUESTION) {
6217 // Set the right side, either from the context, or using the information
6218 // from the left side if it is more precise.
6219 DartType contextType = InferenceContext.getContext(node);
6220 DartType leftType = leftOperand?.staticType;
6221 if (contextType == null || contextType.isDynamic) {
6222 contextType = leftType;
6223 }
6224 InferenceContext.setType(rightOperand, contextType);
6225 }
6226 rightOperand?.accept(this);
10713 } 6227 }
10714 node.accept(elementResolver); 6228 node.accept(elementResolver);
10715 node.accept(typeAnalyzer); 6229 node.accept(typeAnalyzer);
10716 return null; 6230 return null;
10717 } 6231 }
10718 6232
10719 @override 6233 @override
10720 Object visitBlockFunctionBody(BlockFunctionBody node) { 6234 Object visitBlockFunctionBody(BlockFunctionBody node) {
10721 safelyVisit(_commentBeforeFunction);
10722 _overrideManager.enterScope(); 6235 _overrideManager.enterScope();
10723 try { 6236 try {
6237 inferenceContext.pushReturnContext(node);
10724 super.visitBlockFunctionBody(node); 6238 super.visitBlockFunctionBody(node);
10725 } finally { 6239 } finally {
10726 _overrideManager.exitScope(); 6240 _overrideManager.exitScope();
6241 inferenceContext.popReturnContext(node);
10727 } 6242 }
10728 return null; 6243 return null;
10729 } 6244 }
10730 6245
10731 @override 6246 @override
10732 Object visitBreakStatement(BreakStatement node) { 6247 Object visitBreakStatement(BreakStatement node) {
10733 // 6248 //
10734 // We do not visit the label because it needs to be visited in the context 6249 // We do not visit the label because it needs to be visited in the context
10735 // of the statement. 6250 // of the statement.
10736 // 6251 //
10737 node.accept(elementResolver); 6252 node.accept(elementResolver);
10738 node.accept(typeAnalyzer); 6253 node.accept(typeAnalyzer);
10739 return null; 6254 return null;
10740 } 6255 }
10741 6256
10742 @override 6257 @override
6258 Object visitCascadeExpression(CascadeExpression node) {
6259 InferenceContext.setTypeFromNode(node.target, node);
6260 return super.visitCascadeExpression(node);
6261 }
6262
6263 @override
10743 Object visitClassDeclaration(ClassDeclaration node) { 6264 Object visitClassDeclaration(ClassDeclaration node) {
10744 // 6265 //
10745 // Resolve the metadata in the library scope. 6266 // Resolve the metadata in the library scope.
10746 // 6267 //
10747 if (node.metadata != null) { 6268 node.metadata?.accept(this);
10748 node.metadata.accept(this);
10749 }
10750 _enclosingClassDeclaration = node; 6269 _enclosingClassDeclaration = node;
10751 // 6270 //
10752 // Continue the class resolution. 6271 // Continue the class resolution.
10753 // 6272 //
10754 ClassElement outerType = enclosingClass; 6273 ClassElement outerType = enclosingClass;
10755 try { 6274 try {
10756 enclosingClass = node.element; 6275 enclosingClass = node.element;
10757 typeAnalyzer.thisType = 6276 typeAnalyzer.thisType = enclosingClass?.type;
10758 enclosingClass == null ? null : enclosingClass.type;
10759 super.visitClassDeclaration(node); 6277 super.visitClassDeclaration(node);
10760 node.accept(elementResolver); 6278 node.accept(elementResolver);
10761 node.accept(typeAnalyzer); 6279 node.accept(typeAnalyzer);
10762 } finally { 6280 } finally {
10763 typeAnalyzer.thisType = outerType == null ? null : outerType.type; 6281 typeAnalyzer.thisType = outerType?.type;
10764 enclosingClass = outerType; 6282 enclosingClass = outerType;
10765 _enclosingClassDeclaration = null; 6283 _enclosingClassDeclaration = null;
10766 } 6284 }
10767 return null; 6285 return null;
10768 } 6286 }
10769 6287
10770 /** 6288 /**
10771 * Implementation of this method should be synchronized with 6289 * Implementation of this method should be synchronized with
10772 * [visitClassDeclaration]. 6290 * [visitClassDeclaration].
10773 */ 6291 */
10774 visitClassDeclarationIncrementally(ClassDeclaration node) { 6292 visitClassDeclarationIncrementally(ClassDeclaration node) {
10775 // 6293 //
10776 // Resolve the metadata in the library scope. 6294 // Resolve the metadata in the library scope.
10777 // 6295 //
10778 if (node.metadata != null) { 6296 node.metadata?.accept(this);
10779 node.metadata.accept(this);
10780 }
10781 _enclosingClassDeclaration = node; 6297 _enclosingClassDeclaration = node;
10782 // 6298 //
10783 // Continue the class resolution. 6299 // Continue the class resolution.
10784 // 6300 //
10785 enclosingClass = node.element; 6301 enclosingClass = node.element;
10786 typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type; 6302 typeAnalyzer.thisType = enclosingClass?.type;
10787 node.accept(elementResolver); 6303 node.accept(elementResolver);
10788 node.accept(typeAnalyzer); 6304 node.accept(typeAnalyzer);
10789 } 6305 }
10790 6306
10791 @override 6307 @override
10792 Object visitComment(Comment node) { 6308 Object visitComment(Comment node) {
10793 if (node.parent is FunctionDeclaration || 6309 AstNode parent = node.parent;
10794 node.parent is ConstructorDeclaration || 6310 if (parent is FunctionDeclaration ||
10795 node.parent is MethodDeclaration) { 6311 parent is FunctionTypeAlias ||
10796 if (!identical(node, _commentBeforeFunction)) { 6312 parent is ConstructorDeclaration ||
10797 _commentBeforeFunction = node; 6313 parent is MethodDeclaration) {
10798 return null; 6314 return null;
10799 }
10800 } 6315 }
10801 super.visitComment(node); 6316 super.visitComment(node);
10802 _commentBeforeFunction = null;
10803 return null; 6317 return null;
10804 } 6318 }
10805 6319
10806 @override 6320 @override
10807 Object visitCommentReference(CommentReference node) { 6321 Object visitCommentReference(CommentReference node) {
10808 // 6322 //
10809 // We do not visit the identifier because it needs to be visited in the 6323 // We do not visit the identifier because it needs to be visited in the
10810 // context of the reference. 6324 // context of the reference.
10811 // 6325 //
10812 node.accept(elementResolver); 6326 node.accept(elementResolver);
10813 node.accept(typeAnalyzer); 6327 node.accept(typeAnalyzer);
10814 return null; 6328 return null;
10815 } 6329 }
10816 6330
10817 @override 6331 @override
10818 Object visitCompilationUnit(CompilationUnit node) { 6332 Object visitCompilationUnit(CompilationUnit node) {
10819 //
10820 // TODO(brianwilkerson) The goal of the code below is to visit the
10821 // declarations in such an order that we can infer type information for
10822 // top-level variables before we visit references to them. This is better
10823 // than making no effort, but still doesn't completely satisfy that goal
10824 // (consider for example "final var a = b; final var b = 0;"; we'll infer a
10825 // type of 'int' for 'b', but not for 'a' because of the order of the
10826 // visits). Ideally we would create a dependency graph, but that would
10827 // require references to be resolved, which they are not.
10828 //
10829 _overrideManager.enterScope(); 6333 _overrideManager.enterScope();
10830 try { 6334 try {
10831 NodeList<Directive> directives = node.directives; 6335 NodeList<Directive> directives = node.directives;
10832 int directiveCount = directives.length; 6336 int directiveCount = directives.length;
10833 for (int i = 0; i < directiveCount; i++) { 6337 for (int i = 0; i < directiveCount; i++) {
10834 directives[i].accept(this); 6338 directives[i].accept(this);
10835 } 6339 }
10836 NodeList<CompilationUnitMember> declarations = node.declarations; 6340 NodeList<CompilationUnitMember> declarations = node.declarations;
10837 int declarationCount = declarations.length; 6341 int declarationCount = declarations.length;
10838 for (int i = 0; i < declarationCount; i++) { 6342 for (int i = 0; i < declarationCount; i++) {
10839 CompilationUnitMember declaration = declarations[i]; 6343 declarations[i].accept(this);
10840 if (declaration is! ClassDeclaration) {
10841 declaration.accept(this);
10842 }
10843 }
10844 for (int i = 0; i < declarationCount; i++) {
10845 CompilationUnitMember declaration = declarations[i];
10846 if (declaration is ClassDeclaration) {
10847 declaration.accept(this);
10848 }
10849 } 6344 }
10850 } finally { 6345 } finally {
10851 _overrideManager.exitScope(); 6346 _overrideManager.exitScope();
10852 } 6347 }
10853 node.accept(elementResolver); 6348 node.accept(elementResolver);
10854 node.accept(typeAnalyzer); 6349 node.accept(typeAnalyzer);
10855 return null; 6350 return null;
10856 } 6351 }
10857 6352
10858 @override 6353 @override
10859 Object visitConditionalExpression(ConditionalExpression node) { 6354 Object visitConditionalExpression(ConditionalExpression node) {
10860 Expression condition = node.condition; 6355 Expression condition = node.condition;
10861 safelyVisit(condition); 6356 condition?.accept(this);
10862 Expression thenExpression = node.thenExpression; 6357 Expression thenExpression = node.thenExpression;
10863 if (thenExpression != null) { 6358 if (thenExpression != null) {
10864 _overrideManager.enterScope(); 6359 _overrideManager.enterScope();
10865 try { 6360 try {
10866 _promoteManager.enterScope(); 6361 _promoteManager.enterScope();
10867 try { 6362 try {
10868 _propagateTrueState(condition); 6363 _propagateTrueState(condition);
10869 // Type promotion. 6364 // Type promotion.
10870 _promoteTypes(condition); 6365 _promoteTypes(condition);
10871 _clearTypePromotionsIfPotentiallyMutatedIn(thenExpression); 6366 _clearTypePromotionsIfPotentiallyMutatedIn(thenExpression);
10872 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( 6367 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
10873 thenExpression); 6368 thenExpression);
10874 // Visit "then" expression. 6369 // Visit "then" expression.
6370 InferenceContext.setTypeFromNode(thenExpression, node);
10875 thenExpression.accept(this); 6371 thenExpression.accept(this);
10876 } finally { 6372 } finally {
10877 _promoteManager.exitScope(); 6373 _promoteManager.exitScope();
10878 } 6374 }
10879 } finally { 6375 } finally {
10880 _overrideManager.exitScope(); 6376 _overrideManager.exitScope();
10881 } 6377 }
10882 } 6378 }
10883 Expression elseExpression = node.elseExpression; 6379 Expression elseExpression = node.elseExpression;
10884 if (elseExpression != null) { 6380 if (elseExpression != null) {
10885 _overrideManager.enterScope(); 6381 _overrideManager.enterScope();
10886 try { 6382 try {
10887 _propagateFalseState(condition); 6383 _propagateFalseState(condition);
6384 InferenceContext.setTypeFromNode(elseExpression, node);
10888 elseExpression.accept(this); 6385 elseExpression.accept(this);
10889 } finally { 6386 } finally {
10890 _overrideManager.exitScope(); 6387 _overrideManager.exitScope();
10891 } 6388 }
10892 } 6389 }
10893 node.accept(elementResolver); 6390 node.accept(elementResolver);
10894 node.accept(typeAnalyzer); 6391 node.accept(typeAnalyzer);
10895 bool thenIsAbrupt = _isAbruptTerminationExpression(thenExpression); 6392 bool thenIsAbrupt = _isAbruptTerminationExpression(thenExpression);
10896 bool elseIsAbrupt = _isAbruptTerminationExpression(elseExpression); 6393 bool elseIsAbrupt = _isAbruptTerminationExpression(elseExpression);
10897 if (elseIsAbrupt && !thenIsAbrupt) { 6394 if (elseIsAbrupt && !thenIsAbrupt) {
10898 _propagateTrueState(condition); 6395 _propagateTrueState(condition);
10899 _propagateState(thenExpression); 6396 _propagateState(thenExpression);
10900 } else if (thenIsAbrupt && !elseIsAbrupt) { 6397 } else if (thenIsAbrupt && !elseIsAbrupt) {
10901 _propagateFalseState(condition); 6398 _propagateFalseState(condition);
10902 _propagateState(elseExpression); 6399 _propagateState(elseExpression);
10903 } 6400 }
10904 return null; 6401 return null;
10905 } 6402 }
10906 6403
10907 @override 6404 @override
10908 Object visitConstructorDeclaration(ConstructorDeclaration node) { 6405 Object visitConstructorDeclaration(ConstructorDeclaration node) {
10909 ExecutableElement outerFunction = _enclosingFunction; 6406 ExecutableElement outerFunction = _enclosingFunction;
6407 FunctionBody outerFunctionBody = _currentFunctionBody;
10910 try { 6408 try {
6409 _currentFunctionBody = node.body;
10911 _enclosingFunction = node.element; 6410 _enclosingFunction = node.element;
6411 FunctionType type = _enclosingFunction.type;
6412 InferenceContext.setType(node.body, type.returnType);
10912 super.visitConstructorDeclaration(node); 6413 super.visitConstructorDeclaration(node);
10913 } finally { 6414 } finally {
6415 _currentFunctionBody = outerFunctionBody;
10914 _enclosingFunction = outerFunction; 6416 _enclosingFunction = outerFunction;
10915 } 6417 }
10916 ConstructorElementImpl constructor = node.element; 6418 ConstructorElementImpl constructor = node.element;
10917 constructor.constantInitializers = 6419 constructor.constantInitializers =
10918 new ConstantAstCloner().cloneNodeList(node.initializers); 6420 new ConstantAstCloner().cloneNodeList(node.initializers);
10919 return null; 6421 return null;
10920 } 6422 }
10921 6423
10922 @override 6424 @override
6425 void visitConstructorDeclarationInScope(ConstructorDeclaration node) {
6426 super.visitConstructorDeclarationInScope(node);
6427 // Because of needing a different scope for the initializer list, the
6428 // overridden implementation of this method cannot cause the visitNode
6429 // method to be invoked. As a result, we have to hard-code using the
6430 // element resolver and type analyzer to visit the constructor declaration.
6431 node.accept(elementResolver);
6432 node.accept(typeAnalyzer);
6433 safelyVisitComment(node.documentationComment);
6434 }
6435
6436 @override
10923 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { 6437 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
10924 // 6438 //
10925 // We visit the expression, but do not visit the field name because it needs 6439 // We visit the expression, but do not visit the field name because it needs
10926 // to be visited in the context of the constructor field initializer node. 6440 // to be visited in the context of the constructor field initializer node.
10927 // 6441 //
10928 safelyVisit(node.expression); 6442 FieldElement fieldElement = enclosingClass.getField(node.fieldName.name);
6443 InferenceContext.setType(node.expression, fieldElement?.type);
6444 node.expression?.accept(this);
10929 node.accept(elementResolver); 6445 node.accept(elementResolver);
10930 node.accept(typeAnalyzer); 6446 node.accept(typeAnalyzer);
10931 return null; 6447 return null;
10932 } 6448 }
10933 6449
10934 @override 6450 @override
10935 Object visitConstructorName(ConstructorName node) { 6451 Object visitConstructorName(ConstructorName node) {
10936 // 6452 //
10937 // We do not visit either the type name, because it won't be visited anyway, 6453 // We do not visit either the type name, because it won't be visited anyway,
10938 // or the name, because it needs to be visited in the context of the 6454 // or the name, because it needs to be visited in the context of the
(...skipping 10 matching lines...) Expand all
10949 // We do not visit the label because it needs to be visited in the context 6465 // We do not visit the label because it needs to be visited in the context
10950 // of the statement. 6466 // of the statement.
10951 // 6467 //
10952 node.accept(elementResolver); 6468 node.accept(elementResolver);
10953 node.accept(typeAnalyzer); 6469 node.accept(typeAnalyzer);
10954 return null; 6470 return null;
10955 } 6471 }
10956 6472
10957 @override 6473 @override
10958 Object visitDefaultFormalParameter(DefaultFormalParameter node) { 6474 Object visitDefaultFormalParameter(DefaultFormalParameter node) {
6475 InferenceContext.setType(node.defaultValue, node.parameter.element?.type);
10959 super.visitDefaultFormalParameter(node); 6476 super.visitDefaultFormalParameter(node);
10960 ParameterElement element = node.element; 6477 ParameterElement element = node.element;
10961 if (element.initializer != null && node.defaultValue != null) { 6478 if (element.initializer != null && node.defaultValue != null) {
10962 (element.initializer as FunctionElementImpl).returnType = 6479 (element.initializer as FunctionElementImpl).returnType =
10963 node.defaultValue.staticType; 6480 node.defaultValue.staticType;
10964 } 6481 }
10965 FormalParameterList parent = node.parent; 6482 // Clone the ASTs for default formal parameters, so that we can use them
10966 AstNode grandparent = parent.parent; 6483 // during constant evaluation.
10967 if (grandparent is ConstructorDeclaration && 6484 if (!LibraryElementImpl.hasResolutionCapability(
10968 grandparent.constKeyword != null) { 6485 definingLibrary, LibraryResolutionCapability.constantExpressions)) {
10969 // For const constructors, we need to clone the ASTs for default formal
10970 // parameters, so that we can use them during constant evaluation.
10971 ParameterElement element = node.element;
10972 (element as ConstVariableElement).constantInitializer = 6486 (element as ConstVariableElement).constantInitializer =
10973 new ConstantAstCloner().cloneNode(node.defaultValue); 6487 new ConstantAstCloner().cloneNode(node.defaultValue);
10974 } 6488 }
10975 return null; 6489 return null;
10976 } 6490 }
10977 6491
10978 @override 6492 @override
10979 Object visitDoStatement(DoStatement node) { 6493 Object visitDoStatement(DoStatement node) {
10980 _overrideManager.enterScope(); 6494 _overrideManager.enterScope();
10981 try { 6495 try {
10982 super.visitDoStatement(node); 6496 super.visitDoStatement(node);
10983 } finally { 6497 } finally {
10984 _overrideManager.exitScope(); 6498 _overrideManager.exitScope();
10985 } 6499 }
10986 // TODO(brianwilkerson) If the loop can only be exited because the condition 6500 // TODO(brianwilkerson) If the loop can only be exited because the condition
10987 // is false, then propagateFalseState(node.getCondition()); 6501 // is false, then propagateFalseState(node.getCondition());
10988 return null; 6502 return null;
10989 } 6503 }
10990 6504
10991 @override 6505 @override
10992 Object visitEmptyFunctionBody(EmptyFunctionBody node) { 6506 Object visitEmptyFunctionBody(EmptyFunctionBody node) {
10993 safelyVisit(_commentBeforeFunction);
10994 if (resolveOnlyCommentInFunctionBody) { 6507 if (resolveOnlyCommentInFunctionBody) {
10995 return null; 6508 return null;
10996 } 6509 }
10997 return super.visitEmptyFunctionBody(node); 6510 return super.visitEmptyFunctionBody(node);
10998 } 6511 }
10999 6512
11000 @override 6513 @override
11001 Object visitEnumDeclaration(EnumDeclaration node) { 6514 Object visitEnumDeclaration(EnumDeclaration node) {
11002 // 6515 //
11003 // Resolve the metadata in the library scope 6516 // Resolve the metadata in the library scope
11004 // and associate the annotations with the element. 6517 // and associate the annotations with the element.
11005 // 6518 //
11006 if (node.metadata != null) { 6519 if (node.metadata != null) {
11007 node.metadata.accept(this); 6520 node.metadata.accept(this);
11008 ElementResolver.setMetadata(node.element, node); 6521 ElementResolver.resolveMetadata(node);
11009 } 6522 }
11010 // 6523 //
11011 // Continue the enum resolution. 6524 // Continue the enum resolution.
11012 // 6525 //
11013 ClassElement outerType = enclosingClass; 6526 ClassElement outerType = enclosingClass;
11014 try { 6527 try {
11015 enclosingClass = node.element; 6528 enclosingClass = node.element;
11016 typeAnalyzer.thisType = 6529 typeAnalyzer.thisType = enclosingClass?.type;
11017 enclosingClass == null ? null : enclosingClass.type;
11018 super.visitEnumDeclaration(node); 6530 super.visitEnumDeclaration(node);
11019 node.accept(elementResolver); 6531 node.accept(elementResolver);
11020 node.accept(typeAnalyzer); 6532 node.accept(typeAnalyzer);
11021 } finally { 6533 } finally {
11022 typeAnalyzer.thisType = outerType == null ? null : outerType.type; 6534 typeAnalyzer.thisType = outerType?.type;
11023 enclosingClass = outerType; 6535 enclosingClass = outerType;
11024 _enclosingClassDeclaration = null; 6536 _enclosingClassDeclaration = null;
11025 } 6537 }
11026 return null; 6538 return null;
11027 } 6539 }
11028 6540
11029 @override 6541 @override
11030 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { 6542 Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
11031 safelyVisit(_commentBeforeFunction);
11032 if (resolveOnlyCommentInFunctionBody) { 6543 if (resolveOnlyCommentInFunctionBody) {
11033 return null; 6544 return null;
11034 } 6545 }
11035 _overrideManager.enterScope(); 6546 _overrideManager.enterScope();
11036 try { 6547 try {
6548 InferenceContext.setTypeFromNode(node.expression, node);
11037 super.visitExpressionFunctionBody(node); 6549 super.visitExpressionFunctionBody(node);
11038 } finally { 6550 } finally {
11039 _overrideManager.exitScope(); 6551 _overrideManager.exitScope();
11040 } 6552 }
11041 return null; 6553 return null;
11042 } 6554 }
11043 6555
11044 @override 6556 @override
11045 Object visitFieldDeclaration(FieldDeclaration node) { 6557 Object visitFieldDeclaration(FieldDeclaration node) {
11046 _overrideManager.enterScope(); 6558 _overrideManager.enterScope();
(...skipping 19 matching lines...) Expand all
11066 return null; 6578 return null;
11067 } 6579 }
11068 6580
11069 @override 6581 @override
11070 void visitForEachStatementInScope(ForEachStatement node) { 6582 void visitForEachStatementInScope(ForEachStatement node) {
11071 // 6583 //
11072 // We visit the iterator before the loop variable because the loop variable 6584 // We visit the iterator before the loop variable because the loop variable
11073 // cannot be in scope while visiting the iterator. 6585 // cannot be in scope while visiting the iterator.
11074 // 6586 //
11075 Expression iterable = node.iterable; 6587 Expression iterable = node.iterable;
11076 safelyVisit(iterable);
11077 DeclaredIdentifier loopVariable = node.loopVariable; 6588 DeclaredIdentifier loopVariable = node.loopVariable;
11078 SimpleIdentifier identifier = node.identifier; 6589 SimpleIdentifier identifier = node.identifier;
11079 safelyVisit(loopVariable); 6590 if (loopVariable?.type?.type != null) {
11080 safelyVisit(identifier); 6591 InterfaceType targetType = (node.awaitKeyword == null)
6592 ? typeProvider.iterableType
6593 : typeProvider.streamType;
6594 InferenceContext.setType(
6595 iterable, targetType.instantiate([loopVariable.type.type]));
6596 }
6597 iterable?.accept(this);
6598 loopVariable?.accept(this);
6599 identifier?.accept(this);
11081 Statement body = node.body; 6600 Statement body = node.body;
11082 if (body != null) { 6601 if (body != null) {
11083 _overrideManager.enterScope(); 6602 _overrideManager.enterScope();
11084 try { 6603 try {
11085 if (loopVariable != null && iterable != null) { 6604 if (loopVariable != null && iterable != null) {
11086 LocalVariableElement loopElement = loopVariable.element; 6605 LocalVariableElement loopElement = loopVariable.element;
11087 if (loopElement != null) { 6606 if (loopElement != null) {
11088 DartType propagatedType = null; 6607 DartType propagatedType = null;
11089 if (node.awaitKeyword == null) { 6608 if (node.awaitKeyword == null) {
11090 propagatedType = _getIteratorElementType(iterable); 6609 propagatedType = _getIteratorElementType(iterable);
(...skipping 29 matching lines...) Expand all
11120 try { 6639 try {
11121 super.visitForStatement(node); 6640 super.visitForStatement(node);
11122 } finally { 6641 } finally {
11123 _overrideManager.exitScope(); 6642 _overrideManager.exitScope();
11124 } 6643 }
11125 return null; 6644 return null;
11126 } 6645 }
11127 6646
11128 @override 6647 @override
11129 void visitForStatementInScope(ForStatement node) { 6648 void visitForStatementInScope(ForStatement node) {
11130 safelyVisit(node.variables); 6649 node.variables?.accept(this);
11131 safelyVisit(node.initialization); 6650 node.initialization?.accept(this);
11132 safelyVisit(node.condition); 6651 node.condition?.accept(this);
11133 _overrideManager.enterScope(); 6652 _overrideManager.enterScope();
11134 try { 6653 try {
11135 _propagateTrueState(node.condition); 6654 _propagateTrueState(node.condition);
11136 visitStatementInScope(node.body); 6655 visitStatementInScope(node.body);
11137 node.updaters.accept(this); 6656 node.updaters.accept(this);
11138 } finally { 6657 } finally {
11139 _overrideManager.exitScope(); 6658 _overrideManager.exitScope();
11140 } 6659 }
11141 // TODO(brianwilkerson) If the loop can only be exited because the condition 6660 // TODO(brianwilkerson) If the loop can only be exited because the condition
11142 // is false, then propagateFalseState(condition); 6661 // is false, then propagateFalseState(condition);
11143 } 6662 }
11144 6663
11145 @override 6664 @override
11146 Object visitFunctionDeclaration(FunctionDeclaration node) { 6665 Object visitFunctionDeclaration(FunctionDeclaration node) {
11147 ExecutableElement outerFunction = _enclosingFunction; 6666 ExecutableElement outerFunction = _enclosingFunction;
6667 FunctionBody outerFunctionBody = _currentFunctionBody;
11148 try { 6668 try {
11149 SimpleIdentifier functionName = node.name; 6669 SimpleIdentifier functionName = node.name;
6670 _currentFunctionBody = node.functionExpression.body;
11150 _enclosingFunction = functionName.staticElement as ExecutableElement; 6671 _enclosingFunction = functionName.staticElement as ExecutableElement;
6672 InferenceContext.setType(
6673 node.functionExpression, _enclosingFunction.type);
11151 super.visitFunctionDeclaration(node); 6674 super.visitFunctionDeclaration(node);
11152 } finally { 6675 } finally {
6676 _currentFunctionBody = outerFunctionBody;
11153 _enclosingFunction = outerFunction; 6677 _enclosingFunction = outerFunction;
11154 } 6678 }
11155 return null; 6679 return null;
11156 } 6680 }
11157 6681
11158 @override 6682 @override
6683 void visitFunctionDeclarationInScope(FunctionDeclaration node) {
6684 super.visitFunctionDeclarationInScope(node);
6685 safelyVisitComment(node.documentationComment);
6686 }
6687
6688 @override
11159 Object visitFunctionExpression(FunctionExpression node) { 6689 Object visitFunctionExpression(FunctionExpression node) {
11160 ExecutableElement outerFunction = _enclosingFunction; 6690 ExecutableElement outerFunction = _enclosingFunction;
6691 FunctionBody outerFunctionBody = _currentFunctionBody;
11161 try { 6692 try {
6693 _currentFunctionBody = node.body;
11162 _enclosingFunction = node.element; 6694 _enclosingFunction = node.element;
11163 _overrideManager.enterScope(); 6695 _overrideManager.enterScope();
11164 try { 6696 try {
6697 DartType functionType = InferenceContext.getType(node);
6698 if (functionType is FunctionType) {
6699 functionType =
6700 matchFunctionTypeParameters(node.typeParameters, functionType);
6701 if (functionType is FunctionType) {
6702 _inferFormalParameterList(node.parameters, functionType);
6703
6704 DartType returnType;
6705 if (isFutureThen(node.staticParameterElement?.enclosingElement)) {
6706 var futureThenType =
6707 InferenceContext.getContext(node.parent) as FunctionType;
6708
6709 // Pretend the return type of Future<T>.then<S> first parameter is
6710 //
6711 // T -> (S | Future<S>)
6712 //
6713 // We can't represent this in Dart so we populate it here during
6714 // inference.
6715 var typeParamS =
6716 futureThenType.returnType.flattenFutures(typeSystem);
6717 returnType =
6718 FutureUnionType.from(typeParamS, typeProvider, typeSystem);
6719 } else {
6720 returnType = _computeReturnOrYieldType(functionType.returnType);
6721 }
6722
6723 InferenceContext.setType(node.body, returnType);
6724 }
6725 }
11165 super.visitFunctionExpression(node); 6726 super.visitFunctionExpression(node);
11166 } finally { 6727 } finally {
11167 _overrideManager.exitScope(); 6728 _overrideManager.exitScope();
11168 } 6729 }
11169 } finally { 6730 } finally {
6731 _currentFunctionBody = outerFunctionBody;
11170 _enclosingFunction = outerFunction; 6732 _enclosingFunction = outerFunction;
11171 } 6733 }
11172 return null; 6734 return null;
11173 } 6735 }
11174 6736
11175 @override 6737 @override
11176 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { 6738 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
11177 safelyVisit(node.function); 6739 node.function?.accept(this);
11178 node.accept(elementResolver); 6740 node.accept(elementResolver);
11179 _inferFunctionExpressionsParametersTypes(node.argumentList); 6741 _inferArgumentTypesFromContext(node);
11180 safelyVisit(node.argumentList); 6742 node.argumentList?.accept(this);
11181 node.accept(typeAnalyzer); 6743 node.accept(typeAnalyzer);
11182 return null; 6744 return null;
11183 } 6745 }
11184 6746
11185 @override 6747 @override
11186 Object visitFunctionTypeAlias(FunctionTypeAlias node) { 6748 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
11187 // Resolve the metadata in the library scope. 6749 // Resolve the metadata in the library scope.
11188 if (node.metadata != null) { 6750 if (node.metadata != null) {
11189 node.metadata.accept(this); 6751 node.metadata.accept(this);
11190 } 6752 }
11191 FunctionTypeAlias outerAlias = _enclosingFunctionTypeAlias; 6753 FunctionTypeAlias outerAlias = _enclosingFunctionTypeAlias;
11192 _enclosingFunctionTypeAlias = node; 6754 _enclosingFunctionTypeAlias = node;
11193 try { 6755 try {
11194 super.visitFunctionTypeAlias(node); 6756 super.visitFunctionTypeAlias(node);
11195 } finally { 6757 } finally {
11196 _enclosingFunctionTypeAlias = outerAlias; 6758 _enclosingFunctionTypeAlias = outerAlias;
11197 } 6759 }
11198 return null; 6760 return null;
11199 } 6761 }
11200 6762
11201 @override 6763 @override
6764 void visitFunctionTypeAliasInScope(FunctionTypeAlias node) {
6765 super.visitFunctionTypeAliasInScope(node);
6766 safelyVisitComment(node.documentationComment);
6767 }
6768
6769 @override
11202 Object visitHideCombinator(HideCombinator node) => null; 6770 Object visitHideCombinator(HideCombinator node) => null;
11203 6771
11204 @override 6772 @override
11205 Object visitIfStatement(IfStatement node) { 6773 Object visitIfStatement(IfStatement node) {
11206 Expression condition = node.condition; 6774 Expression condition = node.condition;
11207 safelyVisit(condition); 6775 condition?.accept(this);
11208 Map<VariableElement, DartType> thenOverrides = 6776 Map<VariableElement, DartType> thenOverrides =
11209 new HashMap<VariableElement, DartType>(); 6777 const <VariableElement, DartType>{};
11210 Statement thenStatement = node.thenStatement; 6778 Statement thenStatement = node.thenStatement;
11211 if (thenStatement != null) { 6779 if (thenStatement != null) {
11212 _overrideManager.enterScope(); 6780 _overrideManager.enterScope();
11213 try { 6781 try {
11214 _promoteManager.enterScope(); 6782 _promoteManager.enterScope();
11215 try { 6783 try {
11216 _propagateTrueState(condition); 6784 _propagateTrueState(condition);
11217 // Type promotion. 6785 // Type promotion.
11218 _promoteTypes(condition); 6786 _promoteTypes(condition);
11219 _clearTypePromotionsIfPotentiallyMutatedIn(thenStatement); 6787 _clearTypePromotionsIfPotentiallyMutatedIn(thenStatement);
11220 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( 6788 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
11221 thenStatement); 6789 thenStatement);
11222 // Visit "then". 6790 // Visit "then".
11223 visitStatementInScope(thenStatement); 6791 visitStatementInScope(thenStatement);
11224 } finally { 6792 } finally {
11225 _promoteManager.exitScope(); 6793 _promoteManager.exitScope();
11226 } 6794 }
11227 } finally { 6795 } finally {
11228 thenOverrides = _overrideManager.captureLocalOverrides(); 6796 thenOverrides = _overrideManager.captureLocalOverrides();
11229 _overrideManager.exitScope(); 6797 _overrideManager.exitScope();
11230 } 6798 }
11231 } 6799 }
11232 Map<VariableElement, DartType> elseOverrides = 6800 Map<VariableElement, DartType> elseOverrides =
11233 new HashMap<VariableElement, DartType>(); 6801 const <VariableElement, DartType>{};
11234 Statement elseStatement = node.elseStatement; 6802 Statement elseStatement = node.elseStatement;
11235 if (elseStatement != null) { 6803 if (elseStatement != null) {
11236 _overrideManager.enterScope(); 6804 _overrideManager.enterScope();
11237 try { 6805 try {
11238 _propagateFalseState(condition); 6806 _propagateFalseState(condition);
11239 visitStatementInScope(elseStatement); 6807 visitStatementInScope(elseStatement);
11240 } finally { 6808 } finally {
11241 elseOverrides = _overrideManager.captureLocalOverrides(); 6809 elseOverrides = _overrideManager.captureLocalOverrides();
11242 _overrideManager.exitScope(); 6810 _overrideManager.exitScope();
11243 } 6811 }
11244 } 6812 }
11245 node.accept(elementResolver); 6813 node.accept(elementResolver);
11246 node.accept(typeAnalyzer); 6814 node.accept(typeAnalyzer);
11247 // Join overrides. 6815 // Join overrides.
11248 bool thenIsAbrupt = _isAbruptTerminationStatement(thenStatement); 6816 bool thenIsAbrupt = _isAbruptTerminationStatement(thenStatement);
11249 bool elseIsAbrupt = _isAbruptTerminationStatement(elseStatement); 6817 bool elseIsAbrupt = _isAbruptTerminationStatement(elseStatement);
11250 if (elseIsAbrupt && !thenIsAbrupt) { 6818 if (elseIsAbrupt && !thenIsAbrupt) {
11251 _propagateTrueState(condition); 6819 _propagateTrueState(condition);
11252 _overrideManager.applyOverrides(thenOverrides); 6820 _overrideManager.applyOverrides(thenOverrides);
11253 } else if (thenIsAbrupt && !elseIsAbrupt) { 6821 } else if (thenIsAbrupt && !elseIsAbrupt) {
11254 _propagateFalseState(condition); 6822 _propagateFalseState(condition);
11255 _overrideManager.applyOverrides(elseOverrides); 6823 _overrideManager.applyOverrides(elseOverrides);
11256 } else if (!thenIsAbrupt && !elseIsAbrupt) { 6824 } else if (!thenIsAbrupt && !elseIsAbrupt) {
11257 List<Map<VariableElement, DartType>> perBranchOverrides = 6825 List<Map<VariableElement, DartType>> perBranchOverrides =
11258 new List<Map<VariableElement, DartType>>(); 6826 <Map<VariableElement, DartType>>[];
11259 perBranchOverrides.add(thenOverrides); 6827 perBranchOverrides.add(thenOverrides);
11260 perBranchOverrides.add(elseOverrides); 6828 perBranchOverrides.add(elseOverrides);
11261 _overrideManager.mergeOverrides(perBranchOverrides); 6829 _overrideManager.mergeOverrides(perBranchOverrides);
11262 } 6830 }
11263 return null; 6831 return null;
11264 } 6832 }
11265 6833
11266 @override 6834 @override
6835 Object visitInstanceCreationExpression(InstanceCreationExpression node) {
6836 TypeName classTypeName = node.constructorName.type;
6837 // TODO(leafp): Currently, we may re-infer types here, since we
6838 // sometimes resolve multiple times. We should really check that we
6839 // have not already inferred something. However, the obvious ways to
6840 // check this don't work, since we may have been instantiated
6841 // to bounds in an earlier phase, and we *do* want to do inference
6842 // in that case.
6843 if (classTypeName.typeArguments == null) {
6844 // Given a union of context types ` T0 | T1 | ... | Tn`, find the first
6845 // valid instantiation `new C<Ti>`, if it exists.
6846 // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>`
6847 // will become a valid possibility. Right now the only allowed union is
6848 // `T | Future<T>` so we can take a simple approach.
6849 for (var contextType in InferenceContext.getTypes(node)) {
6850 if (contextType is InterfaceType &&
6851 contextType.typeArguments != null &&
6852 contextType.typeArguments.isNotEmpty) {
6853 // TODO(jmesserly): for generic methods we use the
6854 // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to
6855 // be a tad more powerful than matchTypes.
6856 //
6857 // For example it can infer this case:
6858 //
6859 // class E<S, T> extends A<C<S>, T> { ... }
6860 // A<C<int>, String> a0 = /*infer<int, String>*/new E("hello");
6861 //
6862 // See _inferArgumentTypesFromContext in this file for use of it.
6863 List<DartType> targs =
6864 inferenceContext.matchTypes(classTypeName.type, contextType);
6865 if (targs != null && targs.any((t) => !t.isDynamic)) {
6866 ClassElement classElement = classTypeName.type.element;
6867 InterfaceType rawType = classElement.type;
6868 InterfaceType fullType =
6869 rawType.substitute2(targs, rawType.typeArguments);
6870 // The element resolver uses the type on the constructor name, so
6871 // infer it first
6872 typeAnalyzer.inferConstructorName(node.constructorName, fullType);
6873 break;
6874 }
6875 }
6876 }
6877 }
6878 node.constructorName?.accept(this);
6879 FunctionType constructorType = node.constructorName.staticElement?.type;
6880 if (constructorType != null) {
6881 InferenceContext.setType(node.argumentList, constructorType);
6882 }
6883 node.argumentList?.accept(this);
6884 node.accept(elementResolver);
6885 node.accept(typeAnalyzer);
6886 return null;
6887 }
6888
6889 @override
11267 Object visitLabel(Label node) => null; 6890 Object visitLabel(Label node) => null;
11268 6891
11269 @override 6892 @override
11270 Object visitLibraryIdentifier(LibraryIdentifier node) => null; 6893 Object visitLibraryIdentifier(LibraryIdentifier node) => null;
11271 6894
11272 @override 6895 @override
6896 Object visitListLiteral(ListLiteral node) {
6897 DartType contextType = InferenceContext.getType(node);
6898 List<DartType> targs = null;
6899 if (node.typeArguments != null) {
6900 targs = node.typeArguments.arguments.map((t) => t.type).toList();
6901 } else if (contextType is InterfaceType) {
6902 InterfaceType listD =
6903 typeProvider.listType.instantiate([typeProvider.dynamicType]);
6904 targs = inferenceContext.matchTypes(listD, contextType);
6905 }
6906 if (targs != null && targs.length == 1 && !targs[0].isDynamic) {
6907 DartType eType = targs[0];
6908 InterfaceType listT = typeProvider.listType.instantiate([eType]);
6909 for (Expression child in node.elements) {
6910 InferenceContext.setType(child, eType);
6911 }
6912 InferenceContext.setType(node, listT);
6913 } else {
6914 InferenceContext.clearType(node);
6915 }
6916 super.visitListLiteral(node);
6917 return null;
6918 }
6919
6920 @override
6921 Object visitMapLiteral(MapLiteral node) {
6922 DartType contextType = InferenceContext.getType(node);
6923 List<DartType> targs = null;
6924 if (node.typeArguments != null) {
6925 targs = node.typeArguments.arguments.map((t) => t.type).toList();
6926 } else if (contextType is InterfaceType) {
6927 InterfaceType mapD = typeProvider.mapType
6928 .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]);
6929 targs = inferenceContext.matchTypes(mapD, contextType);
6930 }
6931 if (targs != null && targs.length == 2 && targs.any((t) => !t.isDynamic)) {
6932 DartType kType = targs[0];
6933 DartType vType = targs[1];
6934 InterfaceType mapT = typeProvider.mapType.instantiate([kType, vType]);
6935 for (MapLiteralEntry entry in node.entries) {
6936 InferenceContext.setType(entry.key, kType);
6937 InferenceContext.setType(entry.value, vType);
6938 }
6939 InferenceContext.setType(node, mapT);
6940 } else {
6941 InferenceContext.clearType(node);
6942 }
6943 super.visitMapLiteral(node);
6944 return null;
6945 }
6946
6947 @override
11273 Object visitMethodDeclaration(MethodDeclaration node) { 6948 Object visitMethodDeclaration(MethodDeclaration node) {
11274 ExecutableElement outerFunction = _enclosingFunction; 6949 ExecutableElement outerFunction = _enclosingFunction;
6950 FunctionBody outerFunctionBody = _currentFunctionBody;
11275 try { 6951 try {
6952 _currentFunctionBody = node.body;
11276 _enclosingFunction = node.element; 6953 _enclosingFunction = node.element;
6954 DartType returnType =
6955 _computeReturnOrYieldType(_enclosingFunction.type?.returnType);
6956 InferenceContext.setType(node.body, returnType);
11277 super.visitMethodDeclaration(node); 6957 super.visitMethodDeclaration(node);
11278 } finally { 6958 } finally {
6959 _currentFunctionBody = outerFunctionBody;
11279 _enclosingFunction = outerFunction; 6960 _enclosingFunction = outerFunction;
11280 } 6961 }
11281 return null; 6962 return null;
11282 } 6963 }
11283 6964
11284 @override 6965 @override
6966 void visitMethodDeclarationInScope(MethodDeclaration node) {
6967 super.visitMethodDeclarationInScope(node);
6968 safelyVisitComment(node.documentationComment);
6969 }
6970
6971 @override
11285 Object visitMethodInvocation(MethodInvocation node) { 6972 Object visitMethodInvocation(MethodInvocation node) {
11286 // 6973 //
11287 // We visit the target and argument list, but do not visit the method name 6974 // We visit the target and argument list, but do not visit the method name
11288 // because it needs to be visited in the context of the invocation. 6975 // because it needs to be visited in the context of the invocation.
11289 // 6976 //
11290 safelyVisit(node.target); 6977 node.target?.accept(this);
6978 node.typeArguments?.accept(this);
11291 node.accept(elementResolver); 6979 node.accept(elementResolver);
11292 _inferFunctionExpressionsParametersTypes(node.argumentList); 6980 _inferArgumentTypesFromContext(node);
11293 safelyVisit(node.argumentList); 6981 node.argumentList?.accept(this);
11294 node.accept(typeAnalyzer); 6982 node.accept(typeAnalyzer);
11295 return null; 6983 return null;
11296 } 6984 }
11297 6985
11298 @override 6986 @override
6987 Object visitNamedExpression(NamedExpression node) {
6988 InferenceContext.setTypeFromNode(node.expression, node);
6989 return super.visitNamedExpression(node);
6990 }
6991
6992 @override
11299 Object visitNode(AstNode node) { 6993 Object visitNode(AstNode node) {
11300 node.visitChildren(this); 6994 node.visitChildren(this);
11301 node.accept(elementResolver); 6995 node.accept(elementResolver);
11302 node.accept(typeAnalyzer); 6996 node.accept(typeAnalyzer);
11303 return null; 6997 return null;
11304 } 6998 }
11305 6999
11306 @override 7000 @override
7001 Object visitParenthesizedExpression(ParenthesizedExpression node) {
7002 InferenceContext.setTypeFromNode(node.expression, node);
7003 return super.visitParenthesizedExpression(node);
7004 }
7005
7006 @override
11307 Object visitPrefixedIdentifier(PrefixedIdentifier node) { 7007 Object visitPrefixedIdentifier(PrefixedIdentifier node) {
11308 // 7008 //
11309 // We visit the prefix, but do not visit the identifier because it needs to 7009 // We visit the prefix, but do not visit the identifier because it needs to
11310 // be visited in the context of the prefix. 7010 // be visited in the context of the prefix.
11311 // 7011 //
11312 safelyVisit(node.prefix); 7012 node.prefix?.accept(this);
11313 node.accept(elementResolver); 7013 node.accept(elementResolver);
11314 node.accept(typeAnalyzer); 7014 node.accept(typeAnalyzer);
11315 return null; 7015 return null;
11316 } 7016 }
11317 7017
11318 @override 7018 @override
11319 Object visitPropertyAccess(PropertyAccess node) { 7019 Object visitPropertyAccess(PropertyAccess node) {
11320 // 7020 //
11321 // We visit the target, but do not visit the property name because it needs 7021 // We visit the target, but do not visit the property name because it needs
11322 // to be visited in the context of the property access node. 7022 // to be visited in the context of the property access node.
11323 // 7023 //
11324 safelyVisit(node.target); 7024 node.target?.accept(this);
11325 node.accept(elementResolver); 7025 node.accept(elementResolver);
11326 node.accept(typeAnalyzer); 7026 node.accept(typeAnalyzer);
11327 return null; 7027 return null;
11328 } 7028 }
11329 7029
11330 @override 7030 @override
11331 Object visitRedirectingConstructorInvocation( 7031 Object visitRedirectingConstructorInvocation(
11332 RedirectingConstructorInvocation node) { 7032 RedirectingConstructorInvocation node) {
11333 // 7033 //
11334 // We visit the argument list, but do not visit the optional identifier 7034 // We visit the argument list, but do not visit the optional identifier
11335 // because it needs to be visited in the context of the constructor 7035 // because it needs to be visited in the context of the constructor
11336 // invocation. 7036 // invocation.
11337 // 7037 //
11338 safelyVisit(node.argumentList); 7038 InferenceContext.setType(node.argumentList, node.staticElement?.type);
7039 node.argumentList?.accept(this);
11339 node.accept(elementResolver); 7040 node.accept(elementResolver);
11340 node.accept(typeAnalyzer); 7041 node.accept(typeAnalyzer);
11341 return null; 7042 return null;
11342 } 7043 }
11343 7044
11344 @override 7045 @override
7046 Object visitReturnStatement(ReturnStatement node) {
7047 Expression e = node.expression;
7048 InferenceContext.setType(e, inferenceContext.returnContext);
7049 super.visitReturnStatement(node);
7050 DartType type = e?.staticType;
7051 // Generators cannot return values, so don't try to do any inference if
7052 // we're processing erroneous code.
7053 if (type != null && _enclosingFunction?.isGenerator == false) {
7054 if (_enclosingFunction.isAsynchronous) {
7055 type = type.flattenFutures(typeSystem);
7056 }
7057 inferenceContext.addReturnOrYieldType(type);
7058 }
7059 return null;
7060 }
7061
7062 @override
11345 Object visitShowCombinator(ShowCombinator node) => null; 7063 Object visitShowCombinator(ShowCombinator node) => null;
11346 7064
11347 @override 7065 @override
11348 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { 7066 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
11349 // 7067 //
11350 // We visit the argument list, but do not visit the optional identifier 7068 // We visit the argument list, but do not visit the optional identifier
11351 // because it needs to be visited in the context of the constructor 7069 // because it needs to be visited in the context of the constructor
11352 // invocation. 7070 // invocation.
11353 // 7071 //
11354 safelyVisit(node.argumentList); 7072 InferenceContext.setType(node.argumentList, node.staticElement?.type);
7073 node.argumentList?.accept(this);
11355 node.accept(elementResolver); 7074 node.accept(elementResolver);
11356 node.accept(typeAnalyzer); 7075 node.accept(typeAnalyzer);
11357 return null; 7076 return null;
11358 } 7077 }
11359 7078
11360 @override 7079 @override
11361 Object visitSwitchCase(SwitchCase node) { 7080 Object visitSwitchCase(SwitchCase node) {
11362 _overrideManager.enterScope(); 7081 _overrideManager.enterScope();
11363 try { 7082 try {
11364 super.visitSwitchCase(node); 7083 super.visitSwitchCase(node);
(...skipping 26 matching lines...) Expand all
11391 _overrideManager.applyOverrides(overrides); 7110 _overrideManager.applyOverrides(overrides);
11392 } 7111 }
11393 return null; 7112 return null;
11394 } 7113 }
11395 7114
11396 @override 7115 @override
11397 Object visitTypeName(TypeName node) => null; 7116 Object visitTypeName(TypeName node) => null;
11398 7117
11399 @override 7118 @override
11400 Object visitVariableDeclaration(VariableDeclaration node) { 7119 Object visitVariableDeclaration(VariableDeclaration node) {
7120 InferenceContext.setTypeFromNode(node.initializer, node);
11401 super.visitVariableDeclaration(node); 7121 super.visitVariableDeclaration(node);
11402 VariableElement element = node.element; 7122 VariableElement element = node.element;
11403 if (element.initializer != null && node.initializer != null) { 7123 if (element.initializer != null && node.initializer != null) {
11404 (element.initializer as FunctionElementImpl).returnType = 7124 (element.initializer as FunctionElementImpl).returnType =
11405 node.initializer.staticType; 7125 node.initializer.staticType;
11406 } 7126 }
11407 // Note: in addition to cloning the initializers for const variables, we 7127 // Note: in addition to cloning the initializers for const variables, we
11408 // have to clone the initializers for non-static final fields (because if 7128 // have to clone the initializers for non-static final fields (because if
11409 // they occur in a class with a const constructor, they will be needed to 7129 // they occur in a class with a const constructor, they will be needed to
11410 // evaluate the const constructor). 7130 // evaluate the const constructor).
11411 if ((element.isConst || 7131 if ((element.isConst ||
11412 (element is FieldElement && 7132 (element is FieldElement &&
11413 element.isFinal && 7133 element.isFinal &&
11414 !element.isStatic)) && 7134 !element.isStatic)) &&
11415 node.initializer != null) { 7135 node.initializer != null) {
11416 (element as ConstVariableElement).constantInitializer = 7136 (element as ConstVariableElement).constantInitializer =
11417 new ConstantAstCloner().cloneNode(node.initializer); 7137 new ConstantAstCloner().cloneNode(node.initializer);
11418 } 7138 }
11419 return null; 7139 return null;
11420 } 7140 }
11421 7141
11422 @override 7142 @override
7143 visitVariableDeclarationList(VariableDeclarationList node) {
7144 for (VariableDeclaration decl in node.variables) {
7145 InferenceContext.setType(decl, decl.element?.type);
7146 }
7147 super.visitVariableDeclarationList(node);
7148 }
7149
7150 @override
11423 Object visitWhileStatement(WhileStatement node) { 7151 Object visitWhileStatement(WhileStatement node) {
11424 // Note: since we don't call the base class, we have to maintain 7152 // Note: since we don't call the base class, we have to maintain
11425 // _implicitLabelScope ourselves. 7153 // _implicitLabelScope ourselves.
11426 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; 7154 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
11427 try { 7155 try {
11428 _implicitLabelScope = _implicitLabelScope.nest(node); 7156 _implicitLabelScope = _implicitLabelScope.nest(node);
11429 Expression condition = node.condition; 7157 Expression condition = node.condition;
11430 safelyVisit(condition); 7158 condition?.accept(this);
11431 Statement body = node.body; 7159 Statement body = node.body;
11432 if (body != null) { 7160 if (body != null) {
11433 _overrideManager.enterScope(); 7161 _overrideManager.enterScope();
11434 try { 7162 try {
11435 _propagateTrueState(condition); 7163 _propagateTrueState(condition);
11436 visitStatementInScope(body); 7164 visitStatementInScope(body);
11437 } finally { 7165 } finally {
11438 _overrideManager.exitScope(); 7166 _overrideManager.exitScope();
11439 } 7167 }
11440 } 7168 }
11441 } finally { 7169 } finally {
11442 _implicitLabelScope = outerImplicitScope; 7170 _implicitLabelScope = outerImplicitScope;
11443 } 7171 }
11444 // TODO(brianwilkerson) If the loop can only be exited because the condition 7172 // TODO(brianwilkerson) If the loop can only be exited because the condition
11445 // is false, then propagateFalseState(condition); 7173 // is false, then propagateFalseState(condition);
11446 node.accept(elementResolver); 7174 node.accept(elementResolver);
11447 node.accept(typeAnalyzer); 7175 node.accept(typeAnalyzer);
11448 return null; 7176 return null;
11449 } 7177 }
11450 7178
7179 @override
7180 Object visitYieldStatement(YieldStatement node) {
7181 Expression e = node.expression;
7182 DartType returnType = inferenceContext.returnContext;
7183 bool isGenerator = _enclosingFunction?.isGenerator ?? false;
7184 if (returnType != null && isGenerator) {
7185 // If we're not in a generator ([a]sync*, then we shouldn't have a yield.
7186 // so don't infer
7187
7188 // If this just a yield, then we just pass on the element type
7189 DartType type = returnType;
7190 if (node.star != null) {
7191 // If this is a yield*, then we wrap the element return type
7192 // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
7193 InterfaceType wrapperType = _enclosingFunction.isSynchronous
7194 ? typeProvider.iterableType
7195 : typeProvider.streamType;
7196 type = wrapperType.instantiate(<DartType>[type]);
7197 }
7198 InferenceContext.setType(e, type);
7199 }
7200 super.visitYieldStatement(node);
7201 DartType type = e?.staticType;
7202 if (type != null && isGenerator) {
7203 // If this just a yield, then we just pass on the element type
7204 if (node.star != null) {
7205 // If this is a yield*, then we unwrap the element return type
7206 // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
7207 InterfaceType wrapperType = _enclosingFunction.isSynchronous
7208 ? typeProvider.iterableType
7209 : typeProvider.streamType;
7210 type = typeSystem.mostSpecificTypeArgument(type, wrapperType);
7211 }
7212 if (type != null) {
7213 inferenceContext.addReturnOrYieldType(type);
7214 }
7215 }
7216 return null;
7217 }
7218
11451 /** 7219 /**
11452 * Checks each promoted variable in the current scope for compliance with the following 7220 * Checks each promoted variable in the current scope for compliance with the following
11453 * specification statement: 7221 * specification statement:
11454 * 7222 *
11455 * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> t hen the variable 7223 * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> t hen the variable
11456 * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>. 7224 * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>.
11457 */ 7225 */
11458 void _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( 7226 void _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
11459 AstNode target) { 7227 AstNode target) {
11460 for (Element element in _promoteManager.promotedElements) { 7228 for (Element element in _promoteManager.promotedElements) {
11461 if ((element as VariableElementImpl).isPotentiallyMutatedInScope) { 7229 if (_currentFunctionBody.isPotentiallyMutatedInScope(element)) {
11462 if (_isVariableAccessedInClosure(element, target)) { 7230 if (_isVariableAccessedInClosure(element, target)) {
11463 _promoteManager.setType(element, null); 7231 _promoteManager.setType(element, null);
11464 } 7232 }
11465 } 7233 }
11466 } 7234 }
11467 } 7235 }
11468 7236
11469 /** 7237 /**
11470 * Checks each promoted variable in the current scope for compliance with the following 7238 * Checks each promoted variable in the current scope for compliance with the following
11471 * specification statement: 7239 * specification statement:
11472 * 7240 *
11473 * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a clo sure. 7241 * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a clo sure.
11474 */ 7242 */
11475 void _clearTypePromotionsIfPotentiallyMutatedIn(AstNode target) { 7243 void _clearTypePromotionsIfPotentiallyMutatedIn(AstNode target) {
11476 for (Element element in _promoteManager.promotedElements) { 7244 for (Element element in _promoteManager.promotedElements) {
11477 if (_isVariablePotentiallyMutatedIn(element, target)) { 7245 if (_isVariablePotentiallyMutatedIn(element, target)) {
11478 _promoteManager.setType(element, null); 7246 _promoteManager.setType(element, null);
11479 } 7247 }
11480 } 7248 }
11481 } 7249 }
11482 7250
11483 /** 7251 /**
7252 * Given the declared return type of a function, compute the type of the
7253 * values which should be returned or yielded as appropriate. If a type
7254 * cannot be computed from the declared return type, return null.
7255 */
7256 DartType _computeReturnOrYieldType(DartType declaredType) {
7257 bool isGenerator = _enclosingFunction.isGenerator;
7258 bool isAsynchronous = _enclosingFunction.isAsynchronous;
7259
7260 // Ordinary functions just return their declared types.
7261 if (!isGenerator && !isAsynchronous) {
7262 return declaredType;
7263 }
7264 if (declaredType is InterfaceType) {
7265 if (isGenerator) {
7266 // If it's sync* we expect Iterable<T>
7267 // If it's async* we expect Stream<T>
7268 InterfaceType rawType = isAsynchronous
7269 ? typeProvider.streamDynamicType
7270 : typeProvider.iterableDynamicType;
7271 // Match the types to instantiate the type arguments if possible
7272 List<DartType> typeArgs =
7273 inferenceContext.matchTypes(rawType, declaredType);
7274 return (typeArgs?.length == 1) ? typeArgs[0] : null;
7275 }
7276 // async functions expect `Future<T> | T`
7277 var futureTypeParam = declaredType.flattenFutures(typeSystem);
7278 return FutureUnionType.from(futureTypeParam, typeProvider, typeSystem);
7279 }
7280 return declaredType;
7281 }
7282
7283 /**
11484 * The given expression is the expression used to compute the iterator for a 7284 * The given expression is the expression used to compute the iterator for a
11485 * for-each statement. Attempt to compute the type of objects that will be 7285 * for-each statement. Attempt to compute the type of objects that will be
11486 * assigned to the loop variable and return that type. Return `null` if the 7286 * assigned to the loop variable and return that type. Return `null` if the
11487 * type could not be determined. The [iteratorExpression] is the expression 7287 * type could not be determined. The [iteratorExpression] is the expression
11488 * that will return the Iterable being iterated over. 7288 * that will return the Iterable being iterated over.
11489 */ 7289 */
11490 DartType _getIteratorElementType(Expression iteratorExpression) { 7290 DartType _getIteratorElementType(Expression iteratorExpression) {
11491 DartType expressionType = iteratorExpression.bestType; 7291 DartType expressionType = iteratorExpression.bestType;
11492 if (expressionType is InterfaceType) { 7292 if (expressionType is InterfaceType) {
11493 InterfaceType interfaceType = expressionType; 7293 PropertyAccessorElement iteratorFunction =
11494 FunctionType iteratorFunction = 7294 expressionType.lookUpInheritedGetter("iterator");
11495 _inheritanceManager.lookupMemberType(interfaceType, "iterator");
11496 if (iteratorFunction == null) { 7295 if (iteratorFunction == null) {
11497 // TODO(brianwilkerson) Should we report this error? 7296 // TODO(brianwilkerson) Should we report this error?
11498 return null; 7297 return null;
11499 } 7298 }
11500 DartType iteratorType = iteratorFunction.returnType; 7299 DartType iteratorType = iteratorFunction.returnType;
11501 if (iteratorType is InterfaceType) { 7300 if (iteratorType is InterfaceType) {
11502 InterfaceType iteratorInterfaceType = iteratorType; 7301 PropertyAccessorElement currentFunction =
11503 FunctionType currentFunction = _inheritanceManager.lookupMemberType( 7302 iteratorType.lookUpInheritedGetter("current");
11504 iteratorInterfaceType, "current");
11505 if (currentFunction == null) { 7303 if (currentFunction == null) {
11506 // TODO(brianwilkerson) Should we report this error? 7304 // TODO(brianwilkerson) Should we report this error?
11507 return null; 7305 return null;
11508 } 7306 }
11509 return currentFunction.returnType; 7307 return currentFunction.returnType;
11510 } 7308 }
11511 } 7309 }
11512 return null; 7310 return null;
11513 } 7311 }
11514 7312
11515 /** 7313 /**
11516 * The given expression is the expression used to compute the stream for an 7314 * The given expression is the expression used to compute the stream for an
11517 * asyncronous for-each statement. Attempt to compute the type of objects that 7315 * asynchronous for-each statement. Attempt to compute the type of objects
11518 * will be assigned to the loop variable and return that type. Return `null` 7316 * that will be assigned to the loop variable and return that type.
11519 * if the type could not be determined. The [streamExpression] is the 7317 * Return `null` if the type could not be determined. The [streamExpression]
11520 * expression that will return the stream being iterated over. 7318 * is the expression that will return the stream being iterated over.
11521 */ 7319 */
11522 DartType _getStreamElementType(Expression streamExpression) { 7320 DartType _getStreamElementType(Expression streamExpression) {
11523 DartType streamType = streamExpression.bestType; 7321 DartType streamType = streamExpression.bestType;
11524 if (streamType is InterfaceType) { 7322 if (streamType is InterfaceType) {
11525 FunctionType listenFunction = 7323 MethodElement listenFunction = streamType.lookUpInheritedMethod("listen");
11526 _inheritanceManager.lookupMemberType(streamType, "listen");
11527 if (listenFunction == null) { 7324 if (listenFunction == null) {
11528 return null; 7325 return null;
11529 } 7326 }
11530 List<ParameterElement> listenParameters = listenFunction.parameters; 7327 List<ParameterElement> listenParameters = listenFunction.parameters;
11531 if (listenParameters == null || listenParameters.length < 1) { 7328 if (listenParameters == null || listenParameters.length < 1) {
11532 return null; 7329 return null;
11533 } 7330 }
11534 DartType onDataType = listenParameters[0].type; 7331 DartType onDataType = listenParameters[0].type;
11535 if (onDataType is FunctionType) { 7332 if (onDataType is FunctionType) {
11536 List<ParameterElement> onDataParameters = onDataType.parameters; 7333 List<ParameterElement> onDataParameters = onDataType.parameters;
11537 if (onDataParameters == null || onDataParameters.length < 1) { 7334 if (onDataParameters == null || onDataParameters.isEmpty) {
11538 return null; 7335 return null;
11539 } 7336 }
11540 DartType eventType = onDataParameters[0].type; 7337 return onDataParameters[0].type;
11541 // TODO(paulberry): checking that typeParameters.isNotEmpty is a
11542 // band-aid fix for dartbug.com/24191. Figure out what the correct
11543 // logic should be.
11544 if (streamType.typeParameters.isNotEmpty &&
11545 eventType.element == streamType.typeParameters[0]) {
11546 return streamType.typeArguments[0];
11547 }
11548 } 7338 }
11549 } 7339 }
11550 return null; 7340 return null;
11551 } 7341 }
11552 7342
7343 void _inferArgumentTypesFromContext(InvocationExpression node) {
7344 if (!strongMode) {
7345 // Use propagated type inference for lambdas if not in strong mode.
7346 _inferFunctionExpressionsParametersTypes(node.argumentList);
7347 return;
7348 }
7349
7350 DartType contextType = node.staticInvokeType;
7351 if (contextType is FunctionType) {
7352 DartType originalType = node.function.staticType;
7353 DartType returnContextType = InferenceContext.getContext(node);
7354 TypeSystem ts = typeSystem;
7355 if (returnContextType != null &&
7356 node.typeArguments == null &&
7357 originalType is FunctionType &&
7358 originalType.typeFormals.isNotEmpty &&
7359 ts is StrongTypeSystemImpl) {
7360 contextType = ts.inferGenericFunctionCall(
7361 typeProvider,
7362 originalType,
7363 DartType.EMPTY_LIST,
7364 DartType.EMPTY_LIST,
7365 originalType.returnType,
7366 returnContextType);
7367 }
7368
7369 InferenceContext.setType(node.argumentList, contextType);
7370 }
7371 }
7372
7373 void _inferFormalParameterList(FormalParameterList node, DartType type) {
7374 if (typeAnalyzer.inferFormalParameterList(node, type)) {
7375 // TODO(leafp): This gets dropped on the floor if we're in the field
7376 // inference task. We should probably keep these infos.
7377 //
7378 // TODO(jmesserly): this is reporting the context type, and therefore not
7379 // necessarily the correct inferred type for the lambda.
7380 //
7381 // For example, `([x]) {}` could be passed to `int -> void` but its type
7382 // will really be `([int]) -> void`. Similar issue for named arguments.
7383 // It can also happen if the return type is inferred later on to be
7384 // more precise.
7385 //
7386 // This reporting bug defeats the deduplication of error messages and
7387 // results in the same inference message being reported twice.
7388 //
7389 // To get this right, we'd have to delay reporting until we have the
7390 // complete type including return type.
7391 inferenceContext.recordInference(node.parent, type);
7392 }
7393 }
7394
11553 /** 7395 /**
11554 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its 7396 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
11555 * required type is [FunctionType], then infer parameters types from [Function Type]. 7397 * required type is [FunctionType], then infer parameters types from [Function Type].
11556 */ 7398 */
11557 void _inferFunctionExpressionParametersTypes( 7399 void _inferFunctionExpressionParametersTypes(
11558 Expression mayBeClosure, DartType mayByFunctionType) { 7400 Expression mayBeClosure, DartType mayByFunctionType) {
11559 // prepare closure 7401 // prepare closure
11560 if (mayBeClosure is! FunctionExpression) { 7402 if (mayBeClosure is! FunctionExpression) {
11561 return; 7403 return;
11562 } 7404 }
11563 FunctionExpression closure = mayBeClosure as FunctionExpression; 7405 FunctionExpression closure = mayBeClosure as FunctionExpression;
11564 // prepare expected closure type 7406 // prepare expected closure type
11565 if (mayByFunctionType is! FunctionType) { 7407 if (mayByFunctionType is! FunctionType) {
11566 return; 7408 return;
11567 } 7409 }
11568 FunctionType expectedClosureType = mayByFunctionType as FunctionType; 7410 FunctionType expectedClosureType = mayByFunctionType as FunctionType;
11569 // If the expectedClosureType is not more specific than the static type, 7411 // If the expectedClosureType is not more specific than the static type,
11570 // return. 7412 // return.
11571 DartType staticClosureType = 7413 DartType staticClosureType = closure.element?.type;
11572 closure.element != null ? closure.element.type : null;
11573 if (staticClosureType != null && 7414 if (staticClosureType != null &&
11574 !expectedClosureType.isMoreSpecificThan(staticClosureType)) { 7415 !FunctionTypeImpl.relate(
7416 expectedClosureType,
7417 staticClosureType,
7418 (DartType t, DartType s, _, __) =>
7419 (t as TypeImpl).isMoreSpecificThan(s),
7420 new TypeSystemImpl().instantiateToBounds,
7421 returnRelation: (s, t) => true)) {
11575 return; 7422 return;
11576 } 7423 }
11577 // set propagated type for the closure 7424 // set propagated type for the closure
11578 closure.propagatedType = expectedClosureType; 7425 if (!strongMode) {
7426 closure.propagatedType = expectedClosureType;
7427 }
11579 // set inferred types for parameters 7428 // set inferred types for parameters
11580 NodeList<FormalParameter> parameters = closure.parameters.parameters; 7429 NodeList<FormalParameter> parameters = closure.parameters.parameters;
11581 List<ParameterElement> expectedParameters = expectedClosureType.parameters; 7430 List<ParameterElement> expectedParameters = expectedClosureType.parameters;
11582 for (int i = 0; 7431 for (int i = 0;
11583 i < parameters.length && i < expectedParameters.length; 7432 i < parameters.length && i < expectedParameters.length;
11584 i++) { 7433 i++) {
11585 FormalParameter parameter = parameters[i]; 7434 FormalParameter parameter = parameters[i];
11586 ParameterElement element = parameter.element; 7435 ParameterElement element = parameter.element;
11587 DartType currentType = _overrideManager.getBestType(element); 7436 DartType currentType = _overrideManager.getBestType(element);
11588 // may be override the type 7437 // may be override the type
11589 DartType expectedType = expectedParameters[i].type; 7438 DartType expectedType = expectedParameters[i].type;
11590 if (currentType == null || expectedType.isMoreSpecificThan(currentType)) { 7439 if (currentType == null || expectedType.isMoreSpecificThan(currentType)) {
11591 _overrideManager.setType(element, expectedType); 7440 _overrideManager.setType(element, expectedType);
11592 } 7441 }
11593 } 7442 }
11594 } 7443 }
11595 7444
11596 /** 7445 /**
11597 * Try to infer types of parameters of the [FunctionExpression] arguments. 7446 * Try to infer types of parameters of the [FunctionExpression] arguments.
11598 */ 7447 */
11599 void _inferFunctionExpressionsParametersTypes(ArgumentList argumentList) { 7448 void _inferFunctionExpressionsParametersTypes(ArgumentList argumentList) {
11600 for (Expression argument in argumentList.arguments) { 7449 NodeList<Expression> arguments = argumentList.arguments;
7450 int length = arguments.length;
7451 for (int i = 0; i < length; i++) {
7452 Expression argument = arguments[i];
11601 ParameterElement parameter = argument.propagatedParameterElement; 7453 ParameterElement parameter = argument.propagatedParameterElement;
11602 if (parameter == null) { 7454 if (parameter == null) {
11603 parameter = argument.staticParameterElement; 7455 parameter = argument.staticParameterElement;
11604 } 7456 }
11605 if (parameter != null) { 7457 if (parameter != null) {
11606 _inferFunctionExpressionParametersTypes(argument, parameter.type); 7458 _inferFunctionExpressionParametersTypes(argument, parameter.type);
11607 } 7459 }
11608 } 7460 }
11609 } 7461 }
11610 7462
11611 /** 7463 /**
11612 * Return `true` if the given expression terminates abruptly (that is, if any expression 7464 * Return `true` if the given expression terminates abruptly (that is, if any expression
11613 * following the given expression will not be reached). 7465 * following the given expression will not be reached).
11614 * 7466 *
11615 * @param expression the expression being tested 7467 * @param expression the expression being tested
11616 * @return `true` if the given expression terminates abruptly 7468 * @return `true` if the given expression terminates abruptly
11617 */ 7469 */
11618 bool _isAbruptTerminationExpression(Expression expression) { 7470 bool _isAbruptTerminationExpression(Expression expression) {
11619 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we 7471 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we
11620 // would eventually turn this into a method on Expression that returns a 7472 // would eventually turn this into a method on Expression that returns a
11621 // termination indication (normal, abrupt with no exception, abrupt with an 7473 // termination indication (normal, abrupt with no exception, abrupt with an
11622 // exception). 7474 // exception).
11623 while (expression is ParenthesizedExpression) { 7475 expression = expression?.unParenthesized;
11624 expression = (expression as ParenthesizedExpression).expression;
11625 }
11626 return expression is ThrowExpression || expression is RethrowExpression; 7476 return expression is ThrowExpression || expression is RethrowExpression;
11627 } 7477 }
11628 7478
11629 /** 7479 /**
11630 * Return `true` if the given statement terminates abruptly (that is, if any s tatement 7480 * Return `true` if the given statement terminates abruptly (that is, if any s tatement
11631 * following the given statement will not be reached). 7481 * following the given statement will not be reached).
11632 * 7482 *
11633 * @param statement the statement being tested 7483 * @param statement the statement being tested
11634 * @return `true` if the given statement terminates abruptly 7484 * @return `true` if the given statement terminates abruptly
11635 */ 7485 */
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
11716 * type is more specific than the current type. 7566 * type is more specific than the current type.
11717 * 7567 *
11718 * @param expression the expression used to access the static element whose ty pes might be 7568 * @param expression the expression used to access the static element whose ty pes might be
11719 * promoted 7569 * promoted
11720 * @param potentialType the potential type of the elements 7570 * @param potentialType the potential type of the elements
11721 */ 7571 */
11722 void _promote(Expression expression, DartType potentialType) { 7572 void _promote(Expression expression, DartType potentialType) {
11723 VariableElement element = getPromotionStaticElement(expression); 7573 VariableElement element = getPromotionStaticElement(expression);
11724 if (element != null) { 7574 if (element != null) {
11725 // may be mutated somewhere in closure 7575 // may be mutated somewhere in closure
11726 if (element.isPotentiallyMutatedInClosure) { 7576 if (_currentFunctionBody.isPotentiallyMutatedInClosure(element)) {
11727 return; 7577 return;
11728 } 7578 }
11729 // prepare current variable type 7579 // prepare current variable type
11730 DartType type = _promoteManager.getType(element); 7580 DartType type = _promoteManager.getType(element) ??
11731 if (type == null) { 7581 expression.staticType ??
11732 type = expression.staticType; 7582 DynamicTypeImpl.instance;
7583
7584 potentialType ??= DynamicTypeImpl.instance;
7585
7586 // Check if we can promote to potentialType from type.
7587 if (typeSystem.canPromoteToType(potentialType, type)) {
7588 // Do promote type of variable.
7589 _promoteManager.setType(element, potentialType);
11733 } 7590 }
11734 // Declared type should not be "dynamic".
11735 if (type == null || type.isDynamic) {
11736 return;
11737 }
11738 // Promoted type should not be "dynamic".
11739 if (potentialType == null || potentialType.isDynamic) {
11740 return;
11741 }
11742 // Promoted type should be more specific than declared.
11743 if (!potentialType.isMoreSpecificThan(type)) {
11744 return;
11745 }
11746 // Do promote type of variable.
11747 _promoteManager.setType(element, potentialType);
11748 } 7591 }
11749 } 7592 }
11750 7593
11751 /** 7594 /**
11752 * Promotes type information using given condition. 7595 * Promotes type information using given condition.
11753 */ 7596 */
11754 void _promoteTypes(Expression condition) { 7597 void _promoteTypes(Expression condition) {
11755 if (condition is BinaryExpression) { 7598 if (condition is BinaryExpression) {
11756 BinaryExpression binary = condition; 7599 if (condition.operator.type == TokenType.AMPERSAND_AMPERSAND) {
11757 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) { 7600 Expression left = condition.leftOperand;
11758 Expression left = binary.leftOperand; 7601 Expression right = condition.rightOperand;
11759 Expression right = binary.rightOperand;
11760 _promoteTypes(left); 7602 _promoteTypes(left);
11761 _promoteTypes(right); 7603 _promoteTypes(right);
11762 _clearTypePromotionsIfPotentiallyMutatedIn(right); 7604 _clearTypePromotionsIfPotentiallyMutatedIn(right);
11763 } 7605 }
11764 } else if (condition is IsExpression) { 7606 } else if (condition is IsExpression) {
11765 IsExpression is2 = condition; 7607 if (condition.notOperator == null) {
11766 if (is2.notOperator == null) { 7608 _promote(condition.expression, condition.type.type);
11767 _promote(is2.expression, is2.type.type);
11768 } 7609 }
11769 } else if (condition is ParenthesizedExpression) { 7610 } else if (condition is ParenthesizedExpression) {
11770 _promoteTypes(condition.expression); 7611 _promoteTypes(condition.expression);
11771 } 7612 }
11772 } 7613 }
11773 7614
11774 /** 7615 /**
11775 * Propagate any type information that results from knowing that the given con dition will have 7616 * Propagate any type information that results from knowing that the given con dition will have
11776 * been evaluated to 'false'. 7617 * been evaluated to 'false'.
11777 * 7618 *
11778 * @param condition the condition that will have evaluated to 'false' 7619 * @param condition the condition that will have evaluated to 'false'
11779 */ 7620 */
11780 void _propagateFalseState(Expression condition) { 7621 void _propagateFalseState(Expression condition) {
11781 if (condition is BinaryExpression) { 7622 if (condition is BinaryExpression) {
11782 BinaryExpression binary = condition; 7623 if (condition.operator.type == TokenType.BAR_BAR) {
11783 if (binary.operator.type == sc.TokenType.BAR_BAR) { 7624 _propagateFalseState(condition.leftOperand);
11784 _propagateFalseState(binary.leftOperand); 7625 _propagateFalseState(condition.rightOperand);
11785 _propagateFalseState(binary.rightOperand);
11786 } 7626 }
11787 } else if (condition is IsExpression) { 7627 } else if (condition is IsExpression) {
11788 IsExpression is2 = condition; 7628 if (condition.notOperator != null) {
11789 if (is2.notOperator != null) {
11790 // Since an is-statement doesn't actually change the type, we don't 7629 // Since an is-statement doesn't actually change the type, we don't
11791 // let it affect the propagated type when it would result in a loss 7630 // let it affect the propagated type when it would result in a loss
11792 // of precision. 7631 // of precision.
11793 overrideExpression(is2.expression, is2.type.type, false, false); 7632 overrideExpression(
7633 condition.expression, condition.type.type, false, false);
11794 } 7634 }
11795 } else if (condition is PrefixExpression) { 7635 } else if (condition is PrefixExpression) {
11796 PrefixExpression prefix = condition; 7636 if (condition.operator.type == TokenType.BANG) {
11797 if (prefix.operator.type == sc.TokenType.BANG) { 7637 _propagateTrueState(condition.operand);
11798 _propagateTrueState(prefix.operand);
11799 } 7638 }
11800 } else if (condition is ParenthesizedExpression) { 7639 } else if (condition is ParenthesizedExpression) {
11801 _propagateFalseState(condition.expression); 7640 _propagateFalseState(condition.expression);
11802 } 7641 }
11803 } 7642 }
11804 7643
11805 /** 7644 /**
11806 * Propagate any type information that results from knowing that the given exp ression will have 7645 * Propagate any type information that results from knowing that the given exp ression will have
11807 * been evaluated without altering the flow of execution. 7646 * been evaluated without altering the flow of execution.
11808 * 7647 *
11809 * @param expression the expression that will have been evaluated 7648 * @param expression the expression that will have been evaluated
11810 */ 7649 */
11811 void _propagateState(Expression expression) { 7650 void _propagateState(Expression expression) {
11812 // TODO(brianwilkerson) Implement this. 7651 // TODO(brianwilkerson) Implement this.
11813 } 7652 }
11814 7653
11815 /** 7654 /**
11816 * Propagate any type information that results from knowing that the given con dition will have 7655 * Propagate any type information that results from knowing that the given con dition will have
11817 * been evaluated to 'true'. 7656 * been evaluated to 'true'.
11818 * 7657 *
11819 * @param condition the condition that will have evaluated to 'true' 7658 * @param condition the condition that will have evaluated to 'true'
11820 */ 7659 */
11821 void _propagateTrueState(Expression condition) { 7660 void _propagateTrueState(Expression condition) {
11822 if (condition is BinaryExpression) { 7661 if (condition is BinaryExpression) {
11823 BinaryExpression binary = condition; 7662 if (condition.operator.type == TokenType.AMPERSAND_AMPERSAND) {
11824 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) { 7663 _propagateTrueState(condition.leftOperand);
11825 _propagateTrueState(binary.leftOperand); 7664 _propagateTrueState(condition.rightOperand);
11826 _propagateTrueState(binary.rightOperand);
11827 } 7665 }
11828 } else if (condition is IsExpression) { 7666 } else if (condition is IsExpression) {
11829 IsExpression is2 = condition; 7667 if (condition.notOperator == null) {
11830 if (is2.notOperator == null) {
11831 // Since an is-statement doesn't actually change the type, we don't 7668 // Since an is-statement doesn't actually change the type, we don't
11832 // let it affect the propagated type when it would result in a loss 7669 // let it affect the propagated type when it would result in a loss
11833 // of precision. 7670 // of precision.
11834 overrideExpression(is2.expression, is2.type.type, false, false); 7671 overrideExpression(
7672 condition.expression, condition.type.type, false, false);
11835 } 7673 }
11836 } else if (condition is PrefixExpression) { 7674 } else if (condition is PrefixExpression) {
11837 PrefixExpression prefix = condition; 7675 if (condition.operator.type == TokenType.BANG) {
11838 if (prefix.operator.type == sc.TokenType.BANG) { 7676 _propagateFalseState(condition.operand);
11839 _propagateFalseState(prefix.operand);
11840 } 7677 }
11841 } else if (condition is ParenthesizedExpression) { 7678 } else if (condition is ParenthesizedExpression) {
11842 _propagateTrueState(condition.expression); 7679 _propagateTrueState(condition.expression);
11843 } 7680 }
11844 } 7681 }
11845 }
11846
11847 /**
11848 * The abstract class `Scope` defines the behavior common to name scopes used by the resolver
11849 * to determine which names are visible at any given point in the code.
11850 */
11851 abstract class Scope {
11852 /**
11853 * The prefix used to mark an identifier as being private to its library.
11854 */
11855 static int PRIVATE_NAME_PREFIX = 0x5F;
11856 7682
11857 /** 7683 /**
11858 * The suffix added to the declared name of a setter when looking up the sette r. Used to 7684 * Given an [argumentList] and the [parameters] related to the element that
11859 * disambiguate between a getter and a setter that have the same name. 7685 * will be invoked using those arguments, compute the list of parameters that
7686 * correspond to the list of arguments.
7687 *
7688 * An error will be reported to [onError] if any of the arguments cannot be
7689 * matched to a parameter. onError can be null to ignore the error.
7690 *
7691 * The flag [reportAsError] should be `true` if a compile-time error should be
7692 * reported; or `false` if a compile-time warning should be reported.
7693 *
7694 * Returns the parameters that correspond to the arguments. If no parameter
7695 * matched an argument, that position will be `null` in the list.
11860 */ 7696 */
11861 static String SETTER_SUFFIX = "="; 7697 static List<ParameterElement> resolveArgumentsToParameters(
11862 7698 ArgumentList argumentList,
11863 /** 7699 List<ParameterElement> parameters,
11864 * The name used to look up the method used to implement the unary minus opera tor. Used to 7700 void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
11865 * disambiguate between the unary and binary operators. 7701 {bool reportAsError: false}) {
11866 */ 7702 if (parameters.isEmpty && argumentList.arguments.isEmpty) {
11867 static String UNARY_MINUS = "unary-"; 7703 return const <ParameterElement>[];
11868 7704 }
11869 /** 7705 int requiredParameterCount = 0;
11870 * A table mapping names that are defined in this scope to the element represe nting the thing 7706 int unnamedParameterCount = 0;
11871 * declared with that name. 7707 List<ParameterElement> unnamedParameters = new List<ParameterElement>();
11872 */ 7708 HashMap<String, ParameterElement> namedParameters = null;
11873 HashMap<String, Element> _definedNames = new HashMap<String, Element>(); 7709 int length = parameters.length;
11874 7710 for (int i = 0; i < length; i++) {
11875 /** 7711 ParameterElement parameter = parameters[i];
11876 * A flag indicating whether there are any names defined in this scope. 7712 ParameterKind kind = parameter.parameterKind;
11877 */ 7713 if (kind == ParameterKind.REQUIRED) {
11878 bool _hasName = false; 7714 unnamedParameters.add(parameter);
11879 7715 unnamedParameterCount++;
11880 /** 7716 requiredParameterCount++;
11881 * Return the scope in which this scope is lexically enclosed. 7717 } else if (kind == ParameterKind.POSITIONAL) {
11882 * 7718 unnamedParameters.add(parameter);
11883 * @return the scope in which this scope is lexically enclosed 7719 unnamedParameterCount++;
11884 */
11885 Scope get enclosingScope => null;
11886
11887 /**
11888 * Return the listener that is to be informed when an error is encountered.
11889 *
11890 * @return the listener that is to be informed when an error is encountered
11891 */
11892 AnalysisErrorListener get errorListener;
11893
11894 /**
11895 * Add the given element to this scope. If there is already an element with th e given name defined
11896 * in this scope, then an error will be generated and the original element wil l continue to be
11897 * mapped to the name. If there is an element with the given name in an enclos ing scope, then a
11898 * warning will be generated but the given element will hide the inherited ele ment.
11899 *
11900 * @param element the element to be added to this scope
11901 */
11902 void define(Element element) {
11903 String name = _getName(element);
11904 if (name != null && !name.isEmpty) {
11905 if (_definedNames.containsKey(name)) {
11906 errorListener
11907 .onError(getErrorForDuplicate(_definedNames[name], element));
11908 } else { 7720 } else {
11909 _definedNames[name] = element; 7721 namedParameters ??= new HashMap<String, ParameterElement>();
11910 _hasName = true; 7722 namedParameters[parameter.name] = parameter;
11911 } 7723 }
11912 } 7724 }
11913 } 7725 int unnamedIndex = 0;
11914 7726 NodeList<Expression> arguments = argumentList.arguments;
11915 /** 7727 int argumentCount = arguments.length;
11916 * Add the given element to this scope without checking for duplication or hid ing. 7728 List<ParameterElement> resolvedParameters =
11917 * 7729 new List<ParameterElement>(argumentCount);
11918 * @param name the name of the element to be added 7730 int positionalArgumentCount = 0;
11919 * @param element the element to be added to this scope 7731 HashSet<String> usedNames = null;
11920 */ 7732 bool noBlankArguments = true;
11921 void defineNameWithoutChecking(String name, Element element) { 7733 for (int i = 0; i < argumentCount; i++) {
11922 _definedNames[name] = element; 7734 Expression argument = arguments[i];
11923 _hasName = true; 7735 if (argument is NamedExpression) {
11924 } 7736 SimpleIdentifier nameNode = argument.name.label;
11925 7737 String name = nameNode.name;
11926 /** 7738 ParameterElement element =
11927 * Add the given element to this scope without checking for duplication or hid ing. 7739 namedParameters != null ? namedParameters[name] : null;
11928 * 7740 if (element == null) {
11929 * @param element the element to be added to this scope 7741 ErrorCode errorCode = (reportAsError
11930 */ 7742 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
11931 void defineWithoutChecking(Element element) { 7743 : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
11932 _definedNames[_getName(element)] = element; 7744 if (onError != null) {
11933 _hasName = true; 7745 onError(errorCode, nameNode, [name]);
11934 } 7746 }
11935 7747 } else {
11936 /** 7748 resolvedParameters[i] = element;
11937 * Return the error code to be used when reporting that a name being defined l ocally conflicts 7749 nameNode.staticElement = element;
11938 * with another element of the same name in the local scope. 7750 }
11939 * 7751 usedNames ??= new HashSet<String>();
11940 * @param existing the first element to be declared with the conflicting name 7752 if (!usedNames.add(name)) {
11941 * @param duplicate another element declared with the conflicting name 7753 if (onError != null) {
11942 * @return the error code used to report duplicate names within a scope 7754 onError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode,
11943 */ 7755 [name]);
11944 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { 7756 }
11945 // TODO(brianwilkerson) Customize the error message based on the types of 7757 }
11946 // elements that share the same name. 7758 } else {
11947 // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being 7759 if (argument is SimpleIdentifier && argument.name.isEmpty) {
11948 // generated. 7760 noBlankArguments = false;
11949 Source source = duplicate.source; 7761 }
11950 return new AnalysisError(source, duplicate.nameOffset, duplicate.nameLength, 7762 positionalArgumentCount++;
11951 CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]); 7763 if (unnamedIndex < unnamedParameterCount) {
11952 } 7764 resolvedParameters[i] = unnamedParameters[unnamedIndex++];
11953 7765 }
11954 /**
11955 * Return the source that contains the given identifier, or the source associa ted with this scope
11956 * if the source containing the identifier could not be determined.
11957 *
11958 * @param identifier the identifier whose source is to be returned
11959 * @return the source that contains the given identifier
11960 */
11961 Source getSource(AstNode node) {
11962 CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit);
11963 if (unit != null) {
11964 CompilationUnitElement unitElement = unit.element;
11965 if (unitElement != null) {
11966 return unitElement.source;
11967 } 7766 }
11968 } 7767 }
11969 return null; 7768 if (positionalArgumentCount < requiredParameterCount && noBlankArguments) {
11970 } 7769 ErrorCode errorCode = (reportAsError
11971 7770 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
11972 /** 7771 : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
11973 * Return the element with which the given name is associated, or `null` if th e name is not 7772 if (onError != null) {
11974 * defined within this scope. 7773 onError(errorCode, argumentList,
11975 * 7774 [requiredParameterCount, positionalArgumentCount]);
11976 * @param identifier the identifier node to lookup element for, used to report correct kind of a 7775 }
11977 * problem and associate problem with 7776 } else if (positionalArgumentCount > unnamedParameterCount &&
11978 * @param name the name associated with the element to be returned 7777 noBlankArguments) {
11979 * @param referencingLibrary the library that contains the reference to the na me, used to 7778 ErrorCode errorCode = (reportAsError
11980 * implement library-level privacy 7779 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
11981 * @return the element with which the given name is associated 7780 : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
11982 */ 7781 if (onError != null) {
11983 Element internalLookup( 7782 onError(errorCode, argumentList,
11984 Identifier identifier, String name, LibraryElement referencingLibrary); 7783 [unnamedParameterCount, positionalArgumentCount]);
11985
11986 /**
11987 * Return the element with which the given name is associated, or `null` if th e name is not
11988 * defined within this scope. This method only returns elements that are direc tly defined within
11989 * this scope, not elements that are defined in an enclosing scope.
11990 *
11991 * @param name the name associated with the element to be returned
11992 * @param referencingLibrary the library that contains the reference to the na me, used to
11993 * implement library-level privacy
11994 * @return the element with which the given name is associated
11995 */
11996 Element localLookup(String name, LibraryElement referencingLibrary) {
11997 if (_hasName) {
11998 return _definedNames[name];
11999 }
12000 return null;
12001 }
12002
12003 /**
12004 * Return the element with which the given identifier is associated, or `null` if the name
12005 * is not defined within this scope.
12006 *
12007 * @param identifier the identifier associated with the element to be returned
12008 * @param referencingLibrary the library that contains the reference to the na me, used to
12009 * implement library-level privacy
12010 * @return the element with which the given identifier is associated
12011 */
12012 Element lookup(Identifier identifier, LibraryElement referencingLibrary) =>
12013 internalLookup(identifier, identifier.name, referencingLibrary);
12014
12015 /**
12016 * Return the name that will be used to look up the given element.
12017 *
12018 * @param element the element whose look-up name is to be returned
12019 * @return the name that will be used to look up the given element
12020 */
12021 String _getName(Element element) {
12022 if (element is MethodElement) {
12023 MethodElement method = element;
12024 if (method.name == "-" && method.parameters.length == 0) {
12025 return UNARY_MINUS;
12026 } 7784 }
12027 } 7785 }
12028 return element.name; 7786 return resolvedParameters;
12029 } 7787 }
12030
12031 /**
12032 * Return `true` if the given name is a library-private name.
12033 *
12034 * @param name the name being tested
12035 * @return `true` if the given name is a library-private name
12036 */
12037 static bool isPrivateName(String name) =>
12038 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX);
12039 } 7788 }
12040 7789
12041 /** 7790 /**
12042 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST structure is 7791 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST structure is
12043 * being visited. 7792 * being visited.
7793 */
7794 /**
7795 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST structure is
7796 * being visited.
12044 */ 7797 */
12045 abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { 7798 abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
12046 /** 7799 /**
12047 * The element for the library containing the compilation unit being visited. 7800 * The element for the library containing the compilation unit being visited.
12048 */ 7801 */
12049 final LibraryElement definingLibrary; 7802 final LibraryElement definingLibrary;
12050 7803
12051 /** 7804 /**
12052 * The source representing the compilation unit being visited. 7805 * The source representing the compilation unit being visited.
12053 */ 7806 */
12054 final Source source; 7807 final Source source;
12055 7808
12056 /** 7809 /**
12057 * The error listener that will be informed of any errors that are found durin g resolution. 7810 * The object used to access the types from the core library.
12058 */ 7811 */
12059 final AnalysisErrorListener errorListener; 7812 final TypeProvider typeProvider;
7813
7814 /**
7815 * The error reporter that will be informed of any errors that are found
7816 * during resolution.
7817 */
7818 final ErrorReporter errorReporter;
12060 7819
12061 /** 7820 /**
12062 * The scope used to resolve identifiers. 7821 * The scope used to resolve identifiers.
12063 */ 7822 */
12064 Scope nameScope; 7823 Scope nameScope;
12065 7824
12066 /** 7825 /**
12067 * The object used to access the types from the core library.
12068 */
12069 final TypeProvider typeProvider;
12070
12071 /**
12072 * The scope used to resolve unlabeled `break` and `continue` statements. 7826 * The scope used to resolve unlabeled `break` and `continue` statements.
12073 */ 7827 */
12074 ImplicitLabelScope _implicitLabelScope = ImplicitLabelScope.ROOT; 7828 ImplicitLabelScope _implicitLabelScope = ImplicitLabelScope.ROOT;
12075 7829
12076 /** 7830 /**
12077 * The scope used to resolve labels for `break` and `continue` statements, or 7831 * The scope used to resolve labels for `break` and `continue` statements, or
12078 * `null` if no labels have been defined in the current context. 7832 * `null` if no labels have been defined in the current context.
12079 */ 7833 */
12080 LabelScope labelScope; 7834 LabelScope labelScope;
12081 7835
12082 /** 7836 /**
7837 * A flag indicating whether to enable support for allowing access to field
7838 * formal parameters in a constructor's initializer list.
7839 */
7840 bool enableInitializingFormalAccess = false;
7841
7842 /**
12083 * The class containing the AST nodes being visited, 7843 * The class containing the AST nodes being visited,
12084 * or `null` if we are not in the scope of a class. 7844 * or `null` if we are not in the scope of a class.
12085 */ 7845 */
12086 ClassElement enclosingClass; 7846 ClassElement enclosingClass;
12087 7847
12088 /** 7848 /**
12089 * Initialize a newly created visitor to resolve the nodes in a compilation 7849 * Initialize a newly created visitor to resolve the nodes in a compilation
12090 * unit. 7850 * unit.
12091 * 7851 *
12092 * [definingLibrary] is the element for the library containing the 7852 * [definingLibrary] is the element for the library containing the
12093 * compilation unit being visited. 7853 * compilation unit being visited.
12094 * [source] is the source representing the compilation unit being visited. 7854 * [source] is the source representing the compilation unit being visited.
12095 * [typeProvider] is the object used to access the types from the core 7855 * [typeProvider] is the object used to access the types from the core
12096 * library. 7856 * library.
12097 * [errorListener] is the error listener that will be informed of any errors 7857 * [errorListener] is the error listener that will be informed of any errors
12098 * that are found during resolution. 7858 * that are found during resolution.
12099 * [nameScope] is the scope used to resolve identifiers in the node that will 7859 * [nameScope] is the scope used to resolve identifiers in the node that will
12100 * first be visited. If `null` or unspecified, a new [LibraryScope] will be 7860 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
12101 * created based on [definingLibrary] and [typeProvider]. 7861 * created based on [definingLibrary] and [typeProvider].
12102 */ 7862 */
12103 ScopedVisitor( 7863 ScopedVisitor(this.definingLibrary, Source source, this.typeProvider,
12104 this.definingLibrary, this.source, this.typeProvider, this.errorListener, 7864 AnalysisErrorListener errorListener,
12105 {Scope nameScope}) { 7865 {Scope nameScope})
7866 : source = source,
7867 errorReporter = new ErrorReporter(errorListener, source) {
12106 if (nameScope == null) { 7868 if (nameScope == null) {
12107 this.nameScope = new LibraryScope(definingLibrary, errorListener); 7869 this.nameScope = new LibraryScope(definingLibrary);
12108 } else { 7870 } else {
12109 this.nameScope = nameScope; 7871 this.nameScope = nameScope;
12110 } 7872 }
7873 enableInitializingFormalAccess =
7874 definingLibrary.context.analysisOptions.enableInitializingFormalAccess;
12111 } 7875 }
12112 7876
12113 /** 7877 /**
12114 * Return the implicit label scope in which the current node is being 7878 * Return the implicit label scope in which the current node is being
12115 * resolved. 7879 * resolved.
12116 */ 7880 */
12117 ImplicitLabelScope get implicitLabelScope => _implicitLabelScope; 7881 ImplicitLabelScope get implicitLabelScope => _implicitLabelScope;
12118 7882
12119 /** 7883 /**
12120 * Replaces the current [Scope] with the enclosing [Scope]. 7884 * Replaces the current [Scope] with the enclosing [Scope].
12121 * 7885 *
12122 * @return the enclosing [Scope]. 7886 * @return the enclosing [Scope].
12123 */ 7887 */
12124 Scope popNameScope() { 7888 Scope popNameScope() {
12125 nameScope = nameScope.enclosingScope; 7889 nameScope = nameScope.enclosingScope;
12126 return nameScope; 7890 return nameScope;
12127 } 7891 }
12128 7892
12129 /** 7893 /**
12130 * Pushes a new [Scope] into the visitor. 7894 * Pushes a new [Scope] into the visitor.
12131 * 7895 *
12132 * @return the new [Scope]. 7896 * @return the new [Scope].
12133 */ 7897 */
12134 Scope pushNameScope() { 7898 Scope pushNameScope() {
12135 Scope newScope = new EnclosedScope(nameScope); 7899 Scope newScope = new EnclosedScope(nameScope);
12136 nameScope = newScope; 7900 nameScope = newScope;
12137 return nameScope; 7901 return nameScope;
12138 } 7902 }
12139 7903
12140 /**
12141 * Report an error with the given error code and arguments.
12142 *
12143 * @param errorCode the error code of the error to be reported
12144 * @param node the node specifying the location of the error
12145 * @param arguments the arguments to the error, used to compose the error mess age
12146 */
12147 void reportErrorForNode(ErrorCode errorCode, AstNode node,
12148 [List<Object> arguments]) {
12149 errorListener.onError(new AnalysisError(
12150 source, node.offset, node.length, errorCode, arguments));
12151 }
12152
12153 /**
12154 * Report an error with the given error code and arguments.
12155 *
12156 * @param errorCode the error code of the error to be reported
12157 * @param offset the offset of the location of the error
12158 * @param length the length of the location of the error
12159 * @param arguments the arguments to the error, used to compose the error mess age
12160 */
12161 void reportErrorForOffset(ErrorCode errorCode, int offset, int length,
12162 [List<Object> arguments]) {
12163 errorListener.onError(
12164 new AnalysisError(source, offset, length, errorCode, arguments));
12165 }
12166
12167 /**
12168 * Report an error with the given error code and arguments.
12169 *
12170 * @param errorCode the error code of the error to be reported
12171 * @param token the token specifying the location of the error
12172 * @param arguments the arguments to the error, used to compose the error mess age
12173 */
12174 void reportErrorForToken(ErrorCode errorCode, sc.Token token,
12175 [List<Object> arguments]) {
12176 errorListener.onError(new AnalysisError(
12177 source, token.offset, token.length, errorCode, arguments));
12178 }
12179
12180 /**
12181 * Visit the given AST node if it is not null.
12182 *
12183 * @param node the node to be visited
12184 */
12185 void safelyVisit(AstNode node) {
12186 if (node != null) {
12187 node.accept(this);
12188 }
12189 }
12190
12191 @override 7904 @override
12192 Object visitBlock(Block node) { 7905 Object visitBlock(Block node) {
12193 Scope outerScope = nameScope; 7906 Scope outerScope = nameScope;
12194 try { 7907 try {
12195 EnclosedScope enclosedScope = new EnclosedScope(nameScope); 7908 EnclosedScope enclosedScope = new BlockScope(nameScope, node);
12196 _hideNamesDefinedInBlock(enclosedScope, node);
12197 nameScope = enclosedScope; 7909 nameScope = enclosedScope;
12198 super.visitBlock(node); 7910 super.visitBlock(node);
12199 } finally { 7911 } finally {
12200 nameScope = outerScope; 7912 nameScope = outerScope;
12201 } 7913 }
12202 return null; 7914 return null;
12203 } 7915 }
12204 7916
12205 @override 7917 @override
12206 Object visitBlockFunctionBody(BlockFunctionBody node) { 7918 Object visitBlockFunctionBody(BlockFunctionBody node) {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
12258 enclosingClass = outerClass; 7970 enclosingClass = outerClass;
12259 } 7971 }
12260 } 7972 }
12261 } finally { 7973 } finally {
12262 nameScope = outerScope; 7974 nameScope = outerScope;
12263 } 7975 }
12264 return null; 7976 return null;
12265 } 7977 }
12266 7978
12267 void visitClassDeclarationInScope(ClassDeclaration node) { 7979 void visitClassDeclarationInScope(ClassDeclaration node) {
12268 safelyVisit(node.name); 7980 node.name?.accept(this);
12269 safelyVisit(node.typeParameters); 7981 node.typeParameters?.accept(this);
12270 safelyVisit(node.extendsClause); 7982 node.extendsClause?.accept(this);
12271 safelyVisit(node.withClause); 7983 node.withClause?.accept(this);
12272 safelyVisit(node.implementsClause); 7984 node.implementsClause?.accept(this);
12273 safelyVisit(node.nativeClause); 7985 node.nativeClause?.accept(this);
12274 } 7986 }
12275 7987
12276 void visitClassMembersInScope(ClassDeclaration node) { 7988 void visitClassMembersInScope(ClassDeclaration node) {
12277 safelyVisit(node.documentationComment); 7989 node.documentationComment?.accept(this);
12278 node.metadata.accept(this); 7990 node.metadata.accept(this);
12279 node.members.accept(this); 7991 node.members.accept(this);
12280 } 7992 }
12281 7993
12282 @override 7994 @override
12283 Object visitClassTypeAlias(ClassTypeAlias node) { 7995 Object visitClassTypeAlias(ClassTypeAlias node) {
12284 Scope outerScope = nameScope; 7996 Scope outerScope = nameScope;
12285 try { 7997 try {
12286 ClassElement element = node.element; 7998 ClassElement element = node.element;
12287 nameScope = 7999 nameScope =
12288 new ClassScope(new TypeParameterScope(nameScope, element), element); 8000 new ClassScope(new TypeParameterScope(nameScope, element), element);
12289 super.visitClassTypeAlias(node); 8001 super.visitClassTypeAlias(node);
12290 } finally { 8002 } finally {
12291 nameScope = outerScope; 8003 nameScope = outerScope;
12292 } 8004 }
12293 return null; 8005 return null;
12294 } 8006 }
12295 8007
12296 @override 8008 @override
12297 Object visitConstructorDeclaration(ConstructorDeclaration node) { 8009 Object visitConstructorDeclaration(ConstructorDeclaration node) {
12298 ConstructorElement constructorElement = node.element; 8010 ConstructorElement constructorElement = node.element;
8011 if (constructorElement == null) {
8012 StringBuffer buffer = new StringBuffer();
8013 buffer.write("Missing element for constructor ");
8014 buffer.write(node.returnType.name);
8015 if (node.name != null) {
8016 buffer.write(".");
8017 buffer.write(node.name.name);
8018 }
8019 buffer.write(" in ");
8020 buffer.write(definingLibrary.source.fullName);
8021 AnalysisEngine.instance.logger.logInformation(buffer.toString(),
8022 new CaughtException(new AnalysisException(), null));
8023 }
12299 Scope outerScope = nameScope; 8024 Scope outerScope = nameScope;
12300 try { 8025 try {
12301 if (constructorElement == null) { 8026 if (constructorElement != null) {
12302 StringBuffer buffer = new StringBuffer();
12303 buffer.write("Missing element for constructor ");
12304 buffer.write(node.returnType.name);
12305 if (node.name != null) {
12306 buffer.write(".");
12307 buffer.write(node.name.name);
12308 }
12309 buffer.write(" in ");
12310 buffer.write(definingLibrary.source.fullName);
12311 AnalysisEngine.instance.logger.logInformation(buffer.toString(),
12312 new CaughtException(new AnalysisException(), null));
12313 } else {
12314 nameScope = new FunctionScope(nameScope, constructorElement); 8027 nameScope = new FunctionScope(nameScope, constructorElement);
12315 } 8028 }
12316 super.visitConstructorDeclaration(node); 8029 node.documentationComment?.accept(this);
8030 node.metadata.accept(this);
8031 node.returnType?.accept(this);
8032 node.name?.accept(this);
8033 node.parameters?.accept(this);
8034 Scope functionScope = nameScope;
8035 try {
8036 if (constructorElement != null && enableInitializingFormalAccess) {
8037 nameScope =
8038 new ConstructorInitializerScope(nameScope, constructorElement);
8039 }
8040 node.initializers.accept(this);
8041 } finally {
8042 nameScope = functionScope;
8043 }
8044 node.redirectedConstructor?.accept(this);
8045 visitConstructorDeclarationInScope(node);
12317 } finally { 8046 } finally {
12318 nameScope = outerScope; 8047 nameScope = outerScope;
12319 } 8048 }
12320 return null; 8049 return null;
12321 } 8050 }
12322 8051
8052 void visitConstructorDeclarationInScope(ConstructorDeclaration node) {
8053 node.body?.accept(this);
8054 }
8055
12323 @override 8056 @override
12324 Object visitDeclaredIdentifier(DeclaredIdentifier node) { 8057 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
12325 VariableElement element = node.element; 8058 VariableElement element = node.element;
12326 if (element != null) { 8059 if (element != null) {
12327 nameScope.define(element); 8060 nameScope.define(element);
12328 } 8061 }
12329 super.visitDeclaredIdentifier(node); 8062 super.visitDeclaredIdentifier(node);
12330 return null; 8063 return null;
12331 } 8064 }
12332 8065
12333 @override 8066 @override
12334 Object visitDoStatement(DoStatement node) { 8067 Object visitDoStatement(DoStatement node) {
12335 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; 8068 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12336 try { 8069 try {
12337 _implicitLabelScope = _implicitLabelScope.nest(node); 8070 _implicitLabelScope = _implicitLabelScope.nest(node);
12338 visitStatementInScope(node.body); 8071 visitStatementInScope(node.body);
12339 safelyVisit(node.condition); 8072 node.condition?.accept(this);
12340 } finally { 8073 } finally {
12341 _implicitLabelScope = outerImplicitScope; 8074 _implicitLabelScope = outerImplicitScope;
12342 } 8075 }
12343 return null; 8076 return null;
12344 } 8077 }
12345 8078
12346 @override 8079 @override
12347 Object visitEnumDeclaration(EnumDeclaration node) { 8080 Object visitEnumDeclaration(EnumDeclaration node) {
12348 ClassElement classElement = node.element; 8081 ClassElement classElement = node.element;
12349 Scope outerScope = nameScope; 8082 Scope outerScope = nameScope;
(...skipping 13 matching lines...) Expand all
12363 enclosingClass = outerClass; 8096 enclosingClass = outerClass;
12364 } 8097 }
12365 } 8098 }
12366 } finally { 8099 } finally {
12367 nameScope = outerScope; 8100 nameScope = outerScope;
12368 } 8101 }
12369 return null; 8102 return null;
12370 } 8103 }
12371 8104
12372 void visitEnumMembersInScope(EnumDeclaration node) { 8105 void visitEnumMembersInScope(EnumDeclaration node) {
12373 safelyVisit(node.documentationComment); 8106 node.documentationComment?.accept(this);
12374 node.metadata.accept(this); 8107 node.metadata.accept(this);
12375 node.constants.accept(this); 8108 node.constants.accept(this);
12376 } 8109 }
12377 8110
12378 @override 8111 @override
12379 Object visitForEachStatement(ForEachStatement node) { 8112 Object visitForEachStatement(ForEachStatement node) {
12380 Scope outerNameScope = nameScope; 8113 Scope outerNameScope = nameScope;
12381 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; 8114 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12382 try { 8115 try {
12383 nameScope = new EnclosedScope(nameScope); 8116 nameScope = new EnclosedScope(nameScope);
(...skipping 11 matching lines...) Expand all
12395 * the inherited visit method so that ResolverVisitor can intervene when type propagation is 8128 * the inherited visit method so that ResolverVisitor can intervene when type propagation is
12396 * enabled. 8129 * enabled.
12397 * 8130 *
12398 * @param node the statement to be visited 8131 * @param node the statement to be visited
12399 */ 8132 */
12400 void visitForEachStatementInScope(ForEachStatement node) { 8133 void visitForEachStatementInScope(ForEachStatement node) {
12401 // 8134 //
12402 // We visit the iterator before the loop variable because the loop variable 8135 // We visit the iterator before the loop variable because the loop variable
12403 // cannot be in scope while visiting the iterator. 8136 // cannot be in scope while visiting the iterator.
12404 // 8137 //
12405 safelyVisit(node.identifier); 8138 node.identifier?.accept(this);
12406 safelyVisit(node.iterable); 8139 node.iterable?.accept(this);
12407 safelyVisit(node.loopVariable); 8140 node.loopVariable?.accept(this);
12408 visitStatementInScope(node.body); 8141 visitStatementInScope(node.body);
12409 } 8142 }
12410 8143
12411 @override 8144 @override
12412 Object visitFormalParameterList(FormalParameterList node) { 8145 Object visitFormalParameterList(FormalParameterList node) {
12413 super.visitFormalParameterList(node); 8146 super.visitFormalParameterList(node);
12414 // We finished resolving function signature, now include formal parameters 8147 // We finished resolving function signature, now include formal parameters
12415 // scope. Note: we must not do this if the parent is a 8148 // scope. Note: we must not do this if the parent is a
12416 // FunctionTypedFormalParameter, because in that case we aren't finished 8149 // FunctionTypedFormalParameter, because in that case we aren't finished
12417 // resolving the full function signature, just a part of it. 8150 // resolving the full function signature, just a part of it.
(...skipping 23 matching lines...) Expand all
12441 } 8174 }
12442 8175
12443 /** 8176 /**
12444 * Visit the given statement after it's scope has been created. This replaces the normal call to 8177 * Visit the given statement after it's scope has been created. This replaces the normal call to
12445 * the inherited visit method so that ResolverVisitor can intervene when type propagation is 8178 * the inherited visit method so that ResolverVisitor can intervene when type propagation is
12446 * enabled. 8179 * enabled.
12447 * 8180 *
12448 * @param node the statement to be visited 8181 * @param node the statement to be visited
12449 */ 8182 */
12450 void visitForStatementInScope(ForStatement node) { 8183 void visitForStatementInScope(ForStatement node) {
12451 safelyVisit(node.variables); 8184 node.variables?.accept(this);
12452 safelyVisit(node.initialization); 8185 node.initialization?.accept(this);
12453 safelyVisit(node.condition); 8186 node.condition?.accept(this);
12454 node.updaters.accept(this); 8187 node.updaters.accept(this);
12455 visitStatementInScope(node.body); 8188 visitStatementInScope(node.body);
12456 } 8189 }
12457 8190
12458 @override 8191 @override
12459 Object visitFunctionDeclaration(FunctionDeclaration node) { 8192 Object visitFunctionDeclaration(FunctionDeclaration node) {
12460 ExecutableElement functionElement = node.element; 8193 ExecutableElement functionElement = node.element;
12461 if (functionElement != null && 8194 if (functionElement != null &&
12462 functionElement.enclosingElement is! CompilationUnitElement) { 8195 functionElement.enclosingElement is! CompilationUnitElement) {
12463 nameScope.define(functionElement); 8196 nameScope.define(functionElement);
12464 } 8197 }
12465 Scope outerScope = nameScope; 8198 Scope outerScope = nameScope;
12466 try { 8199 try {
12467 if (functionElement == null) { 8200 if (functionElement == null) {
12468 AnalysisEngine.instance.logger.logInformation( 8201 AnalysisEngine.instance.logger.logInformation(
12469 "Missing element for top-level function ${node.name.name} in ${defin ingLibrary.source.fullName}", 8202 "Missing element for top-level function ${node.name.name} in ${defin ingLibrary.source.fullName}",
12470 new CaughtException(new AnalysisException(), null)); 8203 new CaughtException(new AnalysisException(), null));
12471 } else { 8204 } else {
12472 nameScope = new FunctionScope(nameScope, functionElement); 8205 nameScope = new FunctionScope(nameScope, functionElement);
12473 } 8206 }
12474 super.visitFunctionDeclaration(node); 8207 visitFunctionDeclarationInScope(node);
12475 } finally { 8208 } finally {
12476 nameScope = outerScope; 8209 nameScope = outerScope;
12477 } 8210 }
12478 return null; 8211 return null;
12479 } 8212 }
12480 8213
8214 void visitFunctionDeclarationInScope(FunctionDeclaration node) {
8215 super.visitFunctionDeclaration(node);
8216 }
8217
12481 @override 8218 @override
12482 Object visitFunctionExpression(FunctionExpression node) { 8219 Object visitFunctionExpression(FunctionExpression node) {
12483 if (node.parent is FunctionDeclaration) { 8220 if (node.parent is FunctionDeclaration) {
12484 // We have already created a function scope and don't need to do so again. 8221 // We have already created a function scope and don't need to do so again.
12485 super.visitFunctionExpression(node); 8222 super.visitFunctionExpression(node);
12486 } else { 8223 } else {
12487 Scope outerScope = nameScope; 8224 Scope outerScope = nameScope;
12488 try { 8225 try {
12489 ExecutableElement functionElement = node.element; 8226 ExecutableElement functionElement = node.element;
12490 if (functionElement == null) { 8227 if (functionElement == null) {
(...skipping 22 matching lines...) Expand all
12513 } 8250 }
12514 } 8251 }
12515 return null; 8252 return null;
12516 } 8253 }
12517 8254
12518 @override 8255 @override
12519 Object visitFunctionTypeAlias(FunctionTypeAlias node) { 8256 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
12520 Scope outerScope = nameScope; 8257 Scope outerScope = nameScope;
12521 try { 8258 try {
12522 nameScope = new FunctionTypeScope(nameScope, node.element); 8259 nameScope = new FunctionTypeScope(nameScope, node.element);
12523 super.visitFunctionTypeAlias(node); 8260 visitFunctionTypeAliasInScope(node);
12524 } finally { 8261 } finally {
12525 nameScope = outerScope; 8262 nameScope = outerScope;
12526 } 8263 }
12527 return null; 8264 return null;
12528 } 8265 }
12529 8266
8267 void visitFunctionTypeAliasInScope(FunctionTypeAlias node) {
8268 super.visitFunctionTypeAlias(node);
8269 }
8270
12530 @override 8271 @override
12531 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { 8272 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
12532 Scope outerScope = nameScope; 8273 Scope outerScope = nameScope;
12533 try { 8274 try {
12534 ParameterElement parameterElement = node.element; 8275 ParameterElement parameterElement = node.element;
12535 if (parameterElement == null) { 8276 if (parameterElement == null) {
12536 AnalysisEngine.instance.logger.logInformation( 8277 AnalysisEngine.instance.logger.logInformation(
12537 "Missing element for function typed formal parameter ${node.identifi er.name} in ${definingLibrary.source.fullName}", 8278 "Missing element for function typed formal parameter ${node.identifi er.name} in ${definingLibrary.source.fullName}",
12538 new CaughtException(new AnalysisException(), null)); 8279 new CaughtException(new AnalysisException(), null));
12539 } else { 8280 } else {
12540 nameScope = new EnclosedScope(nameScope); 8281 nameScope = new EnclosedScope(nameScope);
12541 for (TypeParameterElement typeParameter 8282 List<TypeParameterElement> typeParameters =
12542 in parameterElement.typeParameters) { 8283 parameterElement.typeParameters;
12543 nameScope.define(typeParameter); 8284 int length = typeParameters.length;
8285 for (int i = 0; i < length; i++) {
8286 nameScope.define(typeParameters[i]);
12544 } 8287 }
12545 } 8288 }
12546 super.visitFunctionTypedFormalParameter(node); 8289 super.visitFunctionTypedFormalParameter(node);
12547 } finally { 8290 } finally {
12548 nameScope = outerScope; 8291 nameScope = outerScope;
12549 } 8292 }
12550 return null; 8293 return null;
12551 } 8294 }
12552 8295
12553 @override 8296 @override
12554 Object visitIfStatement(IfStatement node) { 8297 Object visitIfStatement(IfStatement node) {
12555 safelyVisit(node.condition); 8298 node.condition?.accept(this);
12556 visitStatementInScope(node.thenStatement); 8299 visitStatementInScope(node.thenStatement);
12557 visitStatementInScope(node.elseStatement); 8300 visitStatementInScope(node.elseStatement);
12558 return null; 8301 return null;
12559 } 8302 }
12560 8303
12561 @override 8304 @override
12562 Object visitLabeledStatement(LabeledStatement node) { 8305 Object visitLabeledStatement(LabeledStatement node) {
12563 LabelScope outerScope = _addScopesFor(node.labels, node.unlabeled); 8306 LabelScope outerScope = _addScopesFor(node.labels, node.unlabeled);
12564 try { 8307 try {
12565 super.visitLabeledStatement(node); 8308 super.visitLabeledStatement(node);
12566 } finally { 8309 } finally {
12567 labelScope = outerScope; 8310 labelScope = outerScope;
12568 } 8311 }
12569 return null; 8312 return null;
12570 } 8313 }
12571 8314
12572 @override 8315 @override
12573 Object visitMethodDeclaration(MethodDeclaration node) { 8316 Object visitMethodDeclaration(MethodDeclaration node) {
12574 Scope outerScope = nameScope; 8317 Scope outerScope = nameScope;
12575 try { 8318 try {
12576 ExecutableElement methodElement = node.element; 8319 ExecutableElement methodElement = node.element;
12577 if (methodElement == null) { 8320 if (methodElement == null) {
12578 AnalysisEngine.instance.logger.logInformation( 8321 AnalysisEngine.instance.logger.logInformation(
12579 "Missing element for method ${node.name.name} in ${definingLibrary.s ource.fullName}", 8322 "Missing element for method ${node.name.name} in ${definingLibrary.s ource.fullName}",
12580 new CaughtException(new AnalysisException(), null)); 8323 new CaughtException(new AnalysisException(), null));
12581 } else { 8324 } else {
12582 nameScope = new FunctionScope(nameScope, methodElement); 8325 nameScope = new FunctionScope(nameScope, methodElement);
12583 } 8326 }
12584 super.visitMethodDeclaration(node); 8327 visitMethodDeclarationInScope(node);
12585 } finally { 8328 } finally {
12586 nameScope = outerScope; 8329 nameScope = outerScope;
12587 } 8330 }
12588 return null; 8331 return null;
12589 } 8332 }
12590 8333
8334 void visitMethodDeclarationInScope(MethodDeclaration node) {
8335 super.visitMethodDeclaration(node);
8336 }
8337
12591 /** 8338 /**
12592 * Visit the given statement after it's scope has been created. This is used b y ResolverVisitor to 8339 * Visit the given statement after it's scope has been created. This is used b y ResolverVisitor to
12593 * correctly visit the 'then' and 'else' statements of an 'if' statement. 8340 * correctly visit the 'then' and 'else' statements of an 'if' statement.
12594 * 8341 *
12595 * @param node the statement to be visited 8342 * @param node the statement to be visited
12596 */ 8343 */
12597 void visitStatementInScope(Statement node) { 8344 void visitStatementInScope(Statement node) {
12598 if (node is Block) { 8345 if (node is Block) {
12599 // Don't create a scope around a block because the block will create it's 8346 // Don't create a scope around a block because the block will create it's
12600 // own scope. 8347 // own scope.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
12665 VariableElement element = node.element; 8412 VariableElement element = node.element;
12666 if (element != null) { 8413 if (element != null) {
12667 nameScope.define(element); 8414 nameScope.define(element);
12668 } 8415 }
12669 } 8416 }
12670 return null; 8417 return null;
12671 } 8418 }
12672 8419
12673 @override 8420 @override
12674 Object visitWhileStatement(WhileStatement node) { 8421 Object visitWhileStatement(WhileStatement node) {
12675 safelyVisit(node.condition); 8422 node.condition?.accept(this);
12676 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; 8423 ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
12677 try { 8424 try {
12678 _implicitLabelScope = _implicitLabelScope.nest(node); 8425 _implicitLabelScope = _implicitLabelScope.nest(node);
12679 visitStatementInScope(node.body); 8426 visitStatementInScope(node.body);
12680 } finally { 8427 } finally {
12681 _implicitLabelScope = outerImplicitScope; 8428 _implicitLabelScope = outerImplicitScope;
12682 } 8429 }
12683 return null; 8430 return null;
12684 } 8431 }
12685 8432
12686 /** 8433 /**
12687 * Add scopes for each of the given labels. 8434 * Add scopes for each of the given labels.
12688 * 8435 *
12689 * @param labels the labels for which new scopes are to be added 8436 * @param labels the labels for which new scopes are to be added
12690 * @return the scope that was in effect before the new scopes were added 8437 * @return the scope that was in effect before the new scopes were added
12691 */ 8438 */
12692 LabelScope _addScopesFor(NodeList<Label> labels, AstNode node) { 8439 LabelScope _addScopesFor(NodeList<Label> labels, AstNode node) {
12693 LabelScope outerScope = labelScope; 8440 LabelScope outerScope = labelScope;
12694 for (Label label in labels) { 8441 for (Label label in labels) {
12695 SimpleIdentifier labelNameNode = label.label; 8442 SimpleIdentifier labelNameNode = label.label;
12696 String labelName = labelNameNode.name; 8443 String labelName = labelNameNode.name;
12697 LabelElement labelElement = labelNameNode.staticElement as LabelElement; 8444 LabelElement labelElement = labelNameNode.staticElement as LabelElement;
12698 labelScope = new LabelScope(labelScope, labelName, node, labelElement); 8445 labelScope = new LabelScope(labelScope, labelName, node, labelElement);
12699 } 8446 }
12700 return outerScope; 8447 return outerScope;
12701 } 8448 }
12702
12703 /**
12704 * Marks the local declarations of the given [Block] hidden in the enclosing s cope.
12705 * According to the scoping rules name is hidden if block defines it, but name is defined after
12706 * its declaration statement.
12707 */
12708 void _hideNamesDefinedInBlock(EnclosedScope scope, Block block) {
12709 NodeList<Statement> statements = block.statements;
12710 int statementCount = statements.length;
12711 for (int i = 0; i < statementCount; i++) {
12712 Statement statement = statements[i];
12713 if (statement is VariableDeclarationStatement) {
12714 VariableDeclarationStatement vds = statement;
12715 NodeList<VariableDeclaration> variables = vds.variables.variables;
12716 int variableCount = variables.length;
12717 for (int j = 0; j < variableCount; j++) {
12718 scope.hide(variables[j].element);
12719 }
12720 } else if (statement is FunctionDeclarationStatement) {
12721 FunctionDeclarationStatement fds = statement;
12722 scope.hide(fds.functionDeclaration.element);
12723 }
12724 }
12725 }
12726 }
12727
12728 /**
12729 * Implementation of [TypeSystem] using the strong mode rules.
12730 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
12731 */
12732 class StrongTypeSystemImpl implements TypeSystem {
12733 final _specTypeSystem = new TypeSystemImpl();
12734
12735 StrongTypeSystemImpl();
12736
12737 @override
12738 DartType getLeastUpperBound(
12739 TypeProvider typeProvider, DartType type1, DartType type2) {
12740 // TODO(leafp): Implement a strong mode version of this.
12741 return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
12742 }
12743
12744 // TODO(leafp): Document the rules in play here
12745 @override
12746 bool isAssignableTo(DartType fromType, DartType toType) {
12747 // An actual subtype
12748 if (isSubtypeOf(fromType, toType)) {
12749 return true;
12750 }
12751
12752 // Don't allow implicit downcasts between function types
12753 // and call method objects, as these will almost always fail.
12754 if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
12755 (toType is FunctionType && _getCallMethodType(fromType) != null)) {
12756 return false;
12757 }
12758
12759 // If the subtype relation goes the other way, allow the implicit downcast.
12760 // TODO(leafp): Emit warnings and hints for these in some way.
12761 // TODO(leafp): Consider adding a flag to disable these? Or just rely on
12762 // --warnings-as-errors?
12763 if (isSubtypeOf(toType, fromType) ||
12764 _specTypeSystem.isAssignableTo(toType, fromType)) {
12765 // TODO(leafp): error if type is known to be exact (literal,
12766 // instance creation).
12767 // TODO(leafp): Warn on composite downcast.
12768 // TODO(leafp): hint on object/dynamic downcast.
12769 // TODO(leafp): Consider allowing assignment casts.
12770 return true;
12771 }
12772
12773 return false;
12774 }
12775
12776 @override
12777 bool isSubtypeOf(DartType leftType, DartType rightType) {
12778 return _isSubtypeOf(leftType, rightType, null);
12779 }
12780
12781 FunctionType _getCallMethodType(DartType t) {
12782 if (t is InterfaceType) {
12783 ClassElement element = t.element;
12784 InheritanceManager manager = new InheritanceManager(element.library);
12785 FunctionType callType = manager.lookupMemberType(t, "call");
12786 return callType;
12787 }
12788 return null;
12789 }
12790
12791 // Given a type t, if t is an interface type with a call method
12792 // defined, return the function type for the call method, otherwise
12793 // return null.
12794 _GuardedSubtypeChecker<DartType> _guard(
12795 _GuardedSubtypeChecker<DartType> check) {
12796 return (DartType t1, DartType t2, Set<Element> visited) {
12797 Element element = t1.element;
12798 if (visited == null) {
12799 visited = new HashSet<Element>();
12800 }
12801 if (element == null || !visited.add(element)) {
12802 return false;
12803 }
12804 try {
12805 return check(t1, t2, visited);
12806 } finally {
12807 visited.remove(element);
12808 }
12809 };
12810 }
12811
12812 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
12813 return (t.isDynamic && dynamicIsBottom) || t.isBottom;
12814 }
12815
12816 // Guard against loops in the class hierarchy
12817 /**
12818 * Check that [f1] is a subtype of [f2].
12819 * [fuzzyArrows] indicates whether or not the f1 and f2 should be
12820 * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
12821 * as bottom).
12822 */
12823 bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
12824 {bool fuzzyArrows: true}) {
12825 final r1s = f1.normalParameterTypes;
12826 final o1s = f1.optionalParameterTypes;
12827 final n1s = f1.namedParameterTypes;
12828 final r2s = f2.normalParameterTypes;
12829 final o2s = f2.optionalParameterTypes;
12830 final n2s = f2.namedParameterTypes;
12831 final ret1 = f1.returnType;
12832 final ret2 = f2.returnType;
12833
12834 // A -> B <: C -> D if C <: A and
12835 // either D is void or B <: D
12836 if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
12837 return false;
12838 }
12839
12840 // Reject if one has named and the other has optional
12841 if (n1s.length > 0 && o2s.length > 0) {
12842 return false;
12843 }
12844 if (n2s.length > 0 && o1s.length > 0) {
12845 return false;
12846 }
12847
12848 // Rebind _isSubtypeOf for convenience
12849 _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
12850 _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
12851
12852 // f2 has named parameters
12853 if (n2s.length > 0) {
12854 // Check that every named parameter in f2 has a match in f1
12855 for (String k2 in n2s.keys) {
12856 if (!n1s.containsKey(k2)) {
12857 return false;
12858 }
12859 if (!parameterSubtype(n2s[k2], n1s[k2])) {
12860 return false;
12861 }
12862 }
12863 }
12864 // If we get here, we either have no named parameters,
12865 // or else the named parameters match and we have no optional
12866 // parameters
12867
12868 // If f1 has more required parameters, reject
12869 if (r1s.length > r2s.length) {
12870 return false;
12871 }
12872
12873 // If f2 has more required + optional parameters, reject
12874 if (r2s.length + o2s.length > r1s.length + o1s.length) {
12875 return false;
12876 }
12877
12878 // The parameter lists must look like the following at this point
12879 // where rrr is a region of required, and ooo is a region of optionals.
12880 // f1: rrr ooo ooo ooo
12881 // f2: rrr rrr ooo
12882 int rr = r1s.length; // required in both
12883 int or = r2s.length - r1s.length; // optional in f1, required in f2
12884 int oo = o2s.length; // optional in both
12885
12886 for (int i = 0; i < rr; ++i) {
12887 if (!parameterSubtype(r2s[i], r1s[i])) {
12888 return false;
12889 }
12890 }
12891 for (int i = 0, j = rr; i < or; ++i, ++j) {
12892 if (!parameterSubtype(r2s[j], o1s[i])) {
12893 return false;
12894 }
12895 }
12896 for (int i = or, j = 0; i < oo; ++i, ++j) {
12897 if (!parameterSubtype(o2s[j], o1s[i])) {
12898 return false;
12899 }
12900 }
12901 return true;
12902 }
12903
12904 bool _isInterfaceSubtypeOf(
12905 InterfaceType i1, InterfaceType i2, Set<Element> visited) {
12906 // Guard recursive calls
12907 _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
12908 _guard(_isInterfaceSubtypeOf);
12909
12910 if (i1 == i2) {
12911 return true;
12912 }
12913
12914 if (i1.element == i2.element) {
12915 List<DartType> tArgs1 = i1.typeArguments;
12916 List<DartType> tArgs2 = i2.typeArguments;
12917
12918 assert(tArgs1.length == tArgs2.length);
12919
12920 for (int i = 0; i < tArgs1.length; i++) {
12921 DartType t1 = tArgs1[i];
12922 DartType t2 = tArgs2[i];
12923 if (!isSubtypeOf(t1, t2)) {
12924 return false;
12925 }
12926 }
12927 return true;
12928 }
12929
12930 if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
12931 return true;
12932 }
12933
12934 if (i1.isObject) {
12935 return false;
12936 }
12937
12938 if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
12939 return true;
12940 }
12941
12942 for (final parent in i1.interfaces) {
12943 if (guardedInterfaceSubtype(parent, i2, visited)) {
12944 return true;
12945 }
12946 }
12947
12948 for (final parent in i1.mixins) {
12949 if (guardedInterfaceSubtype(parent, i2, visited)) {
12950 return true;
12951 }
12952 }
12953
12954 return false;
12955 }
12956
12957 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
12958 {bool dynamicIsBottom: false}) {
12959 // Guard recursive calls
12960 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
12961
12962 if (t1 == t2) {
12963 return true;
12964 }
12965
12966 // The types are void, dynamic, bottom, interface types, function types
12967 // and type parameters. We proceed by eliminating these different classes
12968 // from consideration.
12969
12970 // Trivially true.
12971 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
12972 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
12973 return true;
12974 }
12975
12976 // Trivially false.
12977 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
12978 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
12979 return false;
12980 }
12981
12982 // S <: T where S is a type variable
12983 // T is not dynamic or object (handled above)
12984 // S != T (handled above)
12985 // So only true if bound of S is S' and
12986 // S' <: T
12987 if (t1 is TypeParameterType) {
12988 DartType bound = t1.element.bound;
12989 if (bound == null) return false;
12990 return guardedSubtype(bound, t2, visited);
12991 }
12992
12993 if (t2 is TypeParameterType) {
12994 return false;
12995 }
12996
12997 if (t1.isVoid || t2.isVoid) {
12998 return false;
12999 }
13000
13001 // We've eliminated void, dynamic, bottom, and type parameters. The only
13002 // cases are the combinations of interface type and function type.
13003
13004 // A function type can only subtype an interface type if
13005 // the interface type is Function
13006 if (t1 is FunctionType && t2 is InterfaceType) {
13007 return t2.isDartCoreFunction;
13008 }
13009
13010 // An interface type can only subtype a function type if
13011 // the interface type declares a call method with a type
13012 // which is a super type of the function type.
13013 if (t1 is InterfaceType && t2 is FunctionType) {
13014 var callType = _getCallMethodType(t1);
13015 return (callType != null) && _isFunctionSubtypeOf(callType, t2);
13016 }
13017
13018 // Two interface types
13019 if (t1 is InterfaceType && t2 is InterfaceType) {
13020 return _isInterfaceSubtypeOf(t1, t2, visited);
13021 }
13022
13023 return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
13024 }
13025
13026 // TODO(leafp): Document the rules in play here
13027 bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
13028 return (t.isDynamic && !dynamicIsBottom) || t.isObject;
13029 }
13030 } 8449 }
13031 8450
13032 /** 8451 /**
13033 * Instances of this class manage the knowledge of what the set of subtypes are for a given type. 8452 * Instances of this class manage the knowledge of what the set of subtypes are for a given type.
13034 */ 8453 */
13035 class SubtypeManager { 8454 class SubtypeManager {
13036 /** 8455 /**
13037 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype s of the 8456 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype s of the
13038 * key. 8457 * key.
13039 */ 8458 */
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
13081 */ 8500 */
13082 void _computeSubtypesInClass(ClassElement classElement) { 8501 void _computeSubtypesInClass(ClassElement classElement) {
13083 InterfaceType supertypeType = classElement.supertype; 8502 InterfaceType supertypeType = classElement.supertype;
13084 if (supertypeType != null) { 8503 if (supertypeType != null) {
13085 ClassElement supertypeElement = supertypeType.element; 8504 ClassElement supertypeElement = supertypeType.element;
13086 if (supertypeElement != null) { 8505 if (supertypeElement != null) {
13087 _putInSubtypeMap(supertypeElement, classElement); 8506 _putInSubtypeMap(supertypeElement, classElement);
13088 } 8507 }
13089 } 8508 }
13090 List<InterfaceType> interfaceTypes = classElement.interfaces; 8509 List<InterfaceType> interfaceTypes = classElement.interfaces;
13091 for (InterfaceType interfaceType in interfaceTypes) { 8510 int interfaceLength = interfaceTypes.length;
8511 for (int i = 0; i < interfaceLength; i++) {
8512 InterfaceType interfaceType = interfaceTypes[i];
13092 ClassElement interfaceElement = interfaceType.element; 8513 ClassElement interfaceElement = interfaceType.element;
13093 if (interfaceElement != null) { 8514 if (interfaceElement != null) {
13094 _putInSubtypeMap(interfaceElement, classElement); 8515 _putInSubtypeMap(interfaceElement, classElement);
13095 } 8516 }
13096 } 8517 }
13097 List<InterfaceType> mixinTypes = classElement.mixins; 8518 List<InterfaceType> mixinTypes = classElement.mixins;
13098 for (InterfaceType mixinType in mixinTypes) { 8519 int mixinLength = mixinTypes.length;
8520 for (int i = 0; i < mixinLength; i++) {
8521 InterfaceType mixinType = mixinTypes[i];
13099 ClassElement mixinElement = mixinType.element; 8522 ClassElement mixinElement = mixinType.element;
13100 if (mixinElement != null) { 8523 if (mixinElement != null) {
13101 _putInSubtypeMap(mixinElement, classElement); 8524 _putInSubtypeMap(mixinElement, classElement);
13102 } 8525 }
13103 } 8526 }
13104 } 8527 }
13105 8528
13106 /** 8529 /**
13107 * Given some [CompilationUnitElement], this method calls 8530 * Given some [CompilationUnitElement], this method calls
13108 * [computeAllSubtypes] on all of the [ClassElement]s in the 8531 * [computeAllSubtypes] on all of the [ClassElement]s in the
13109 * compilation unit. 8532 * compilation unit.
13110 * 8533 *
13111 * @param unitElement the compilation unit element 8534 * @param unitElement the compilation unit element
13112 */ 8535 */
13113 void _computeSubtypesInCompilationUnit(CompilationUnitElement unitElement) { 8536 void _computeSubtypesInCompilationUnit(CompilationUnitElement unitElement) {
13114 List<ClassElement> classElements = unitElement.types; 8537 List<ClassElement> classElements = unitElement.types;
13115 for (ClassElement classElement in classElements) { 8538 int length = classElements.length;
8539 for (int i = 0; i < length; i++) {
8540 ClassElement classElement = classElements[i];
13116 _computeSubtypesInClass(classElement); 8541 _computeSubtypesInClass(classElement);
13117 } 8542 }
13118 } 8543 }
13119 8544
13120 /** 8545 /**
13121 * Given some [LibraryElement], this method calls 8546 * Given some [LibraryElement], this method calls
13122 * [computeAllSubtypes] on all of the [ClassElement]s in the 8547 * [computeAllSubtypes] on all of the [ClassElement]s in the
13123 * compilation unit, and itself for all imported and exported libraries. All v isited libraries are 8548 * compilation unit, and itself for all imported and exported libraries. All v isited libraries are
13124 * added to the [visitedLibraries] set. 8549 * added to the [visitedLibraries] set.
13125 * 8550 *
13126 * @param libraryElement the library element 8551 * @param libraryElement the library element
13127 */ 8552 */
13128 void _computeSubtypesInLibrary(LibraryElement libraryElement) { 8553 void _computeSubtypesInLibrary(LibraryElement libraryElement) {
13129 if (libraryElement == null || _visitedLibraries.contains(libraryElement)) { 8554 if (libraryElement == null || _visitedLibraries.contains(libraryElement)) {
13130 return; 8555 return;
13131 } 8556 }
13132 _visitedLibraries.add(libraryElement); 8557 _visitedLibraries.add(libraryElement);
13133 _computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit); 8558 _computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit);
13134 List<CompilationUnitElement> parts = libraryElement.parts; 8559 List<CompilationUnitElement> parts = libraryElement.parts;
13135 for (CompilationUnitElement part in parts) { 8560 int partLength = parts.length;
8561 for (int i = 0; i < partLength; i++) {
8562 CompilationUnitElement part = parts[i];
13136 _computeSubtypesInCompilationUnit(part); 8563 _computeSubtypesInCompilationUnit(part);
13137 } 8564 }
13138 List<LibraryElement> imports = libraryElement.importedLibraries; 8565 List<LibraryElement> imports = libraryElement.importedLibraries;
13139 for (LibraryElement importElt in imports) { 8566 int importLength = imports.length;
8567 for (int i = 0; i < importLength; i++) {
8568 LibraryElement importElt = imports[i];
13140 _computeSubtypesInLibrary(importElt.library); 8569 _computeSubtypesInLibrary(importElt.library);
13141 } 8570 }
13142 List<LibraryElement> exports = libraryElement.exportedLibraries; 8571 List<LibraryElement> exports = libraryElement.exportedLibraries;
13143 for (LibraryElement exportElt in exports) { 8572 int exportLength = exports.length;
8573 for (int i = 0; i < exportLength; i++) {
8574 LibraryElement exportElt = exports[i];
13144 _computeSubtypesInLibrary(exportElt.library); 8575 _computeSubtypesInLibrary(exportElt.library);
13145 } 8576 }
13146 } 8577 }
13147 8578
13148 /** 8579 /**
13149 * Add some key/ value pair into the [subtypeMap] map. 8580 * Add some key/ value pair into the [subtypeMap] map.
13150 * 8581 *
13151 * @param supertypeElement the key for the [subtypeMap] map 8582 * @param supertypeElement the key for the [subtypeMap] map
13152 * @param subtypeElement the value for the [subtypeMap] map 8583 * @param subtypeElement the value for the [subtypeMap] map
13153 */ 8584 */
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
13211 void findIn(CompilationUnit unit) { 8642 void findIn(CompilationUnit unit) {
13212 _gatherTodoComments(unit.beginToken); 8643 _gatherTodoComments(unit.beginToken);
13213 } 8644 }
13214 8645
13215 /** 8646 /**
13216 * Search the comment tokens reachable from the given token and create errors for each to-do 8647 * Search the comment tokens reachable from the given token and create errors for each to-do
13217 * comment. 8648 * comment.
13218 * 8649 *
13219 * @param token the head of the list of tokens being searched 8650 * @param token the head of the list of tokens being searched
13220 */ 8651 */
13221 void _gatherTodoComments(sc.Token token) { 8652 void _gatherTodoComments(Token token) {
13222 while (token != null && token.type != sc.TokenType.EOF) { 8653 while (token != null && token.type != TokenType.EOF) {
13223 sc.Token commentToken = token.precedingComments; 8654 Token commentToken = token.precedingComments;
13224 while (commentToken != null) { 8655 while (commentToken != null) {
13225 if (commentToken.type == sc.TokenType.SINGLE_LINE_COMMENT || 8656 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT ||
13226 commentToken.type == sc.TokenType.MULTI_LINE_COMMENT) { 8657 commentToken.type == TokenType.MULTI_LINE_COMMENT) {
13227 _scrapeTodoComment(commentToken); 8658 _scrapeTodoComment(commentToken);
13228 } 8659 }
13229 commentToken = commentToken.next; 8660 commentToken = commentToken.next;
13230 } 8661 }
13231 token = token.next; 8662 token = token.next;
13232 } 8663 }
13233 } 8664 }
13234 8665
13235 /** 8666 /**
13236 * Look for user defined tasks in comments and convert them into info level an alysis issues. 8667 * Look for user defined tasks in comments and convert them into info level an alysis issues.
13237 * 8668 *
13238 * @param commentToken the comment token to analyze 8669 * @param commentToken the comment token to analyze
13239 */ 8670 */
13240 void _scrapeTodoComment(sc.Token commentToken) { 8671 void _scrapeTodoComment(Token commentToken) {
13241 JavaPatternMatcher matcher = 8672 Iterable<Match> matches =
13242 new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme); 8673 TodoCode.TODO_REGEX.allMatches(commentToken.lexeme);
13243 if (matcher.find()) { 8674 for (Match match in matches) {
13244 int offset = 8675 int offset = commentToken.offset + match.start + match.group(1).length;
13245 commentToken.offset + matcher.start() + matcher.group(1).length; 8676 int length = match.group(2).length;
13246 int length = matcher.group(2).length;
13247 _errorReporter.reportErrorForOffset( 8677 _errorReporter.reportErrorForOffset(
13248 TodoCode.TODO, offset, length, [matcher.group(2)]); 8678 TodoCode.TODO, offset, length, [match.group(2)]);
13249 } 8679 }
13250 } 8680 }
13251 } 8681 }
13252 8682
8683 /**
8684 * Helper for resolving [TypeName]s.
8685 *
8686 * The client must set [nameScope] before calling [resolveTypeName].
8687 */
8688 class TypeNameResolver {
8689 final TypeSystem typeSystem;
8690 final DartType dynamicType;
8691 final DartType undefinedType;
8692 final LibraryElement definingLibrary;
8693 final Source source;
8694 final AnalysisErrorListener errorListener;
8695
8696 Scope nameScope;
8697
8698 TypeNameResolver(this.typeSystem, TypeProvider typeProvider,
8699 this.definingLibrary, this.source, this.errorListener)
8700 : dynamicType = typeProvider.dynamicType,
8701 undefinedType = typeProvider.undefinedType;
8702
8703 /**
8704 * Report an error with the given error code and arguments.
8705 *
8706 * @param errorCode the error code of the error to be reported
8707 * @param node the node specifying the location of the error
8708 * @param arguments the arguments to the error, used to compose the error mess age
8709 */
8710 void reportErrorForNode(ErrorCode errorCode, AstNode node,
8711 [List<Object> arguments]) {
8712 errorListener.onError(new AnalysisError(
8713 source, node.offset, node.length, errorCode, arguments));
8714 }
8715
8716 /**
8717 * Resolve the given [TypeName] - set its element and static type. Only the
8718 * given [node] is resolved, all its children must be already resolved.
8719 *
8720 * The client must set [nameScope] before calling [resolveTypeName].
8721 */
8722 void resolveTypeName(TypeName node) {
8723 Identifier typeName = node.name;
8724 _setElement(typeName, null); // Clear old Elements from previous run.
8725 TypeArgumentList argumentList = node.typeArguments;
8726 Element element = nameScope.lookup(typeName, definingLibrary);
8727 if (element == null) {
8728 //
8729 // Check to see whether the type name is either 'dynamic' or 'void',
8730 // neither of which are in the name scope and hence will not be found by
8731 // normal means.
8732 //
8733 if (typeName.name == dynamicType.name) {
8734 _setElement(typeName, dynamicType.element);
8735 // if (argumentList != null) {
8736 // // TODO(brianwilkerson) Report this error
8737 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, dynamicType.getName(), 0, argumentList.getArguments().size());
8738 // }
8739 typeName.staticType = dynamicType;
8740 node.type = dynamicType;
8741 return;
8742 }
8743 VoidTypeImpl voidType = VoidTypeImpl.instance;
8744 if (typeName.name == voidType.name) {
8745 // There is no element for 'void'.
8746 // if (argumentList != null) {
8747 // // TODO(brianwilkerson) Report this error
8748 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, voidType.getName(), 0, argumentList.getArguments().size());
8749 // }
8750 typeName.staticType = voidType;
8751 node.type = voidType;
8752 return;
8753 }
8754 if (nameScope.shouldIgnoreUndefined(typeName)) {
8755 typeName.staticType = undefinedType;
8756 node.type = undefinedType;
8757 return;
8758 }
8759 //
8760 // If not, the look to see whether we might have created the wrong AST
8761 // structure for a constructor name. If so, fix the AST structure and then
8762 // proceed.
8763 //
8764 AstNode parent = node.parent;
8765 if (typeName is PrefixedIdentifier &&
8766 parent is ConstructorName &&
8767 argumentList == null) {
8768 ConstructorName name = parent;
8769 if (name.name == null) {
8770 PrefixedIdentifier prefixedIdentifier =
8771 typeName as PrefixedIdentifier;
8772 SimpleIdentifier prefix = prefixedIdentifier.prefix;
8773 element = nameScope.lookup(prefix, definingLibrary);
8774 if (element is PrefixElement) {
8775 if (nameScope.shouldIgnoreUndefined(typeName)) {
8776 typeName.staticType = undefinedType;
8777 node.type = undefinedType;
8778 return;
8779 }
8780 AstNode grandParent = parent.parent;
8781 if (grandParent is InstanceCreationExpression &&
8782 grandParent.isConst) {
8783 // If, if this is a const expression, then generate a
8784 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
8785 reportErrorForNode(
8786 CompileTimeErrorCode.CONST_WITH_NON_TYPE,
8787 prefixedIdentifier.identifier,
8788 [prefixedIdentifier.identifier.name]);
8789 } else {
8790 // Else, if this expression is a new expression, report a
8791 // NEW_WITH_NON_TYPE warning.
8792 reportErrorForNode(
8793 StaticWarningCode.NEW_WITH_NON_TYPE,
8794 prefixedIdentifier.identifier,
8795 [prefixedIdentifier.identifier.name]);
8796 }
8797 _setElement(prefix, element);
8798 return;
8799 } else if (element != null) {
8800 //
8801 // Rewrite the constructor name. The parser, when it sees a
8802 // constructor named "a.b", cannot tell whether "a" is a prefix and
8803 // "b" is a class name, or whether "a" is a class name and "b" is a
8804 // constructor name. It arbitrarily chooses the former, but in this
8805 // case was wrong.
8806 //
8807 name.name = prefixedIdentifier.identifier;
8808 name.period = prefixedIdentifier.period;
8809 node.name = prefix;
8810 typeName = prefix;
8811 }
8812 }
8813 }
8814 if (nameScope.shouldIgnoreUndefined(typeName)) {
8815 typeName.staticType = undefinedType;
8816 node.type = undefinedType;
8817 return;
8818 }
8819 }
8820 // check element
8821 bool elementValid = element is! MultiplyDefinedElement;
8822 if (elementValid &&
8823 element is! ClassElement &&
8824 _isTypeNameInInstanceCreationExpression(node)) {
8825 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
8826 InstanceCreationExpression creation =
8827 node.parent.parent as InstanceCreationExpression;
8828 if (creation.isConst) {
8829 if (element == null) {
8830 reportErrorForNode(
8831 CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
8832 } else {
8833 reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE,
8834 typeNameSimple, [typeName]);
8835 }
8836 elementValid = false;
8837 } else {
8838 if (element != null) {
8839 reportErrorForNode(
8840 StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
8841 elementValid = false;
8842 }
8843 }
8844 }
8845 if (elementValid && element == null) {
8846 // We couldn't resolve the type name.
8847 // TODO(jwren) Consider moving the check for
8848 // CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE from the
8849 // ErrorVerifier, so that we don't have two errors on a built in
8850 // identifier being used as a class name.
8851 // See CompileTimeErrorCodeTest.test_builtInIdentifierAsType().
8852 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
8853 RedirectingConstructorKind redirectingConstructorKind;
8854 if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) {
8855 reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
8856 typeName, [typeName.name]);
8857 } else if (typeNameSimple.name == "boolean") {
8858 reportErrorForNode(
8859 StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
8860 } else if (_isTypeNameInCatchClause(node)) {
8861 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
8862 [typeName.name]);
8863 } else if (_isTypeNameInAsExpression(node)) {
8864 reportErrorForNode(
8865 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
8866 } else if (_isTypeNameInIsExpression(node)) {
8867 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
8868 typeName, [typeName.name]);
8869 } else if ((redirectingConstructorKind =
8870 _getRedirectingConstructorKind(node)) !=
8871 null) {
8872 ErrorCode errorCode =
8873 (redirectingConstructorKind == RedirectingConstructorKind.CONST
8874 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
8875 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
8876 reportErrorForNode(errorCode, typeName, [typeName.name]);
8877 } else if (_isTypeNameInTypeArgumentList(node)) {
8878 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
8879 typeName, [typeName.name]);
8880 } else {
8881 reportErrorForNode(
8882 StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
8883 }
8884 elementValid = false;
8885 }
8886 if (!elementValid) {
8887 if (element is MultiplyDefinedElement) {
8888 _setElement(typeName, element);
8889 }
8890 typeName.staticType = undefinedType;
8891 node.type = undefinedType;
8892 return;
8893 }
8894 DartType type = null;
8895 if (element is ClassElement) {
8896 _setElement(typeName, element);
8897 type = element.type;
8898 } else if (element is FunctionTypeAliasElement) {
8899 _setElement(typeName, element);
8900 type = element.type;
8901 } else if (element is TypeParameterElement) {
8902 _setElement(typeName, element);
8903 type = element.type;
8904 // if (argumentList != null) {
8905 // // Type parameters cannot have type arguments.
8906 // // TODO(brianwilkerson) Report this error.
8907 // // resolver.reportError(ResolverErrorCode.?, keyType);
8908 // }
8909 } else if (element is MultiplyDefinedElement) {
8910 List<Element> elements = element.conflictingElements;
8911 type = _getTypeWhenMultiplyDefined(elements);
8912 if (type != null) {
8913 node.type = type;
8914 }
8915 } else {
8916 // The name does not represent a type.
8917 RedirectingConstructorKind redirectingConstructorKind;
8918 if (_isTypeNameInCatchClause(node)) {
8919 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
8920 [typeName.name]);
8921 } else if (_isTypeNameInAsExpression(node)) {
8922 reportErrorForNode(
8923 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
8924 } else if (_isTypeNameInIsExpression(node)) {
8925 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName,
8926 [typeName.name]);
8927 } else if ((redirectingConstructorKind =
8928 _getRedirectingConstructorKind(node)) !=
8929 null) {
8930 ErrorCode errorCode =
8931 (redirectingConstructorKind == RedirectingConstructorKind.CONST
8932 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
8933 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
8934 reportErrorForNode(errorCode, typeName, [typeName.name]);
8935 } else if (_isTypeNameInTypeArgumentList(node)) {
8936 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
8937 typeName, [typeName.name]);
8938 } else {
8939 AstNode parent = typeName.parent;
8940 while (parent is TypeName) {
8941 parent = parent.parent;
8942 }
8943 if (parent is ExtendsClause ||
8944 parent is ImplementsClause ||
8945 parent is WithClause ||
8946 parent is ClassTypeAlias) {
8947 // Ignored. The error will be reported elsewhere.
8948 } else if (element is LocalVariableElement ||
8949 (element is FunctionElement &&
8950 element.enclosingElement is ExecutableElement)) {
8951 reportErrorForNode(CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION,
8952 typeName, [typeName.name]);
8953 } else {
8954 reportErrorForNode(
8955 StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
8956 }
8957 }
8958 typeName.staticType = dynamicType;
8959 node.type = dynamicType;
8960 return;
8961 }
8962 if (argumentList != null) {
8963 NodeList<TypeName> arguments = argumentList.arguments;
8964 int argumentCount = arguments.length;
8965 List<DartType> parameters = typeSystem.typeFormalsAsTypes(type);
8966 int parameterCount = parameters.length;
8967 List<DartType> typeArguments = new List<DartType>(parameterCount);
8968 if (argumentCount == parameterCount) {
8969 for (int i = 0; i < parameterCount; i++) {
8970 TypeName argumentTypeName = arguments[i];
8971 DartType argumentType = _getType(argumentTypeName);
8972 if (argumentType == null) {
8973 argumentType = dynamicType;
8974 }
8975 typeArguments[i] = argumentType;
8976 }
8977 } else {
8978 reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node,
8979 [typeName.name, parameterCount, argumentCount]);
8980 for (int i = 0; i < parameterCount; i++) {
8981 typeArguments[i] = dynamicType;
8982 }
8983 }
8984 type = typeSystem.instantiateType(type, typeArguments);
8985 } else {
8986 type = typeSystem.instantiateToBounds(type);
8987 }
8988 typeName.staticType = type;
8989 node.type = type;
8990 }
8991
8992 /**
8993 * The number of type arguments in the given type name does not match the numb er of parameters in
8994 * the corresponding class element. Return the error code that should be used to report this
8995 * error.
8996 *
8997 * @param node the type name with the wrong number of type arguments
8998 * @return the error code that should be used to report that the wrong number of type arguments
8999 * were provided
9000 */
9001 ErrorCode _getInvalidTypeParametersErrorCode(TypeName node) {
9002 AstNode parent = node.parent;
9003 if (parent is ConstructorName) {
9004 parent = parent.parent;
9005 if (parent is InstanceCreationExpression) {
9006 if (parent.isConst) {
9007 return CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS;
9008 } else {
9009 return StaticWarningCode.NEW_WITH_INVALID_TYPE_PARAMETERS;
9010 }
9011 }
9012 }
9013 return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
9014 }
9015
9016 /**
9017 * Checks if the given type name is the target in a redirected constructor.
9018 *
9019 * @param typeName the type name to analyze
9020 * @return some [RedirectingConstructorKind] if the given type name is used as the type in a
9021 * redirected constructor, or `null` otherwise
9022 */
9023 RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
9024 AstNode parent = typeName.parent;
9025 if (parent is ConstructorName) {
9026 AstNode grandParent = parent.parent;
9027 if (grandParent is ConstructorDeclaration) {
9028 if (identical(grandParent.redirectedConstructor, parent)) {
9029 if (grandParent.constKeyword != null) {
9030 return RedirectingConstructorKind.CONST;
9031 }
9032 return RedirectingConstructorKind.NORMAL;
9033 }
9034 }
9035 }
9036 return null;
9037 }
9038
9039 /**
9040 * Return the type represented by the given type name.
9041 *
9042 * @param typeName the type name representing the type to be returned
9043 * @return the type represented by the type name
9044 */
9045 DartType _getType(TypeName typeName) {
9046 DartType type = typeName.type;
9047 if (type == null) {
9048 return undefinedType;
9049 }
9050 return type;
9051 }
9052
9053 /**
9054 * Returns the simple identifier of the given (may be qualified) type name.
9055 *
9056 * @param typeName the (may be qualified) qualified type name
9057 * @return the simple identifier of the given (may be qualified) type name.
9058 */
9059 SimpleIdentifier _getTypeSimpleIdentifier(Identifier typeName) {
9060 if (typeName is SimpleIdentifier) {
9061 return typeName;
9062 } else {
9063 return (typeName as PrefixedIdentifier).identifier;
9064 }
9065 }
9066
9067 /**
9068 * Given the multiple elements to which a single name could potentially be res olved, return the
9069 * single interface type that should be used, or `null` if there is no clear c hoice.
9070 *
9071 * @param elements the elements to which a single name could potentially be re solved
9072 * @return the single interface type that should be used for the type name
9073 */
9074 InterfaceType _getTypeWhenMultiplyDefined(List<Element> elements) {
9075 InterfaceType type = null;
9076 int length = elements.length;
9077 for (int i = 0; i < length; i++) {
9078 Element element = elements[i];
9079 if (element is ClassElement) {
9080 if (type != null) {
9081 return null;
9082 }
9083 type = element.type;
9084 }
9085 }
9086 return type;
9087 }
9088
9089 /**
9090 * Checks if the given type name is used as the type in an as expression.
9091 *
9092 * @param typeName the type name to analyzer
9093 * @return `true` if the given type name is used as the type in an as expressi on
9094 */
9095 bool _isTypeNameInAsExpression(TypeName typeName) {
9096 AstNode parent = typeName.parent;
9097 if (parent is AsExpression) {
9098 return identical(parent.type, typeName);
9099 }
9100 return false;
9101 }
9102
9103 /**
9104 * Checks if the given type name is used as the exception type in a catch clau se.
9105 *
9106 * @param typeName the type name to analyzer
9107 * @return `true` if the given type name is used as the exception type in a ca tch clause
9108 */
9109 bool _isTypeNameInCatchClause(TypeName typeName) {
9110 AstNode parent = typeName.parent;
9111 if (parent is CatchClause) {
9112 return identical(parent.exceptionType, typeName);
9113 }
9114 return false;
9115 }
9116
9117 /**
9118 * Checks if the given type name is used as the type in an instance creation e xpression.
9119 *
9120 * @param typeName the type name to analyzer
9121 * @return `true` if the given type name is used as the type in an instance cr eation
9122 * expression
9123 */
9124 bool _isTypeNameInInstanceCreationExpression(TypeName typeName) {
9125 AstNode parent = typeName.parent;
9126 if (parent is ConstructorName &&
9127 parent.parent is InstanceCreationExpression) {
9128 return parent != null && identical(parent.type, typeName);
9129 }
9130 return false;
9131 }
9132
9133 /**
9134 * Checks if the given type name is used as the type in an is expression.
9135 *
9136 * @param typeName the type name to analyzer
9137 * @return `true` if the given type name is used as the type in an is expressi on
9138 */
9139 bool _isTypeNameInIsExpression(TypeName typeName) {
9140 AstNode parent = typeName.parent;
9141 if (parent is IsExpression) {
9142 return identical(parent.type, typeName);
9143 }
9144 return false;
9145 }
9146
9147 /**
9148 * Checks if the given type name used in a type argument list.
9149 *
9150 * @param typeName the type name to analyzer
9151 * @return `true` if the given type name is in a type argument list
9152 */
9153 bool _isTypeNameInTypeArgumentList(TypeName typeName) =>
9154 typeName.parent is TypeArgumentList;
9155
9156 /**
9157 * Records the new Element for a TypeName's Identifier.
9158 *
9159 * A null may be passed in to indicate that the element can't be resolved.
9160 * (During a re-run of a task, it's important to clear any previous value
9161 * of the element.)
9162 */
9163 void _setElement(Identifier typeName, Element element) {
9164 if (typeName is SimpleIdentifier) {
9165 typeName.staticElement = element;
9166 } else if (typeName is PrefixedIdentifier) {
9167 typeName.identifier.staticElement = element;
9168 SimpleIdentifier prefix = typeName.prefix;
9169 prefix.staticElement = nameScope.lookup(prefix, definingLibrary);
9170 }
9171 }
9172
9173 /**
9174 * @return `true` if the name of the given [TypeName] is an built-in identifie r.
9175 */
9176 static bool _isBuiltInIdentifier(TypeName node) {
9177 Token token = node.name.beginToken;
9178 return token.type == TokenType.KEYWORD;
9179 }
9180
9181 /**
9182 * @return `true` if given [TypeName] is used as a type annotation.
9183 */
9184 static bool _isTypeAnnotation(TypeName node) {
9185 AstNode parent = node.parent;
9186 if (parent is VariableDeclarationList) {
9187 return identical(parent.type, node);
9188 } else if (parent is FieldFormalParameter) {
9189 return identical(parent.type, node);
9190 } else if (parent is SimpleFormalParameter) {
9191 return identical(parent.type, node);
9192 }
9193 return false;
9194 }
9195 }
9196
13253 /** 9197 /**
13254 * Instances of the class `TypeOverrideManager` manage the ability to override t he type of an 9198 * Instances of the class `TypeOverrideManager` manage the ability to override t he type of an
13255 * element within a given context. 9199 * element within a given context.
13256 */ 9200 */
13257 class TypeOverrideManager { 9201 class TypeOverrideManager {
13258 /** 9202 /**
13259 * The current override scope, or `null` if no scope has been entered. 9203 * The current override scope, or `null` if no scope has been entered.
13260 */ 9204 */
13261 TypeOverrideManager_TypeOverrideScope currentScope; 9205 TypeOverrideManager_TypeOverrideScope currentScope;
13262 9206
13263 /** 9207 /**
13264 * Apply a set of overrides that were previously captured. 9208 * Apply a set of overrides that were previously captured.
13265 * 9209 *
13266 * @param overrides the overrides to be applied 9210 * @param overrides the overrides to be applied
13267 */ 9211 */
13268 void applyOverrides(Map<VariableElement, DartType> overrides) { 9212 void applyOverrides(Map<VariableElement, DartType> overrides) {
13269 if (currentScope == null) { 9213 if (currentScope == null) {
13270 throw new IllegalStateException("Cannot apply overrides without a scope"); 9214 throw new StateError("Cannot apply overrides without a scope");
13271 } 9215 }
13272 currentScope.applyOverrides(overrides); 9216 currentScope.applyOverrides(overrides);
13273 } 9217 }
13274 9218
13275 /** 9219 /**
13276 * Return a table mapping the elements whose type is overridden in the current scope to the 9220 * Return a table mapping the elements whose type is overridden in the current scope to the
13277 * overriding type. 9221 * overriding type.
13278 * 9222 *
13279 * @return the overrides in the current scope 9223 * @return the overrides in the current scope
13280 */ 9224 */
13281 Map<VariableElement, DartType> captureLocalOverrides() { 9225 Map<VariableElement, DartType> captureLocalOverrides() {
13282 if (currentScope == null) { 9226 if (currentScope == null) {
13283 throw new IllegalStateException( 9227 throw new StateError("Cannot capture local overrides without a scope");
13284 "Cannot capture local overrides without a scope");
13285 } 9228 }
13286 return currentScope.captureLocalOverrides(); 9229 return currentScope.captureLocalOverrides();
13287 } 9230 }
13288 9231
13289 /** 9232 /**
13290 * Return a map from the elements for the variables in the given list that hav e their types 9233 * Return a map from the elements for the variables in the given list that hav e their types
13291 * overridden to the overriding type. 9234 * overridden to the overriding type.
13292 * 9235 *
13293 * @param variableList the list of variables whose overriding types are to be captured 9236 * @param variableList the list of variables whose overriding types are to be captured
13294 * @return a table mapping elements to their overriding types 9237 * @return a table mapping elements to their overriding types
13295 */ 9238 */
13296 Map<VariableElement, DartType> captureOverrides( 9239 Map<VariableElement, DartType> captureOverrides(
13297 VariableDeclarationList variableList) { 9240 VariableDeclarationList variableList) {
13298 if (currentScope == null) { 9241 if (currentScope == null) {
13299 throw new IllegalStateException( 9242 throw new StateError("Cannot capture overrides without a scope");
13300 "Cannot capture overrides without a scope");
13301 } 9243 }
13302 return currentScope.captureOverrides(variableList); 9244 return currentScope.captureOverrides(variableList);
13303 } 9245 }
13304 9246
13305 /** 9247 /**
13306 * Enter a new override scope. 9248 * Enter a new override scope.
13307 */ 9249 */
13308 void enterScope() { 9250 void enterScope() {
13309 currentScope = new TypeOverrideManager_TypeOverrideScope(currentScope); 9251 currentScope = new TypeOverrideManager_TypeOverrideScope(currentScope);
13310 } 9252 }
13311 9253
13312 /** 9254 /**
13313 * Exit the current override scope. 9255 * Exit the current override scope.
13314 */ 9256 */
13315 void exitScope() { 9257 void exitScope() {
13316 if (currentScope == null) { 9258 if (currentScope == null) {
13317 throw new IllegalStateException("No scope to exit"); 9259 throw new StateError("No scope to exit");
13318 } 9260 }
13319 currentScope = currentScope._outerScope; 9261 currentScope = currentScope._outerScope;
13320 } 9262 }
13321 9263
13322 /** 9264 /**
13323 * Return the best type information available for the given element. If the ty pe of the element 9265 * Return the best type information available for the given element. If the ty pe of the element
13324 * has been overridden, then return the overriding type. Otherwise, return the static type. 9266 * has been overridden, then return the overriding type. Otherwise, return the static type.
13325 * 9267 *
13326 * @param element the element for which type information is to be returned 9268 * @param element the element for which type information is to be returned
13327 * @return the best type information available for the given element 9269 * @return the best type information available for the given element
13328 */ 9270 */
13329 DartType getBestType(VariableElement element) { 9271 DartType getBestType(VariableElement element) {
13330 DartType bestType = getType(element); 9272 DartType bestType = getType(element);
13331 return bestType == null ? element.type : bestType; 9273 return bestType ?? element.type;
13332 } 9274 }
13333 9275
13334 /** 9276 /**
13335 * Return the overridden type of the given element, or `null` if the type of t he element has 9277 * Return the overridden type of the given element, or `null` if the type of t he element has
13336 * not been overridden. 9278 * not been overridden.
13337 * 9279 *
13338 * @param element the element whose type might have been overridden 9280 * @param element the element whose type might have been overridden
13339 * @return the overridden type of the given element 9281 * @return the overridden type of the given element
13340 */ 9282 */
13341 DartType getType(Element element) { 9283 DartType getType(Element element) {
13342 if (currentScope == null) { 9284 if (currentScope == null) {
13343 return null; 9285 return null;
13344 } 9286 }
13345 return currentScope.getType(element); 9287 return currentScope.getType(element);
13346 } 9288 }
13347 9289
13348 /** 9290 /**
13349 * Update overrides assuming [perBranchOverrides] is the collection of 9291 * Update overrides assuming [perBranchOverrides] is the collection of
13350 * per-branch overrides for *all* branches flowing into a join point. 9292 * per-branch overrides for *all* branches flowing into a join point.
13351 * 9293 *
13352 * If a variable type in any of branches is not the same as its type before 9294 * If a variable type in any of branches is not the same as its type before
13353 * the branching, then its propagated type is reset to `null`. 9295 * the branching, then its propagated type is reset to `null`.
13354 */ 9296 */
13355 void mergeOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) { 9297 void mergeOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) {
13356 for (Map<VariableElement, DartType> branch in perBranchOverrides) { 9298 int length = perBranchOverrides.length;
9299 for (int i = 0; i < length; i++) {
9300 Map<VariableElement, DartType> branch = perBranchOverrides[i];
13357 branch.forEach((VariableElement variable, DartType branchType) { 9301 branch.forEach((VariableElement variable, DartType branchType) {
13358 DartType currentType = currentScope.getType(variable); 9302 DartType currentType = currentScope.getType(variable);
13359 if (currentType != branchType) { 9303 if (currentType != branchType) {
13360 currentScope.resetType(variable); 9304 currentScope.resetType(variable);
13361 } 9305 }
13362 }); 9306 });
13363 } 9307 }
13364 } 9308 }
13365 9309
13366 /** 9310 /**
13367 * Set the overridden type of the given element to the given type 9311 * Set the overridden type of the given element to the given type
13368 * 9312 *
13369 * @param element the element whose type might have been overridden 9313 * @param element the element whose type might have been overridden
13370 * @param type the overridden type of the given element 9314 * @param type the overridden type of the given element
13371 */ 9315 */
13372 void setType(VariableElement element, DartType type) { 9316 void setType(VariableElement element, DartType type) {
13373 if (currentScope == null) { 9317 if (currentScope == null) {
13374 throw new IllegalStateException("Cannot override without a scope"); 9318 throw new StateError("Cannot override without a scope");
13375 } 9319 }
13376 currentScope.setType(element, type); 9320 currentScope.setType(element, type);
13377 } 9321 }
13378 } 9322 }
13379 9323
13380 /** 9324 /**
13381 * Instances of the class `TypeOverrideScope` represent a scope in which the typ es of 9325 * Instances of the class `TypeOverrideScope` represent a scope in which the typ es of
13382 * elements can be overridden. 9326 * elements can be overridden.
13383 */ 9327 */
13384 class TypeOverrideManager_TypeOverrideScope { 9328 class TypeOverrideManager_TypeOverrideScope {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
13443 } 9387 }
13444 9388
13445 /** 9389 /**
13446 * Return the overridden type of the given element, or `null` if the type of t he element 9390 * Return the overridden type of the given element, or `null` if the type of t he element
13447 * has not been overridden. 9391 * has not been overridden.
13448 * 9392 *
13449 * @param element the element whose type might have been overridden 9393 * @param element the element whose type might have been overridden
13450 * @return the overridden type of the given element 9394 * @return the overridden type of the given element
13451 */ 9395 */
13452 DartType getType(Element element) { 9396 DartType getType(Element element) {
13453 if (element is PropertyAccessorElement) { 9397 Element nonAccessor =
13454 element = (element as PropertyAccessorElement).variable; 9398 element is PropertyAccessorElement ? element.variable : element;
13455 } 9399 DartType type = _overridenTypes[nonAccessor];
13456 DartType type = _overridenTypes[element]; 9400 if (_overridenTypes.containsKey(nonAccessor)) {
13457 if (_overridenTypes.containsKey(element)) {
13458 return type; 9401 return type;
13459 } 9402 }
13460 if (type != null) { 9403 return type ?? _outerScope?.getType(element);
13461 return type;
13462 } else if (_outerScope != null) {
13463 return _outerScope.getType(element);
13464 }
13465 return null;
13466 } 9404 }
13467 9405
13468 /** 9406 /**
13469 * Clears the overridden type of the given [element]. 9407 * Clears the overridden type of the given [element].
13470 */ 9408 */
13471 void resetType(VariableElement element) { 9409 void resetType(VariableElement element) {
13472 _overridenTypes[element] = null; 9410 _overridenTypes[element] = null;
13473 } 9411 }
13474 9412
13475 /** 9413 /**
13476 * Set the overridden type of the given element to the given type 9414 * Set the overridden type of the given element to the given type
13477 * 9415 *
13478 * @param element the element whose type might have been overridden 9416 * @param element the element whose type might have been overridden
13479 * @param type the overridden type of the given element 9417 * @param type the overridden type of the given element
13480 */ 9418 */
13481 void setType(VariableElement element, DartType type) { 9419 void setType(VariableElement element, DartType type) {
13482 _overridenTypes[element] = type; 9420 _overridenTypes[element] = type;
13483 } 9421 }
13484 } 9422 }
13485 9423
13486 /** 9424 /**
13487 * Instances of the class `TypeParameterScope` implement the scope defined by th e type 9425 * This class resolves bounds of type parameters of classes, class and function
13488 * parameters in a class. 9426 * type aliases.
13489 */ 9427 */
13490 class TypeParameterScope extends EnclosedScope { 9428 class TypeParameterBoundsResolver {
9429 final TypeProvider typeProvider;
9430 final LibraryElement library;
9431 final Source source;
9432 final AnalysisErrorListener errorListener;
9433
9434 Scope libraryScope = null;
9435 TypeNameResolver typeNameResolver = null;
9436
9437 TypeParameterBoundsResolver(
9438 this.typeProvider, this.library, this.source, this.errorListener);
9439
13491 /** 9440 /**
13492 * Initialize a newly created scope enclosed within another scope. 9441 * Resolve bounds of type parameters of classes, class and function type
13493 * 9442 * aliases.
13494 * @param enclosingScope the scope in which this scope is lexically enclosed
13495 * @param typeElement the element representing the type represented by this sc ope
13496 */ 9443 */
13497 TypeParameterScope(Scope enclosingScope, ClassElement typeElement) 9444 void resolveTypeBounds(CompilationUnit unit) {
13498 : super(enclosingScope) { 9445 for (CompilationUnitMember unitMember in unit.declarations) {
13499 if (typeElement == null) { 9446 if (unitMember is ClassDeclaration) {
13500 throw new IllegalArgumentException("class element cannot be null"); 9447 _resolveTypeParameters(unitMember.typeParameters,
9448 () => new TypeParameterScope(libraryScope, unitMember.element));
9449 } else if (unitMember is ClassTypeAlias) {
9450 _resolveTypeParameters(unitMember.typeParameters,
9451 () => new TypeParameterScope(libraryScope, unitMember.element));
9452 } else if (unitMember is FunctionTypeAlias) {
9453 _resolveTypeParameters(unitMember.typeParameters,
9454 () => new FunctionTypeScope(libraryScope, unitMember.element));
9455 }
13501 } 9456 }
13502 _defineTypeParameters(typeElement);
13503 } 9457 }
13504 9458
13505 /** 9459 void _resolveTypeName(TypeName typeName) {
13506 * Define the type parameters for the class. 9460 typeName.typeArguments?.arguments?.forEach(_resolveTypeName);
13507 * 9461 typeNameResolver.resolveTypeName(typeName);
13508 * @param typeElement the element representing the type represented by this sc ope 9462 // TODO(scheglov) report error when don't apply type bounds for type bounds
13509 */ 9463 }
13510 void _defineTypeParameters(ClassElement typeElement) { 9464
13511 for (TypeParameterElement typeParameter in typeElement.typeParameters) { 9465 void _resolveTypeParameters(
13512 define(typeParameter); 9466 TypeParameterList typeParameters, Scope createTypeParametersScope()) {
9467 if (typeParameters != null) {
9468 Scope typeParametersScope = null;
9469 for (TypeParameter typeParameter in typeParameters.typeParameters) {
9470 TypeName bound = typeParameter.bound;
9471 if (bound != null) {
9472 Element typeParameterElement = typeParameter.name.staticElement;
9473 if (typeParameterElement is TypeParameterElementImpl) {
9474 if (LibraryElementImpl.hasResolutionCapability(
9475 library, LibraryResolutionCapability.resolvedTypeNames)) {
9476 bound.type = typeParameterElement.bound;
9477 } else {
9478 libraryScope ??= new LibraryScope(library);
9479 typeParametersScope ??= createTypeParametersScope();
9480 typeNameResolver ??= new TypeNameResolver(new TypeSystemImpl(),
9481 typeProvider, library, source, errorListener);
9482 typeNameResolver.nameScope = typeParametersScope;
9483 _resolveTypeName(bound);
9484 typeParameterElement.bound = bound.type;
9485 }
9486 }
9487 }
9488 }
13513 } 9489 }
13514 } 9490 }
13515 } 9491 }
13516 9492
13517 /** 9493 /**
13518 * Instances of the class `TypePromotionManager` manage the ability to promote t ypes of local 9494 * Instances of the class `TypePromotionManager` manage the ability to promote t ypes of local
13519 * variables and formal parameters from their declared types based on control fl ow. 9495 * variables and formal parameters from their declared types based on control fl ow.
13520 */ 9496 */
13521 class TypePromotionManager { 9497 class TypePromotionManager {
13522 /** 9498 /**
(...skipping 11 matching lines...) Expand all
13534 */ 9510 */
13535 void enterScope() { 9511 void enterScope() {
13536 currentScope = new TypePromotionManager_TypePromoteScope(currentScope); 9512 currentScope = new TypePromotionManager_TypePromoteScope(currentScope);
13537 } 9513 }
13538 9514
13539 /** 9515 /**
13540 * Exit the current promotion scope. 9516 * Exit the current promotion scope.
13541 */ 9517 */
13542 void exitScope() { 9518 void exitScope() {
13543 if (currentScope == null) { 9519 if (currentScope == null) {
13544 throw new IllegalStateException("No scope to exit"); 9520 throw new StateError("No scope to exit");
13545 } 9521 }
13546 currentScope = currentScope._outerScope; 9522 currentScope = currentScope._outerScope;
13547 } 9523 }
13548 9524
13549 /** 9525 /**
13550 * Returns static type of the given variable - declared or promoted. 9526 * Return the static type of the given [variable] - declared or promoted.
13551 *
13552 * @return the static type of the given variable - declared or promoted
13553 */ 9527 */
13554 DartType getStaticType(VariableElement variable) { 9528 DartType getStaticType(VariableElement variable) =>
13555 DartType staticType = getType(variable); 9529 getType(variable) ?? variable.type;
13556 if (staticType == null) {
13557 staticType = variable.type;
13558 }
13559 return staticType;
13560 }
13561 9530
13562 /** 9531 /**
13563 * Return the promoted type of the given element, or `null` if the type of the element has 9532 * Return the promoted type of the given [element], or `null` if the type of
13564 * not been promoted. 9533 * the element has not been promoted.
13565 *
13566 * @param element the element whose type might have been promoted
13567 * @return the promoted type of the given element
13568 */ 9534 */
13569 DartType getType(Element element) { 9535 DartType getType(Element element) => currentScope?.getType(element);
13570 if (currentScope == null) {
13571 return null;
13572 }
13573 return currentScope.getType(element);
13574 }
13575 9536
13576 /** 9537 /**
13577 * Set the promoted type of the given element to the given type. 9538 * Set the promoted type of the given element to the given type.
13578 * 9539 *
13579 * @param element the element whose type might have been promoted 9540 * @param element the element whose type might have been promoted
13580 * @param type the promoted type of the given element 9541 * @param type the promoted type of the given element
13581 */ 9542 */
13582 void setType(Element element, DartType type) { 9543 void setType(Element element, DartType type) {
13583 if (currentScope == null) { 9544 if (currentScope == null) {
13584 throw new IllegalStateException("Cannot promote without a scope"); 9545 throw new StateError("Cannot promote without a scope");
13585 } 9546 }
13586 currentScope.setType(element, type); 9547 currentScope.setType(element, type);
13587 } 9548 }
13588 } 9549 }
13589 9550
13590 /** 9551 /**
13591 * Instances of the class `TypePromoteScope` represent a scope in which the type s of 9552 * Instances of the class `TypePromoteScope` represent a scope in which the type s of
13592 * elements can be promoted. 9553 * elements can be promoted.
13593 */ 9554 */
13594 class TypePromotionManager_TypePromoteScope { 9555 class TypePromotionManager_TypePromoteScope {
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
13773 9734
13774 /** 9735 /**
13775 * Return the type representing the built-in type 'Type'. 9736 * Return the type representing the built-in type 'Type'.
13776 */ 9737 */
13777 InterfaceType get typeType; 9738 InterfaceType get typeType;
13778 9739
13779 /** 9740 /**
13780 * Return the type representing typenames that can't be resolved. 9741 * Return the type representing typenames that can't be resolved.
13781 */ 9742 */
13782 DartType get undefinedType; 9743 DartType get undefinedType;
9744
9745 /**
9746 * Return 'true' if [id] is the name of a getter on
9747 * the Object type.
9748 */
9749 bool isObjectGetter(String id);
9750
9751 /**
9752 * Return 'true' if [id] is the name of a method or getter on
9753 * the Object type.
9754 */
9755 bool isObjectMember(String id);
9756
9757 /**
9758 * Return 'true' if [id] is the name of a method on
9759 * the Object type.
9760 */
9761 bool isObjectMethod(String id);
9762 }
9763
9764 /**
9765 * Provide common functionality shared by the various TypeProvider
9766 * implementations.
9767 */
9768 abstract class TypeProviderBase implements TypeProvider {
9769 @override
9770 List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
9771 nullType,
9772 numType,
9773 intType,
9774 doubleType,
9775 boolType,
9776 stringType
9777 ];
9778
9779 @override
9780 bool isObjectGetter(String id) {
9781 PropertyAccessorElement element = objectType.element.getGetter(id);
9782 return (element != null && !element.isStatic);
9783 }
9784
9785 @override
9786 bool isObjectMember(String id) {
9787 return isObjectGetter(id) || isObjectMethod(id);
9788 }
9789
9790 @override
9791 bool isObjectMethod(String id) {
9792 MethodElement element = objectType.element.getMethod(id);
9793 return (element != null && !element.isStatic);
9794 }
13783 } 9795 }
13784 9796
13785 /** 9797 /**
13786 * Instances of the class `TypeProviderImpl` provide access to types defined by the language 9798 * Instances of the class `TypeProviderImpl` provide access to types defined by the language
13787 * by looking for those types in the element model for the core library. 9799 * by looking for those types in the element model for the core library.
13788 */ 9800 */
13789 class TypeProviderImpl implements TypeProvider { 9801 class TypeProviderImpl extends TypeProviderBase {
13790 /** 9802 /**
13791 * The type representing the built-in type 'bool'. 9803 * The type representing the built-in type 'bool'.
13792 */ 9804 */
13793 InterfaceType _boolType; 9805 InterfaceType _boolType;
13794 9806
13795 /** 9807 /**
13796 * The type representing the type 'bottom'. 9808 * The type representing the type 'bottom'.
13797 */ 9809 */
13798 DartType _bottomType; 9810 DartType _bottomType;
13799 9811
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
13902 */ 9914 */
13903 InterfaceType _symbolType; 9915 InterfaceType _symbolType;
13904 9916
13905 /** 9917 /**
13906 * The type representing the built-in type 'Type'. 9918 * The type representing the built-in type 'Type'.
13907 */ 9919 */
13908 InterfaceType _typeType; 9920 InterfaceType _typeType;
13909 9921
13910 /** 9922 /**
13911 * The type representing typenames that can't be resolved. 9923 * The type representing typenames that can't be resolved.
13912 */
13913 DartType _undefinedType;
13914
13915 /**
13916 * Initialize a newly created type provider to provide the types defined in
13917 * the given [coreLibrary] and [asyncLibrary].
13918 */
13919 TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) {
13920 Namespace coreNamespace =
13921 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary);
13922 Namespace asyncNamespace =
13923 new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary);
13924 _initializeFrom(coreNamespace, asyncNamespace);
13925 }
13926
13927 /**
13928 * Initialize a newly created type provider to provide the types defined in
13929 * the given [Namespace]s.
13930 */
13931 TypeProviderImpl.forNamespaces(
13932 Namespace coreNamespace, Namespace asyncNamespace) {
13933 _initializeFrom(coreNamespace, asyncNamespace);
13934 }
13935
13936 @override
13937 InterfaceType get boolType => _boolType;
13938
13939 @override
13940 DartType get bottomType => _bottomType;
13941
13942 @override
13943 InterfaceType get deprecatedType => _deprecatedType;
13944
13945 @override
13946 InterfaceType get doubleType => _doubleType;
13947
13948 @override
13949 DartType get dynamicType => _dynamicType;
13950
13951 @override
13952 InterfaceType get functionType => _functionType;
13953
13954 @override
13955 InterfaceType get futureDynamicType => _futureDynamicType;
13956
13957 @override
13958 InterfaceType get futureNullType => _futureNullType;
13959
13960 @override
13961 InterfaceType get futureType => _futureType;
13962
13963 @override
13964 InterfaceType get intType => _intType;
13965
13966 @override
13967 InterfaceType get iterableDynamicType => _iterableDynamicType;
13968
13969 @override
13970 InterfaceType get iterableType => _iterableType;
13971
13972 @override
13973 InterfaceType get listType => _listType;
13974
13975 @override
13976 InterfaceType get mapType => _mapType;
13977
13978 @override
13979 List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
13980 nullType,
13981 numType,
13982 intType,
13983 doubleType,
13984 boolType,
13985 stringType
13986 ];
13987
13988 @override
13989 DartObjectImpl get nullObject {
13990 if (_nullObject == null) {
13991 _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
13992 }
13993 return _nullObject;
13994 }
13995
13996 @override
13997 InterfaceType get nullType => _nullType;
13998
13999 @override
14000 InterfaceType get numType => _numType;
14001
14002 @override
14003 InterfaceType get objectType => _objectType;
14004
14005 @override
14006 InterfaceType get stackTraceType => _stackTraceType;
14007
14008 @override
14009 InterfaceType get streamDynamicType => _streamDynamicType;
14010
14011 @override
14012 InterfaceType get streamType => _streamType;
14013
14014 @override
14015 InterfaceType get stringType => _stringType;
14016
14017 @override
14018 InterfaceType get symbolType => _symbolType;
14019
14020 @override
14021 InterfaceType get typeType => _typeType;
14022
14023 @override
14024 DartType get undefinedType => _undefinedType;
14025
14026 /**
14027 * Return the type with the given name from the given namespace, or `null` if there is no
14028 * class with the given name.
14029 *
14030 * @param namespace the namespace in which to search for the given name
14031 * @param typeName the name of the type being searched for
14032 * @return the type that was found
14033 */
14034 InterfaceType _getType(Namespace namespace, String typeName) {
14035 Element element = namespace.get(typeName);
14036 if (element == null) {
14037 AnalysisEngine.instance.logger
14038 .logInformation("No definition of type $typeName");
14039 return null;
14040 }
14041 return (element as ClassElement).type;
14042 }
14043
14044 /**
14045 * Initialize the types provided by this type provider from the given
14046 * [Namespace]s.
14047 */
14048 void _initializeFrom(Namespace coreNamespace, Namespace asyncNamespace) {
14049 _boolType = _getType(coreNamespace, "bool");
14050 _bottomType = BottomTypeImpl.instance;
14051 _deprecatedType = _getType(coreNamespace, "Deprecated");
14052 _doubleType = _getType(coreNamespace, "double");
14053 _dynamicType = DynamicTypeImpl.instance;
14054 _functionType = _getType(coreNamespace, "Function");
14055 _futureType = _getType(asyncNamespace, "Future");
14056 _intType = _getType(coreNamespace, "int");
14057 _iterableType = _getType(coreNamespace, "Iterable");
14058 _listType = _getType(coreNamespace, "List");
14059 _mapType = _getType(coreNamespace, "Map");
14060 _nullType = _getType(coreNamespace, "Null");
14061 _numType = _getType(coreNamespace, "num");
14062 _objectType = _getType(coreNamespace, "Object");
14063 _stackTraceType = _getType(coreNamespace, "StackTrace");
14064 _streamType = _getType(asyncNamespace, "Stream");
14065 _stringType = _getType(coreNamespace, "String");
14066 _symbolType = _getType(coreNamespace, "Symbol");
14067 _typeType = _getType(coreNamespace, "Type");
14068 _undefinedType = UndefinedTypeImpl.instance;
14069 _futureDynamicType = _futureType.substitute4(<DartType>[_dynamicType]);
14070 _futureNullType = _futureType.substitute4(<DartType>[_nullType]);
14071 _iterableDynamicType = _iterableType.substitute4(<DartType>[_dynamicType]);
14072 _streamDynamicType = _streamType.substitute4(<DartType>[_dynamicType]);
14073 }
14074 }
14075
14076 /**
14077 * Instances of the class `TypeResolverVisitor` are used to resolve the types as sociated with
14078 * the elements in the element model. This includes the types of superclasses, m ixins, interfaces,
14079 * fields, methods, parameters, and local variables. As a side-effect, this also finishes building
14080 * the type hierarchy.
14081 */
14082 class TypeResolverVisitor extends ScopedVisitor {
14083 /**
14084 * The type representing the type 'dynamic'.
14085 */
14086 DartType _dynamicType;
14087
14088 /**
14089 * The type representing typenames that can't be resolved.
14090 */ 9924 */
14091 DartType _undefinedType; 9925 DartType _undefinedType;
14092 9926
14093 /** 9927 /**
9928 * Initialize a newly created type provider to provide the types defined in
9929 * the given [coreLibrary] and [asyncLibrary].
9930 */
9931 TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) {
9932 Namespace coreNamespace =
9933 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary);
9934 Namespace asyncNamespace =
9935 new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary);
9936 _initializeFrom(coreNamespace, asyncNamespace);
9937 }
9938
9939 /**
9940 * Initialize a newly created type provider to provide the types defined in
9941 * the given [Namespace]s.
9942 */
9943 TypeProviderImpl.forNamespaces(
9944 Namespace coreNamespace, Namespace asyncNamespace) {
9945 _initializeFrom(coreNamespace, asyncNamespace);
9946 }
9947
9948 @override
9949 InterfaceType get boolType => _boolType;
9950
9951 @override
9952 DartType get bottomType => _bottomType;
9953
9954 @override
9955 InterfaceType get deprecatedType => _deprecatedType;
9956
9957 @override
9958 InterfaceType get doubleType => _doubleType;
9959
9960 @override
9961 DartType get dynamicType => _dynamicType;
9962
9963 @override
9964 InterfaceType get functionType => _functionType;
9965
9966 @override
9967 InterfaceType get futureDynamicType => _futureDynamicType;
9968
9969 @override
9970 InterfaceType get futureNullType => _futureNullType;
9971
9972 @override
9973 InterfaceType get futureType => _futureType;
9974
9975 @override
9976 InterfaceType get intType => _intType;
9977
9978 @override
9979 InterfaceType get iterableDynamicType => _iterableDynamicType;
9980
9981 @override
9982 InterfaceType get iterableType => _iterableType;
9983
9984 @override
9985 InterfaceType get listType => _listType;
9986
9987 @override
9988 InterfaceType get mapType => _mapType;
9989
9990 @override
9991 DartObjectImpl get nullObject {
9992 if (_nullObject == null) {
9993 _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
9994 }
9995 return _nullObject;
9996 }
9997
9998 @override
9999 InterfaceType get nullType => _nullType;
10000
10001 @override
10002 InterfaceType get numType => _numType;
10003
10004 @override
10005 InterfaceType get objectType => _objectType;
10006
10007 @override
10008 InterfaceType get stackTraceType => _stackTraceType;
10009
10010 @override
10011 InterfaceType get streamDynamicType => _streamDynamicType;
10012
10013 @override
10014 InterfaceType get streamType => _streamType;
10015
10016 @override
10017 InterfaceType get stringType => _stringType;
10018
10019 @override
10020 InterfaceType get symbolType => _symbolType;
10021
10022 @override
10023 InterfaceType get typeType => _typeType;
10024
10025 @override
10026 DartType get undefinedType => _undefinedType;
10027
10028 /**
10029 * Return the type with the given name from the given namespace, or `null` if there is no
10030 * class with the given name.
10031 *
10032 * @param namespace the namespace in which to search for the given name
10033 * @param typeName the name of the type being searched for
10034 * @return the type that was found
10035 */
10036 InterfaceType _getType(Namespace namespace, String typeName) {
10037 Element element = namespace.get(typeName);
10038 if (element == null) {
10039 AnalysisEngine.instance.logger
10040 .logInformation("No definition of type $typeName");
10041 return null;
10042 }
10043 return (element as ClassElement).type;
10044 }
10045
10046 /**
10047 * Initialize the types provided by this type provider from the given
10048 * [Namespace]s.
10049 */
10050 void _initializeFrom(Namespace coreNamespace, Namespace asyncNamespace) {
10051 _boolType = _getType(coreNamespace, "bool");
10052 _bottomType = BottomTypeImpl.instance;
10053 _deprecatedType = _getType(coreNamespace, "Deprecated");
10054 _doubleType = _getType(coreNamespace, "double");
10055 _dynamicType = DynamicTypeImpl.instance;
10056 _functionType = _getType(coreNamespace, "Function");
10057 _futureType = _getType(asyncNamespace, "Future");
10058 _intType = _getType(coreNamespace, "int");
10059 _iterableType = _getType(coreNamespace, "Iterable");
10060 _listType = _getType(coreNamespace, "List");
10061 _mapType = _getType(coreNamespace, "Map");
10062 _nullType = _getType(coreNamespace, "Null");
10063 _numType = _getType(coreNamespace, "num");
10064 _objectType = _getType(coreNamespace, "Object");
10065 _stackTraceType = _getType(coreNamespace, "StackTrace");
10066 _streamType = _getType(asyncNamespace, "Stream");
10067 _stringType = _getType(coreNamespace, "String");
10068 _symbolType = _getType(coreNamespace, "Symbol");
10069 _typeType = _getType(coreNamespace, "Type");
10070 _undefinedType = UndefinedTypeImpl.instance;
10071 _futureDynamicType = _futureType.instantiate(<DartType>[_dynamicType]);
10072 _futureNullType = _futureType.instantiate(<DartType>[_nullType]);
10073 _iterableDynamicType = _iterableType.instantiate(<DartType>[_dynamicType]);
10074 _streamDynamicType = _streamType.instantiate(<DartType>[_dynamicType]);
10075 }
10076 }
10077
10078 /**
10079 * Instances of the class `TypeResolverVisitor` are used to resolve the types as sociated with
10080 * the elements in the element model. This includes the types of superclasses, m ixins, interfaces,
10081 * fields, methods, parameters, and local variables. As a side-effect, this also finishes building
10082 * the type hierarchy.
10083 */
10084 class TypeResolverVisitor extends ScopedVisitor {
10085 /**
10086 * The type representing the type 'dynamic'.
10087 */
10088 DartType _dynamicType;
10089
10090 /**
10091 * The type representing typenames that can't be resolved.
10092 */
10093 DartType _undefinedType;
10094
10095 /**
14094 * The flag specifying if currently visited class references 'super' expressio n. 10096 * The flag specifying if currently visited class references 'super' expressio n.
14095 */ 10097 */
14096 bool _hasReferenceToSuper = false; 10098 bool _hasReferenceToSuper = false;
14097 10099
14098 /** 10100 /**
10101 * True if we're analyzing in strong mode.
10102 */
10103 bool _strongMode;
10104
10105 /**
10106 * Type type system in use for this resolver pass.
10107 */
10108 TypeSystem _typeSystem;
10109
10110 /**
10111 * The helper to resolve [TypeName]s.
10112 */
10113 TypeNameResolver _typeNameResolver;
10114
10115 /**
14099 * Initialize a newly created visitor to resolve the nodes in an AST node. 10116 * Initialize a newly created visitor to resolve the nodes in an AST node.
14100 * 10117 *
14101 * [definingLibrary] is the element for the library containing the node being 10118 * [definingLibrary] is the element for the library containing the node being
14102 * visited. 10119 * visited.
14103 * [source] is the source representing the compilation unit containing the 10120 * [source] is the source representing the compilation unit containing the
14104 * node being visited. 10121 * node being visited.
14105 * [typeProvider] is the object used to access the types from the core 10122 * [typeProvider] is the object used to access the types from the core
14106 * library. 10123 * library.
14107 * [errorListener] is the error listener that will be informed of any errors 10124 * [errorListener] is the error listener that will be informed of any errors
14108 * that are found during resolution. 10125 * that are found during resolution.
14109 * [nameScope] is the scope used to resolve identifiers in the node that will 10126 * [nameScope] is the scope used to resolve identifiers in the node that will
14110 * first be visited. If `null` or unspecified, a new [LibraryScope] will be 10127 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
14111 * created based on [definingLibrary] and [typeProvider]. 10128 * created based on [definingLibrary] and [typeProvider].
14112 */ 10129 */
14113 TypeResolverVisitor(LibraryElement definingLibrary, Source source, 10130 TypeResolverVisitor(LibraryElement definingLibrary, Source source,
14114 TypeProvider typeProvider, AnalysisErrorListener errorListener, 10131 TypeProvider typeProvider, AnalysisErrorListener errorListener,
14115 {Scope nameScope}) 10132 {Scope nameScope})
14116 : super(definingLibrary, source, typeProvider, errorListener, 10133 : super(definingLibrary, source, typeProvider, errorListener,
14117 nameScope: nameScope) { 10134 nameScope: nameScope) {
14118 _dynamicType = typeProvider.dynamicType; 10135 _dynamicType = typeProvider.dynamicType;
14119 _undefinedType = typeProvider.undefinedType; 10136 _undefinedType = typeProvider.undefinedType;
10137 _strongMode = definingLibrary.context.analysisOptions.strongMode;
10138 _typeSystem = TypeSystem.create(definingLibrary.context);
10139 _typeNameResolver = new TypeNameResolver(
10140 _typeSystem, typeProvider, definingLibrary, source, errorListener);
14120 } 10141 }
14121 10142
14122 @override 10143 @override
14123 Object visitAnnotation(Annotation node) { 10144 Object visitAnnotation(Annotation node) {
14124 // 10145 //
14125 // Visit annotations, if the annotation is @proxy, on a class, and "proxy" 10146 // Visit annotations, if the annotation is @proxy, on a class, and "proxy"
14126 // resolves to the proxy annotation in dart.core, then create create the 10147 // resolves to the proxy annotation in dart.core, then resolve the
14127 // ElementAnnotationImpl and set it as the metadata on the enclosing class. 10148 // ElementAnnotation.
14128 // 10149 //
14129 // Element resolution is done in the ElementResolver, and this work will be 10150 // Element resolution is done in the ElementResolver, and this work will be
14130 // done in the general case for all annotations in the ElementResolver. 10151 // done in the general case for all annotations in the ElementResolver.
14131 // The reason we resolve this particular element early is so that 10152 // The reason we resolve this particular element early is so that
14132 // ClassElement.isProxy() returns the correct information during all 10153 // ClassElement.isProxy() returns the correct information during all
14133 // phases of the ElementResolver. 10154 // phases of the ElementResolver.
14134 // 10155 //
14135 super.visitAnnotation(node); 10156 super.visitAnnotation(node);
14136 Identifier identifier = node.name; 10157 Identifier identifier = node.name;
14137 if (identifier.name.endsWith(ElementAnnotationImpl.PROXY_VARIABLE_NAME) && 10158 if (identifier.name.endsWith(ElementAnnotationImpl.PROXY_VARIABLE_NAME) &&
14138 node.parent is ClassDeclaration) { 10159 node.parent is ClassDeclaration) {
14139 Element element = nameScope.lookup(identifier, definingLibrary); 10160 Element element = nameScope.lookup(identifier, definingLibrary);
14140 if (element != null && 10161 if (element != null &&
14141 element.library.isDartCore && 10162 element.library.isDartCore &&
14142 element is PropertyAccessorElement) { 10163 element is PropertyAccessorElement) {
14143 // This is the @proxy from dart.core 10164 // This is the @proxy from dart.core
14144 ClassDeclaration classDeclaration = node.parent as ClassDeclaration; 10165 ElementAnnotationImpl elementAnnotation = node.elementAnnotation;
14145 ElementAnnotationImpl elementAnnotation = 10166 elementAnnotation.element = element;
14146 new ElementAnnotationImpl(element);
14147 node.elementAnnotation = elementAnnotation;
14148 (classDeclaration.element as ClassElementImpl).metadata =
14149 <ElementAnnotationImpl>[elementAnnotation];
14150 } 10167 }
14151 } 10168 }
14152 return null; 10169 return null;
14153 } 10170 }
14154 10171
14155 @override 10172 @override
14156 Object visitCatchClause(CatchClause node) { 10173 Object visitCatchClause(CatchClause node) {
14157 super.visitCatchClause(node); 10174 super.visitCatchClause(node);
14158 SimpleIdentifier exception = node.exceptionParameter; 10175 SimpleIdentifier exception = node.exceptionParameter;
14159 if (exception != null) { 10176 if (exception != null) {
14160 // If an 'on' clause is provided the type of the exception parameter is 10177 // If an 'on' clause is provided the type of the exception parameter is
14161 // the type in the 'on' clause. Otherwise, the type of the exception 10178 // the type in the 'on' clause. Otherwise, the type of the exception
14162 // parameter is 'Object'. 10179 // parameter is 'Object'.
14163 TypeName exceptionTypeName = node.exceptionType; 10180 TypeName exceptionTypeName = node.exceptionType;
14164 DartType exceptionType; 10181 DartType exceptionType;
14165 if (exceptionTypeName == null) { 10182 if (exceptionTypeName == null) {
14166 exceptionType = typeProvider.dynamicType; 10183 exceptionType = typeProvider.dynamicType;
14167 } else { 10184 } else {
14168 exceptionType = _getType(exceptionTypeName); 10185 exceptionType = _typeNameResolver._getType(exceptionTypeName);
14169 } 10186 }
14170 _recordType(exception, exceptionType); 10187 _recordType(exception, exceptionType);
14171 Element element = exception.staticElement; 10188 Element element = exception.staticElement;
14172 if (element is VariableElementImpl) { 10189 if (element is VariableElementImpl) {
14173 element.type = exceptionType; 10190 element.type = exceptionType;
14174 } else { 10191 } else {
14175 // TODO(brianwilkerson) Report the internal error 10192 // TODO(brianwilkerson) Report the internal error
14176 } 10193 }
14177 } 10194 }
14178 SimpleIdentifier stackTrace = node.stackTraceParameter; 10195 SimpleIdentifier stackTrace = node.stackTraceParameter;
14179 if (stackTrace != null) { 10196 if (stackTrace != null) {
14180 _recordType(stackTrace, typeProvider.stackTraceType); 10197 _recordType(stackTrace, typeProvider.stackTraceType);
14181 Element element = stackTrace.staticElement; 10198 Element element = stackTrace.staticElement;
14182 if (element is VariableElementImpl) { 10199 if (element is VariableElementImpl) {
14183 element.type = typeProvider.stackTraceType; 10200 element.type = typeProvider.stackTraceType;
14184 } else { 10201 } else {
14185 // TODO(brianwilkerson) Report the internal error 10202 // TODO(brianwilkerson) Report the internal error
14186 } 10203 }
14187 } 10204 }
14188 return null; 10205 return null;
14189 } 10206 }
14190 10207
14191 @override 10208 @override
14192 Object visitClassDeclaration(ClassDeclaration node) { 10209 Object visitClassDeclaration(ClassDeclaration node) {
14193 _hasReferenceToSuper = false; 10210 _hasReferenceToSuper = false;
14194 super.visitClassDeclaration(node); 10211 super.visitClassDeclaration(node);
14195 ClassElementImpl classElement = _getClassElement(node.name); 10212 ClassElementImpl classElement = _getClassElement(node.name);
14196 if (classElement != null) { 10213 if (classElement != null) {
10214 // Clear this flag, as we just invalidated any inferred member types.
10215 classElement.hasBeenInferred = false;
14197 classElement.hasReferenceToSuper = _hasReferenceToSuper; 10216 classElement.hasReferenceToSuper = _hasReferenceToSuper;
14198 } 10217 }
14199 return null; 10218 return null;
14200 } 10219 }
14201 10220
14202 @override 10221 @override
14203 void visitClassDeclarationInScope(ClassDeclaration node) { 10222 void visitClassDeclarationInScope(ClassDeclaration node) {
14204 super.visitClassDeclarationInScope(node); 10223 super.visitClassDeclarationInScope(node);
14205 ExtendsClause extendsClause = node.extendsClause; 10224 ExtendsClause extendsClause = node.extendsClause;
14206 WithClause withClause = node.withClause; 10225 WithClause withClause = node.withClause;
14207 ImplementsClause implementsClause = node.implementsClause; 10226 ImplementsClause implementsClause = node.implementsClause;
14208 ClassElementImpl classElement = _getClassElement(node.name); 10227 ClassElementImpl classElement = _getClassElement(node.name);
14209 InterfaceType superclassType = null; 10228 InterfaceType superclassType = null;
14210 if (extendsClause != null) { 10229 if (extendsClause != null) {
14211 ErrorCode errorCode = (withClause == null 10230 ErrorCode errorCode = (withClause == null
14212 ? CompileTimeErrorCode.EXTENDS_NON_CLASS 10231 ? CompileTimeErrorCode.EXTENDS_NON_CLASS
14213 : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS); 10232 : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
14214 superclassType = _resolveType(extendsClause.superclass, errorCode, 10233 superclassType = _resolveType(extendsClause.superclass, errorCode,
14215 CompileTimeErrorCode.EXTENDS_ENUM, errorCode); 10234 CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
14216 if (!identical(superclassType, typeProvider.objectType)) {
14217 classElement.validMixin = false;
14218 }
14219 } 10235 }
14220 if (classElement != null) { 10236 if (classElement != null) {
14221 if (superclassType == null) { 10237 if (superclassType == null) {
14222 InterfaceType objectType = typeProvider.objectType; 10238 InterfaceType objectType = typeProvider.objectType;
14223 if (!identical(classElement.type, objectType)) { 10239 if (!identical(classElement.type, objectType)) {
14224 superclassType = objectType; 10240 superclassType = objectType;
14225 } 10241 }
14226 } 10242 }
14227 classElement.supertype = superclassType; 10243 classElement.supertype = superclassType;
14228 } 10244 }
14229 _resolve(classElement, withClause, implementsClause); 10245 _resolve(classElement, withClause, implementsClause);
14230 return null; 10246 return null;
14231 } 10247 }
14232 10248
14233 @override 10249 @override
14234 void visitClassMembersInScope(ClassDeclaration node) { 10250 void visitClassMembersInScope(ClassDeclaration node) {
10251 node.documentationComment?.accept(this);
10252 node.metadata.accept(this);
14235 // 10253 //
14236 // Process field declarations before constructors and methods so that the 10254 // Process field declarations before constructors and methods so that the
14237 // types of field formal parameters can be correctly resolved. 10255 // types of field formal parameters can be correctly resolved.
14238 // 10256 //
14239 List<ClassMember> nonFields = new List<ClassMember>(); 10257 List<ClassMember> nonFields = new List<ClassMember>();
14240 node.visitChildren( 10258 NodeList<ClassMember> members = node.members;
14241 new _TypeResolverVisitor_visitClassMembersInScope(this, nonFields)); 10259 int length = members.length;
10260 for (int i = 0; i < length; i++) {
10261 ClassMember member = members[i];
10262 if (member is ConstructorDeclaration) {
10263 nonFields.add(member);
10264 } else {
10265 member.accept(this);
10266 }
10267 }
14242 int count = nonFields.length; 10268 int count = nonFields.length;
14243 for (int i = 0; i < count; i++) { 10269 for (int i = 0; i < count; i++) {
14244 nonFields[i].accept(this); 10270 nonFields[i].accept(this);
14245 } 10271 }
14246 } 10272 }
14247 10273
14248 @override 10274 @override
14249 Object visitClassTypeAlias(ClassTypeAlias node) { 10275 Object visitClassTypeAlias(ClassTypeAlias node) {
14250 super.visitClassTypeAlias(node); 10276 super.visitClassTypeAlias(node);
14251 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS; 10277 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
14252 InterfaceType superclassType = _resolveType(node.superclass, errorCode, 10278 InterfaceType superclassType = _resolveType(node.superclass, errorCode,
14253 CompileTimeErrorCode.EXTENDS_ENUM, errorCode); 10279 CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
14254 if (superclassType == null) { 10280 if (superclassType == null) {
14255 superclassType = typeProvider.objectType; 10281 superclassType = typeProvider.objectType;
14256 } 10282 }
14257 ClassElementImpl classElement = _getClassElement(node.name); 10283 ClassElementImpl classElement = _getClassElement(node.name);
14258 if (classElement != null) { 10284 if (classElement != null) {
14259 classElement.supertype = superclassType; 10285 classElement.supertype = superclassType;
14260 } 10286 }
14261 _resolve(classElement, node.withClause, node.implementsClause); 10287 _resolve(classElement, node.withClause, node.implementsClause);
14262 return null; 10288 return null;
14263 } 10289 }
14264 10290
14265 @override 10291 @override
14266 Object visitConstructorDeclaration(ConstructorDeclaration node) { 10292 Object visitConstructorDeclaration(ConstructorDeclaration node) {
14267 super.visitConstructorDeclaration(node); 10293 super.visitConstructorDeclaration(node);
14268 ExecutableElementImpl element = node.element as ExecutableElementImpl; 10294 if (node.element == null) {
14269 if (element == null) {
14270 ClassDeclaration classNode = 10295 ClassDeclaration classNode =
14271 node.getAncestor((node) => node is ClassDeclaration); 10296 node.getAncestor((node) => node is ClassDeclaration);
14272 StringBuffer buffer = new StringBuffer(); 10297 StringBuffer buffer = new StringBuffer();
14273 buffer.write("The element for the constructor "); 10298 buffer.write("The element for the constructor ");
14274 buffer.write(node.name == null ? "<unnamed>" : node.name.name); 10299 buffer.write(node.name == null ? "<unnamed>" : node.name.name);
14275 buffer.write(" in "); 10300 buffer.write(" in ");
14276 if (classNode == null) { 10301 if (classNode == null) {
14277 buffer.write("<unknown class>"); 10302 buffer.write("<unknown class>");
14278 } else { 10303 } else {
14279 buffer.write(classNode.name.name); 10304 buffer.write(classNode.name.name);
14280 } 10305 }
14281 buffer.write(" in "); 10306 buffer.write(" in ");
14282 buffer.write(source.fullName); 10307 buffer.write(source.fullName);
14283 buffer.write(" was not set while trying to resolve types."); 10308 buffer.write(" was not set while trying to resolve types.");
14284 AnalysisEngine.instance.logger.logError(buffer.toString(), 10309 AnalysisEngine.instance.logger.logError(buffer.toString(),
14285 new CaughtException(new AnalysisException(), null)); 10310 new CaughtException(new AnalysisException(), null));
14286 } else {
14287 ClassElement definingClass = element.enclosingElement as ClassElement;
14288 element.returnType = definingClass.type;
14289 FunctionTypeImpl type = new FunctionTypeImpl(element);
14290 type.typeArguments = definingClass.type.typeArguments;
14291 element.type = type;
14292 } 10311 }
14293 return null; 10312 return null;
14294 } 10313 }
14295 10314
14296 @override 10315 @override
14297 Object visitDeclaredIdentifier(DeclaredIdentifier node) { 10316 Object visitDeclaredIdentifier(DeclaredIdentifier node) {
14298 super.visitDeclaredIdentifier(node); 10317 super.visitDeclaredIdentifier(node);
14299 DartType declaredType; 10318 DartType declaredType;
14300 TypeName typeName = node.type; 10319 TypeName typeName = node.type;
14301 if (typeName == null) { 10320 if (typeName == null) {
14302 declaredType = _dynamicType; 10321 declaredType = _dynamicType;
14303 } else { 10322 } else {
14304 declaredType = _getType(typeName); 10323 declaredType = _typeNameResolver._getType(typeName);
14305 } 10324 }
14306 LocalVariableElementImpl element = node.element as LocalVariableElementImpl; 10325 LocalVariableElementImpl element = node.element as LocalVariableElementImpl;
14307 element.type = declaredType; 10326 element.type = declaredType;
14308 return null; 10327 return null;
14309 } 10328 }
14310 10329
14311 @override 10330 @override
14312 Object visitFieldFormalParameter(FieldFormalParameter node) { 10331 Object visitFieldFormalParameter(FieldFormalParameter node) {
14313 super.visitFieldFormalParameter(node); 10332 super.visitFieldFormalParameter(node);
14314 Element element = node.identifier.staticElement; 10333 Element element = node.identifier.staticElement;
14315 if (element is ParameterElementImpl) { 10334 if (element is ParameterElementImpl) {
14316 ParameterElementImpl parameter = element;
14317 FormalParameterList parameterList = node.parameters; 10335 FormalParameterList parameterList = node.parameters;
14318 if (parameterList == null) { 10336 if (parameterList == null) {
14319 DartType type; 10337 DartType type;
14320 TypeName typeName = node.type; 10338 TypeName typeName = node.type;
14321 if (typeName == null) { 10339 if (typeName == null) {
14322 element.hasImplicitType = true; 10340 element.hasImplicitType = true;
14323 type = _dynamicType; 10341 if (element is FieldFormalParameterElement) {
14324 if (parameter is FieldFormalParameterElement) {
14325 FieldElement fieldElement = 10342 FieldElement fieldElement =
14326 (parameter as FieldFormalParameterElement).field; 10343 (element as FieldFormalParameterElement).field;
14327 if (fieldElement != null) { 10344 type = fieldElement?.type;
14328 type = fieldElement.type;
14329 }
14330 } 10345 }
14331 } else { 10346 } else {
14332 type = _getType(typeName); 10347 type = _typeNameResolver._getType(typeName);
14333 } 10348 }
14334 parameter.type = type; 10349 element.type = type ?? _dynamicType;
14335 } else { 10350 } else {
14336 _setFunctionTypedParameterType(parameter, node.type, node.parameters); 10351 _setFunctionTypedParameterType(element, node.type, node.parameters);
14337 } 10352 }
14338 } else { 10353 } else {
14339 // TODO(brianwilkerson) Report this internal error 10354 // TODO(brianwilkerson) Report this internal error
14340 } 10355 }
14341 return null; 10356 return null;
14342 } 10357 }
14343 10358
14344 @override 10359 @override
14345 Object visitFunctionDeclaration(FunctionDeclaration node) { 10360 Object visitFunctionDeclaration(FunctionDeclaration node) {
14346 super.visitFunctionDeclaration(node); 10361 super.visitFunctionDeclaration(node);
14347 ExecutableElementImpl element = node.element as ExecutableElementImpl; 10362 ExecutableElementImpl element = node.element as ExecutableElementImpl;
14348 if (element == null) { 10363 if (element == null) {
14349 StringBuffer buffer = new StringBuffer(); 10364 StringBuffer buffer = new StringBuffer();
14350 buffer.write("The element for the top-level function "); 10365 buffer.write("The element for the top-level function ");
14351 buffer.write(node.name); 10366 buffer.write(node.name);
14352 buffer.write(" in "); 10367 buffer.write(" in ");
14353 buffer.write(source.fullName); 10368 buffer.write(source.fullName);
14354 buffer.write(" was not set while trying to resolve types."); 10369 buffer.write(" was not set while trying to resolve types.");
14355 AnalysisEngine.instance.logger.logError(buffer.toString(), 10370 AnalysisEngine.instance.logger.logError(buffer.toString(),
14356 new CaughtException(new AnalysisException(), null)); 10371 new CaughtException(new AnalysisException(), null));
14357 } 10372 }
14358 element.returnType = _computeReturnType(node.returnType); 10373 element.returnType = _computeReturnType(node.returnType);
14359 FunctionTypeImpl type = new FunctionTypeImpl(element); 10374 element.type = new FunctionTypeImpl(element);
14360 ClassElement definingClass = 10375 _inferSetterReturnType(element);
14361 element.getAncestor((element) => element is ClassElement);
14362 if (definingClass != null) {
14363 type.typeArguments = definingClass.type.typeArguments;
14364 }
14365 element.type = type;
14366 return null; 10376 return null;
14367 } 10377 }
14368 10378
14369 @override 10379 @override
14370 Object visitFunctionTypeAlias(FunctionTypeAlias node) { 10380 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
14371 FunctionTypeAliasElementImpl element = 10381 FunctionTypeAliasElementImpl element =
14372 node.element as FunctionTypeAliasElementImpl; 10382 node.element as FunctionTypeAliasElementImpl;
14373 super.visitFunctionTypeAlias(node); 10383 super.visitFunctionTypeAlias(node);
14374 element.returnType = _computeReturnType(node.returnType); 10384 element.returnType = _computeReturnType(node.returnType);
14375 return null; 10385 return null;
(...skipping 27 matching lines...) Expand all
14403 } else { 10413 } else {
14404 buffer.write(classNode.name.name); 10414 buffer.write(classNode.name.name);
14405 } 10415 }
14406 buffer.write(" in "); 10416 buffer.write(" in ");
14407 buffer.write(source.fullName); 10417 buffer.write(source.fullName);
14408 buffer.write(" was not set while trying to resolve types."); 10418 buffer.write(" was not set while trying to resolve types.");
14409 AnalysisEngine.instance.logger.logError(buffer.toString(), 10419 AnalysisEngine.instance.logger.logError(buffer.toString(),
14410 new CaughtException(new AnalysisException(), null)); 10420 new CaughtException(new AnalysisException(), null));
14411 } 10421 }
14412 element.returnType = _computeReturnType(node.returnType); 10422 element.returnType = _computeReturnType(node.returnType);
14413 FunctionTypeImpl type = new FunctionTypeImpl(element); 10423 element.type = new FunctionTypeImpl(element);
14414 ClassElement definingClass = 10424 _inferSetterReturnType(element);
14415 element.getAncestor((element) => element is ClassElement);
14416 if (definingClass != null) {
14417 type.typeArguments = definingClass.type.typeArguments;
14418 }
14419 element.type = type;
14420 if (element is PropertyAccessorElement) { 10425 if (element is PropertyAccessorElement) {
14421 PropertyAccessorElement accessor = element as PropertyAccessorElement; 10426 PropertyAccessorElement accessor = element as PropertyAccessorElement;
14422 PropertyInducingElementImpl variable = 10427 PropertyInducingElementImpl variable =
14423 accessor.variable as PropertyInducingElementImpl; 10428 accessor.variable as PropertyInducingElementImpl;
14424 if (accessor.isGetter) { 10429 if (accessor.isGetter) {
14425 variable.type = type.baseReturnType; 10430 variable.type = element.returnType;
14426 } else if (variable.type == null) { 10431 } else if (variable.type == null) {
14427 List<ParameterElement> parameters = type.baseParameters; 10432 List<ParameterElement> parameters = element.parameters;
14428 if (parameters != null && parameters.length > 0) { 10433 if (parameters != null && parameters.length > 0) {
14429 variable.type = parameters[0].type; 10434 variable.type = parameters[0].type;
14430 } 10435 }
14431 } 10436 }
14432 } 10437 }
14433 return null; 10438 return null;
14434 } 10439 }
14435 10440
14436 @override 10441 @override
14437 Object visitSimpleFormalParameter(SimpleFormalParameter node) { 10442 Object visitSimpleFormalParameter(SimpleFormalParameter node) {
14438 super.visitSimpleFormalParameter(node); 10443 super.visitSimpleFormalParameter(node);
14439 DartType declaredType; 10444 DartType declaredType;
14440 TypeName typeName = node.type; 10445 TypeName typeName = node.type;
14441 if (typeName == null) { 10446 if (typeName == null) {
14442 declaredType = _dynamicType; 10447 declaredType = _dynamicType;
14443 } else { 10448 } else {
14444 declaredType = _getType(typeName); 10449 declaredType = _typeNameResolver._getType(typeName);
14445 } 10450 }
14446 Element element = node.identifier.staticElement; 10451 Element element = node.identifier.staticElement;
14447 if (element is ParameterElement) { 10452 if (element is ParameterElementImpl) {
14448 (element as ParameterElementImpl).type = declaredType; 10453 element.type = declaredType;
14449 } else { 10454 } else {
14450 // TODO(brianwilkerson) Report the internal error. 10455 // TODO(brianwilkerson) Report the internal error.
14451 } 10456 }
14452 return null; 10457 return null;
14453 } 10458 }
14454 10459
14455 @override 10460 @override
14456 Object visitSuperExpression(SuperExpression node) { 10461 Object visitSuperExpression(SuperExpression node) {
14457 _hasReferenceToSuper = true; 10462 _hasReferenceToSuper = true;
14458 return super.visitSuperExpression(node); 10463 return super.visitSuperExpression(node);
14459 } 10464 }
14460 10465
14461 @override 10466 @override
14462 Object visitTypeName(TypeName node) { 10467 Object visitTypeName(TypeName node) {
14463 super.visitTypeName(node); 10468 super.visitTypeName(node);
14464 Identifier typeName = node.name; 10469 _typeNameResolver.nameScope = this.nameScope;
14465 TypeArgumentList argumentList = node.typeArguments; 10470 _typeNameResolver.resolveTypeName(node);
14466 Element element = nameScope.lookup(typeName, definingLibrary);
14467 if (element == null) {
14468 //
14469 // Check to see whether the type name is either 'dynamic' or 'void',
14470 // neither of which are in the name scope and hence will not be found by
14471 // normal means.
14472 //
14473 if (typeName.name == _dynamicType.name) {
14474 _setElement(typeName, _dynamicType.element);
14475 if (argumentList != null) {
14476 // TODO(brianwilkerson) Report this error
14477 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, dynamicType.getName(), 0, argumentList.getArguments().size());
14478 }
14479 typeName.staticType = _dynamicType;
14480 node.type = _dynamicType;
14481 return null;
14482 }
14483 VoidTypeImpl voidType = VoidTypeImpl.instance;
14484 if (typeName.name == voidType.name) {
14485 // There is no element for 'void'.
14486 if (argumentList != null) {
14487 // TODO(brianwilkerson) Report this error
14488 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU MENTS, node, voidType.getName(), 0, argumentList.getArguments().size());
14489 }
14490 typeName.staticType = voidType;
14491 node.type = voidType;
14492 return null;
14493 }
14494 //
14495 // If not, the look to see whether we might have created the wrong AST
14496 // structure for a constructor name. If so, fix the AST structure and then
14497 // proceed.
14498 //
14499 AstNode parent = node.parent;
14500 if (typeName is PrefixedIdentifier &&
14501 parent is ConstructorName &&
14502 argumentList == null) {
14503 ConstructorName name = parent;
14504 if (name.name == null) {
14505 PrefixedIdentifier prefixedIdentifier =
14506 typeName as PrefixedIdentifier;
14507 SimpleIdentifier prefix = prefixedIdentifier.prefix;
14508 element = nameScope.lookup(prefix, definingLibrary);
14509 if (element is PrefixElement) {
14510 if (parent.parent is InstanceCreationExpression &&
14511 (parent.parent as InstanceCreationExpression).isConst) {
14512 // If, if this is a const expression, then generate a
14513 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
14514 reportErrorForNode(
14515 CompileTimeErrorCode.CONST_WITH_NON_TYPE,
14516 prefixedIdentifier.identifier,
14517 [prefixedIdentifier.identifier.name]);
14518 } else {
14519 // Else, if this expression is a new expression, report a
14520 // NEW_WITH_NON_TYPE warning.
14521 reportErrorForNode(
14522 StaticWarningCode.NEW_WITH_NON_TYPE,
14523 prefixedIdentifier.identifier,
14524 [prefixedIdentifier.identifier.name]);
14525 }
14526 _setElement(prefix, element);
14527 return null;
14528 } else if (element != null) {
14529 //
14530 // Rewrite the constructor name. The parser, when it sees a
14531 // constructor named "a.b", cannot tell whether "a" is a prefix and
14532 // "b" is a class name, or whether "a" is a class name and "b" is a
14533 // constructor name. It arbitrarily chooses the former, but in this
14534 // case was wrong.
14535 //
14536 name.name = prefixedIdentifier.identifier;
14537 name.period = prefixedIdentifier.period;
14538 node.name = prefix;
14539 typeName = prefix;
14540 }
14541 }
14542 }
14543 }
14544 // check element
14545 bool elementValid = element is! MultiplyDefinedElement;
14546 if (elementValid &&
14547 element is! ClassElement &&
14548 _isTypeNameInInstanceCreationExpression(node)) {
14549 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
14550 InstanceCreationExpression creation =
14551 node.parent.parent as InstanceCreationExpression;
14552 if (creation.isConst) {
14553 if (element == null) {
14554 reportErrorForNode(
14555 CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
14556 } else {
14557 reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE,
14558 typeNameSimple, [typeName]);
14559 }
14560 elementValid = false;
14561 } else {
14562 if (element != null) {
14563 reportErrorForNode(
14564 StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
14565 elementValid = false;
14566 }
14567 }
14568 }
14569 if (elementValid && element == null) {
14570 // We couldn't resolve the type name.
14571 // TODO(jwren) Consider moving the check for
14572 // CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE from the
14573 // ErrorVerifier, so that we don't have two errors on a built in
14574 // identifier being used as a class name.
14575 // See CompileTimeErrorCodeTest.test_builtInIdentifierAsType().
14576 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName);
14577 RedirectingConstructorKind redirectingConstructorKind;
14578 if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) {
14579 reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE,
14580 typeName, [typeName.name]);
14581 } else if (typeNameSimple.name == "boolean") {
14582 reportErrorForNode(
14583 StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
14584 } else if (_isTypeNameInCatchClause(node)) {
14585 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
14586 [typeName.name]);
14587 } else if (_isTypeNameInAsExpression(node)) {
14588 reportErrorForNode(
14589 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
14590 } else if (_isTypeNameInIsExpression(node)) {
14591 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME,
14592 typeName, [typeName.name]);
14593 } else if ((redirectingConstructorKind =
14594 _getRedirectingConstructorKind(node)) !=
14595 null) {
14596 ErrorCode errorCode = (redirectingConstructorKind ==
14597 RedirectingConstructorKind.CONST
14598 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
14599 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
14600 reportErrorForNode(errorCode, typeName, [typeName.name]);
14601 } else if (_isTypeNameInTypeArgumentList(node)) {
14602 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
14603 typeName, [typeName.name]);
14604 } else {
14605 reportErrorForNode(
14606 StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
14607 }
14608 elementValid = false;
14609 }
14610 if (!elementValid) {
14611 if (element is MultiplyDefinedElement) {
14612 _setElement(typeName, element);
14613 } else {
14614 _setElement(typeName, _dynamicType.element);
14615 }
14616 typeName.staticType = _undefinedType;
14617 node.type = _undefinedType;
14618 return null;
14619 }
14620 DartType type = null;
14621 if (element is ClassElement) {
14622 _setElement(typeName, element);
14623 type = element.type;
14624 } else if (element is FunctionTypeAliasElement) {
14625 _setElement(typeName, element);
14626 type = element.type;
14627 } else if (element is TypeParameterElement) {
14628 _setElement(typeName, element);
14629 type = element.type;
14630 if (argumentList != null) {
14631 // Type parameters cannot have type arguments.
14632 // TODO(brianwilkerson) Report this error.
14633 // resolver.reportError(ResolverErrorCode.?, keyType);
14634 }
14635 } else if (element is MultiplyDefinedElement) {
14636 List<Element> elements = element.conflictingElements;
14637 type = _getTypeWhenMultiplyDefined(elements);
14638 if (type != null) {
14639 node.type = type;
14640 }
14641 } else {
14642 // The name does not represent a type.
14643 RedirectingConstructorKind redirectingConstructorKind;
14644 if (_isTypeNameInCatchClause(node)) {
14645 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName,
14646 [typeName.name]);
14647 } else if (_isTypeNameInAsExpression(node)) {
14648 reportErrorForNode(
14649 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
14650 } else if (_isTypeNameInIsExpression(node)) {
14651 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName,
14652 [typeName.name]);
14653 } else if ((redirectingConstructorKind =
14654 _getRedirectingConstructorKind(node)) !=
14655 null) {
14656 ErrorCode errorCode = (redirectingConstructorKind ==
14657 RedirectingConstructorKind.CONST
14658 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS
14659 : StaticWarningCode.REDIRECT_TO_NON_CLASS);
14660 reportErrorForNode(errorCode, typeName, [typeName.name]);
14661 } else if (_isTypeNameInTypeArgumentList(node)) {
14662 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
14663 typeName, [typeName.name]);
14664 } else {
14665 AstNode parent = typeName.parent;
14666 while (parent is TypeName) {
14667 parent = parent.parent;
14668 }
14669 if (parent is ExtendsClause ||
14670 parent is ImplementsClause ||
14671 parent is WithClause ||
14672 parent is ClassTypeAlias) {
14673 // Ignored. The error will be reported elsewhere.
14674 } else {
14675 reportErrorForNode(
14676 StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
14677 }
14678 }
14679 _setElement(typeName, _dynamicType.element);
14680 typeName.staticType = _dynamicType;
14681 node.type = _dynamicType;
14682 return null;
14683 }
14684 if (argumentList != null) {
14685 NodeList<TypeName> arguments = argumentList.arguments;
14686 int argumentCount = arguments.length;
14687 List<DartType> parameters = _getTypeArguments(type);
14688 int parameterCount = parameters.length;
14689 List<DartType> typeArguments = new List<DartType>(parameterCount);
14690 if (argumentCount == parameterCount) {
14691 for (int i = 0; i < parameterCount; i++) {
14692 TypeName argumentTypeName = arguments[i];
14693 DartType argumentType = _getType(argumentTypeName);
14694 if (argumentType == null) {
14695 argumentType = _dynamicType;
14696 }
14697 typeArguments[i] = argumentType;
14698 }
14699 } else {
14700 reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node,
14701 [typeName.name, parameterCount, argumentCount]);
14702 for (int i = 0; i < parameterCount; i++) {
14703 typeArguments[i] = _dynamicType;
14704 }
14705 }
14706 if (type is InterfaceTypeImpl) {
14707 InterfaceTypeImpl interfaceType = type as InterfaceTypeImpl;
14708 type = interfaceType.substitute4(typeArguments);
14709 } else if (type is FunctionTypeImpl) {
14710 FunctionTypeImpl functionType = type as FunctionTypeImpl;
14711 type = functionType.substitute3(typeArguments);
14712 } else {
14713 // TODO(brianwilkerson) Report this internal error.
14714 }
14715 } else {
14716 //
14717 // Check for the case where there are no type arguments given for a
14718 // parameterized type.
14719 //
14720 List<DartType> parameters = _getTypeArguments(type);
14721 int parameterCount = parameters.length;
14722 if (parameterCount > 0) {
14723 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
14724 List<DartType> arguments = new List<DartType>(parameterCount);
14725 for (int i = 0; i < parameterCount; i++) {
14726 arguments[i] = dynamicType;
14727 }
14728 type = type.substitute2(arguments, parameters);
14729 }
14730 }
14731 typeName.staticType = type;
14732 node.type = type;
14733 return null; 10471 return null;
14734 } 10472 }
14735 10473
14736 @override 10474 @override
14737 Object visitTypeParameter(TypeParameter node) { 10475 Object visitTypeParameter(TypeParameter node) {
14738 super.visitTypeParameter(node); 10476 super.visitTypeParameter(node);
14739 TypeName bound = node.bound; 10477 AstNode parent2 = node.parent?.parent;
14740 if (bound != null) { 10478 if (parent2 is ClassDeclaration ||
14741 TypeParameterElementImpl typeParameter = 10479 parent2 is ClassTypeAlias ||
14742 node.name.staticElement as TypeParameterElementImpl; 10480 parent2 is FunctionTypeAlias) {
14743 if (typeParameter != null) { 10481 // Bounds of parameters of classes and function type aliases are
14744 typeParameter.bound = bound.type; 10482 // already resolved.
10483 } else {
10484 TypeName bound = node.bound;
10485 if (bound != null) {
10486 TypeParameterElementImpl typeParameter =
10487 node.name.staticElement as TypeParameterElementImpl;
10488 if (typeParameter != null) {
10489 typeParameter.bound = bound.type;
10490 }
14745 } 10491 }
14746 } 10492 }
14747 return null; 10493 return null;
14748 } 10494 }
14749 10495
14750 @override 10496 @override
14751 Object visitVariableDeclaration(VariableDeclaration node) { 10497 Object visitVariableDeclaration(VariableDeclaration node) {
14752 super.visitVariableDeclaration(node); 10498 super.visitVariableDeclaration(node);
14753 DartType declaredType; 10499 DartType declaredType;
14754 TypeName typeName = (node.parent as VariableDeclarationList).type; 10500 TypeName typeName = (node.parent as VariableDeclarationList).type;
14755 if (typeName == null) { 10501 if (typeName == null) {
14756 declaredType = _dynamicType; 10502 declaredType = _dynamicType;
14757 } else { 10503 } else {
14758 declaredType = _getType(typeName); 10504 declaredType = _typeNameResolver._getType(typeName);
14759 } 10505 }
14760 Element element = node.name.staticElement; 10506 Element element = node.name.staticElement;
14761 if (element is VariableElement) { 10507 if (element is VariableElementImpl) {
14762 (element as VariableElementImpl).type = declaredType; 10508 element.type = declaredType;
14763 if (element is PropertyInducingElement) {
14764 PropertyInducingElement variableElement = element;
14765 PropertyAccessorElementImpl getter =
14766 variableElement.getter as PropertyAccessorElementImpl;
14767 getter.returnType = declaredType;
14768 FunctionTypeImpl getterType = new FunctionTypeImpl(getter);
14769 ClassElement definingClass =
14770 element.getAncestor((element) => element is ClassElement);
14771 if (definingClass != null) {
14772 getterType.typeArguments = definingClass.type.typeArguments;
14773 }
14774 getter.type = getterType;
14775 PropertyAccessorElementImpl setter =
14776 variableElement.setter as PropertyAccessorElementImpl;
14777 if (setter != null) {
14778 List<ParameterElement> parameters = setter.parameters;
14779 if (parameters.length > 0) {
14780 (parameters[0] as ParameterElementImpl).type = declaredType;
14781 }
14782 setter.returnType = VoidTypeImpl.instance;
14783 FunctionTypeImpl setterType = new FunctionTypeImpl(setter);
14784 if (definingClass != null) {
14785 setterType.typeArguments = definingClass.type.typeArguments;
14786 }
14787 setter.type = setterType;
14788 }
14789 }
14790 } else {
14791 // TODO(brianwilkerson) Report the internal error.
14792 } 10509 }
14793 return null; 10510 return null;
14794 } 10511 }
14795 10512
14796 /** 10513 /**
14797 * Given a type name representing the return type of a function, compute the r eturn type of the 10514 * Given a type name representing the return type of a function, compute the r eturn type of the
14798 * function. 10515 * function.
14799 * 10516 *
14800 * @param returnType the type name representing the return type of the functio n 10517 * @param returnType the type name representing the return type of the functio n
14801 * @return the return type that was computed 10518 * @return the return type that was computed
(...skipping 15 matching lines...) Expand all
14817 ClassElementImpl _getClassElement(SimpleIdentifier identifier) { 10534 ClassElementImpl _getClassElement(SimpleIdentifier identifier) {
14818 // TODO(brianwilkerson) Seems like we should be using 10535 // TODO(brianwilkerson) Seems like we should be using
14819 // ClassDeclaration.getElement(). 10536 // ClassDeclaration.getElement().
14820 if (identifier == null) { 10537 if (identifier == null) {
14821 // TODO(brianwilkerson) Report this 10538 // TODO(brianwilkerson) Report this
14822 // Internal error: We should never build a class declaration without a 10539 // Internal error: We should never build a class declaration without a
14823 // name. 10540 // name.
14824 return null; 10541 return null;
14825 } 10542 }
14826 Element element = identifier.staticElement; 10543 Element element = identifier.staticElement;
14827 if (element is! ClassElementImpl) { 10544 if (element is ClassElementImpl) {
14828 // TODO(brianwilkerson) Report this 10545 return element;
14829 // Internal error: Failed to create an element for a class declaration. 10546 }
14830 return null; 10547 // TODO(brianwilkerson) Report this
14831 } 10548 // Internal error: Failed to create an element for a class declaration.
14832 return element as ClassElementImpl; 10549 return null;
14833 } 10550 }
14834 10551
14835 /** 10552 /**
14836 * Return an array containing all of the elements associated with the paramete rs in the given 10553 * Return an array containing all of the elements associated with the paramete rs in the given
14837 * list. 10554 * list.
14838 * 10555 *
14839 * @param parameterList the list of parameters whose elements are to be return ed 10556 * @param parameterList the list of parameters whose elements are to be return ed
14840 * @return the elements associated with the parameters 10557 * @return the elements associated with the parameters
14841 */ 10558 */
14842 List<ParameterElement> _getElements(FormalParameterList parameterList) { 10559 List<ParameterElement> _getElements(FormalParameterList parameterList) {
14843 List<ParameterElement> elements = new List<ParameterElement>(); 10560 List<ParameterElement> elements = new List<ParameterElement>();
14844 for (FormalParameter parameter in parameterList.parameters) { 10561 for (FormalParameter parameter in parameterList.parameters) {
14845 ParameterElement element = 10562 ParameterElement element =
14846 parameter.identifier.staticElement as ParameterElement; 10563 parameter.identifier.staticElement as ParameterElement;
14847 // TODO(brianwilkerson) Understand why the element would be null. 10564 // TODO(brianwilkerson) Understand why the element would be null.
14848 if (element != null) { 10565 if (element != null) {
14849 elements.add(element); 10566 elements.add(element);
14850 } 10567 }
14851 } 10568 }
14852 return elements; 10569 return elements;
14853 } 10570 }
14854 10571
14855 /** 10572 /**
14856 * The number of type arguments in the given type name does not match the numb er of parameters in 10573 * In strong mode we infer "void" as the setter return type (as void is the
14857 * the corresponding class element. Return the error code that should be used to report this 10574 * only legal return type for a setter). This allows us to give better
14858 * error. 10575 * errors later if an invalid type is returned.
14859 * 10576 */
14860 * @param node the type name with the wrong number of type arguments 10577 void _inferSetterReturnType(ExecutableElementImpl element) {
14861 * @return the error code that should be used to report that the wrong number of type arguments 10578 if (_strongMode &&
14862 * were provided 10579 element is PropertyAccessorElementImpl &&
14863 */ 10580 element.isSetter &&
14864 ErrorCode _getInvalidTypeParametersErrorCode(TypeName node) { 10581 element.hasImplicitReturnType) {
14865 AstNode parent = node.parent; 10582 element.returnType = VoidTypeImpl.instance;
14866 if (parent is ConstructorName) { 10583 }
14867 parent = parent.parent; 10584 }
14868 if (parent is InstanceCreationExpression) {
14869 if (parent.isConst) {
14870 return CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS;
14871 } else {
14872 return StaticWarningCode.NEW_WITH_INVALID_TYPE_PARAMETERS;
14873 }
14874 }
14875 }
14876 return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
14877 }
14878
14879 /**
14880 * Checks if the given type name is the target in a redirected constructor.
14881 *
14882 * @param typeName the type name to analyze
14883 * @return some [RedirectingConstructorKind] if the given type name is used as the type in a
14884 * redirected constructor, or `null` otherwise
14885 */
14886 RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
14887 AstNode parent = typeName.parent;
14888 if (parent is ConstructorName) {
14889 ConstructorName constructorName = parent as ConstructorName;
14890 parent = constructorName.parent;
14891 if (parent is ConstructorDeclaration) {
14892 if (identical(parent.redirectedConstructor, constructorName)) {
14893 if (parent.constKeyword != null) {
14894 return RedirectingConstructorKind.CONST;
14895 }
14896 return RedirectingConstructorKind.NORMAL;
14897 }
14898 }
14899 }
14900 return null;
14901 }
14902
14903 /**
14904 * Return the type represented by the given type name.
14905 *
14906 * @param typeName the type name representing the type to be returned
14907 * @return the type represented by the type name
14908 */
14909 DartType _getType(TypeName typeName) {
14910 DartType type = typeName.type;
14911 if (type == null) {
14912 return _undefinedType;
14913 }
14914 return type;
14915 }
14916
14917 /**
14918 * Return the type arguments associated with the given type.
14919 *
14920 * @param type the type whole type arguments are to be returned
14921 * @return the type arguments associated with the given type
14922 */
14923 List<DartType> _getTypeArguments(DartType type) {
14924 if (type is InterfaceType) {
14925 return type.typeArguments;
14926 } else if (type is FunctionType) {
14927 return type.typeArguments;
14928 }
14929 return DartType.EMPTY_LIST;
14930 }
14931
14932 /**
14933 * Returns the simple identifier of the given (may be qualified) type name.
14934 *
14935 * @param typeName the (may be qualified) qualified type name
14936 * @return the simple identifier of the given (may be qualified) type name.
14937 */
14938 SimpleIdentifier _getTypeSimpleIdentifier(Identifier typeName) {
14939 if (typeName is SimpleIdentifier) {
14940 return typeName;
14941 } else {
14942 return (typeName as PrefixedIdentifier).identifier;
14943 }
14944 }
14945
14946 /**
14947 * Given the multiple elements to which a single name could potentially be res olved, return the
14948 * single interface type that should be used, or `null` if there is no clear c hoice.
14949 *
14950 * @param elements the elements to which a single name could potentially be re solved
14951 * @return the single interface type that should be used for the type name
14952 */
14953 InterfaceType _getTypeWhenMultiplyDefined(List<Element> elements) {
14954 InterfaceType type = null;
14955 for (Element element in elements) {
14956 if (element is ClassElement) {
14957 if (type != null) {
14958 return null;
14959 }
14960 type = element.type;
14961 }
14962 }
14963 return type;
14964 }
14965
14966 /**
14967 * Checks if the given type name is used as the type in an as expression.
14968 *
14969 * @param typeName the type name to analyzer
14970 * @return `true` if the given type name is used as the type in an as expressi on
14971 */
14972 bool _isTypeNameInAsExpression(TypeName typeName) {
14973 AstNode parent = typeName.parent;
14974 if (parent is AsExpression) {
14975 AsExpression asExpression = parent;
14976 return identical(asExpression.type, typeName);
14977 }
14978 return false;
14979 }
14980
14981 /**
14982 * Checks if the given type name is used as the exception type in a catch clau se.
14983 *
14984 * @param typeName the type name to analyzer
14985 * @return `true` if the given type name is used as the exception type in a ca tch clause
14986 */
14987 bool _isTypeNameInCatchClause(TypeName typeName) {
14988 AstNode parent = typeName.parent;
14989 if (parent is CatchClause) {
14990 CatchClause catchClause = parent;
14991 return identical(catchClause.exceptionType, typeName);
14992 }
14993 return false;
14994 }
14995
14996 /**
14997 * Checks if the given type name is used as the type in an instance creation e xpression.
14998 *
14999 * @param typeName the type name to analyzer
15000 * @return `true` if the given type name is used as the type in an instance cr eation
15001 * expression
15002 */
15003 bool _isTypeNameInInstanceCreationExpression(TypeName typeName) {
15004 AstNode parent = typeName.parent;
15005 if (parent is ConstructorName &&
15006 parent.parent is InstanceCreationExpression) {
15007 ConstructorName constructorName = parent;
15008 return constructorName != null &&
15009 identical(constructorName.type, typeName);
15010 }
15011 return false;
15012 }
15013
15014 /**
15015 * Checks if the given type name is used as the type in an is expression.
15016 *
15017 * @param typeName the type name to analyzer
15018 * @return `true` if the given type name is used as the type in an is expressi on
15019 */
15020 bool _isTypeNameInIsExpression(TypeName typeName) {
15021 AstNode parent = typeName.parent;
15022 if (parent is IsExpression) {
15023 IsExpression isExpression = parent;
15024 return identical(isExpression.type, typeName);
15025 }
15026 return false;
15027 }
15028
15029 /**
15030 * Checks if the given type name used in a type argument list.
15031 *
15032 * @param typeName the type name to analyzer
15033 * @return `true` if the given type name is in a type argument list
15034 */
15035 bool _isTypeNameInTypeArgumentList(TypeName typeName) =>
15036 typeName.parent is TypeArgumentList;
15037 10585
15038 /** 10586 /**
15039 * Record that the static type of the given node is the given type. 10587 * Record that the static type of the given node is the given type.
15040 * 10588 *
15041 * @param expression the node whose type is to be recorded 10589 * @param expression the node whose type is to be recorded
15042 * @param type the static type of the node 10590 * @param type the static type of the node
15043 */ 10591 */
15044 Object _recordType(Expression expression, DartType type) { 10592 Object _recordType(Expression expression, DartType type) {
15045 if (type == null) { 10593 if (type == null) {
15046 expression.staticType = _dynamicType; 10594 expression.staticType = _dynamicType;
(...skipping 15 matching lines...) Expand all
15062 void _resolve(ClassElementImpl classElement, WithClause withClause, 10610 void _resolve(ClassElementImpl classElement, WithClause withClause,
15063 ImplementsClause implementsClause) { 10611 ImplementsClause implementsClause) {
15064 if (withClause != null) { 10612 if (withClause != null) {
15065 List<InterfaceType> mixinTypes = _resolveTypes( 10613 List<InterfaceType> mixinTypes = _resolveTypes(
15066 withClause.mixinTypes, 10614 withClause.mixinTypes,
15067 CompileTimeErrorCode.MIXIN_OF_NON_CLASS, 10615 CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
15068 CompileTimeErrorCode.MIXIN_OF_ENUM, 10616 CompileTimeErrorCode.MIXIN_OF_ENUM,
15069 CompileTimeErrorCode.MIXIN_OF_NON_CLASS); 10617 CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
15070 if (classElement != null) { 10618 if (classElement != null) {
15071 classElement.mixins = mixinTypes; 10619 classElement.mixins = mixinTypes;
15072 classElement.withClauseRange =
15073 new SourceRange(withClause.offset, withClause.length);
15074 } 10620 }
15075 } 10621 }
15076 if (implementsClause != null) { 10622 if (implementsClause != null) {
15077 NodeList<TypeName> interfaces = implementsClause.interfaces; 10623 NodeList<TypeName> interfaces = implementsClause.interfaces;
15078 List<InterfaceType> interfaceTypes = _resolveTypes( 10624 List<InterfaceType> interfaceTypes = _resolveTypes(
15079 interfaces, 10625 interfaces,
15080 CompileTimeErrorCode.IMPLEMENTS_NON_CLASS, 10626 CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
15081 CompileTimeErrorCode.IMPLEMENTS_ENUM, 10627 CompileTimeErrorCode.IMPLEMENTS_ENUM,
15082 CompileTimeErrorCode.IMPLEMENTS_DYNAMIC); 10628 CompileTimeErrorCode.IMPLEMENTS_DYNAMIC);
15083 if (classElement != null) { 10629 if (classElement != null) {
15084 classElement.interfaces = interfaceTypes; 10630 classElement.interfaces = interfaceTypes;
15085 } 10631 }
15086 // TODO(brianwilkerson) Move the following checks to ErrorVerifier. 10632 // TODO(brianwilkerson) Move the following checks to ErrorVerifier.
15087 int count = interfaces.length; 10633 int count = interfaces.length;
15088 List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false); 10634 List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false);
15089 for (int i = 0; i < detectedRepeatOnIndex.length; i++) { 10635 for (int i = 0; i < detectedRepeatOnIndex.length; i++) {
15090 detectedRepeatOnIndex[i] = false; 10636 detectedRepeatOnIndex[i] = false;
15091 } 10637 }
15092 for (int i = 0; i < count; i++) { 10638 for (int i = 0; i < count; i++) {
15093 TypeName typeName = interfaces[i]; 10639 TypeName typeName = interfaces[i];
15094 if (!detectedRepeatOnIndex[i]) { 10640 if (!detectedRepeatOnIndex[i]) {
15095 Element element = typeName.name.staticElement; 10641 Element element = typeName.name.staticElement;
15096 for (int j = i + 1; j < count; j++) { 10642 for (int j = i + 1; j < count; j++) {
15097 TypeName typeName2 = interfaces[j]; 10643 TypeName typeName2 = interfaces[j];
15098 Identifier identifier2 = typeName2.name; 10644 Identifier identifier2 = typeName2.name;
15099 String name2 = identifier2.name; 10645 String name2 = identifier2.name;
15100 Element element2 = identifier2.staticElement; 10646 Element element2 = identifier2.staticElement;
15101 if (element != null && element == element2) { 10647 if (element != null && element == element2) {
15102 detectedRepeatOnIndex[j] = true; 10648 detectedRepeatOnIndex[j] = true;
15103 reportErrorForNode( 10649 errorReporter.reportErrorForNode(
15104 CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]); 10650 CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
15105 } 10651 }
15106 } 10652 }
15107 } 10653 }
15108 } 10654 }
15109 } 10655 }
15110 } 10656 }
15111 10657
15112 /** 10658 /**
15113 * Return the type specified by the given name. 10659 * Return the type specified by the given name.
15114 * 10660 *
15115 * @param typeName the type name specifying the type to be returned 10661 * @param typeName the type name specifying the type to be returned
15116 * @param nonTypeError the error to produce if the type name is defined to be something other than 10662 * @param nonTypeError the error to produce if the type name is defined to be something other than
15117 * a type 10663 * a type
15118 * @param enumTypeError the error to produce if the type name is defined to be an enum 10664 * @param enumTypeError the error to produce if the type name is defined to be an enum
15119 * @param dynamicTypeError the error to produce if the type name is "dynamic" 10665 * @param dynamicTypeError the error to produce if the type name is "dynamic"
15120 * @return the type specified by the type name 10666 * @return the type specified by the type name
15121 */ 10667 */
15122 InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError, 10668 InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError,
15123 ErrorCode enumTypeError, ErrorCode dynamicTypeError) { 10669 ErrorCode enumTypeError, ErrorCode dynamicTypeError) {
15124 DartType type = typeName.type; 10670 DartType type = typeName.type;
15125 if (type is InterfaceType) { 10671 if (type is InterfaceType) {
15126 ClassElement element = type.element; 10672 ClassElement element = type.element;
15127 if (element != null && element.isEnum) { 10673 if (element != null && element.isEnum) {
15128 reportErrorForNode(enumTypeError, typeName); 10674 errorReporter.reportErrorForNode(enumTypeError, typeName);
15129 return null; 10675 return null;
15130 } 10676 }
15131 return type; 10677 return type;
15132 } 10678 }
15133 // If the type is not an InterfaceType, then visitTypeName() sets the type 10679 // If the type is not an InterfaceType, then visitTypeName() sets the type
15134 // to be a DynamicTypeImpl 10680 // to be a DynamicTypeImpl
15135 Identifier name = typeName.name; 10681 Identifier name = typeName.name;
15136 if (name.name == sc.Keyword.DYNAMIC.syntax) { 10682 if (name.name == Keyword.DYNAMIC.syntax) {
15137 reportErrorForNode(dynamicTypeError, name, [name.name]); 10683 errorReporter.reportErrorForNode(dynamicTypeError, name, [name.name]);
15138 } else { 10684 } else if (!nameScope.shouldIgnoreUndefined(name)) {
15139 reportErrorForNode(nonTypeError, name, [name.name]); 10685 errorReporter.reportErrorForNode(nonTypeError, name, [name.name]);
15140 } 10686 }
15141 return null; 10687 return null;
15142 } 10688 }
15143 10689
15144 /** 10690 /**
15145 * Resolve the types in the given list of type names. 10691 * Resolve the types in the given list of type names.
15146 * 10692 *
15147 * @param typeNames the type names to be resolved 10693 * @param typeNames the type names to be resolved
15148 * @param nonTypeError the error to produce if the type name is defined to be something other than 10694 * @param nonTypeError the error to produce if the type name is defined to be something other than
15149 * a type 10695 * a type
(...skipping 10 matching lines...) Expand all
15160 for (TypeName typeName in typeNames) { 10706 for (TypeName typeName in typeNames) {
15161 InterfaceType type = 10707 InterfaceType type =
15162 _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError); 10708 _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError);
15163 if (type != null) { 10709 if (type != null) {
15164 types.add(type); 10710 types.add(type);
15165 } 10711 }
15166 } 10712 }
15167 return types; 10713 return types;
15168 } 10714 }
15169 10715
15170 void _setElement(Identifier typeName, Element element) {
15171 if (element != null) {
15172 if (typeName is SimpleIdentifier) {
15173 typeName.staticElement = element;
15174 } else if (typeName is PrefixedIdentifier) {
15175 PrefixedIdentifier identifier = typeName;
15176 identifier.identifier.staticElement = element;
15177 SimpleIdentifier prefix = identifier.prefix;
15178 Element prefixElement = nameScope.lookup(prefix, definingLibrary);
15179 if (prefixElement != null) {
15180 prefix.staticElement = prefixElement;
15181 }
15182 }
15183 }
15184 }
15185
15186 /** 10716 /**
15187 * Given a parameter element, create a function type based on the given return type and parameter 10717 * Given a parameter element, create a function type based on the given return type and parameter
15188 * list and associate the created type with the element. 10718 * list and associate the created type with the element.
15189 * 10719 *
15190 * @param element the parameter element whose type is to be set 10720 * @param element the parameter element whose type is to be set
15191 * @param returnType the (possibly `null`) return type of the function 10721 * @param returnType the (possibly `null`) return type of the function
15192 * @param parameterList the list of parameters to the function 10722 * @param parameterList the list of parameters to the function
15193 */ 10723 */
15194 void _setFunctionTypedParameterType(ParameterElementImpl element, 10724 void _setFunctionTypedParameterType(ParameterElementImpl element,
15195 TypeName returnType, FormalParameterList parameterList) { 10725 TypeName returnType, FormalParameterList parameterList) {
15196 List<ParameterElement> parameters = _getElements(parameterList); 10726 List<ParameterElement> parameters = _getElements(parameterList);
15197 FunctionTypeAliasElementImpl aliasElement = 10727 FunctionElementImpl functionElement = new FunctionElementImpl.forNode(null);
15198 new FunctionTypeAliasElementImpl.forNode(null); 10728 functionElement.synthetic = true;
15199 aliasElement.synthetic = true; 10729 functionElement.shareParameters(parameters);
15200 aliasElement.shareParameters(parameters); 10730 functionElement.returnType = _computeReturnType(returnType);
15201 aliasElement.returnType = _computeReturnType(returnType); 10731 functionElement.enclosingElement = element;
15202 // FunctionTypeAliasElementImpl assumes the enclosing element is a 10732 functionElement.shareTypeParameters(element.typeParameters);
15203 // CompilationUnitElement (because non-synthetic function types can only be 10733 element.type = new FunctionTypeImpl(functionElement);
15204 // declared at top level), so to avoid breaking things, go find the 10734 functionElement.type = element.type;
15205 // compilation unit element.
15206 aliasElement.enclosingElement =
15207 element.getAncestor((element) => element is CompilationUnitElement);
15208 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(aliasElement);
15209 ClassElement definingClass =
15210 element.getAncestor((element) => element is ClassElement);
15211 if (definingClass != null) {
15212 aliasElement.shareTypeParameters(definingClass.typeParameters);
15213 type.typeArguments = definingClass.type.typeArguments;
15214 } else {
15215 FunctionTypeAliasElement alias =
15216 element.getAncestor((element) => element is FunctionTypeAliasElement);
15217 while (alias != null && alias.isSynthetic) {
15218 alias =
15219 alias.getAncestor((element) => element is FunctionTypeAliasElement);
15220 }
15221 if (alias != null) {
15222 aliasElement.typeParameters = alias.typeParameters;
15223 type.typeArguments = alias.type.typeArguments;
15224 } else {
15225 type.typeArguments = DartType.EMPTY_LIST;
15226 }
15227 }
15228 element.type = type;
15229 }
15230
15231 /**
15232 * @return `true` if the name of the given [TypeName] is an built-in identifie r.
15233 */
15234 static bool _isBuiltInIdentifier(TypeName node) {
15235 sc.Token token = node.name.beginToken;
15236 return token.type == sc.TokenType.KEYWORD;
15237 }
15238
15239 /**
15240 * @return `true` if given [TypeName] is used as a type annotation.
15241 */
15242 static bool _isTypeAnnotation(TypeName node) {
15243 AstNode parent = node.parent;
15244 if (parent is VariableDeclarationList) {
15245 return identical(parent.type, node);
15246 }
15247 if (parent is FieldFormalParameter) {
15248 return identical(parent.type, node);
15249 }
15250 if (parent is SimpleFormalParameter) {
15251 return identical(parent.type, node);
15252 }
15253 return false;
15254 } 10735 }
15255 } 10736 }
15256 10737
15257 /**
15258 * The interface `TypeSystem` defines the behavior of an object representing
15259 * the type system. This provides a common location to put methods that act on
15260 * types but may need access to more global data structures, and it paves the
15261 * way for a possible future where we may wish to make the type system
15262 * pluggable.
15263 */
15264 abstract class TypeSystem {
15265 /**
15266 * Compute the least upper bound of two types.
15267 */
15268 DartType getLeastUpperBound(
15269 TypeProvider typeProvider, DartType type1, DartType type2);
15270
15271 /**
15272 * Return `true` if the [leftType] is assignable to the [rightType] (that is,
15273 * if leftType <==> rightType).
15274 */
15275 bool isAssignableTo(DartType leftType, DartType rightType);
15276
15277 /**
15278 * Return `true` if the [leftType] is a subtype of the [rightType] (that is,
15279 * if leftType <: rightType).
15280 */
15281 bool isSubtypeOf(DartType leftType, DartType rightType);
15282
15283 /**
15284 * Create either a strong mode or regular type system based on context.
15285 */
15286 static TypeSystem create(AnalysisContext context) {
15287 return (context.analysisOptions.strongMode)
15288 ? new StrongTypeSystemImpl()
15289 : new TypeSystemImpl();
15290 }
15291 }
15292
15293 /**
15294 * Implementation of [TypeSystem] using the rules in the Dart specification.
15295 */
15296 class TypeSystemImpl implements TypeSystem {
15297 TypeSystemImpl();
15298
15299 @override
15300 DartType getLeastUpperBound(
15301 TypeProvider typeProvider, DartType type1, DartType type2) {
15302 // The least upper bound relation is reflexive.
15303 if (identical(type1, type2)) {
15304 return type1;
15305 }
15306 // The least upper bound of dynamic and any type T is dynamic.
15307 if (type1.isDynamic) {
15308 return type1;
15309 }
15310 if (type2.isDynamic) {
15311 return type2;
15312 }
15313 // The least upper bound of void and any type T != dynamic is void.
15314 if (type1.isVoid) {
15315 return type1;
15316 }
15317 if (type2.isVoid) {
15318 return type2;
15319 }
15320 // The least upper bound of bottom and any type T is T.
15321 if (type1.isBottom) {
15322 return type2;
15323 }
15324 if (type2.isBottom) {
15325 return type1;
15326 }
15327 // Let U be a type variable with upper bound B. The least upper bound of U
15328 // and a type T is the least upper bound of B and T.
15329 while (type1 is TypeParameterType) {
15330 // TODO(paulberry): is this correct in the complex of F-bounded
15331 // polymorphism?
15332 DartType bound = (type1 as TypeParameterType).element.bound;
15333 if (bound == null) {
15334 bound = typeProvider.objectType;
15335 }
15336 type1 = bound;
15337 }
15338 while (type2 is TypeParameterType) {
15339 // TODO(paulberry): is this correct in the context of F-bounded
15340 // polymorphism?
15341 DartType bound = (type2 as TypeParameterType).element.bound;
15342 if (bound == null) {
15343 bound = typeProvider.objectType;
15344 }
15345 type2 = bound;
15346 }
15347 // The least upper bound of a function type and an interface type T is the
15348 // least upper bound of Function and T.
15349 if (type1 is FunctionType && type2 is InterfaceType) {
15350 type1 = typeProvider.functionType;
15351 }
15352 if (type2 is FunctionType && type1 is InterfaceType) {
15353 type2 = typeProvider.functionType;
15354 }
15355
15356 // At this point type1 and type2 should both either be interface types or
15357 // function types.
15358 if (type1 is InterfaceType && type2 is InterfaceType) {
15359 InterfaceType result =
15360 InterfaceTypeImpl.computeLeastUpperBound(type1, type2);
15361 if (result == null) {
15362 return typeProvider.dynamicType;
15363 }
15364 return result;
15365 } else if (type1 is FunctionType && type2 is FunctionType) {
15366 FunctionType result =
15367 FunctionTypeImpl.computeLeastUpperBound(type1, type2);
15368 if (result == null) {
15369 return typeProvider.functionType;
15370 }
15371 return result;
15372 } else {
15373 // Should never happen. As a defensive measure, return the dynamic type.
15374 assert(false);
15375 return typeProvider.dynamicType;
15376 }
15377 }
15378
15379 @override
15380 bool isAssignableTo(DartType leftType, DartType rightType) {
15381 return leftType.isAssignableTo(rightType);
15382 }
15383
15384 @override
15385 bool isSubtypeOf(DartType leftType, DartType rightType) {
15386 return leftType.isSubtypeOf(rightType);
15387 }
15388 }
15389
15390 /** 10738 /**
15391 * Instances of the class [UnusedLocalElementsVerifier] traverse an element 10739 * Instances of the class [UnusedLocalElementsVerifier] traverse an element
15392 * structure looking for cases of [HintCode.UNUSED_ELEMENT], 10740 * structure looking for cases of [HintCode.UNUSED_ELEMENT],
15393 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc. 10741 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc.
15394 */ 10742 */
15395 class UnusedLocalElementsVerifier extends RecursiveElementVisitor { 10743 class UnusedLocalElementsVerifier extends RecursiveElementVisitor {
15396 /** 10744 /**
15397 * The error listener to which errors will be reported. 10745 * The error listener to which errors will be reported.
15398 */ 10746 */
15399 final AnalysisErrorListener _errorListener; 10747 final AnalysisErrorListener _errorListener;
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
15537 } 10885 }
15538 } 10886 }
15539 } 10887 }
15540 10888
15541 /** 10889 /**
15542 * A container with information about used imports prefixes and used imported 10890 * A container with information about used imports prefixes and used imported
15543 * elements. 10891 * elements.
15544 */ 10892 */
15545 class UsedImportedElements { 10893 class UsedImportedElements {
15546 /** 10894 /**
15547 * The set of referenced [PrefixElement]s. 10895 * The map of referenced [PrefixElement]s and the [Element]s that they prefix.
15548 */ 10896 */
15549 final Set<PrefixElement> prefixes = new HashSet<PrefixElement>(); 10897 final Map<PrefixElement, List<Element>> prefixMap =
10898 new HashMap<PrefixElement, List<Element>>();
15550 10899
15551 /** 10900 /**
15552 * The set of referenced top-level [Element]s. 10901 * The set of referenced top-level [Element]s.
15553 */ 10902 */
15554 final Set<Element> elements = new HashSet<Element>(); 10903 final Set<Element> elements = new HashSet<Element>();
15555 } 10904 }
15556 10905
15557 /** 10906 /**
15558 * A container with sets of used [Element]s. 10907 * A container with sets of used [Element]s.
15559 * All these elements are defined in a single compilation unit or a library. 10908 * All these elements are defined in a single compilation unit or a library.
(...skipping 26 matching lines...) Expand all
15586 /** 10935 /**
15587 * Names of resolved or unresolved class members that are read in the 10936 * Names of resolved or unresolved class members that are read in the
15588 * library. 10937 * library.
15589 */ 10938 */
15590 final HashSet<String> readMembers = new HashSet<String>(); 10939 final HashSet<String> readMembers = new HashSet<String>();
15591 10940
15592 UsedLocalElements(); 10941 UsedLocalElements();
15593 10942
15594 factory UsedLocalElements.merge(List<UsedLocalElements> parts) { 10943 factory UsedLocalElements.merge(List<UsedLocalElements> parts) {
15595 UsedLocalElements result = new UsedLocalElements(); 10944 UsedLocalElements result = new UsedLocalElements();
15596 for (UsedLocalElements part in parts) { 10945 int length = parts.length;
10946 for (int i = 0; i < length; i++) {
10947 UsedLocalElements part = parts[i];
15597 result.elements.addAll(part.elements); 10948 result.elements.addAll(part.elements);
15598 result.catchExceptionElements.addAll(part.catchExceptionElements); 10949 result.catchExceptionElements.addAll(part.catchExceptionElements);
15599 result.catchStackTraceElements.addAll(part.catchStackTraceElements); 10950 result.catchStackTraceElements.addAll(part.catchStackTraceElements);
15600 result.members.addAll(part.members); 10951 result.members.addAll(part.members);
15601 result.readMembers.addAll(part.readMembers); 10952 result.readMembers.addAll(part.readMembers);
15602 } 10953 }
15603 return result; 10954 return result;
15604 } 10955 }
15605 10956
15606 void addCatchException(LocalVariableElement element) { 10957 void addCatchException(LocalVariableElement element) {
(...skipping 28 matching lines...) Expand all
15635 * [SimpleIdentifier]s to local variables and formal parameters. 10986 * [SimpleIdentifier]s to local variables and formal parameters.
15636 */ 10987 */
15637 class VariableResolverVisitor extends ScopedVisitor { 10988 class VariableResolverVisitor extends ScopedVisitor {
15638 /** 10989 /**
15639 * The method or function that we are currently visiting, or `null` if we are not inside a 10990 * The method or function that we are currently visiting, or `null` if we are not inside a
15640 * method or function. 10991 * method or function.
15641 */ 10992 */
15642 ExecutableElement _enclosingFunction; 10993 ExecutableElement _enclosingFunction;
15643 10994
15644 /** 10995 /**
10996 * Information about local variables in the enclosing function or method.
10997 */
10998 LocalVariableInfo _localVariableInfo;
10999
11000 /**
15645 * Initialize a newly created visitor to resolve the nodes in an AST node. 11001 * Initialize a newly created visitor to resolve the nodes in an AST node.
15646 * 11002 *
15647 * [definingLibrary] is the element for the library containing the node being 11003 * [definingLibrary] is the element for the library containing the node being
15648 * visited. 11004 * visited.
15649 * [source] is the source representing the compilation unit containing the 11005 * [source] is the source representing the compilation unit containing the
15650 * node being visited 11006 * node being visited
15651 * [typeProvider] is the object used to access the types from the core 11007 * [typeProvider] is the object used to access the types from the core
15652 * library. 11008 * library.
15653 * [errorListener] is the error listener that will be informed of any errors 11009 * [errorListener] is the error listener that will be informed of any errors
15654 * that are found during resolution. 11010 * that are found during resolution.
15655 * [nameScope] is the scope used to resolve identifiers in the node that will 11011 * [nameScope] is the scope used to resolve identifiers in the node that will
15656 * first be visited. If `null` or unspecified, a new [LibraryScope] will be 11012 * first be visited. If `null` or unspecified, a new [LibraryScope] will be
15657 * created based on [definingLibrary] and [typeProvider]. 11013 * created based on [definingLibrary] and [typeProvider].
15658 */ 11014 */
15659 VariableResolverVisitor(LibraryElement definingLibrary, Source source, 11015 VariableResolverVisitor(LibraryElement definingLibrary, Source source,
15660 TypeProvider typeProvider, AnalysisErrorListener errorListener, 11016 TypeProvider typeProvider, AnalysisErrorListener errorListener,
15661 {Scope nameScope}) 11017 {Scope nameScope})
15662 : super(definingLibrary, source, typeProvider, errorListener, 11018 : super(definingLibrary, source, typeProvider, errorListener,
15663 nameScope: nameScope); 11019 nameScope: nameScope);
15664 11020
15665 /** 11021 @override
15666 * Initialize a newly created visitor to resolve the nodes in a compilation un it. 11022 Object visitBlockFunctionBody(BlockFunctionBody node) {
15667 * 11023 assert(_localVariableInfo != null);
15668 * @param library the library containing the compilation unit being resolved 11024 return super.visitBlockFunctionBody(node);
15669 * @param source the source representing the compilation unit being visited 11025 }
15670 * @param typeProvider the object used to access the types from the core libra ry 11026
15671 * 11027 @override
15672 * Deprecated. Please use unnamed constructor instead. 11028 Object visitConstructorDeclaration(ConstructorDeclaration node) {
15673 */ 11029 ExecutableElement outerFunction = _enclosingFunction;
15674 @deprecated 11030 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
15675 VariableResolverVisitor.con1( 11031 try {
15676 Library library, Source source, TypeProvider typeProvider) 11032 _localVariableInfo ??= new LocalVariableInfo();
15677 : this( 11033 (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
15678 library.libraryElement, source, typeProvider, library.errorListener, 11034 _enclosingFunction = node.element;
15679 nameScope: library.libraryScope); 11035 return super.visitConstructorDeclaration(node);
11036 } finally {
11037 _localVariableInfo = outerLocalVariableInfo;
11038 _enclosingFunction = outerFunction;
11039 }
11040 }
15680 11041
15681 @override 11042 @override
15682 Object visitExportDirective(ExportDirective node) => null; 11043 Object visitExportDirective(ExportDirective node) => null;
15683 11044
15684 @override 11045 @override
11046 Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
11047 assert(_localVariableInfo != null);
11048 return super.visitExpressionFunctionBody(node);
11049 }
11050
11051 @override
15685 Object visitFunctionDeclaration(FunctionDeclaration node) { 11052 Object visitFunctionDeclaration(FunctionDeclaration node) {
15686 ExecutableElement outerFunction = _enclosingFunction; 11053 ExecutableElement outerFunction = _enclosingFunction;
11054 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
15687 try { 11055 try {
11056 _localVariableInfo ??= new LocalVariableInfo();
11057 (node.functionExpression.body as FunctionBodyImpl).localVariableInfo =
11058 _localVariableInfo;
15688 _enclosingFunction = node.element; 11059 _enclosingFunction = node.element;
15689 return super.visitFunctionDeclaration(node); 11060 return super.visitFunctionDeclaration(node);
15690 } finally { 11061 } finally {
11062 _localVariableInfo = outerLocalVariableInfo;
15691 _enclosingFunction = outerFunction; 11063 _enclosingFunction = outerFunction;
15692 } 11064 }
15693 } 11065 }
15694 11066
15695 @override 11067 @override
15696 Object visitFunctionExpression(FunctionExpression node) { 11068 Object visitFunctionExpression(FunctionExpression node) {
15697 if (node.parent is! FunctionDeclaration) { 11069 if (node.parent is! FunctionDeclaration) {
15698 ExecutableElement outerFunction = _enclosingFunction; 11070 ExecutableElement outerFunction = _enclosingFunction;
11071 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
15699 try { 11072 try {
11073 _localVariableInfo ??= new LocalVariableInfo();
11074 (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
15700 _enclosingFunction = node.element; 11075 _enclosingFunction = node.element;
15701 return super.visitFunctionExpression(node); 11076 return super.visitFunctionExpression(node);
15702 } finally { 11077 } finally {
11078 _localVariableInfo = outerLocalVariableInfo;
15703 _enclosingFunction = outerFunction; 11079 _enclosingFunction = outerFunction;
15704 } 11080 }
15705 } else { 11081 } else {
15706 return super.visitFunctionExpression(node); 11082 return super.visitFunctionExpression(node);
15707 } 11083 }
15708 } 11084 }
15709 11085
15710 @override 11086 @override
15711 Object visitImportDirective(ImportDirective node) => null; 11087 Object visitImportDirective(ImportDirective node) => null;
15712 11088
15713 @override 11089 @override
15714 Object visitMethodDeclaration(MethodDeclaration node) { 11090 Object visitMethodDeclaration(MethodDeclaration node) {
15715 ExecutableElement outerFunction = _enclosingFunction; 11091 ExecutableElement outerFunction = _enclosingFunction;
11092 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
15716 try { 11093 try {
11094 _localVariableInfo ??= new LocalVariableInfo();
11095 (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
15717 _enclosingFunction = node.element; 11096 _enclosingFunction = node.element;
15718 return super.visitMethodDeclaration(node); 11097 return super.visitMethodDeclaration(node);
15719 } finally { 11098 } finally {
11099 _localVariableInfo = outerLocalVariableInfo;
15720 _enclosingFunction = outerFunction; 11100 _enclosingFunction = outerFunction;
15721 } 11101 }
15722 } 11102 }
15723 11103
15724 @override 11104 @override
15725 Object visitSimpleIdentifier(SimpleIdentifier node) { 11105 Object visitSimpleIdentifier(SimpleIdentifier node) {
15726 // Ignore if already resolved - declaration or type. 11106 // Ignore if already resolved - declaration or type.
15727 if (node.inDeclarationContext()) { 11107 if (node.inDeclarationContext()) {
15728 return null; 11108 return null;
15729 } 11109 }
(...skipping 25 matching lines...) Expand all
15755 if (parent is Label) { 11135 if (parent is Label) {
15756 return null; 11136 return null;
15757 } 11137 }
15758 // Prepare VariableElement. 11138 // Prepare VariableElement.
15759 Element element = nameScope.lookup(node, definingLibrary); 11139 Element element = nameScope.lookup(node, definingLibrary);
15760 if (element is! VariableElement) { 11140 if (element is! VariableElement) {
15761 return null; 11141 return null;
15762 } 11142 }
15763 // Must be local or parameter. 11143 // Must be local or parameter.
15764 ElementKind kind = element.kind; 11144 ElementKind kind = element.kind;
15765 if (kind == ElementKind.LOCAL_VARIABLE) { 11145 if (kind == ElementKind.LOCAL_VARIABLE || kind == ElementKind.PARAMETER) {
15766 node.staticElement = element;
15767 LocalVariableElementImpl variableImpl =
15768 element as LocalVariableElementImpl;
15769 if (node.inSetterContext()) {
15770 variableImpl.markPotentiallyMutatedInScope();
15771 if (element.enclosingElement != _enclosingFunction) {
15772 variableImpl.markPotentiallyMutatedInClosure();
15773 }
15774 }
15775 } else if (kind == ElementKind.PARAMETER) {
15776 node.staticElement = element; 11146 node.staticElement = element;
15777 if (node.inSetterContext()) { 11147 if (node.inSetterContext()) {
15778 ParameterElementImpl parameterImpl = element as ParameterElementImpl; 11148 _localVariableInfo.potentiallyMutatedInScope.add(element);
15779 parameterImpl.markPotentiallyMutatedInScope(); 11149 if (element.enclosingElement != _enclosingFunction) {
15780 // If we are in some closure, check if it is not the same as where 11150 _localVariableInfo.potentiallyMutatedInClosure.add(element);
15781 // variable is declared.
15782 if (_enclosingFunction != null &&
15783 (element.enclosingElement != _enclosingFunction)) {
15784 parameterImpl.markPotentiallyMutatedInClosure();
15785 } 11151 }
15786 } 11152 }
15787 } 11153 }
15788 return null; 11154 return null;
15789 } 11155 }
15790 11156
15791 @override 11157 @override
15792 Object visitTypeName(TypeName node) { 11158 Object visitTypeName(TypeName node) {
15793 return null; 11159 return null;
15794 } 11160 }
15795 } 11161 }
15796 11162
15797 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor { 11163 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor {
15798 final ConstantVerifier verifier; 11164 final ConstantVerifier verifier;
15799 11165
15800 List<ParameterElement> parameterElements; 11166 List<ParameterElement> parameterElements;
15801 11167
15802 TypeSystem _typeSystem; 11168 TypeSystem _typeSystem;
15803 11169
15804 _ConstantVerifier_validateInitializerExpression( 11170 _ConstantVerifier_validateInitializerExpression(
15805 TypeProvider typeProvider, 11171 TypeProvider typeProvider,
15806 ErrorReporter errorReporter, 11172 ErrorReporter errorReporter,
15807 this.verifier, 11173 this.verifier,
15808 this.parameterElements, 11174 this.parameterElements,
15809 DeclaredVariables declaredVariables, 11175 DeclaredVariables declaredVariables,
15810 {TypeSystem typeSystem}) 11176 {TypeSystem typeSystem})
15811 : _typeSystem = (typeSystem != null) ? typeSystem : new TypeSystemImpl(), 11177 : _typeSystem = typeSystem ?? new TypeSystemImpl(),
15812 super( 11178 super(
15813 new ConstantEvaluationEngine(typeProvider, declaredVariables, 11179 new ConstantEvaluationEngine(typeProvider, declaredVariables,
15814 typeSystem: typeSystem), 11180 typeSystem: typeSystem),
15815 errorReporter); 11181 errorReporter);
15816 11182
15817 @override 11183 @override
15818 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) { 11184 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
15819 Element element = node.staticElement; 11185 Element element = node.staticElement;
15820 for (ParameterElement parameterElement in parameterElements) { 11186 int length = parameterElements.length;
11187 for (int i = 0; i < length; i++) {
11188 ParameterElement parameterElement = parameterElements[i];
15821 if (identical(parameterElement, element) && parameterElement != null) { 11189 if (identical(parameterElement, element) && parameterElement != null) {
15822 DartType type = parameterElement.type; 11190 DartType type = parameterElement.type;
15823 if (type != null) { 11191 if (type != null) {
15824 if (type.isDynamic) { 11192 if (type.isDynamic) {
15825 return new DartObjectImpl( 11193 return new DartObjectImpl(
15826 verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE); 11194 verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE);
15827 } else if (_typeSystem.isSubtypeOf(type, verifier._boolType)) { 11195 } else if (_typeSystem.isSubtypeOf(type, verifier._boolType)) {
15828 return new DartObjectImpl( 11196 return new DartObjectImpl(
15829 verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE); 11197 verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE);
15830 } else if (_typeSystem.isSubtypeOf( 11198 } else if (_typeSystem.isSubtypeOf(
(...skipping 20 matching lines...) Expand all
15851 } 11219 }
15852 return new DartObjectImpl( 11220 return new DartObjectImpl(
15853 type is InterfaceType ? type : verifier._typeProvider.objectType, 11221 type is InterfaceType ? type : verifier._typeProvider.objectType,
15854 GenericState.UNKNOWN_VALUE); 11222 GenericState.UNKNOWN_VALUE);
15855 } 11223 }
15856 } 11224 }
15857 return super.visitSimpleIdentifier(node); 11225 return super.visitSimpleIdentifier(node);
15858 } 11226 }
15859 } 11227 }
15860 11228
15861 class _ElementBuilder_visitClassDeclaration extends UnifyingAstVisitor<Object> {
15862 final ElementBuilder builder;
15863
15864 List<ClassMember> nonFields;
15865
15866 _ElementBuilder_visitClassDeclaration(this.builder, this.nonFields) : super();
15867
15868 @override
15869 Object visitConstructorDeclaration(ConstructorDeclaration node) {
15870 nonFields.add(node);
15871 return null;
15872 }
15873
15874 @override
15875 Object visitMethodDeclaration(MethodDeclaration node) {
15876 nonFields.add(node);
15877 return null;
15878 }
15879
15880 @override
15881 Object visitNode(AstNode node) => node.accept(builder);
15882 }
15883
15884 class _ResolverVisitor_isVariableAccessedInClosure 11229 class _ResolverVisitor_isVariableAccessedInClosure
15885 extends RecursiveAstVisitor<Object> { 11230 extends RecursiveAstVisitor<Object> {
15886 final Element variable; 11231 final Element variable;
15887 11232
15888 bool result = false; 11233 bool result = false;
15889 11234
15890 bool _inClosure = false; 11235 bool _inClosure = false;
15891 11236
15892 _ResolverVisitor_isVariableAccessedInClosure(this.variable); 11237 _ResolverVisitor_isVariableAccessedInClosure(this.variable);
15893 11238
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
15928 return null; 11273 return null;
15929 } 11274 }
15930 if (identical(node.staticElement, variable)) { 11275 if (identical(node.staticElement, variable)) {
15931 if (node.inSetterContext()) { 11276 if (node.inSetterContext()) {
15932 result = true; 11277 result = true;
15933 } 11278 }
15934 } 11279 }
15935 return null; 11280 return null;
15936 } 11281 }
15937 } 11282 }
15938
15939 class _TypeResolverVisitor_visitClassMembersInScope
15940 extends UnifyingAstVisitor<Object> {
15941 final TypeResolverVisitor TypeResolverVisitor_this;
15942
15943 List<ClassMember> nonFields;
15944
15945 _TypeResolverVisitor_visitClassMembersInScope(
15946 this.TypeResolverVisitor_this, this.nonFields)
15947 : super();
15948
15949 @override
15950 Object visitConstructorDeclaration(ConstructorDeclaration node) {
15951 nonFields.add(node);
15952 return null;
15953 }
15954
15955 @override
15956 Object visitExtendsClause(ExtendsClause node) => null;
15957
15958 @override
15959 Object visitImplementsClause(ImplementsClause node) => null;
15960
15961 @override
15962 Object visitMethodDeclaration(MethodDeclaration node) {
15963 nonFields.add(node);
15964 return null;
15965 }
15966
15967 @override
15968 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this);
15969
15970 @override
15971 Object visitWithClause(WithClause node) => null;
15972 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/generated/parser.dart ('k') | packages/analyzer/lib/src/generated/scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698