OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library engine.resolver.error_verifier; | |
6 | |
7 import 'dart:collection'; | |
8 import "dart:math" as math; | |
9 | |
10 import 'package:analyzer/src/generated/static_type_analyzer.dart'; | |
11 | |
12 import 'ast.dart'; | |
13 import 'constant.dart'; | |
14 import 'element.dart'; | |
15 import 'element_resolver.dart'; | |
16 import 'error.dart'; | |
17 import 'java_engine.dart'; | |
18 import 'parser.dart' show Parser, ParserErrorCode; | |
19 import 'resolver.dart'; | |
20 import 'scanner.dart' as sc; | |
21 import 'sdk.dart' show DartSdk, SdkLibrary; | |
22 import 'utilities_dart.dart'; | |
23 | |
24 /** | |
25 * A visitor used to traverse an AST structure looking for additional errors and | |
26 * warnings not covered by the parser and resolver. | |
27 */ | |
28 class ErrorVerifier extends RecursiveAstVisitor<Object> { | |
29 /** | |
30 * Static final string with value `"getter "` used in the construction of the | |
31 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE], and | |
32 * similar, error code messages. | |
33 * | |
34 * See [_checkForNonAbstractClassInheritsAbstractMember]. | |
35 */ | |
36 static String _GETTER_SPACE = "getter "; | |
37 | |
38 /** | |
39 * Static final string with value `"setter "` used in the construction of the | |
40 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE], and | |
41 * similar, error code messages. | |
42 * | |
43 * See [_checkForNonAbstractClassInheritsAbstractMember]. | |
44 */ | |
45 static String _SETTER_SPACE = "setter "; | |
46 | |
47 /** | |
48 * The error reporter by which errors will be reported. | |
49 */ | |
50 final ErrorReporter _errorReporter; | |
51 | |
52 /** | |
53 * The current library that is being analyzed. | |
54 */ | |
55 final LibraryElement _currentLibrary; | |
56 | |
57 /** | |
58 * The type representing the type 'bool'. | |
59 */ | |
60 InterfaceType _boolType; | |
61 | |
62 /** | |
63 * The type representing the type 'int'. | |
64 */ | |
65 InterfaceType _intType; | |
66 | |
67 /** | |
68 * The object providing access to the types defined by the language. | |
69 */ | |
70 final TypeProvider _typeProvider; | |
71 | |
72 /** | |
73 * The manager for the inheritance mappings. | |
74 */ | |
75 final InheritanceManager _inheritanceManager; | |
76 | |
77 /** | |
78 * A flag indicating whether the visitor is currently within a constructor | |
79 * declaration that is 'const'. | |
80 * | |
81 * See [visitConstructorDeclaration]. | |
82 */ | |
83 bool _isEnclosingConstructorConst = false; | |
84 | |
85 /** | |
86 * A flag indicating whether we are currently within a function body marked as | |
87 * being asynchronous. | |
88 */ | |
89 bool _inAsync = false; | |
90 | |
91 /** | |
92 * A flag indicating whether we are currently within a function body marked a | |
93 * being a generator. | |
94 */ | |
95 bool _inGenerator = false; | |
96 | |
97 /** | |
98 * A flag indicating whether the visitor is currently within a catch clause. | |
99 * | |
100 * See [visitCatchClause]. | |
101 */ | |
102 bool _isInCatchClause = false; | |
103 | |
104 /** | |
105 * A flag indicating whether the visitor is currently within a comment. | |
106 */ | |
107 bool _isInComment = false; | |
108 | |
109 /** | |
110 * A flag indicating whether the visitor is currently within an instance | |
111 * creation expression. | |
112 */ | |
113 bool _isInConstInstanceCreation = false; | |
114 | |
115 /** | |
116 * A flag indicating whether the visitor is currently within a native class | |
117 * declaration. | |
118 */ | |
119 bool _isInNativeClass = false; | |
120 | |
121 /** | |
122 * A flag indicating whether the visitor is currently within a static variable | |
123 * declaration. | |
124 */ | |
125 bool _isInStaticVariableDeclaration = false; | |
126 | |
127 /** | |
128 * A flag indicating whether the visitor is currently within an instance | |
129 * variable declaration. | |
130 */ | |
131 bool _isInInstanceVariableDeclaration = false; | |
132 | |
133 /** | |
134 * A flag indicating whether the visitor is currently within an instance | |
135 * variable initializer. | |
136 */ | |
137 bool _isInInstanceVariableInitializer = false; | |
138 | |
139 /** | |
140 * A flag indicating whether the visitor is currently within a constructor | |
141 * initializer. | |
142 */ | |
143 bool _isInConstructorInitializer = false; | |
144 | |
145 /** | |
146 * This is set to `true` iff the visitor is currently within a function typed | |
147 * formal parameter. | |
148 */ | |
149 bool _isInFunctionTypedFormalParameter = false; | |
150 | |
151 /** | |
152 * A flag indicating whether the visitor is currently within a static method. | |
153 * By "method" here getter, setter and operator declarations are also implied | |
154 * since they are all represented with a [MethodDeclaration] in the AST | |
155 * structure. | |
156 */ | |
157 bool _isInStaticMethod = false; | |
158 | |
159 /** | |
160 * A flag indicating whether the visitor is currently within a factory | |
161 * constructor. | |
162 */ | |
163 bool _isInFactory = false; | |
164 | |
165 /** | |
166 * A flag indicating whether the visitor is currently within code in the SDK. | |
167 */ | |
168 bool _isInSystemLibrary = false; | |
169 | |
170 /** | |
171 * A flag indicating whether the current library contains at least one import | |
172 * directive with a URI that uses the "dart-ext" scheme. | |
173 */ | |
174 bool _hasExtUri = false; | |
175 | |
176 /** | |
177 * This is set to `false` on the entry of every [BlockFunctionBody], and is | |
178 * restored to the enclosing value on exit. The value is used in | |
179 * [_checkForMixedReturns] to prevent both | |
180 * [StaticWarningCode.MIXED_RETURN_TYPES] and | |
181 * [StaticWarningCode.RETURN_WITHOUT_VALUE] from being generated in the same | |
182 * function body. | |
183 */ | |
184 bool _hasReturnWithoutValue = false; | |
185 | |
186 /** | |
187 * The class containing the AST nodes being visited, or `null` if we are not | |
188 * in the scope of a class. | |
189 */ | |
190 ClassElement _enclosingClass; | |
191 | |
192 /** | |
193 * The method or function that we are currently visiting, or `null` if we are | |
194 * not inside a method or function. | |
195 */ | |
196 ExecutableElement _enclosingFunction; | |
197 | |
198 /** | |
199 * The return statements found in the method or function that we are currently | |
200 * visiting that have a return value. | |
201 */ | |
202 List<ReturnStatement> _returnsWith = new List<ReturnStatement>(); | |
203 | |
204 /** | |
205 * The return statements found in the method or function that we are currently | |
206 * visiting that do not have a return value. | |
207 */ | |
208 List<ReturnStatement> _returnsWithout = new List<ReturnStatement>(); | |
209 | |
210 /** | |
211 * This map is initialized when visiting the contents of a class declaration. | |
212 * If the visitor is not in an enclosing class declaration, then the map is | |
213 * set to `null`. | |
214 * | |
215 * When set the map maps the set of [FieldElement]s in the class to an | |
216 * [INIT_STATE.NOT_INIT] or [INIT_STATE.INIT_IN_DECLARATION]. The `checkFor*` | |
217 * methods, specifically [_checkForAllFinalInitializedErrorCodes], can make a | |
218 * copy of the map to compute error code states. The `checkFor*` methods | |
219 * should only ever make a copy, or read from this map after it has been set | |
220 * in [visitClassDeclaration]. | |
221 * | |
222 * See [visitClassDeclaration], and [_checkForAllFinalInitializedErrorCodes]. | |
223 */ | |
224 HashMap<FieldElement, INIT_STATE> _initialFieldElementsMap; | |
225 | |
226 /** | |
227 * A table mapping name of the library to the export directive which export | |
228 * this library. | |
229 */ | |
230 HashMap<String, LibraryElement> _nameToExportElement = | |
231 new HashMap<String, LibraryElement>(); | |
232 | |
233 /** | |
234 * A table mapping name of the library to the import directive which import | |
235 * this library. | |
236 */ | |
237 HashMap<String, LibraryElement> _nameToImportElement = | |
238 new HashMap<String, LibraryElement>(); | |
239 | |
240 /** | |
241 * A table mapping names to the exported elements. | |
242 */ | |
243 HashMap<String, Element> _exportedElements = new HashMap<String, Element>(); | |
244 | |
245 /** | |
246 * A set of the names of the variable initializers we are visiting now. | |
247 */ | |
248 HashSet<String> _namesForReferenceToDeclaredVariableInInitializer = | |
249 new HashSet<String>(); | |
250 | |
251 /** | |
252 * A list of types used by the [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS] | |
253 * and [CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS] error codes. | |
254 */ | |
255 List<InterfaceType> _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT; | |
256 | |
257 /** | |
258 * Initialize a newly created error verifier. | |
259 */ | |
260 ErrorVerifier(this._errorReporter, this._currentLibrary, this._typeProvider, | |
261 this._inheritanceManager) { | |
262 this._isInSystemLibrary = _currentLibrary.source.isInSystemLibrary; | |
263 this._hasExtUri = _currentLibrary.hasExtUri; | |
264 _isEnclosingConstructorConst = false; | |
265 _isInCatchClause = false; | |
266 _isInStaticVariableDeclaration = false; | |
267 _isInInstanceVariableDeclaration = false; | |
268 _isInInstanceVariableInitializer = false; | |
269 _isInConstructorInitializer = false; | |
270 _isInStaticMethod = false; | |
271 _boolType = _typeProvider.boolType; | |
272 _intType = _typeProvider.intType; | |
273 _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT = _typeProvider.nonSubtypableTypes; | |
274 } | |
275 | |
276 @override | |
277 Object visitAnnotation(Annotation node) { | |
278 _checkForInvalidAnnotationFromDeferredLibrary(node); | |
279 return super.visitAnnotation(node); | |
280 } | |
281 | |
282 @override | |
283 Object visitArgumentList(ArgumentList node) { | |
284 _checkForArgumentTypesNotAssignableInList(node); | |
285 return super.visitArgumentList(node); | |
286 } | |
287 | |
288 @override | |
289 Object visitAsExpression(AsExpression node) { | |
290 _checkForTypeAnnotationDeferredClass(node.type); | |
291 return super.visitAsExpression(node); | |
292 } | |
293 | |
294 @override | |
295 Object visitAssertStatement(AssertStatement node) { | |
296 _checkForNonBoolExpression(node); | |
297 return super.visitAssertStatement(node); | |
298 } | |
299 | |
300 @override | |
301 Object visitAssignmentExpression(AssignmentExpression node) { | |
302 sc.TokenType operatorType = node.operator.type; | |
303 Expression lhs = node.leftHandSide; | |
304 Expression rhs = node.rightHandSide; | |
305 if (operatorType == sc.TokenType.EQ || | |
306 operatorType == sc.TokenType.QUESTION_QUESTION_EQ) { | |
307 _checkForInvalidAssignment(lhs, rhs); | |
308 } else { | |
309 _checkForInvalidCompoundAssignment(node, lhs, rhs); | |
310 _checkForArgumentTypeNotAssignableForArgument(rhs); | |
311 } | |
312 _checkForAssignmentToFinal(lhs); | |
313 return super.visitAssignmentExpression(node); | |
314 } | |
315 | |
316 @override | |
317 Object visitAwaitExpression(AwaitExpression node) { | |
318 if (!_inAsync) { | |
319 _errorReporter.reportErrorForToken( | |
320 CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT, node.awaitKeyword); | |
321 } | |
322 return super.visitAwaitExpression(node); | |
323 } | |
324 | |
325 @override | |
326 Object visitBinaryExpression(BinaryExpression node) { | |
327 sc.Token operator = node.operator; | |
328 sc.TokenType type = operator.type; | |
329 if (type == sc.TokenType.AMPERSAND_AMPERSAND || | |
330 type == sc.TokenType.BAR_BAR) { | |
331 String lexeme = operator.lexeme; | |
332 _checkForAssignability(node.leftOperand, _boolType, | |
333 StaticTypeWarningCode.NON_BOOL_OPERAND, [lexeme]); | |
334 _checkForAssignability(node.rightOperand, _boolType, | |
335 StaticTypeWarningCode.NON_BOOL_OPERAND, [lexeme]); | |
336 } else { | |
337 _checkForArgumentTypeNotAssignableForArgument(node.rightOperand); | |
338 } | |
339 return super.visitBinaryExpression(node); | |
340 } | |
341 | |
342 @override | |
343 Object visitBlockFunctionBody(BlockFunctionBody node) { | |
344 bool wasInAsync = _inAsync; | |
345 bool wasInGenerator = _inGenerator; | |
346 bool previousHasReturnWithoutValue = _hasReturnWithoutValue; | |
347 _hasReturnWithoutValue = false; | |
348 List<ReturnStatement> previousReturnsWith = _returnsWith; | |
349 List<ReturnStatement> previousReturnsWithout = _returnsWithout; | |
350 try { | |
351 _inAsync = node.isAsynchronous; | |
352 _inGenerator = node.isGenerator; | |
353 _returnsWith = new List<ReturnStatement>(); | |
354 _returnsWithout = new List<ReturnStatement>(); | |
355 super.visitBlockFunctionBody(node); | |
356 _checkForMixedReturns(node); | |
357 } finally { | |
358 _inAsync = wasInAsync; | |
359 _inGenerator = wasInGenerator; | |
360 _returnsWith = previousReturnsWith; | |
361 _returnsWithout = previousReturnsWithout; | |
362 _hasReturnWithoutValue = previousHasReturnWithoutValue; | |
363 } | |
364 return null; | |
365 } | |
366 | |
367 @override | |
368 Object visitBreakStatement(BreakStatement node) { | |
369 SimpleIdentifier labelNode = node.label; | |
370 if (labelNode != null) { | |
371 Element labelElement = labelNode.staticElement; | |
372 if (labelElement is LabelElementImpl && labelElement.isOnSwitchMember) { | |
373 _errorReporter.reportErrorForNode( | |
374 ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labelNode); | |
375 } | |
376 } | |
377 return null; | |
378 } | |
379 | |
380 @override | |
381 Object visitCatchClause(CatchClause node) { | |
382 bool previousIsInCatchClause = _isInCatchClause; | |
383 try { | |
384 _isInCatchClause = true; | |
385 _checkForTypeAnnotationDeferredClass(node.exceptionType); | |
386 return super.visitCatchClause(node); | |
387 } finally { | |
388 _isInCatchClause = previousIsInCatchClause; | |
389 } | |
390 } | |
391 | |
392 @override | |
393 Object visitClassDeclaration(ClassDeclaration node) { | |
394 ClassElement outerClass = _enclosingClass; | |
395 try { | |
396 _isInNativeClass = node.nativeClause != null; | |
397 _enclosingClass = node.element; | |
398 ExtendsClause extendsClause = node.extendsClause; | |
399 ImplementsClause implementsClause = node.implementsClause; | |
400 WithClause withClause = node.withClause; | |
401 _checkForBuiltInIdentifierAsName( | |
402 node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME); | |
403 _checkForMemberWithClassName(); | |
404 _checkForNoDefaultSuperConstructorImplicit(node); | |
405 _checkForConflictingTypeVariableErrorCodes(node); | |
406 // Only do error checks on the clause nodes if there is a non-null clause | |
407 if (implementsClause != null || | |
408 extendsClause != null || | |
409 withClause != null) { | |
410 // Only check for all of the inheritance logic around clauses if there | |
411 // isn't an error code such as "Cannot extend double" already on the | |
412 // class. | |
413 if (!_checkForImplementsDisallowedClass(implementsClause) && | |
414 !_checkForExtendsDisallowedClass(extendsClause) && | |
415 !_checkForAllMixinErrorCodes(withClause)) { | |
416 _checkForExtendsDeferredClass(extendsClause); | |
417 _checkForImplementsDeferredClass(implementsClause); | |
418 _checkForNonAbstractClassInheritsAbstractMember(node.name); | |
419 _checkForInconsistentMethodInheritance(); | |
420 _checkForRecursiveInterfaceInheritance(_enclosingClass); | |
421 _checkForConflictingGetterAndMethod(); | |
422 _checkForConflictingInstanceGetterAndSuperclassMember(); | |
423 _checkImplementsSuperClass(node); | |
424 _checkImplementsFunctionWithoutCall(node); | |
425 _checkForMixinHasNoConstructors(node); | |
426 } | |
427 } | |
428 visitClassDeclarationIncrementally(node); | |
429 _checkForFinalNotInitializedInClass(node); | |
430 _checkForDuplicateDefinitionInheritance(); | |
431 _checkForConflictingInstanceMethodSetter(node); | |
432 return super.visitClassDeclaration(node); | |
433 } finally { | |
434 _isInNativeClass = false; | |
435 _initialFieldElementsMap = null; | |
436 _enclosingClass = outerClass; | |
437 } | |
438 } | |
439 | |
440 /** | |
441 * Implementation of this method should be synchronized with | |
442 * [visitClassDeclaration]. | |
443 */ | |
444 void visitClassDeclarationIncrementally(ClassDeclaration node) { | |
445 _isInNativeClass = node.nativeClause != null; | |
446 _enclosingClass = node.element; | |
447 // initialize initialFieldElementsMap | |
448 if (_enclosingClass != null) { | |
449 List<FieldElement> fieldElements = _enclosingClass.fields; | |
450 _initialFieldElementsMap = new HashMap<FieldElement, INIT_STATE>(); | |
451 for (FieldElement fieldElement in fieldElements) { | |
452 if (!fieldElement.isSynthetic) { | |
453 _initialFieldElementsMap[fieldElement] = fieldElement.initializer == | |
454 null ? INIT_STATE.NOT_INIT : INIT_STATE.INIT_IN_DECLARATION; | |
455 } | |
456 } | |
457 } | |
458 } | |
459 | |
460 @override | |
461 Object visitClassTypeAlias(ClassTypeAlias node) { | |
462 _checkForBuiltInIdentifierAsName( | |
463 node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME); | |
464 ClassElement outerClassElement = _enclosingClass; | |
465 try { | |
466 _enclosingClass = node.element; | |
467 ImplementsClause implementsClause = node.implementsClause; | |
468 // Only check for all of the inheritance logic around clauses if there | |
469 // isn't an error code such as "Cannot extend double" already on the | |
470 // class. | |
471 if (!_checkForExtendsDisallowedClassInTypeAlias(node) && | |
472 !_checkForImplementsDisallowedClass(implementsClause) && | |
473 !_checkForAllMixinErrorCodes(node.withClause)) { | |
474 _checkForExtendsDeferredClassInTypeAlias(node); | |
475 _checkForImplementsDeferredClass(implementsClause); | |
476 _checkForRecursiveInterfaceInheritance(_enclosingClass); | |
477 _checkForNonAbstractClassInheritsAbstractMember(node.name); | |
478 _checkForMixinHasNoConstructors(node); | |
479 } | |
480 } finally { | |
481 _enclosingClass = outerClassElement; | |
482 } | |
483 return super.visitClassTypeAlias(node); | |
484 } | |
485 | |
486 @override | |
487 Object visitComment(Comment node) { | |
488 _isInComment = true; | |
489 try { | |
490 return super.visitComment(node); | |
491 } finally { | |
492 _isInComment = false; | |
493 } | |
494 } | |
495 | |
496 @override | |
497 Object visitCompilationUnit(CompilationUnit node) { | |
498 _checkForDeferredPrefixCollisions(node); | |
499 return super.visitCompilationUnit(node); | |
500 } | |
501 | |
502 @override | |
503 Object visitConditionalExpression(ConditionalExpression node) { | |
504 _checkForNonBoolCondition(node.condition); | |
505 return super.visitConditionalExpression(node); | |
506 } | |
507 | |
508 @override | |
509 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
510 ExecutableElement outerFunction = _enclosingFunction; | |
511 try { | |
512 ConstructorElement constructorElement = node.element; | |
513 _enclosingFunction = constructorElement; | |
514 _isEnclosingConstructorConst = node.constKeyword != null; | |
515 _isInFactory = node.factoryKeyword != null; | |
516 _checkForInvalidModifierOnBody( | |
517 node.body, CompileTimeErrorCode.INVALID_MODIFIER_ON_CONSTRUCTOR); | |
518 _checkForConstConstructorWithNonFinalField(node, constructorElement); | |
519 _checkForConstConstructorWithNonConstSuper(node); | |
520 _checkForConflictingConstructorNameAndMember(node, constructorElement); | |
521 _checkForAllFinalInitializedErrorCodes(node); | |
522 _checkForRedirectingConstructorErrorCodes(node); | |
523 _checkForMultipleSuperInitializers(node); | |
524 _checkForRecursiveConstructorRedirect(node, constructorElement); | |
525 if (!_checkForRecursiveFactoryRedirect(node, constructorElement)) { | |
526 _checkForAllRedirectConstructorErrorCodes(node); | |
527 } | |
528 _checkForUndefinedConstructorInInitializerImplicit(node); | |
529 _checkForRedirectToNonConstConstructor(node, constructorElement); | |
530 _checkForReturnInGenerativeConstructor(node); | |
531 return super.visitConstructorDeclaration(node); | |
532 } finally { | |
533 _isEnclosingConstructorConst = false; | |
534 _isInFactory = false; | |
535 _enclosingFunction = outerFunction; | |
536 } | |
537 } | |
538 | |
539 @override | |
540 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
541 _isInConstructorInitializer = true; | |
542 try { | |
543 SimpleIdentifier fieldName = node.fieldName; | |
544 Element staticElement = fieldName.staticElement; | |
545 _checkForInvalidField(node, fieldName, staticElement); | |
546 _checkForFieldInitializerNotAssignable(node, staticElement); | |
547 return super.visitConstructorFieldInitializer(node); | |
548 } finally { | |
549 _isInConstructorInitializer = false; | |
550 } | |
551 } | |
552 | |
553 @override | |
554 Object visitContinueStatement(ContinueStatement node) { | |
555 SimpleIdentifier labelNode = node.label; | |
556 if (labelNode != null) { | |
557 Element labelElement = labelNode.staticElement; | |
558 if (labelElement is LabelElementImpl && | |
559 labelElement.isOnSwitchStatement) { | |
560 _errorReporter.reportErrorForNode( | |
561 ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode); | |
562 } | |
563 } | |
564 return null; | |
565 } | |
566 | |
567 @override | |
568 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
569 _checkForInvalidAssignment(node.identifier, node.defaultValue); | |
570 _checkForDefaultValueInFunctionTypedParameter(node); | |
571 return super.visitDefaultFormalParameter(node); | |
572 } | |
573 | |
574 @override | |
575 Object visitDoStatement(DoStatement node) { | |
576 _checkForNonBoolCondition(node.condition); | |
577 return super.visitDoStatement(node); | |
578 } | |
579 | |
580 @override | |
581 Object visitExportDirective(ExportDirective node) { | |
582 ExportElement exportElement = node.element; | |
583 if (exportElement != null) { | |
584 LibraryElement exportedLibrary = exportElement.exportedLibrary; | |
585 _checkForAmbiguousExport(node, exportElement, exportedLibrary); | |
586 _checkForExportDuplicateLibraryName(node, exportElement, exportedLibrary); | |
587 _checkForExportInternalLibrary(node, exportElement); | |
588 } | |
589 return super.visitExportDirective(node); | |
590 } | |
591 | |
592 @override | |
593 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { | |
594 bool wasInAsync = _inAsync; | |
595 bool wasInGenerator = _inGenerator; | |
596 try { | |
597 _inAsync = node.isAsynchronous; | |
598 _inGenerator = node.isGenerator; | |
599 FunctionType functionType = | |
600 _enclosingFunction == null ? null : _enclosingFunction.type; | |
601 DartType expectedReturnType = functionType == null | |
602 ? DynamicTypeImpl.instance | |
603 : functionType.returnType; | |
604 _checkForReturnOfInvalidType(node.expression, expectedReturnType); | |
605 return super.visitExpressionFunctionBody(node); | |
606 } finally { | |
607 _inAsync = wasInAsync; | |
608 _inGenerator = wasInGenerator; | |
609 } | |
610 } | |
611 | |
612 @override | |
613 Object visitFieldDeclaration(FieldDeclaration node) { | |
614 _isInStaticVariableDeclaration = node.isStatic; | |
615 _isInInstanceVariableDeclaration = !_isInStaticVariableDeclaration; | |
616 if (_isInInstanceVariableDeclaration) { | |
617 VariableDeclarationList variables = node.fields; | |
618 if (variables.isConst) { | |
619 _errorReporter.reportErrorForToken( | |
620 CompileTimeErrorCode.CONST_INSTANCE_FIELD, variables.keyword); | |
621 } | |
622 } | |
623 try { | |
624 _checkForAllInvalidOverrideErrorCodesForField(node); | |
625 return super.visitFieldDeclaration(node); | |
626 } finally { | |
627 _isInStaticVariableDeclaration = false; | |
628 _isInInstanceVariableDeclaration = false; | |
629 } | |
630 } | |
631 | |
632 @override | |
633 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
634 _checkForValidField(node); | |
635 _checkForConstFormalParameter(node); | |
636 _checkForPrivateOptionalParameter(node); | |
637 _checkForFieldInitializingFormalRedirectingConstructor(node); | |
638 _checkForTypeAnnotationDeferredClass(node.type); | |
639 return super.visitFieldFormalParameter(node); | |
640 } | |
641 | |
642 @override | |
643 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
644 ExecutableElement outerFunction = _enclosingFunction; | |
645 try { | |
646 SimpleIdentifier identifier = node.name; | |
647 String methodName = ""; | |
648 if (identifier != null) { | |
649 methodName = identifier.name; | |
650 } | |
651 _enclosingFunction = node.element; | |
652 TypeName returnType = node.returnType; | |
653 if (node.isSetter || node.isGetter) { | |
654 _checkForMismatchedAccessorTypes(node, methodName); | |
655 if (node.isSetter) { | |
656 FunctionExpression functionExpression = node.functionExpression; | |
657 if (functionExpression != null) { | |
658 _checkForWrongNumberOfParametersForSetter( | |
659 identifier, functionExpression.parameters); | |
660 } | |
661 _checkForNonVoidReturnTypeForSetter(returnType); | |
662 } | |
663 } | |
664 if (node.isSetter) { | |
665 _checkForInvalidModifierOnBody(node.functionExpression.body, | |
666 CompileTimeErrorCode.INVALID_MODIFIER_ON_SETTER); | |
667 } | |
668 _checkForTypeAnnotationDeferredClass(returnType); | |
669 _checkForIllegalReturnType(returnType); | |
670 return super.visitFunctionDeclaration(node); | |
671 } finally { | |
672 _enclosingFunction = outerFunction; | |
673 } | |
674 } | |
675 | |
676 @override | |
677 Object visitFunctionExpression(FunctionExpression node) { | |
678 // If this function expression is wrapped in a function declaration, don't | |
679 // change the enclosingFunction field. | |
680 if (node.parent is! FunctionDeclaration) { | |
681 ExecutableElement outerFunction = _enclosingFunction; | |
682 try { | |
683 _enclosingFunction = node.element; | |
684 return super.visitFunctionExpression(node); | |
685 } finally { | |
686 _enclosingFunction = outerFunction; | |
687 } | |
688 } else { | |
689 return super.visitFunctionExpression(node); | |
690 } | |
691 } | |
692 | |
693 @override | |
694 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
695 Expression functionExpression = node.function; | |
696 DartType expressionType = functionExpression.staticType; | |
697 if (!_isFunctionType(expressionType)) { | |
698 _errorReporter.reportErrorForNode( | |
699 StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, | |
700 functionExpression); | |
701 } | |
702 return super.visitFunctionExpressionInvocation(node); | |
703 } | |
704 | |
705 @override | |
706 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
707 _checkForBuiltInIdentifierAsName( | |
708 node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME); | |
709 _checkForDefaultValueInFunctionTypeAlias(node); | |
710 _checkForTypeAliasCannotReferenceItself_function(node); | |
711 return super.visitFunctionTypeAlias(node); | |
712 } | |
713 | |
714 @override | |
715 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
716 bool old = _isInFunctionTypedFormalParameter; | |
717 _isInFunctionTypedFormalParameter = true; | |
718 try { | |
719 _checkForTypeAnnotationDeferredClass(node.returnType); | |
720 return super.visitFunctionTypedFormalParameter(node); | |
721 } finally { | |
722 _isInFunctionTypedFormalParameter = old; | |
723 } | |
724 } | |
725 | |
726 @override | |
727 Object visitIfStatement(IfStatement node) { | |
728 _checkForNonBoolCondition(node.condition); | |
729 return super.visitIfStatement(node); | |
730 } | |
731 | |
732 @override | |
733 Object visitImportDirective(ImportDirective node) { | |
734 ImportElement importElement = node.element; | |
735 if (importElement != null) { | |
736 _checkForImportDuplicateLibraryName(node, importElement); | |
737 _checkForImportInternalLibrary(node, importElement); | |
738 } | |
739 return super.visitImportDirective(node); | |
740 } | |
741 | |
742 @override | |
743 Object visitIndexExpression(IndexExpression node) { | |
744 _checkForArgumentTypeNotAssignableForArgument(node.index); | |
745 return super.visitIndexExpression(node); | |
746 } | |
747 | |
748 @override | |
749 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
750 bool wasInConstInstanceCreation = _isInConstInstanceCreation; | |
751 _isInConstInstanceCreation = node.isConst; | |
752 try { | |
753 ConstructorName constructorName = node.constructorName; | |
754 TypeName typeName = constructorName.type; | |
755 DartType type = typeName.type; | |
756 if (type is InterfaceType) { | |
757 InterfaceType interfaceType = type; | |
758 _checkForConstOrNewWithAbstractClass(node, typeName, interfaceType); | |
759 _checkForConstOrNewWithEnum(node, typeName, interfaceType); | |
760 if (_isInConstInstanceCreation) { | |
761 _checkForConstWithNonConst(node); | |
762 _checkForConstWithUndefinedConstructor( | |
763 node, constructorName, typeName); | |
764 _checkForConstWithTypeParameters(typeName); | |
765 _checkForConstDeferredClass(node, constructorName, typeName); | |
766 } else { | |
767 _checkForNewWithUndefinedConstructor(node, constructorName, typeName); | |
768 } | |
769 } | |
770 return super.visitInstanceCreationExpression(node); | |
771 } finally { | |
772 _isInConstInstanceCreation = wasInConstInstanceCreation; | |
773 } | |
774 } | |
775 | |
776 @override | |
777 Object visitIsExpression(IsExpression node) { | |
778 _checkForTypeAnnotationDeferredClass(node.type); | |
779 return super.visitIsExpression(node); | |
780 } | |
781 | |
782 @override | |
783 Object visitListLiteral(ListLiteral node) { | |
784 TypeArgumentList typeArguments = node.typeArguments; | |
785 if (typeArguments != null) { | |
786 if (node.constKeyword != null) { | |
787 NodeList<TypeName> arguments = typeArguments.arguments; | |
788 if (arguments.length != 0) { | |
789 _checkForInvalidTypeArgumentInConstTypedLiteral(arguments, | |
790 CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_LIST); | |
791 } | |
792 } | |
793 _checkForExpectedOneListTypeArgument(node, typeArguments); | |
794 _checkForListElementTypeNotAssignable(node, typeArguments); | |
795 } | |
796 return super.visitListLiteral(node); | |
797 } | |
798 | |
799 @override | |
800 Object visitMapLiteral(MapLiteral node) { | |
801 TypeArgumentList typeArguments = node.typeArguments; | |
802 if (typeArguments != null) { | |
803 NodeList<TypeName> arguments = typeArguments.arguments; | |
804 if (arguments.length != 0) { | |
805 if (node.constKeyword != null) { | |
806 _checkForInvalidTypeArgumentInConstTypedLiteral(arguments, | |
807 CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_MAP); | |
808 } | |
809 } | |
810 _checkExpectedTwoMapTypeArguments(typeArguments); | |
811 _checkForMapTypeNotAssignable(node, typeArguments); | |
812 } | |
813 _checkForNonConstMapAsExpressionStatement(node); | |
814 return super.visitMapLiteral(node); | |
815 } | |
816 | |
817 @override | |
818 Object visitMethodDeclaration(MethodDeclaration node) { | |
819 ExecutableElement previousFunction = _enclosingFunction; | |
820 try { | |
821 _isInStaticMethod = node.isStatic; | |
822 _enclosingFunction = node.element; | |
823 SimpleIdentifier identifier = node.name; | |
824 String methodName = ""; | |
825 if (identifier != null) { | |
826 methodName = identifier.name; | |
827 } | |
828 TypeName returnTypeName = node.returnType; | |
829 if (node.isSetter || node.isGetter) { | |
830 _checkForMismatchedAccessorTypes(node, methodName); | |
831 } | |
832 if (node.isGetter) { | |
833 _checkForVoidReturnType(node); | |
834 _checkForConflictingStaticGetterAndInstanceSetter(node); | |
835 } else if (node.isSetter) { | |
836 _checkForInvalidModifierOnBody( | |
837 node.body, CompileTimeErrorCode.INVALID_MODIFIER_ON_SETTER); | |
838 _checkForWrongNumberOfParametersForSetter(node.name, node.parameters); | |
839 _checkForNonVoidReturnTypeForSetter(returnTypeName); | |
840 _checkForConflictingStaticSetterAndInstanceMember(node); | |
841 } else if (node.isOperator) { | |
842 _checkForOptionalParameterInOperator(node); | |
843 _checkForWrongNumberOfParametersForOperator(node); | |
844 _checkForNonVoidReturnTypeForOperator(node); | |
845 } | |
846 _checkForConcreteClassWithAbstractMember(node); | |
847 _checkForAllInvalidOverrideErrorCodesForMethod(node); | |
848 _checkForTypeAnnotationDeferredClass(returnTypeName); | |
849 _checkForIllegalReturnType(returnTypeName); | |
850 return super.visitMethodDeclaration(node); | |
851 } finally { | |
852 _enclosingFunction = previousFunction; | |
853 _isInStaticMethod = false; | |
854 } | |
855 } | |
856 | |
857 @override | |
858 Object visitMethodInvocation(MethodInvocation node) { | |
859 Expression target = node.realTarget; | |
860 SimpleIdentifier methodName = node.methodName; | |
861 if (target != null) { | |
862 bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD; | |
863 ClassElement typeReference = | |
864 ElementResolver.getTypeReference(target, isConditional); | |
865 _checkForStaticAccessToInstanceMember(typeReference, methodName); | |
866 _checkForInstanceAccessToStaticMember(typeReference, methodName); | |
867 } else { | |
868 _checkForUnqualifiedReferenceToNonLocalStaticMember(methodName); | |
869 } | |
870 return super.visitMethodInvocation(node); | |
871 } | |
872 | |
873 @override | |
874 Object visitNativeClause(NativeClause node) { | |
875 // TODO(brianwilkerson) Figure out the right rule for when 'native' is | |
876 // allowed. | |
877 if (!_isInSystemLibrary) { | |
878 _errorReporter.reportErrorForNode( | |
879 ParserErrorCode.NATIVE_CLAUSE_IN_NON_SDK_CODE, node); | |
880 } | |
881 return super.visitNativeClause(node); | |
882 } | |
883 | |
884 @override | |
885 Object visitNativeFunctionBody(NativeFunctionBody node) { | |
886 _checkForNativeFunctionBodyInNonSDKCode(node); | |
887 return super.visitNativeFunctionBody(node); | |
888 } | |
889 | |
890 @override | |
891 Object visitPostfixExpression(PostfixExpression node) { | |
892 _checkForAssignmentToFinal(node.operand); | |
893 _checkForIntNotAssignable(node.operand); | |
894 return super.visitPostfixExpression(node); | |
895 } | |
896 | |
897 @override | |
898 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
899 if (node.parent is! Annotation) { | |
900 ClassElement typeReference = | |
901 ElementResolver.getTypeReference(node.prefix, false); | |
902 SimpleIdentifier name = node.identifier; | |
903 _checkForStaticAccessToInstanceMember(typeReference, name); | |
904 _checkForInstanceAccessToStaticMember(typeReference, name); | |
905 } | |
906 return super.visitPrefixedIdentifier(node); | |
907 } | |
908 | |
909 @override | |
910 Object visitPrefixExpression(PrefixExpression node) { | |
911 sc.TokenType operatorType = node.operator.type; | |
912 Expression operand = node.operand; | |
913 if (operatorType == sc.TokenType.BANG) { | |
914 _checkForNonBoolNegationExpression(operand); | |
915 } else if (operatorType.isIncrementOperator) { | |
916 _checkForAssignmentToFinal(operand); | |
917 } | |
918 _checkForIntNotAssignable(operand); | |
919 return super.visitPrefixExpression(node); | |
920 } | |
921 | |
922 @override | |
923 Object visitPropertyAccess(PropertyAccess node) { | |
924 bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD; | |
925 ClassElement typeReference = | |
926 ElementResolver.getTypeReference(node.realTarget, isConditional); | |
927 SimpleIdentifier propertyName = node.propertyName; | |
928 _checkForStaticAccessToInstanceMember(typeReference, propertyName); | |
929 _checkForInstanceAccessToStaticMember(typeReference, propertyName); | |
930 return super.visitPropertyAccess(node); | |
931 } | |
932 | |
933 @override | |
934 Object visitRedirectingConstructorInvocation( | |
935 RedirectingConstructorInvocation node) { | |
936 _isInConstructorInitializer = true; | |
937 try { | |
938 return super.visitRedirectingConstructorInvocation(node); | |
939 } finally { | |
940 _isInConstructorInitializer = false; | |
941 } | |
942 } | |
943 | |
944 @override | |
945 Object visitRethrowExpression(RethrowExpression node) { | |
946 _checkForRethrowOutsideCatch(node); | |
947 return super.visitRethrowExpression(node); | |
948 } | |
949 | |
950 @override | |
951 Object visitReturnStatement(ReturnStatement node) { | |
952 if (node.expression == null) { | |
953 _returnsWithout.add(node); | |
954 } else { | |
955 _returnsWith.add(node); | |
956 } | |
957 _checkForAllReturnStatementErrorCodes(node); | |
958 return super.visitReturnStatement(node); | |
959 } | |
960 | |
961 @override | |
962 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
963 _checkForConstFormalParameter(node); | |
964 _checkForPrivateOptionalParameter(node); | |
965 _checkForTypeAnnotationDeferredClass(node.type); | |
966 return super.visitSimpleFormalParameter(node); | |
967 } | |
968 | |
969 @override | |
970 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
971 _checkForImplicitThisReferenceInInitializer(node); | |
972 if (!_isUnqualifiedReferenceToNonLocalStaticMemberAllowed(node)) { | |
973 _checkForUnqualifiedReferenceToNonLocalStaticMember(node); | |
974 } | |
975 return super.visitSimpleIdentifier(node); | |
976 } | |
977 | |
978 @override | |
979 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
980 _isInConstructorInitializer = true; | |
981 try { | |
982 return super.visitSuperConstructorInvocation(node); | |
983 } finally { | |
984 _isInConstructorInitializer = false; | |
985 } | |
986 } | |
987 | |
988 @override | |
989 Object visitSwitchStatement(SwitchStatement node) { | |
990 _checkForSwitchExpressionNotAssignable(node); | |
991 _checkForCaseBlocksNotTerminated(node); | |
992 _checkForMissingEnumConstantInSwitch(node); | |
993 return super.visitSwitchStatement(node); | |
994 } | |
995 | |
996 @override | |
997 Object visitThisExpression(ThisExpression node) { | |
998 _checkForInvalidReferenceToThis(node); | |
999 return super.visitThisExpression(node); | |
1000 } | |
1001 | |
1002 @override | |
1003 Object visitThrowExpression(ThrowExpression node) { | |
1004 _checkForConstEvalThrowsException(node); | |
1005 return super.visitThrowExpression(node); | |
1006 } | |
1007 | |
1008 @override | |
1009 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
1010 _checkForFinalNotInitialized(node.variables); | |
1011 return super.visitTopLevelVariableDeclaration(node); | |
1012 } | |
1013 | |
1014 @override | |
1015 Object visitTypeArgumentList(TypeArgumentList node) { | |
1016 NodeList<TypeName> list = node.arguments; | |
1017 for (TypeName typeName in list) { | |
1018 _checkForTypeAnnotationDeferredClass(typeName); | |
1019 } | |
1020 return super.visitTypeArgumentList(node); | |
1021 } | |
1022 | |
1023 @override | |
1024 Object visitTypeName(TypeName node) { | |
1025 _checkForTypeArgumentNotMatchingBounds(node); | |
1026 _checkForTypeParameterReferencedByStatic(node); | |
1027 return super.visitTypeName(node); | |
1028 } | |
1029 | |
1030 @override | |
1031 Object visitTypeParameter(TypeParameter node) { | |
1032 _checkForBuiltInIdentifierAsName(node.name, | |
1033 CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME); | |
1034 _checkForTypeParameterSupertypeOfItsBound(node); | |
1035 _checkForTypeAnnotationDeferredClass(node.bound); | |
1036 return super.visitTypeParameter(node); | |
1037 } | |
1038 | |
1039 @override | |
1040 Object visitVariableDeclaration(VariableDeclaration node) { | |
1041 SimpleIdentifier nameNode = node.name; | |
1042 Expression initializerNode = node.initializer; | |
1043 // do checks | |
1044 _checkForInvalidAssignment(nameNode, initializerNode); | |
1045 // visit name | |
1046 nameNode.accept(this); | |
1047 // visit initializer | |
1048 String name = nameNode.name; | |
1049 _namesForReferenceToDeclaredVariableInInitializer.add(name); | |
1050 bool wasInInstanceVariableInitializer = _isInInstanceVariableInitializer; | |
1051 _isInInstanceVariableInitializer = _isInInstanceVariableDeclaration; | |
1052 try { | |
1053 if (initializerNode != null) { | |
1054 initializerNode.accept(this); | |
1055 } | |
1056 } finally { | |
1057 _isInInstanceVariableInitializer = wasInInstanceVariableInitializer; | |
1058 _namesForReferenceToDeclaredVariableInInitializer.remove(name); | |
1059 } | |
1060 // done | |
1061 return null; | |
1062 } | |
1063 | |
1064 @override | |
1065 Object visitVariableDeclarationList(VariableDeclarationList node) { | |
1066 _checkForTypeAnnotationDeferredClass(node.type); | |
1067 return super.visitVariableDeclarationList(node); | |
1068 } | |
1069 | |
1070 @override | |
1071 Object visitVariableDeclarationStatement(VariableDeclarationStatement node) { | |
1072 _checkForFinalNotInitialized(node.variables); | |
1073 return super.visitVariableDeclarationStatement(node); | |
1074 } | |
1075 | |
1076 @override | |
1077 Object visitWhileStatement(WhileStatement node) { | |
1078 _checkForNonBoolCondition(node.condition); | |
1079 return super.visitWhileStatement(node); | |
1080 } | |
1081 | |
1082 @override | |
1083 Object visitYieldStatement(YieldStatement node) { | |
1084 if (_inGenerator) { | |
1085 _checkForYieldOfInvalidType(node.expression, node.star != null); | |
1086 } else { | |
1087 CompileTimeErrorCode errorCode; | |
1088 if (node.star != null) { | |
1089 errorCode = CompileTimeErrorCode.YIELD_EACH_IN_NON_GENERATOR; | |
1090 } else { | |
1091 errorCode = CompileTimeErrorCode.YIELD_IN_NON_GENERATOR; | |
1092 } | |
1093 _errorReporter.reportErrorForNode(errorCode, node); | |
1094 } | |
1095 return super.visitYieldStatement(node); | |
1096 } | |
1097 | |
1098 /** | |
1099 * Verify that the given list of [typeArguments] contains exactly two | |
1100 * elements. | |
1101 * | |
1102 * See [StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS]. | |
1103 */ | |
1104 bool _checkExpectedTwoMapTypeArguments(TypeArgumentList typeArguments) { | |
1105 // check number of type arguments | |
1106 int num = typeArguments.arguments.length; | |
1107 if (num == 2) { | |
1108 return false; | |
1109 } | |
1110 // report problem | |
1111 _errorReporter.reportErrorForNode( | |
1112 StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS, typeArguments, | |
1113 [num]); | |
1114 return true; | |
1115 } | |
1116 | |
1117 /** | |
1118 * Verify that the given [constructor] declaration does not violate any of the | |
1119 * error codes relating to the initialization of fields in the enclosing | |
1120 * class. | |
1121 * | |
1122 * See [_initialFieldElementsMap], | |
1123 * [StaticWarningCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR], and | |
1124 * [CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES]. | |
1125 */ | |
1126 bool _checkForAllFinalInitializedErrorCodes( | |
1127 ConstructorDeclaration constructor) { | |
1128 if (constructor.factoryKeyword != null || | |
1129 constructor.redirectedConstructor != null || | |
1130 constructor.externalKeyword != null) { | |
1131 return false; | |
1132 } | |
1133 // Ignore if native class. | |
1134 if (_isInNativeClass) { | |
1135 return false; | |
1136 } | |
1137 bool foundError = false; | |
1138 HashMap<FieldElement, INIT_STATE> fieldElementsMap = | |
1139 new HashMap<FieldElement, INIT_STATE>.from(_initialFieldElementsMap); | |
1140 // Visit all of the field formal parameters | |
1141 NodeList<FormalParameter> formalParameters = | |
1142 constructor.parameters.parameters; | |
1143 for (FormalParameter formalParameter in formalParameters) { | |
1144 FormalParameter parameter = formalParameter; | |
1145 if (parameter is DefaultFormalParameter) { | |
1146 parameter = (parameter as DefaultFormalParameter).parameter; | |
1147 } | |
1148 if (parameter is FieldFormalParameter) { | |
1149 FieldElement fieldElement = | |
1150 (parameter.element as FieldFormalParameterElementImpl).field; | |
1151 INIT_STATE state = fieldElementsMap[fieldElement]; | |
1152 if (state == INIT_STATE.NOT_INIT) { | |
1153 fieldElementsMap[fieldElement] = INIT_STATE.INIT_IN_FIELD_FORMAL; | |
1154 } else if (state == INIT_STATE.INIT_IN_DECLARATION) { | |
1155 if (fieldElement.isFinal || fieldElement.isConst) { | |
1156 _errorReporter.reportErrorForNode( | |
1157 StaticWarningCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCT
OR, | |
1158 formalParameter.identifier, [fieldElement.displayName]); | |
1159 foundError = true; | |
1160 } | |
1161 } else if (state == INIT_STATE.INIT_IN_FIELD_FORMAL) { | |
1162 if (fieldElement.isFinal || fieldElement.isConst) { | |
1163 _errorReporter.reportErrorForNode( | |
1164 CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES, | |
1165 formalParameter.identifier, [fieldElement.displayName]); | |
1166 foundError = true; | |
1167 } | |
1168 } | |
1169 } | |
1170 } | |
1171 // Visit all of the initializers | |
1172 NodeList<ConstructorInitializer> initializers = constructor.initializers; | |
1173 for (ConstructorInitializer constructorInitializer in initializers) { | |
1174 if (constructorInitializer is RedirectingConstructorInvocation) { | |
1175 return false; | |
1176 } | |
1177 if (constructorInitializer is ConstructorFieldInitializer) { | |
1178 ConstructorFieldInitializer constructorFieldInitializer = | |
1179 constructorInitializer; | |
1180 SimpleIdentifier fieldName = constructorFieldInitializer.fieldName; | |
1181 Element element = fieldName.staticElement; | |
1182 if (element is FieldElement) { | |
1183 FieldElement fieldElement = element; | |
1184 INIT_STATE state = fieldElementsMap[fieldElement]; | |
1185 if (state == INIT_STATE.NOT_INIT) { | |
1186 fieldElementsMap[fieldElement] = INIT_STATE.INIT_IN_INITIALIZERS; | |
1187 } else if (state == INIT_STATE.INIT_IN_DECLARATION) { | |
1188 if (fieldElement.isFinal || fieldElement.isConst) { | |
1189 _errorReporter.reportErrorForNode( | |
1190 StaticWarningCode.FIELD_INITIALIZED_IN_INITIALIZER_AND_DECLARA
TION, | |
1191 fieldName); | |
1192 foundError = true; | |
1193 } | |
1194 } else if (state == INIT_STATE.INIT_IN_FIELD_FORMAL) { | |
1195 _errorReporter.reportErrorForNode( | |
1196 CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALI
ZER, | |
1197 fieldName); | |
1198 foundError = true; | |
1199 } else if (state == INIT_STATE.INIT_IN_INITIALIZERS) { | |
1200 _errorReporter.reportErrorForNode( | |
1201 CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS, | |
1202 fieldName, [fieldElement.displayName]); | |
1203 foundError = true; | |
1204 } | |
1205 } | |
1206 } | |
1207 } | |
1208 // Prepare a list of not initialized fields. | |
1209 List<FieldElement> notInitFinalFields = <FieldElement>[]; | |
1210 fieldElementsMap.forEach((FieldElement fieldElement, INIT_STATE state) { | |
1211 if (state == INIT_STATE.NOT_INIT) { | |
1212 if (fieldElement.isFinal) { | |
1213 notInitFinalFields.add(fieldElement); | |
1214 } | |
1215 } | |
1216 }); | |
1217 // Visit all of the states in the map to ensure that none were never | |
1218 // initialized. | |
1219 fieldElementsMap.forEach((FieldElement fieldElement, INIT_STATE state) { | |
1220 if (state == INIT_STATE.NOT_INIT) { | |
1221 if (fieldElement.isConst) { | |
1222 _errorReporter.reportErrorForNode( | |
1223 CompileTimeErrorCode.CONST_NOT_INITIALIZED, | |
1224 constructor.returnType, [fieldElement.name]); | |
1225 foundError = true; | |
1226 } | |
1227 } | |
1228 }); | |
1229 if (notInitFinalFields.isNotEmpty) { | |
1230 foundError = true; | |
1231 AnalysisErrorWithProperties analysisError; | |
1232 if (notInitFinalFields.length == 1) { | |
1233 analysisError = _errorReporter.newErrorWithProperties( | |
1234 StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1, | |
1235 constructor.returnType, [notInitFinalFields[0].name]); | |
1236 } else if (notInitFinalFields.length == 2) { | |
1237 analysisError = _errorReporter.newErrorWithProperties( | |
1238 StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2, | |
1239 constructor.returnType, [ | |
1240 notInitFinalFields[0].name, | |
1241 notInitFinalFields[1].name | |
1242 ]); | |
1243 } else { | |
1244 analysisError = _errorReporter.newErrorWithProperties( | |
1245 StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS, | |
1246 constructor.returnType, [ | |
1247 notInitFinalFields[0].name, | |
1248 notInitFinalFields[1].name, | |
1249 notInitFinalFields.length - 2 | |
1250 ]); | |
1251 } | |
1252 analysisError.setProperty( | |
1253 ErrorProperty.NOT_INITIALIZED_FIELDS, notInitFinalFields); | |
1254 _errorReporter.reportError(analysisError); | |
1255 } | |
1256 return foundError; | |
1257 } | |
1258 | |
1259 /** | |
1260 * Check the given [executableElement] against override-error codes. The | |
1261 * [overriddenExecutable] is the element that the executable element is | |
1262 * overriding. The [parameters] is the parameters of the executable element. | |
1263 * The [errorNameTarget] is the node to report problems on. | |
1264 * | |
1265 * See [StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC
], | |
1266 * [CompileTimeErrorCode.INVALID_OVERRIDE_REQUIRED], | |
1267 * [CompileTimeErrorCode.INVALID_OVERRIDE_POSITIONAL], | |
1268 * [CompileTimeErrorCode.INVALID_OVERRIDE_NAMED], | |
1269 * [StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE], | |
1270 * [StaticWarningCode.INVALID_METHOD_OVERRIDE_RETURN_TYPE], | |
1271 * [StaticWarningCode.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE], | |
1272 * [StaticWarningCode.INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE], | |
1273 * [StaticWarningCode.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE], | |
1274 * [StaticWarningCode.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE], and | |
1275 * [StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES]. | |
1276 */ | |
1277 bool _checkForAllInvalidOverrideErrorCodes( | |
1278 ExecutableElement executableElement, | |
1279 ExecutableElement overriddenExecutable, List<ParameterElement> parameters, | |
1280 List<AstNode> parameterLocations, SimpleIdentifier errorNameTarget) { | |
1281 bool isGetter = false; | |
1282 bool isSetter = false; | |
1283 if (executableElement is PropertyAccessorElement) { | |
1284 PropertyAccessorElement accessorElement = executableElement; | |
1285 isGetter = accessorElement.isGetter; | |
1286 isSetter = accessorElement.isSetter; | |
1287 } | |
1288 String executableElementName = executableElement.name; | |
1289 FunctionType overridingFT = executableElement.type; | |
1290 FunctionType overriddenFT = overriddenExecutable.type; | |
1291 InterfaceType enclosingType = _enclosingClass.type; | |
1292 overriddenFT = _inheritanceManager | |
1293 .substituteTypeArgumentsInMemberFromInheritance( | |
1294 overriddenFT, executableElementName, enclosingType); | |
1295 if (overridingFT == null || overriddenFT == null) { | |
1296 return false; | |
1297 } | |
1298 DartType overridingFTReturnType = overridingFT.returnType; | |
1299 DartType overriddenFTReturnType = overriddenFT.returnType; | |
1300 List<DartType> overridingNormalPT = overridingFT.normalParameterTypes; | |
1301 List<DartType> overriddenNormalPT = overriddenFT.normalParameterTypes; | |
1302 List<DartType> overridingPositionalPT = overridingFT.optionalParameterTypes; | |
1303 List<DartType> overriddenPositionalPT = overriddenFT.optionalParameterTypes; | |
1304 Map<String, DartType> overridingNamedPT = overridingFT.namedParameterTypes; | |
1305 Map<String, DartType> overriddenNamedPT = overriddenFT.namedParameterTypes; | |
1306 // CTEC.INVALID_OVERRIDE_REQUIRED, CTEC.INVALID_OVERRIDE_POSITIONAL and | |
1307 // CTEC.INVALID_OVERRIDE_NAMED | |
1308 if (overridingNormalPT.length > overriddenNormalPT.length) { | |
1309 _errorReporter.reportErrorForNode( | |
1310 StaticWarningCode.INVALID_OVERRIDE_REQUIRED, errorNameTarget, [ | |
1311 overriddenNormalPT.length, | |
1312 overriddenExecutable.enclosingElement.displayName | |
1313 ]); | |
1314 return true; | |
1315 } | |
1316 if (overridingNormalPT.length + overridingPositionalPT.length < | |
1317 overriddenPositionalPT.length + overriddenNormalPT.length) { | |
1318 _errorReporter.reportErrorForNode( | |
1319 StaticWarningCode.INVALID_OVERRIDE_POSITIONAL, errorNameTarget, [ | |
1320 overriddenPositionalPT.length + overriddenNormalPT.length, | |
1321 overriddenExecutable.enclosingElement.displayName | |
1322 ]); | |
1323 return true; | |
1324 } | |
1325 // For each named parameter in the overridden method, verify that there is | |
1326 // the same name in the overriding method. | |
1327 for (String overriddenParamName in overriddenNamedPT.keys) { | |
1328 if (!overridingNamedPT.containsKey(overriddenParamName)) { | |
1329 // The overridden method expected the overriding method to have | |
1330 // overridingParamName, but it does not. | |
1331 _errorReporter.reportErrorForNode( | |
1332 StaticWarningCode.INVALID_OVERRIDE_NAMED, errorNameTarget, [ | |
1333 overriddenParamName, | |
1334 overriddenExecutable.enclosingElement.displayName | |
1335 ]); | |
1336 return true; | |
1337 } | |
1338 } | |
1339 // SWC.INVALID_METHOD_OVERRIDE_RETURN_TYPE | |
1340 if (overriddenFTReturnType != VoidTypeImpl.instance && | |
1341 !overridingFTReturnType.isAssignableTo(overriddenFTReturnType)) { | |
1342 _errorReporter.reportTypeErrorForNode(!isGetter | |
1343 ? StaticWarningCode.INVALID_METHOD_OVERRIDE_RETURN_TYPE | |
1344 : StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE, | |
1345 errorNameTarget, [ | |
1346 overridingFTReturnType, | |
1347 overriddenFTReturnType, | |
1348 overriddenExecutable.enclosingElement.displayName | |
1349 ]); | |
1350 return true; | |
1351 } | |
1352 // SWC.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE | |
1353 if (parameterLocations == null) { | |
1354 return false; | |
1355 } | |
1356 int parameterIndex = 0; | |
1357 for (int i = 0; i < overridingNormalPT.length; i++) { | |
1358 if (!overridingNormalPT[i].isAssignableTo(overriddenNormalPT[i])) { | |
1359 _errorReporter.reportTypeErrorForNode(!isSetter | |
1360 ? StaticWarningCode.INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE | |
1361 : StaticWarningCode.INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE, | |
1362 parameterLocations[parameterIndex], [ | |
1363 overridingNormalPT[i], | |
1364 overriddenNormalPT[i], | |
1365 overriddenExecutable.enclosingElement.displayName | |
1366 ]); | |
1367 return true; | |
1368 } | |
1369 parameterIndex++; | |
1370 } | |
1371 // SWC.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE | |
1372 for (int i = 0; i < overriddenPositionalPT.length; i++) { | |
1373 if (!overridingPositionalPT[i] | |
1374 .isAssignableTo(overriddenPositionalPT[i])) { | |
1375 _errorReporter.reportTypeErrorForNode( | |
1376 StaticWarningCode.INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE, | |
1377 parameterLocations[parameterIndex], [ | |
1378 overridingPositionalPT[i], | |
1379 overriddenPositionalPT[i], | |
1380 overriddenExecutable.enclosingElement.displayName | |
1381 ]); | |
1382 return true; | |
1383 } | |
1384 parameterIndex++; | |
1385 } | |
1386 // SWC.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE & | |
1387 // SWC.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES | |
1388 for (String overriddenName in overriddenNamedPT.keys) { | |
1389 DartType overridingType = overridingNamedPT[overriddenName]; | |
1390 if (overridingType == null) { | |
1391 // Error, this is never reached- INVALID_OVERRIDE_NAMED would have been | |
1392 // created above if this could be reached. | |
1393 continue; | |
1394 } | |
1395 DartType overriddenType = overriddenNamedPT[overriddenName]; | |
1396 if (!overriddenType.isAssignableTo(overridingType)) { | |
1397 // lookup the parameter for the error to select | |
1398 ParameterElement parameterToSelect = null; | |
1399 AstNode parameterLocationToSelect = null; | |
1400 for (int i = 0; i < parameters.length; i++) { | |
1401 ParameterElement parameter = parameters[i]; | |
1402 if (parameter.parameterKind == ParameterKind.NAMED && | |
1403 overriddenName == parameter.name) { | |
1404 parameterToSelect = parameter; | |
1405 parameterLocationToSelect = parameterLocations[i]; | |
1406 break; | |
1407 } | |
1408 } | |
1409 if (parameterToSelect != null) { | |
1410 _errorReporter.reportTypeErrorForNode( | |
1411 StaticWarningCode.INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE, | |
1412 parameterLocationToSelect, [ | |
1413 overridingType, | |
1414 overriddenType, | |
1415 overriddenExecutable.enclosingElement.displayName | |
1416 ]); | |
1417 return true; | |
1418 } | |
1419 } | |
1420 } | |
1421 // SWC.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES | |
1422 // | |
1423 // Create three lists: a list of the optional parameter ASTs | |
1424 // (FormalParameters), a list of the optional parameters elements from our | |
1425 // method, and finally a list of the optional parameter elements from the | |
1426 // method we are overriding. | |
1427 // | |
1428 bool foundError = false; | |
1429 List<AstNode> formalParameters = new List<AstNode>(); | |
1430 List<ParameterElementImpl> parameterElts = new List<ParameterElementImpl>(); | |
1431 List<ParameterElementImpl> overriddenParameterElts = | |
1432 new List<ParameterElementImpl>(); | |
1433 List<ParameterElement> overriddenPEs = overriddenExecutable.parameters; | |
1434 for (int i = 0; i < parameters.length; i++) { | |
1435 ParameterElement parameter = parameters[i]; | |
1436 if (parameter.parameterKind.isOptional) { | |
1437 formalParameters.add(parameterLocations[i]); | |
1438 parameterElts.add(parameter as ParameterElementImpl); | |
1439 } | |
1440 } | |
1441 for (ParameterElement parameterElt in overriddenPEs) { | |
1442 if (parameterElt.parameterKind.isOptional) { | |
1443 if (parameterElt is ParameterElementImpl) { | |
1444 overriddenParameterElts.add(parameterElt); | |
1445 } | |
1446 } | |
1447 } | |
1448 // | |
1449 // Next compare the list of optional parameter elements to the list of | |
1450 // overridden optional parameter elements. | |
1451 // | |
1452 if (parameterElts.length > 0) { | |
1453 if (parameterElts[0].parameterKind == ParameterKind.NAMED) { | |
1454 // Named parameters, consider the names when matching the parameterElts | |
1455 // to the overriddenParameterElts | |
1456 for (int i = 0; i < parameterElts.length; i++) { | |
1457 ParameterElementImpl parameterElt = parameterElts[i]; | |
1458 EvaluationResultImpl result = parameterElt.evaluationResult; | |
1459 // TODO (jwren) Ignore Object types, see Dart bug 11287 | |
1460 if (_isUserDefinedObject(result)) { | |
1461 continue; | |
1462 } | |
1463 String parameterName = parameterElt.name; | |
1464 for (int j = 0; j < overriddenParameterElts.length; j++) { | |
1465 ParameterElementImpl overriddenParameterElt = | |
1466 overriddenParameterElts[j]; | |
1467 if (overriddenParameterElt.initializer == null) { | |
1468 // There is no warning if the overridden parameter has an | |
1469 // implicit default. | |
1470 continue; | |
1471 } | |
1472 String overriddenParameterName = overriddenParameterElt.name; | |
1473 if (parameterName != null && | |
1474 parameterName == overriddenParameterName) { | |
1475 EvaluationResultImpl overriddenResult = | |
1476 overriddenParameterElt.evaluationResult; | |
1477 if (_isUserDefinedObject(overriddenResult)) { | |
1478 break; | |
1479 } | |
1480 if (!result.equalValues(_typeProvider, overriddenResult)) { | |
1481 _errorReporter.reportErrorForNode( | |
1482 StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_
NAMED, | |
1483 formalParameters[i], [ | |
1484 overriddenExecutable.enclosingElement.displayName, | |
1485 overriddenExecutable.displayName, | |
1486 parameterName | |
1487 ]); | |
1488 foundError = true; | |
1489 } | |
1490 } | |
1491 } | |
1492 } | |
1493 } else { | |
1494 // Positional parameters, consider the positions when matching the | |
1495 // parameterElts to the overriddenParameterElts | |
1496 for (int i = 0; | |
1497 i < parameterElts.length && i < overriddenParameterElts.length; | |
1498 i++) { | |
1499 ParameterElementImpl parameterElt = parameterElts[i]; | |
1500 EvaluationResultImpl result = parameterElt.evaluationResult; | |
1501 // TODO (jwren) Ignore Object types, see Dart bug 11287 | |
1502 if (_isUserDefinedObject(result)) { | |
1503 continue; | |
1504 } | |
1505 ParameterElementImpl overriddenParameterElt = | |
1506 overriddenParameterElts[i]; | |
1507 if (overriddenParameterElt.initializer == null) { | |
1508 // There is no warning if the overridden parameter has an implicit | |
1509 // default. | |
1510 continue; | |
1511 } | |
1512 EvaluationResultImpl overriddenResult = | |
1513 overriddenParameterElt.evaluationResult; | |
1514 if (_isUserDefinedObject(overriddenResult)) { | |
1515 continue; | |
1516 } | |
1517 if (!result.equalValues(_typeProvider, overriddenResult)) { | |
1518 _errorReporter.reportErrorForNode( | |
1519 StaticWarningCode.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_POSI
TIONAL, | |
1520 formalParameters[i], [ | |
1521 overriddenExecutable.enclosingElement.displayName, | |
1522 overriddenExecutable.displayName | |
1523 ]); | |
1524 foundError = true; | |
1525 } | |
1526 } | |
1527 } | |
1528 } | |
1529 return foundError; | |
1530 } | |
1531 | |
1532 /** | |
1533 * Check the given [executableElement] against override-error codes. This | |
1534 * method computes the given executableElement is overriding and calls | |
1535 * [_checkForAllInvalidOverrideErrorCodes] when the [InheritanceManager] | |
1536 * returns a [MultiplyInheritedExecutableElement], this method loops through | |
1537 * the list in the [MultiplyInheritedExecutableElement]. The [parameters] are | |
1538 * the parameters of the executable element. The [errorNameTarget] is the node | |
1539 * to report problems on. | |
1540 */ | |
1541 bool _checkForAllInvalidOverrideErrorCodesForExecutable( | |
1542 ExecutableElement executableElement, List<ParameterElement> parameters, | |
1543 List<AstNode> parameterLocations, SimpleIdentifier errorNameTarget) { | |
1544 // | |
1545 // Compute the overridden executable from the InheritanceManager | |
1546 // | |
1547 List<ExecutableElement> overriddenExecutables = _inheritanceManager | |
1548 .lookupOverrides(_enclosingClass, executableElement.name); | |
1549 if (_checkForInstanceMethodNameCollidesWithSuperclassStatic( | |
1550 executableElement, errorNameTarget)) { | |
1551 return true; | |
1552 } | |
1553 for (ExecutableElement overriddenElement in overriddenExecutables) { | |
1554 if (_checkForAllInvalidOverrideErrorCodes(executableElement, | |
1555 overriddenElement, parameters, parameterLocations, errorNameTarget)) { | |
1556 return true; | |
1557 } | |
1558 } | |
1559 return false; | |
1560 } | |
1561 | |
1562 /** | |
1563 * Check the given field [declaration] against override-error codes. | |
1564 * | |
1565 * See [_checkForAllInvalidOverrideErrorCodes]. | |
1566 */ | |
1567 bool _checkForAllInvalidOverrideErrorCodesForField( | |
1568 FieldDeclaration declaration) { | |
1569 if (_enclosingClass == null || declaration.isStatic) { | |
1570 return false; | |
1571 } | |
1572 bool hasProblems = false; | |
1573 VariableDeclarationList fields = declaration.fields; | |
1574 for (VariableDeclaration field in fields.variables) { | |
1575 FieldElement element = field.element as FieldElement; | |
1576 if (element == null) { | |
1577 continue; | |
1578 } | |
1579 PropertyAccessorElement getter = element.getter; | |
1580 PropertyAccessorElement setter = element.setter; | |
1581 SimpleIdentifier fieldName = field.name; | |
1582 if (getter != null) { | |
1583 if (_checkForAllInvalidOverrideErrorCodesForExecutable(getter, | |
1584 ParameterElement.EMPTY_LIST, AstNode.EMPTY_LIST, fieldName)) { | |
1585 hasProblems = true; | |
1586 } | |
1587 } | |
1588 if (setter != null) { | |
1589 if (_checkForAllInvalidOverrideErrorCodesForExecutable( | |
1590 setter, setter.parameters, <AstNode>[fieldName], fieldName)) { | |
1591 hasProblems = true; | |
1592 } | |
1593 } | |
1594 } | |
1595 return hasProblems; | |
1596 } | |
1597 | |
1598 /** | |
1599 * Check the given [method] declaration against override-error codes. | |
1600 * | |
1601 * See [_checkForAllInvalidOverrideErrorCodes]. | |
1602 */ | |
1603 bool _checkForAllInvalidOverrideErrorCodesForMethod( | |
1604 MethodDeclaration method) { | |
1605 if (_enclosingClass == null || | |
1606 method.isStatic || | |
1607 method.body is NativeFunctionBody) { | |
1608 return false; | |
1609 } | |
1610 ExecutableElement executableElement = method.element; | |
1611 if (executableElement == null) { | |
1612 return false; | |
1613 } | |
1614 SimpleIdentifier methodName = method.name; | |
1615 if (methodName.isSynthetic) { | |
1616 return false; | |
1617 } | |
1618 FormalParameterList formalParameterList = method.parameters; | |
1619 NodeList<FormalParameter> parameterList = | |
1620 formalParameterList != null ? formalParameterList.parameters : null; | |
1621 List<AstNode> parameters = | |
1622 parameterList != null ? new List.from(parameterList) : null; | |
1623 return _checkForAllInvalidOverrideErrorCodesForExecutable(executableElement, | |
1624 executableElement.parameters, parameters, methodName); | |
1625 } | |
1626 | |
1627 /** | |
1628 * Verify that all classes of the given [withClause] are valid. | |
1629 * | |
1630 * See [CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR], | |
1631 * [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT], and | |
1632 * [CompileTimeErrorCode.MIXIN_REFERENCES_SUPER]. | |
1633 */ | |
1634 bool _checkForAllMixinErrorCodes(WithClause withClause) { | |
1635 if (withClause == null) { | |
1636 return false; | |
1637 } | |
1638 bool problemReported = false; | |
1639 for (TypeName mixinName in withClause.mixinTypes) { | |
1640 DartType mixinType = mixinName.type; | |
1641 if (mixinType is! InterfaceType) { | |
1642 continue; | |
1643 } | |
1644 if (_checkForExtendsOrImplementsDisallowedClass( | |
1645 mixinName, CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS)) { | |
1646 problemReported = true; | |
1647 } else { | |
1648 ClassElement mixinElement = (mixinType as InterfaceType).element; | |
1649 if (_checkForExtendsOrImplementsDeferredClass( | |
1650 mixinName, CompileTimeErrorCode.MIXIN_DEFERRED_CLASS)) { | |
1651 problemReported = true; | |
1652 } | |
1653 if (_checkForMixinDeclaresConstructor(mixinName, mixinElement)) { | |
1654 problemReported = true; | |
1655 } | |
1656 if (_checkForMixinInheritsNotFromObject(mixinName, mixinElement)) { | |
1657 problemReported = true; | |
1658 } | |
1659 if (_checkForMixinReferencesSuper(mixinName, mixinElement)) { | |
1660 problemReported = true; | |
1661 } | |
1662 } | |
1663 } | |
1664 return problemReported; | |
1665 } | |
1666 | |
1667 /** | |
1668 * Check for errors related to the redirected constructors. | |
1669 * | |
1670 * See [StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE], | |
1671 * [StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE], and | |
1672 * [StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR]. | |
1673 */ | |
1674 bool _checkForAllRedirectConstructorErrorCodes( | |
1675 ConstructorDeclaration declaration) { | |
1676 // | |
1677 // Prepare redirected constructor node | |
1678 // | |
1679 ConstructorName redirectedConstructor = declaration.redirectedConstructor; | |
1680 if (redirectedConstructor == null) { | |
1681 return false; | |
1682 } | |
1683 // | |
1684 // Prepare redirected constructor type | |
1685 // | |
1686 ConstructorElement redirectedElement = redirectedConstructor.staticElement; | |
1687 if (redirectedElement == null) { | |
1688 // | |
1689 // If the element is null, we check for the | |
1690 // REDIRECT_TO_MISSING_CONSTRUCTOR case | |
1691 // | |
1692 TypeName constructorTypeName = redirectedConstructor.type; | |
1693 DartType redirectedType = constructorTypeName.type; | |
1694 if (redirectedType != null && | |
1695 redirectedType.element != null && | |
1696 !redirectedType.isDynamic) { | |
1697 // | |
1698 // Prepare the constructor name | |
1699 // | |
1700 String constructorStrName = constructorTypeName.name.name; | |
1701 if (redirectedConstructor.name != null) { | |
1702 constructorStrName += ".${redirectedConstructor.name.name}"; | |
1703 } | |
1704 ErrorCode errorCode = (declaration.constKeyword != null | |
1705 ? CompileTimeErrorCode.REDIRECT_TO_MISSING_CONSTRUCTOR | |
1706 : StaticWarningCode.REDIRECT_TO_MISSING_CONSTRUCTOR); | |
1707 _errorReporter.reportErrorForNode(errorCode, redirectedConstructor, [ | |
1708 constructorStrName, | |
1709 redirectedType.displayName | |
1710 ]); | |
1711 return true; | |
1712 } | |
1713 return false; | |
1714 } | |
1715 FunctionType redirectedType = redirectedElement.type; | |
1716 DartType redirectedReturnType = redirectedType.returnType; | |
1717 // | |
1718 // Report specific problem when return type is incompatible | |
1719 // | |
1720 FunctionType constructorType = declaration.element.type; | |
1721 DartType constructorReturnType = constructorType.returnType; | |
1722 if (!redirectedReturnType.isAssignableTo(constructorReturnType)) { | |
1723 _errorReporter.reportErrorForNode( | |
1724 StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE, | |
1725 redirectedConstructor, [redirectedReturnType, constructorReturnType]); | |
1726 return true; | |
1727 } | |
1728 // | |
1729 // Check parameters | |
1730 // | |
1731 if (!redirectedType.isSubtypeOf(constructorType)) { | |
1732 _errorReporter.reportErrorForNode( | |
1733 StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION_TYPE, | |
1734 redirectedConstructor, [redirectedType, constructorType]); | |
1735 return true; | |
1736 } | |
1737 return false; | |
1738 } | |
1739 | |
1740 /** | |
1741 * Check that the return [statement] of the form <i>return e;</i> is not in a | |
1742 * generative constructor. | |
1743 * | |
1744 * Check that return statements without expressions are not in a generative | |
1745 * constructor and the return type is not assignable to `null`; that is, we | |
1746 * don't have `return;` if the enclosing method has a return type. | |
1747 * | |
1748 * Check that the return type matches the type of the declared return type in | |
1749 * the enclosing method or function. | |
1750 * | |
1751 * See [CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR], | |
1752 * [StaticWarningCode.RETURN_WITHOUT_VALUE], and | |
1753 * [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]. | |
1754 */ | |
1755 bool _checkForAllReturnStatementErrorCodes(ReturnStatement statement) { | |
1756 FunctionType functionType = | |
1757 _enclosingFunction == null ? null : _enclosingFunction.type; | |
1758 DartType expectedReturnType = functionType == null | |
1759 ? DynamicTypeImpl.instance | |
1760 : functionType.returnType; | |
1761 Expression returnExpression = statement.expression; | |
1762 // RETURN_IN_GENERATIVE_CONSTRUCTOR | |
1763 bool isGenerativeConstructor = _enclosingFunction is ConstructorElement && | |
1764 !(_enclosingFunction as ConstructorElement).isFactory; | |
1765 if (isGenerativeConstructor) { | |
1766 if (returnExpression == null) { | |
1767 return false; | |
1768 } | |
1769 _errorReporter.reportErrorForNode( | |
1770 CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR, | |
1771 returnExpression); | |
1772 return true; | |
1773 } | |
1774 // RETURN_WITHOUT_VALUE | |
1775 if (returnExpression == null) { | |
1776 if (_inGenerator || | |
1777 _computeReturnTypeForMethod(null) | |
1778 .isAssignableTo(expectedReturnType)) { | |
1779 return false; | |
1780 } | |
1781 _hasReturnWithoutValue = true; | |
1782 _errorReporter.reportErrorForNode( | |
1783 StaticWarningCode.RETURN_WITHOUT_VALUE, statement); | |
1784 return true; | |
1785 } else if (_inGenerator) { | |
1786 // RETURN_IN_GENERATOR | |
1787 _errorReporter.reportErrorForNode( | |
1788 CompileTimeErrorCode.RETURN_IN_GENERATOR, statement); | |
1789 } | |
1790 // RETURN_OF_INVALID_TYPE | |
1791 return _checkForReturnOfInvalidType(returnExpression, expectedReturnType); | |
1792 } | |
1793 | |
1794 /** | |
1795 * Verify that the export namespace of the given export [directive] does not | |
1796 * export any name already exported by another export directive. The | |
1797 * [exportElement] is the [ExportElement] retrieved from the node. If the | |
1798 * element in the node was `null`, then this method is not called. The | |
1799 * [exportedLibrary] is the library element containing the exported element. | |
1800 * | |
1801 * See [CompileTimeErrorCode.AMBIGUOUS_EXPORT]. | |
1802 */ | |
1803 bool _checkForAmbiguousExport(ExportDirective directive, | |
1804 ExportElement exportElement, LibraryElement exportedLibrary) { | |
1805 if (exportedLibrary == null) { | |
1806 return false; | |
1807 } | |
1808 // check exported names | |
1809 Namespace namespace = | |
1810 new NamespaceBuilder().createExportNamespaceForDirective(exportElement); | |
1811 Map<String, Element> definedNames = namespace.definedNames; | |
1812 for (String name in definedNames.keys) { | |
1813 Element element = definedNames[name]; | |
1814 Element prevElement = _exportedElements[name]; | |
1815 if (element != null && prevElement != null && prevElement != element) { | |
1816 _errorReporter.reportErrorForNode(CompileTimeErrorCode.AMBIGUOUS_EXPORT, | |
1817 directive, [ | |
1818 name, | |
1819 prevElement.library.definingCompilationUnit.displayName, | |
1820 element.library.definingCompilationUnit.displayName | |
1821 ]); | |
1822 return true; | |
1823 } else { | |
1824 _exportedElements[name] = element; | |
1825 } | |
1826 } | |
1827 return false; | |
1828 } | |
1829 | |
1830 /** | |
1831 * Verify that the given [expression] can be assigned to its corresponding | |
1832 * parameters. The [expectedStaticType] is the expected static type of the | |
1833 * parameter. The [actualStaticType] is the actual static type of the | |
1834 * argument. | |
1835 * | |
1836 * This method corresponds to | |
1837 * [BestPracticesVerifier.checkForArgumentTypeNotAssignable]. | |
1838 * | |
1839 * See [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE], | |
1840 * [CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE], | |
1841 * [StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE], | |
1842 * [CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE], | |
1843 * [CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE], | |
1844 * [StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE], and | |
1845 * [StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE]. | |
1846 */ | |
1847 bool _checkForArgumentTypeNotAssignable(Expression expression, | |
1848 DartType expectedStaticType, DartType actualStaticType, | |
1849 ErrorCode errorCode) { | |
1850 // | |
1851 // Warning case: test static type information | |
1852 // | |
1853 if (actualStaticType != null && expectedStaticType != null) { | |
1854 if (!actualStaticType.isAssignableTo(expectedStaticType)) { | |
1855 _errorReporter.reportTypeErrorForNode( | |
1856 errorCode, expression, [actualStaticType, expectedStaticType]); | |
1857 return true; | |
1858 } | |
1859 } | |
1860 return false; | |
1861 } | |
1862 | |
1863 /** | |
1864 * Verify that the given [argument] can be assigned to its corresponding | |
1865 * parameter. | |
1866 * | |
1867 * This method corresponds to | |
1868 * [BestPracticesVerifier.checkForArgumentTypeNotAssignableForArgument]. | |
1869 * | |
1870 * See [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. | |
1871 */ | |
1872 bool _checkForArgumentTypeNotAssignableForArgument(Expression argument) { | |
1873 if (argument == null) { | |
1874 return false; | |
1875 } | |
1876 ParameterElement staticParameterElement = argument.staticParameterElement; | |
1877 DartType staticParameterType = | |
1878 staticParameterElement == null ? null : staticParameterElement.type; | |
1879 return _checkForArgumentTypeNotAssignableWithExpectedTypes(argument, | |
1880 staticParameterType, StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); | |
1881 } | |
1882 | |
1883 /** | |
1884 * Verify that the given [expression] can be assigned to its corresponding | |
1885 * parameters. The [expectedStaticType] is the expected static type. | |
1886 * | |
1887 * This method corresponds to | |
1888 * [BestPracticesVerifier.checkForArgumentTypeNotAssignableWithExpectedTypes]. | |
1889 * | |
1890 * See [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE], | |
1891 * [CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE], | |
1892 * [StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE], | |
1893 * [CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE], | |
1894 * [CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE], | |
1895 * [StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE], and | |
1896 * [StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE]. | |
1897 */ | |
1898 bool _checkForArgumentTypeNotAssignableWithExpectedTypes( | |
1899 Expression expression, DartType expectedStaticType, | |
1900 ErrorCode errorCode) => _checkForArgumentTypeNotAssignable( | |
1901 expression, expectedStaticType, getStaticType(expression), errorCode); | |
1902 | |
1903 /** | |
1904 * Verify that the arguments in the given [argumentList] can be assigned to | |
1905 * their corresponding parameters. | |
1906 * | |
1907 * This method corresponds to | |
1908 * [BestPracticesVerifier.checkForArgumentTypesNotAssignableInList]. | |
1909 * | |
1910 * See [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. | |
1911 */ | |
1912 bool _checkForArgumentTypesNotAssignableInList(ArgumentList argumentList) { | |
1913 if (argumentList == null) { | |
1914 return false; | |
1915 } | |
1916 bool problemReported = false; | |
1917 for (Expression argument in argumentList.arguments) { | |
1918 if (_checkForArgumentTypeNotAssignableForArgument(argument)) { | |
1919 problemReported = true; | |
1920 } | |
1921 } | |
1922 return problemReported; | |
1923 } | |
1924 | |
1925 /** | |
1926 * Check that the static type of the given expression is assignable to the | |
1927 * given type. If it isn't, report an error with the given error code. The | |
1928 * [type] is the type that the expression must be assignable to. The | |
1929 * [errorCode] is the error code to be reported. The [arguments] are the | |
1930 * arguments to pass in when creating the error. | |
1931 */ | |
1932 bool _checkForAssignability(Expression expression, InterfaceType type, | |
1933 ErrorCode errorCode, List<Object> arguments) { | |
1934 if (expression == null) { | |
1935 return false; | |
1936 } | |
1937 DartType expressionType = expression.staticType; | |
1938 if (expressionType == null) { | |
1939 return false; | |
1940 } | |
1941 if (expressionType.isAssignableTo(type)) { | |
1942 return false; | |
1943 } | |
1944 _errorReporter.reportErrorForNode(errorCode, expression, arguments); | |
1945 return true; | |
1946 } | |
1947 | |
1948 /** | |
1949 * Verify that the given [expression] is not final. | |
1950 * | |
1951 * See [StaticWarningCode.ASSIGNMENT_TO_CONST], | |
1952 * [StaticWarningCode.ASSIGNMENT_TO_FINAL], and | |
1953 * [StaticWarningCode.ASSIGNMENT_TO_METHOD]. | |
1954 */ | |
1955 bool _checkForAssignmentToFinal(Expression expression) { | |
1956 // prepare element | |
1957 Element element = null; | |
1958 AstNode highlightedNode = expression; | |
1959 if (expression is Identifier) { | |
1960 element = expression.staticElement; | |
1961 if (expression is PrefixedIdentifier) { | |
1962 highlightedNode = expression.identifier; | |
1963 } | |
1964 } else if (expression is PropertyAccess) { | |
1965 PropertyAccess propertyAccess = expression; | |
1966 element = propertyAccess.propertyName.staticElement; | |
1967 highlightedNode = propertyAccess.propertyName; | |
1968 } | |
1969 // check if element is assignable | |
1970 if (element is PropertyAccessorElement) { | |
1971 PropertyAccessorElement accessor = element as PropertyAccessorElement; | |
1972 element = accessor.variable; | |
1973 } | |
1974 if (element is VariableElement) { | |
1975 if (element.isConst) { | |
1976 _errorReporter.reportErrorForNode( | |
1977 StaticWarningCode.ASSIGNMENT_TO_CONST, expression); | |
1978 return true; | |
1979 } | |
1980 if (element.isFinal) { | |
1981 if (element is FieldElementImpl && | |
1982 element.setter == null && | |
1983 element.isSynthetic) { | |
1984 _errorReporter.reportErrorForNode( | |
1985 StaticWarningCode.ASSIGNMENT_TO_FINAL_NO_SETTER, highlightedNode, | |
1986 [element.name, element.enclosingElement.displayName]); | |
1987 return true; | |
1988 } | |
1989 _errorReporter.reportErrorForNode(StaticWarningCode.ASSIGNMENT_TO_FINAL, | |
1990 highlightedNode, [element.name]); | |
1991 return true; | |
1992 } | |
1993 return false; | |
1994 } | |
1995 if (element is FunctionElement) { | |
1996 _errorReporter.reportErrorForNode( | |
1997 StaticWarningCode.ASSIGNMENT_TO_FUNCTION, expression); | |
1998 return true; | |
1999 } | |
2000 if (element is MethodElement) { | |
2001 _errorReporter.reportErrorForNode( | |
2002 StaticWarningCode.ASSIGNMENT_TO_METHOD, expression); | |
2003 return true; | |
2004 } | |
2005 if (element is ClassElement || | |
2006 element is FunctionTypeAliasElement || | |
2007 element is TypeParameterElement) { | |
2008 _errorReporter.reportErrorForNode( | |
2009 StaticWarningCode.ASSIGNMENT_TO_TYPE, expression); | |
2010 return true; | |
2011 } | |
2012 return false; | |
2013 } | |
2014 | |
2015 /** | |
2016 * Verify that the given [identifier] is not a keyword, and generates the | |
2017 * given [errorCode] on the identifier if it is a keyword. | |
2018 * | |
2019 * See [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME], | |
2020 * [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME], and | |
2021 * [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME]. | |
2022 */ | |
2023 bool _checkForBuiltInIdentifierAsName( | |
2024 SimpleIdentifier identifier, ErrorCode errorCode) { | |
2025 sc.Token token = identifier.token; | |
2026 if (token.type == sc.TokenType.KEYWORD) { | |
2027 _errorReporter.reportErrorForNode( | |
2028 errorCode, identifier, [identifier.name]); | |
2029 return true; | |
2030 } | |
2031 return false; | |
2032 } | |
2033 | |
2034 /** | |
2035 * Verify that the given [switchCase] is terminated with 'break', 'continue', | |
2036 * 'return' or 'throw'. | |
2037 * | |
2038 * see [StaticWarningCode.CASE_BLOCK_NOT_TERMINATED]. | |
2039 */ | |
2040 bool _checkForCaseBlockNotTerminated(SwitchCase switchCase) { | |
2041 NodeList<Statement> statements = switchCase.statements; | |
2042 if (statements.isEmpty) { | |
2043 // fall-through without statements at all | |
2044 AstNode parent = switchCase.parent; | |
2045 if (parent is SwitchStatement) { | |
2046 SwitchStatement switchStatement = parent; | |
2047 NodeList<SwitchMember> members = switchStatement.members; | |
2048 int index = members.indexOf(switchCase); | |
2049 if (index != -1 && index < members.length - 1) { | |
2050 return false; | |
2051 } | |
2052 } | |
2053 // no other switch member after this one | |
2054 } else { | |
2055 Statement statement = statements[statements.length - 1]; | |
2056 // terminated with statement | |
2057 if (statement is BreakStatement || | |
2058 statement is ContinueStatement || | |
2059 statement is ReturnStatement) { | |
2060 return false; | |
2061 } | |
2062 // terminated with 'throw' expression | |
2063 if (statement is ExpressionStatement) { | |
2064 Expression expression = statement.expression; | |
2065 if (expression is ThrowExpression) { | |
2066 return false; | |
2067 } | |
2068 } | |
2069 } | |
2070 // report error | |
2071 _errorReporter.reportErrorForToken( | |
2072 StaticWarningCode.CASE_BLOCK_NOT_TERMINATED, switchCase.keyword); | |
2073 return true; | |
2074 } | |
2075 | |
2076 /** | |
2077 * Verify that the switch cases in the given switch [statement] are terminated | |
2078 * with 'break', 'continue', 'return' or 'throw'. | |
2079 * | |
2080 * See [StaticWarningCode.CASE_BLOCK_NOT_TERMINATED]. | |
2081 */ | |
2082 bool _checkForCaseBlocksNotTerminated(SwitchStatement statement) { | |
2083 bool foundError = false; | |
2084 NodeList<SwitchMember> members = statement.members; | |
2085 int lastMember = members.length - 1; | |
2086 for (int i = 0; i < lastMember; i++) { | |
2087 SwitchMember member = members[i]; | |
2088 if (member is SwitchCase && _checkForCaseBlockNotTerminated(member)) { | |
2089 foundError = true; | |
2090 } | |
2091 } | |
2092 return foundError; | |
2093 } | |
2094 | |
2095 /** | |
2096 * Verify that the given [method] declaration is abstract only if the | |
2097 * enclosing class is also abstract. | |
2098 * | |
2099 * See [StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER]. | |
2100 */ | |
2101 bool _checkForConcreteClassWithAbstractMember(MethodDeclaration method) { | |
2102 if (method.isAbstract && | |
2103 _enclosingClass != null && | |
2104 !_enclosingClass.isAbstract) { | |
2105 SimpleIdentifier nameNode = method.name; | |
2106 String memberName = nameNode.name; | |
2107 ExecutableElement overriddenMember; | |
2108 if (method.isGetter) { | |
2109 overriddenMember = _enclosingClass.lookUpInheritedConcreteGetter( | |
2110 memberName, _currentLibrary); | |
2111 } else if (method.isSetter) { | |
2112 overriddenMember = _enclosingClass.lookUpInheritedConcreteSetter( | |
2113 memberName, _currentLibrary); | |
2114 } else { | |
2115 overriddenMember = _enclosingClass.lookUpInheritedConcreteMethod( | |
2116 memberName, _currentLibrary); | |
2117 } | |
2118 if (overriddenMember == null) { | |
2119 _errorReporter.reportErrorForNode( | |
2120 StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER, nameNode, [ | |
2121 memberName, | |
2122 _enclosingClass.displayName | |
2123 ]); | |
2124 return true; | |
2125 } | |
2126 } | |
2127 return false; | |
2128 } | |
2129 | |
2130 /** | |
2131 * Verify all possible conflicts of the given [constructor]'s name with other | |
2132 * constructors and members of the same class. The [constructorElement] is the | |
2133 * constructor's element. | |
2134 * | |
2135 * See [CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_DEFAULT], | |
2136 * [CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_NAME], | |
2137 * [CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD], and | |
2138 * [CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD]. | |
2139 */ | |
2140 bool _checkForConflictingConstructorNameAndMember( | |
2141 ConstructorDeclaration constructor, | |
2142 ConstructorElement constructorElement) { | |
2143 SimpleIdentifier constructorName = constructor.name; | |
2144 String name = constructorElement.name; | |
2145 ClassElement classElement = constructorElement.enclosingElement; | |
2146 // constructors | |
2147 List<ConstructorElement> constructors = classElement.constructors; | |
2148 for (ConstructorElement otherConstructor in constructors) { | |
2149 if (identical(otherConstructor, constructorElement)) { | |
2150 continue; | |
2151 } | |
2152 if (name == otherConstructor.name) { | |
2153 if (name == null || name.length == 0) { | |
2154 _errorReporter.reportErrorForNode( | |
2155 CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_DEFAULT, constructor); | |
2156 } else { | |
2157 _errorReporter.reportErrorForNode( | |
2158 CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR_NAME, constructor, | |
2159 [name]); | |
2160 } | |
2161 return true; | |
2162 } | |
2163 } | |
2164 // conflict with class member | |
2165 if (constructorName != null && | |
2166 constructorElement != null && | |
2167 !constructorName.isSynthetic) { | |
2168 // fields | |
2169 FieldElement field = classElement.getField(name); | |
2170 if (field != null) { | |
2171 _errorReporter.reportErrorForNode( | |
2172 CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD, | |
2173 constructor, [name]); | |
2174 return true; | |
2175 } | |
2176 // methods | |
2177 MethodElement method = classElement.getMethod(name); | |
2178 if (method != null) { | |
2179 _errorReporter.reportErrorForNode( | |
2180 CompileTimeErrorCode.CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD, | |
2181 constructor, [name]); | |
2182 return true; | |
2183 } | |
2184 } | |
2185 return false; | |
2186 } | |
2187 | |
2188 /** | |
2189 * Verify that the [_enclosingClass] does not have a method and getter pair | |
2190 * with the same name on, via inheritance. | |
2191 * | |
2192 * See [CompileTimeErrorCode.CONFLICTING_GETTER_AND_METHOD], and | |
2193 * [CompileTimeErrorCode.CONFLICTING_METHOD_AND_GETTER]. | |
2194 */ | |
2195 bool _checkForConflictingGetterAndMethod() { | |
2196 if (_enclosingClass == null) { | |
2197 return false; | |
2198 } | |
2199 bool hasProblem = false; | |
2200 // method declared in the enclosing class vs. inherited getter | |
2201 for (MethodElement method in _enclosingClass.methods) { | |
2202 String name = method.name; | |
2203 // find inherited property accessor (and can be only getter) | |
2204 ExecutableElement inherited = | |
2205 _inheritanceManager.lookupInheritance(_enclosingClass, name); | |
2206 if (inherited is! PropertyAccessorElement) { | |
2207 continue; | |
2208 } | |
2209 // report problem | |
2210 hasProblem = true; | |
2211 _errorReporter.reportErrorForOffset( | |
2212 CompileTimeErrorCode.CONFLICTING_GETTER_AND_METHOD, method.nameOffset, | |
2213 name.length, [ | |
2214 _enclosingClass.displayName, | |
2215 inherited.enclosingElement.displayName, | |
2216 name | |
2217 ]); | |
2218 } | |
2219 // getter declared in the enclosing class vs. inherited method | |
2220 for (PropertyAccessorElement accessor in _enclosingClass.accessors) { | |
2221 if (!accessor.isGetter) { | |
2222 continue; | |
2223 } | |
2224 String name = accessor.name; | |
2225 // find inherited method | |
2226 ExecutableElement inherited = | |
2227 _inheritanceManager.lookupInheritance(_enclosingClass, name); | |
2228 if (inherited is! MethodElement) { | |
2229 continue; | |
2230 } | |
2231 // report problem | |
2232 hasProblem = true; | |
2233 _errorReporter.reportErrorForOffset( | |
2234 CompileTimeErrorCode.CONFLICTING_METHOD_AND_GETTER, | |
2235 accessor.nameOffset, name.length, [ | |
2236 _enclosingClass.displayName, | |
2237 inherited.enclosingElement.displayName, | |
2238 name | |
2239 ]); | |
2240 } | |
2241 // done | |
2242 return hasProblem; | |
2243 } | |
2244 | |
2245 /** | |
2246 * Verify that the superclass of the [_enclosingClass] does not declare | |
2247 * accessible static members with the same name as the instance | |
2248 * getters/setters declared in [_enclosingClass]. | |
2249 * | |
2250 * See [StaticWarningCode.CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER],
and | |
2251 * [StaticWarningCode.CONFLICTING_INSTANCE_SETTER_AND_SUPERCLASS_MEMBER]. | |
2252 */ | |
2253 bool _checkForConflictingInstanceGetterAndSuperclassMember() { | |
2254 if (_enclosingClass == null) { | |
2255 return false; | |
2256 } | |
2257 InterfaceType enclosingType = _enclosingClass.type; | |
2258 // check every accessor | |
2259 bool hasProblem = false; | |
2260 for (PropertyAccessorElement accessor in _enclosingClass.accessors) { | |
2261 // we analyze instance accessors here | |
2262 if (accessor.isStatic) { | |
2263 continue; | |
2264 } | |
2265 // prepare accessor properties | |
2266 String name = accessor.displayName; | |
2267 bool getter = accessor.isGetter; | |
2268 // if non-final variable, ignore setter - we alreay reported problem for | |
2269 // getter | |
2270 if (accessor.isSetter && accessor.isSynthetic) { | |
2271 continue; | |
2272 } | |
2273 // try to find super element | |
2274 ExecutableElement superElement; | |
2275 superElement = | |
2276 enclosingType.lookUpGetterInSuperclass(name, _currentLibrary); | |
2277 if (superElement == null) { | |
2278 superElement = | |
2279 enclosingType.lookUpSetterInSuperclass(name, _currentLibrary); | |
2280 } | |
2281 if (superElement == null) { | |
2282 superElement = | |
2283 enclosingType.lookUpMethodInSuperclass(name, _currentLibrary); | |
2284 } | |
2285 if (superElement == null) { | |
2286 continue; | |
2287 } | |
2288 // OK, not static | |
2289 if (!superElement.isStatic) { | |
2290 continue; | |
2291 } | |
2292 // prepare "super" type to report its name | |
2293 ClassElement superElementClass = | |
2294 superElement.enclosingElement as ClassElement; | |
2295 InterfaceType superElementType = superElementClass.type; | |
2296 // report problem | |
2297 hasProblem = true; | |
2298 if (getter) { | |
2299 _errorReporter.reportErrorForElement( | |
2300 StaticWarningCode.CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER, | |
2301 accessor, [superElementType.displayName]); | |
2302 } else { | |
2303 _errorReporter.reportErrorForElement( | |
2304 StaticWarningCode.CONFLICTING_INSTANCE_SETTER_AND_SUPERCLASS_MEMBER, | |
2305 accessor, [superElementType.displayName]); | |
2306 } | |
2307 } | |
2308 // done | |
2309 return hasProblem; | |
2310 } | |
2311 | |
2312 /** | |
2313 * Verify that the enclosing class does not have a setter with the same name | |
2314 * as the given instance method declaration. | |
2315 * | |
2316 * TODO(jwren) add other "conflicting" error codes into algorithm/ data | |
2317 * structure. | |
2318 * | |
2319 * See [StaticWarningCode.CONFLICTING_INSTANCE_METHOD_SETTER]. | |
2320 */ | |
2321 bool _checkForConflictingInstanceMethodSetter(ClassDeclaration declaration) { | |
2322 // Reference all of the class members in this class. | |
2323 NodeList<ClassMember> classMembers = declaration.members; | |
2324 if (classMembers.isEmpty) { | |
2325 return false; | |
2326 } | |
2327 // Create a HashMap to track conflicting members, and then loop through | |
2328 // members in the class to construct the HashMap, at the same time, | |
2329 // look for violations. Don't add members if they are part of a conflict, | |
2330 // this prevents multiple warnings for one issue. | |
2331 bool foundError = false; | |
2332 HashMap<String, ClassMember> memberHashMap = | |
2333 new HashMap<String, ClassMember>(); | |
2334 for (ClassMember classMember in classMembers) { | |
2335 if (classMember is MethodDeclaration) { | |
2336 MethodDeclaration method = classMember; | |
2337 if (method.isStatic) { | |
2338 continue; | |
2339 } | |
2340 // prepare name | |
2341 SimpleIdentifier name = method.name; | |
2342 if (name == null) { | |
2343 continue; | |
2344 } | |
2345 bool addThisMemberToTheMap = true; | |
2346 bool isGetter = method.isGetter; | |
2347 bool isSetter = method.isSetter; | |
2348 bool isOperator = method.isOperator; | |
2349 bool isMethod = !isGetter && !isSetter && !isOperator; | |
2350 // Do lookups in the enclosing class (and the inherited member) if the | |
2351 // member is a method or a setter for | |
2352 // StaticWarningCode.CONFLICTING_INSTANCE_METHOD_SETTER warning. | |
2353 if (isMethod) { | |
2354 String setterName = "${name.name}="; | |
2355 Element enclosingElementOfSetter = null; | |
2356 ClassMember conflictingSetter = memberHashMap[setterName]; | |
2357 if (conflictingSetter != null) { | |
2358 enclosingElementOfSetter = | |
2359 conflictingSetter.element.enclosingElement; | |
2360 } else { | |
2361 ExecutableElement elementFromInheritance = _inheritanceManager | |
2362 .lookupInheritance(_enclosingClass, setterName); | |
2363 if (elementFromInheritance != null) { | |
2364 enclosingElementOfSetter = | |
2365 elementFromInheritance.enclosingElement; | |
2366 } | |
2367 } | |
2368 if (enclosingElementOfSetter != null) { | |
2369 // report problem | |
2370 _errorReporter.reportErrorForNode( | |
2371 StaticWarningCode.CONFLICTING_INSTANCE_METHOD_SETTER, name, [ | |
2372 _enclosingClass.displayName, | |
2373 name.name, | |
2374 enclosingElementOfSetter.displayName | |
2375 ]); | |
2376 foundError = true; | |
2377 addThisMemberToTheMap = false; | |
2378 } | |
2379 } else if (isSetter) { | |
2380 String methodName = name.name; | |
2381 ClassMember conflictingMethod = memberHashMap[methodName]; | |
2382 if (conflictingMethod != null && | |
2383 conflictingMethod is MethodDeclaration && | |
2384 !conflictingMethod.isGetter) { | |
2385 // report problem | |
2386 _errorReporter.reportErrorForNode( | |
2387 StaticWarningCode.CONFLICTING_INSTANCE_METHOD_SETTER2, name, [ | |
2388 _enclosingClass.displayName, | |
2389 name.name | |
2390 ]); | |
2391 foundError = true; | |
2392 addThisMemberToTheMap = false; | |
2393 } | |
2394 } | |
2395 // Finally, add this member into the HashMap. | |
2396 if (addThisMemberToTheMap) { | |
2397 if (method.isSetter) { | |
2398 memberHashMap["${name.name}="] = method; | |
2399 } else { | |
2400 memberHashMap[name.name] = method; | |
2401 } | |
2402 } | |
2403 } | |
2404 } | |
2405 return foundError; | |
2406 } | |
2407 | |
2408 /** | |
2409 * Verify that the enclosing class does not have an instance member with the | |
2410 * same name as the given static [method] declaration. | |
2411 * | |
2412 * See [StaticWarningCode.CONFLICTING_STATIC_GETTER_AND_INSTANCE_SETTER]. | |
2413 */ | |
2414 bool _checkForConflictingStaticGetterAndInstanceSetter( | |
2415 MethodDeclaration method) { | |
2416 if (!method.isStatic) { | |
2417 return false; | |
2418 } | |
2419 // prepare name | |
2420 SimpleIdentifier nameNode = method.name; | |
2421 if (nameNode == null) { | |
2422 return false; | |
2423 } | |
2424 String name = nameNode.name; | |
2425 // prepare enclosing type | |
2426 if (_enclosingClass == null) { | |
2427 return false; | |
2428 } | |
2429 InterfaceType enclosingType = _enclosingClass.type; | |
2430 // try to find setter | |
2431 ExecutableElement setter = | |
2432 enclosingType.lookUpSetter(name, _currentLibrary); | |
2433 if (setter == null) { | |
2434 return false; | |
2435 } | |
2436 // OK, also static | |
2437 if (setter.isStatic) { | |
2438 return false; | |
2439 } | |
2440 // prepare "setter" type to report its name | |
2441 ClassElement setterClass = setter.enclosingElement as ClassElement; | |
2442 InterfaceType setterType = setterClass.type; | |
2443 // report problem | |
2444 _errorReporter.reportErrorForNode( | |
2445 StaticWarningCode.CONFLICTING_STATIC_GETTER_AND_INSTANCE_SETTER, | |
2446 nameNode, [setterType.displayName]); | |
2447 return true; | |
2448 } | |
2449 | |
2450 /** | |
2451 * Verify that the enclosing class does not have an instance member with the | |
2452 * same name as the given static [method] declaration. | |
2453 * | |
2454 * See [StaticWarningCode.CONFLICTING_STATIC_SETTER_AND_INSTANCE_MEMBER]. | |
2455 */ | |
2456 bool _checkForConflictingStaticSetterAndInstanceMember( | |
2457 MethodDeclaration method) { | |
2458 if (!method.isStatic) { | |
2459 return false; | |
2460 } | |
2461 // prepare name | |
2462 SimpleIdentifier nameNode = method.name; | |
2463 if (nameNode == null) { | |
2464 return false; | |
2465 } | |
2466 String name = nameNode.name; | |
2467 // prepare enclosing type | |
2468 if (_enclosingClass == null) { | |
2469 return false; | |
2470 } | |
2471 InterfaceType enclosingType = _enclosingClass.type; | |
2472 // try to find member | |
2473 ExecutableElement member; | |
2474 member = enclosingType.lookUpMethod(name, _currentLibrary); | |
2475 if (member == null) { | |
2476 member = enclosingType.lookUpGetter(name, _currentLibrary); | |
2477 } | |
2478 if (member == null) { | |
2479 member = enclosingType.lookUpSetter(name, _currentLibrary); | |
2480 } | |
2481 if (member == null) { | |
2482 return false; | |
2483 } | |
2484 // OK, also static | |
2485 if (member.isStatic) { | |
2486 return false; | |
2487 } | |
2488 // prepare "member" type to report its name | |
2489 ClassElement memberClass = member.enclosingElement as ClassElement; | |
2490 InterfaceType memberType = memberClass.type; | |
2491 // report problem | |
2492 _errorReporter.reportErrorForNode( | |
2493 StaticWarningCode.CONFLICTING_STATIC_SETTER_AND_INSTANCE_MEMBER, | |
2494 nameNode, [memberType.displayName]); | |
2495 return true; | |
2496 } | |
2497 | |
2498 /** | |
2499 * Verify all conflicts between type variable and enclosing class. | |
2500 * TODO(scheglov) | |
2501 * | |
2502 * See [CompileTimeErrorCode.CONFLICTING_TYPE_VARIABLE_AND_CLASS], and | |
2503 * [CompileTimeErrorCode.CONFLICTING_TYPE_VARIABLE_AND_MEMBER]. | |
2504 */ | |
2505 bool _checkForConflictingTypeVariableErrorCodes( | |
2506 ClassDeclaration declaration) { | |
2507 bool problemReported = false; | |
2508 for (TypeParameterElement typeParameter in _enclosingClass.typeParameters) { | |
2509 String name = typeParameter.name; | |
2510 // name is same as the name of the enclosing class | |
2511 if (_enclosingClass.name == name) { | |
2512 _errorReporter.reportErrorForOffset( | |
2513 CompileTimeErrorCode.CONFLICTING_TYPE_VARIABLE_AND_CLASS, | |
2514 typeParameter.nameOffset, name.length, [name]); | |
2515 problemReported = true; | |
2516 } | |
2517 // check members | |
2518 if (_enclosingClass.getMethod(name) != null || | |
2519 _enclosingClass.getGetter(name) != null || | |
2520 _enclosingClass.getSetter(name) != null) { | |
2521 _errorReporter.reportErrorForOffset( | |
2522 CompileTimeErrorCode.CONFLICTING_TYPE_VARIABLE_AND_MEMBER, | |
2523 typeParameter.nameOffset, name.length, [name]); | |
2524 problemReported = true; | |
2525 } | |
2526 } | |
2527 return problemReported; | |
2528 } | |
2529 | |
2530 /** | |
2531 * Verify that if the given [constructor] declaration is 'const' then there | |
2532 * are no invocations of non-'const' super constructors. | |
2533 * | |
2534 * See [CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER]. | |
2535 */ | |
2536 bool _checkForConstConstructorWithNonConstSuper( | |
2537 ConstructorDeclaration constructor) { | |
2538 if (!_isEnclosingConstructorConst) { | |
2539 return false; | |
2540 } | |
2541 // OK, const factory, checked elsewhere | |
2542 if (constructor.factoryKeyword != null) { | |
2543 return false; | |
2544 } | |
2545 // check for mixins | |
2546 if (_enclosingClass.mixins.length != 0) { | |
2547 _errorReporter.reportErrorForNode( | |
2548 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_MIXIN, | |
2549 constructor.returnType); | |
2550 return true; | |
2551 } | |
2552 // try to find and check super constructor invocation | |
2553 for (ConstructorInitializer initializer in constructor.initializers) { | |
2554 if (initializer is SuperConstructorInvocation) { | |
2555 SuperConstructorInvocation superInvocation = initializer; | |
2556 ConstructorElement element = superInvocation.staticElement; | |
2557 if (element == null || element.isConst) { | |
2558 return false; | |
2559 } | |
2560 _errorReporter.reportErrorForNode( | |
2561 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER, | |
2562 superInvocation, [element.enclosingElement.displayName]); | |
2563 return true; | |
2564 } | |
2565 } | |
2566 // no explicit super constructor invocation, check default constructor | |
2567 InterfaceType supertype = _enclosingClass.supertype; | |
2568 if (supertype == null) { | |
2569 return false; | |
2570 } | |
2571 if (supertype.isObject) { | |
2572 return false; | |
2573 } | |
2574 ConstructorElement unnamedConstructor = | |
2575 supertype.element.unnamedConstructor; | |
2576 if (unnamedConstructor == null) { | |
2577 return false; | |
2578 } | |
2579 if (unnamedConstructor.isConst) { | |
2580 return false; | |
2581 } | |
2582 // default constructor is not 'const', report problem | |
2583 _errorReporter.reportErrorForNode( | |
2584 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER, | |
2585 constructor.returnType, [supertype.displayName]); | |
2586 return true; | |
2587 } | |
2588 | |
2589 /** | |
2590 * Verify that if the given [constructor] declaration is 'const' then there | |
2591 * are no non-final instance variable. The [constructorElement] is the | |
2592 * constructor element. | |
2593 * | |
2594 * See [CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD]. | |
2595 */ | |
2596 bool _checkForConstConstructorWithNonFinalField( | |
2597 ConstructorDeclaration constructor, | |
2598 ConstructorElement constructorElement) { | |
2599 if (!_isEnclosingConstructorConst) { | |
2600 return false; | |
2601 } | |
2602 // check if there is non-final field | |
2603 ClassElement classElement = constructorElement.enclosingElement; | |
2604 if (!classElement.hasNonFinalField) { | |
2605 return false; | |
2606 } | |
2607 // report problem | |
2608 _errorReporter.reportErrorForNode( | |
2609 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD, | |
2610 constructor); | |
2611 return true; | |
2612 } | |
2613 | |
2614 /** | |
2615 * Verify that the given 'const' instance creation [expression] is not | |
2616 * creating a deferred type. The [constructorName] is the constructor name, | |
2617 * always non-`null`. The [typeName] is the name of the type defining the | |
2618 * constructor, always non-`null`. | |
2619 * | |
2620 * See [CompileTimeErrorCode.CONST_DEFERRED_CLASS]. | |
2621 */ | |
2622 bool _checkForConstDeferredClass(InstanceCreationExpression expression, | |
2623 ConstructorName constructorName, TypeName typeName) { | |
2624 if (typeName.isDeferred) { | |
2625 _errorReporter.reportErrorForNode( | |
2626 CompileTimeErrorCode.CONST_DEFERRED_CLASS, constructorName, | |
2627 [typeName.name.name]); | |
2628 return true; | |
2629 } | |
2630 return false; | |
2631 } | |
2632 | |
2633 /** | |
2634 * Verify that the given throw [expression] is not enclosed in a 'const' | |
2635 * constructor declaration. | |
2636 * | |
2637 * See [CompileTimeErrorCode.CONST_CONSTRUCTOR_THROWS_EXCEPTION]. | |
2638 */ | |
2639 bool _checkForConstEvalThrowsException(ThrowExpression expression) { | |
2640 if (_isEnclosingConstructorConst) { | |
2641 _errorReporter.reportErrorForNode( | |
2642 CompileTimeErrorCode.CONST_CONSTRUCTOR_THROWS_EXCEPTION, expression); | |
2643 return true; | |
2644 } | |
2645 return false; | |
2646 } | |
2647 | |
2648 /** | |
2649 * Verify that the given normal formal [parameter] is not 'const'. | |
2650 * | |
2651 * See [CompileTimeErrorCode.CONST_FORMAL_PARAMETER]. | |
2652 */ | |
2653 bool _checkForConstFormalParameter(NormalFormalParameter parameter) { | |
2654 if (parameter.isConst) { | |
2655 _errorReporter.reportErrorForNode( | |
2656 CompileTimeErrorCode.CONST_FORMAL_PARAMETER, parameter); | |
2657 return true; | |
2658 } | |
2659 return false; | |
2660 } | |
2661 | |
2662 /** | |
2663 * Verify that the given instance creation [expression] is not being invoked | |
2664 * on an abstract class. The [typeName] is the [TypeName] of the | |
2665 * [ConstructorName] from the [InstanceCreationExpression], this is the AST | |
2666 * node that the error is attached to. The [type] is the type being | |
2667 * constructed with this [InstanceCreationExpression]. | |
2668 * | |
2669 * See [StaticWarningCode.CONST_WITH_ABSTRACT_CLASS], and | |
2670 * [StaticWarningCode.NEW_WITH_ABSTRACT_CLASS]. | |
2671 */ | |
2672 bool _checkForConstOrNewWithAbstractClass( | |
2673 InstanceCreationExpression expression, TypeName typeName, | |
2674 InterfaceType type) { | |
2675 if (type.element.isAbstract) { | |
2676 ConstructorElement element = expression.staticElement; | |
2677 if (element != null && !element.isFactory) { | |
2678 if ((expression.keyword as sc.KeywordToken).keyword == | |
2679 sc.Keyword.CONST) { | |
2680 _errorReporter.reportErrorForNode( | |
2681 StaticWarningCode.CONST_WITH_ABSTRACT_CLASS, typeName); | |
2682 } else { | |
2683 _errorReporter.reportErrorForNode( | |
2684 StaticWarningCode.NEW_WITH_ABSTRACT_CLASS, typeName); | |
2685 } | |
2686 return true; | |
2687 } | |
2688 } | |
2689 return false; | |
2690 } | |
2691 | |
2692 /** | |
2693 * Verify that the given instance creation [expression] is not being invoked | |
2694 * on an enum. The [typeName] is the [TypeName] of the [ConstructorName] from | |
2695 * the [InstanceCreationExpression], this is the AST node that the error is | |
2696 * attached to. The [type] is the type being constructed with this | |
2697 * [InstanceCreationExpression]. | |
2698 * | |
2699 * See [CompileTimeErrorCode.INSTANTIATE_ENUM]. | |
2700 */ | |
2701 bool _checkForConstOrNewWithEnum(InstanceCreationExpression expression, | |
2702 TypeName typeName, InterfaceType type) { | |
2703 if (type.element.isEnum) { | |
2704 _errorReporter.reportErrorForNode( | |
2705 CompileTimeErrorCode.INSTANTIATE_ENUM, typeName); | |
2706 return true; | |
2707 } | |
2708 return false; | |
2709 } | |
2710 | |
2711 /** | |
2712 * Verify that the given 'const' instance creation [expression] is not being | |
2713 * invoked on a constructor that is not 'const'. | |
2714 * | |
2715 * This method assumes that the instance creation was tested to be 'const' | |
2716 * before being called. | |
2717 * | |
2718 * See [CompileTimeErrorCode.CONST_WITH_NON_CONST]. | |
2719 */ | |
2720 bool _checkForConstWithNonConst(InstanceCreationExpression expression) { | |
2721 ConstructorElement constructorElement = expression.staticElement; | |
2722 if (constructorElement != null && !constructorElement.isConst) { | |
2723 _errorReporter.reportErrorForNode( | |
2724 CompileTimeErrorCode.CONST_WITH_NON_CONST, expression); | |
2725 return true; | |
2726 } | |
2727 return false; | |
2728 } | |
2729 | |
2730 /** | |
2731 * Verify that the given [typeName] does not reference any type parameters. | |
2732 * | |
2733 * See [CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS]. | |
2734 */ | |
2735 bool _checkForConstWithTypeParameters(TypeName typeName) { | |
2736 // something wrong with AST | |
2737 if (typeName == null) { | |
2738 return false; | |
2739 } | |
2740 Identifier name = typeName.name; | |
2741 if (name == null) { | |
2742 return false; | |
2743 } | |
2744 // should not be a type parameter | |
2745 if (name.staticElement is TypeParameterElement) { | |
2746 _errorReporter.reportErrorForNode( | |
2747 CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS, name); | |
2748 } | |
2749 // check type arguments | |
2750 TypeArgumentList typeArguments = typeName.typeArguments; | |
2751 if (typeArguments != null) { | |
2752 bool hasError = false; | |
2753 for (TypeName argument in typeArguments.arguments) { | |
2754 if (_checkForConstWithTypeParameters(argument)) { | |
2755 hasError = true; | |
2756 } | |
2757 } | |
2758 return hasError; | |
2759 } | |
2760 // OK | |
2761 return false; | |
2762 } | |
2763 | |
2764 /** | |
2765 * Verify that if the given 'const' instance creation [expression] is being | |
2766 * invoked on the resolved constructor. The [constructorName] is the | |
2767 * constructor name, always non-`null`. The [typeName] is the name of the type | |
2768 * defining the constructor, always non-`null`. | |
2769 * | |
2770 * This method assumes that the instance creation was tested to be 'const' | |
2771 * before being called. | |
2772 * | |
2773 * See [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR], and | |
2774 * [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT]. | |
2775 */ | |
2776 bool _checkForConstWithUndefinedConstructor( | |
2777 InstanceCreationExpression expression, ConstructorName constructorName, | |
2778 TypeName typeName) { | |
2779 // OK if resolved | |
2780 if (expression.staticElement != null) { | |
2781 return false; | |
2782 } | |
2783 DartType type = typeName.type; | |
2784 if (type is InterfaceType) { | |
2785 ClassElement element = type.element; | |
2786 if (element != null && element.isEnum) { | |
2787 // We have already reported the error. | |
2788 return false; | |
2789 } | |
2790 } | |
2791 Identifier className = typeName.name; | |
2792 // report as named or default constructor absence | |
2793 SimpleIdentifier name = constructorName.name; | |
2794 if (name != null) { | |
2795 _errorReporter.reportErrorForNode( | |
2796 CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR, name, [ | |
2797 className, | |
2798 name | |
2799 ]); | |
2800 } else { | |
2801 _errorReporter.reportErrorForNode( | |
2802 CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT, | |
2803 constructorName, [className]); | |
2804 } | |
2805 return true; | |
2806 } | |
2807 | |
2808 /** | |
2809 * Verify that there are no default parameters in the given function type | |
2810 * [alias]. | |
2811 * | |
2812 * See [CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS]. | |
2813 */ | |
2814 bool _checkForDefaultValueInFunctionTypeAlias(FunctionTypeAlias alias) { | |
2815 bool result = false; | |
2816 FormalParameterList formalParameterList = alias.parameters; | |
2817 NodeList<FormalParameter> parameters = formalParameterList.parameters; | |
2818 for (FormalParameter formalParameter in parameters) { | |
2819 if (formalParameter is DefaultFormalParameter) { | |
2820 DefaultFormalParameter defaultFormalParameter = formalParameter; | |
2821 if (defaultFormalParameter.defaultValue != null) { | |
2822 _errorReporter.reportErrorForNode( | |
2823 CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS, alias); | |
2824 result = true; | |
2825 } | |
2826 } | |
2827 } | |
2828 return result; | |
2829 } | |
2830 | |
2831 /** | |
2832 * Verify that the given default formal [parameter] is not part of a function | |
2833 * typed parameter. | |
2834 * | |
2835 * See [CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER]. | |
2836 */ | |
2837 bool _checkForDefaultValueInFunctionTypedParameter( | |
2838 DefaultFormalParameter parameter) { | |
2839 // OK, not in a function typed parameter. | |
2840 if (!_isInFunctionTypedFormalParameter) { | |
2841 return false; | |
2842 } | |
2843 // OK, no default value. | |
2844 if (parameter.defaultValue == null) { | |
2845 return false; | |
2846 } | |
2847 // Report problem. | |
2848 _errorReporter.reportErrorForNode( | |
2849 CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER, | |
2850 parameter); | |
2851 return true; | |
2852 } | |
2853 | |
2854 /** | |
2855 * Verify that any deferred imports in the given compilation [unit] have a | |
2856 * unique prefix. | |
2857 * | |
2858 * See [CompileTimeErrorCode.SHARED_DEFERRED_PREFIX]. | |
2859 */ | |
2860 bool _checkForDeferredPrefixCollisions(CompilationUnit unit) { | |
2861 bool foundError = false; | |
2862 NodeList<Directive> directives = unit.directives; | |
2863 int count = directives.length; | |
2864 if (count > 0) { | |
2865 HashMap<PrefixElement, List<ImportDirective>> prefixToDirectivesMap = | |
2866 new HashMap<PrefixElement, List<ImportDirective>>(); | |
2867 for (int i = 0; i < count; i++) { | |
2868 Directive directive = directives[i]; | |
2869 if (directive is ImportDirective) { | |
2870 ImportDirective importDirective = directive; | |
2871 SimpleIdentifier prefix = importDirective.prefix; | |
2872 if (prefix != null) { | |
2873 Element element = prefix.staticElement; | |
2874 if (element is PrefixElement) { | |
2875 PrefixElement prefixElement = element; | |
2876 List<ImportDirective> elements = | |
2877 prefixToDirectivesMap[prefixElement]; | |
2878 if (elements == null) { | |
2879 elements = new List<ImportDirective>(); | |
2880 prefixToDirectivesMap[prefixElement] = elements; | |
2881 } | |
2882 elements.add(importDirective); | |
2883 } | |
2884 } | |
2885 } | |
2886 } | |
2887 for (List<ImportDirective> imports in prefixToDirectivesMap.values) { | |
2888 if (_hasDeferredPrefixCollision(imports)) { | |
2889 foundError = true; | |
2890 } | |
2891 } | |
2892 } | |
2893 return foundError; | |
2894 } | |
2895 | |
2896 /** | |
2897 * Verify that the enclosing class does not have an instance member with the | |
2898 * given name of the static member. | |
2899 * | |
2900 * See [CompileTimeErrorCode.DUPLICATE_DEFINITION_INHERITANCE]. | |
2901 */ | |
2902 bool _checkForDuplicateDefinitionInheritance() { | |
2903 if (_enclosingClass == null) { | |
2904 return false; | |
2905 } | |
2906 bool hasProblem = false; | |
2907 for (ExecutableElement member in _enclosingClass.methods) { | |
2908 if (member.isStatic && _checkForDuplicateDefinitionOfMember(member)) { | |
2909 hasProblem = true; | |
2910 } | |
2911 } | |
2912 for (ExecutableElement member in _enclosingClass.accessors) { | |
2913 if (member.isStatic && _checkForDuplicateDefinitionOfMember(member)) { | |
2914 hasProblem = true; | |
2915 } | |
2916 } | |
2917 return hasProblem; | |
2918 } | |
2919 | |
2920 /** | |
2921 * Verify that the enclosing class does not have an instance member with the | |
2922 * given name of the [staticMember]. | |
2923 * | |
2924 * See [CompileTimeErrorCode.DUPLICATE_DEFINITION_INHERITANCE]. | |
2925 */ | |
2926 bool _checkForDuplicateDefinitionOfMember(ExecutableElement staticMember) { | |
2927 // prepare name | |
2928 String name = staticMember.name; | |
2929 if (name == null) { | |
2930 return false; | |
2931 } | |
2932 // try to find member | |
2933 ExecutableElement inheritedMember = | |
2934 _inheritanceManager.lookupInheritance(_enclosingClass, name); | |
2935 if (inheritedMember == null) { | |
2936 return false; | |
2937 } | |
2938 // OK, also static | |
2939 if (inheritedMember.isStatic) { | |
2940 return false; | |
2941 } | |
2942 // determine the display name, use the extended display name if the | |
2943 // enclosing class of the inherited member is in a different source | |
2944 String displayName; | |
2945 Element enclosingElement = inheritedMember.enclosingElement; | |
2946 if (enclosingElement.source == _enclosingClass.source) { | |
2947 displayName = enclosingElement.displayName; | |
2948 } else { | |
2949 displayName = enclosingElement.getExtendedDisplayName(null); | |
2950 } | |
2951 // report problem | |
2952 _errorReporter.reportErrorForOffset( | |
2953 CompileTimeErrorCode.DUPLICATE_DEFINITION_INHERITANCE, | |
2954 staticMember.nameOffset, name.length, [name, displayName]); | |
2955 return true; | |
2956 } | |
2957 | |
2958 /** | |
2959 * Verify that if the given list [literal] has type arguments then there is | |
2960 * exactly one. The [typeArguments] are the type arguments. | |
2961 * | |
2962 * See [StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS]. | |
2963 */ | |
2964 bool _checkForExpectedOneListTypeArgument( | |
2965 ListLiteral literal, TypeArgumentList typeArguments) { | |
2966 // check number of type arguments | |
2967 int num = typeArguments.arguments.length; | |
2968 if (num == 1) { | |
2969 return false; | |
2970 } | |
2971 // report problem | |
2972 _errorReporter.reportErrorForNode( | |
2973 StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS, typeArguments, | |
2974 [num]); | |
2975 return true; | |
2976 } | |
2977 | |
2978 /** | |
2979 * Verify that the given export [directive] has a unique name among other | |
2980 * exported libraries. The [exportElement] is the [ExportElement] retrieved | |
2981 * from the node, if the element in the node was `null`, then this method is | |
2982 * not called. The [exportedLibrary] is the library element containing the | |
2983 * exported element. | |
2984 * | |
2985 * See [CompileTimeErrorCode.EXPORT_DUPLICATED_LIBRARY_NAME]. | |
2986 */ | |
2987 bool _checkForExportDuplicateLibraryName(ExportDirective directive, | |
2988 ExportElement exportElement, LibraryElement exportedLibrary) { | |
2989 if (exportedLibrary == null) { | |
2990 return false; | |
2991 } | |
2992 String name = exportedLibrary.name; | |
2993 // check if there is other exported library with the same name | |
2994 LibraryElement prevLibrary = _nameToExportElement[name]; | |
2995 if (prevLibrary != null) { | |
2996 if (prevLibrary != exportedLibrary) { | |
2997 if (name.isEmpty) { | |
2998 _errorReporter.reportErrorForNode( | |
2999 StaticWarningCode.EXPORT_DUPLICATED_LIBRARY_UNNAMED, directive, [ | |
3000 prevLibrary.definingCompilationUnit.displayName, | |
3001 exportedLibrary.definingCompilationUnit.displayName | |
3002 ]); | |
3003 } else { | |
3004 _errorReporter.reportErrorForNode( | |
3005 StaticWarningCode.EXPORT_DUPLICATED_LIBRARY_NAMED, directive, [ | |
3006 prevLibrary.definingCompilationUnit.displayName, | |
3007 exportedLibrary.definingCompilationUnit.displayName, | |
3008 name | |
3009 ]); | |
3010 } | |
3011 return true; | |
3012 } | |
3013 } else { | |
3014 _nameToExportElement[name] = exportedLibrary; | |
3015 } | |
3016 // OK | |
3017 return false; | |
3018 } | |
3019 | |
3020 /** | |
3021 * Check that if the visiting library is not system, then any given library | |
3022 * should not be SDK internal library. The [exportElement] is the | |
3023 * [ExportElement] retrieved from the node, if the element in the node was | |
3024 * `null`, then this method is not called. | |
3025 * | |
3026 * See [CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY]. | |
3027 */ | |
3028 bool _checkForExportInternalLibrary( | |
3029 ExportDirective directive, ExportElement exportElement) { | |
3030 if (_isInSystemLibrary) { | |
3031 return false; | |
3032 } | |
3033 // should be private | |
3034 DartSdk sdk = _currentLibrary.context.sourceFactory.dartSdk; | |
3035 String uri = exportElement.uri; | |
3036 SdkLibrary sdkLibrary = sdk.getSdkLibrary(uri); | |
3037 if (sdkLibrary == null) { | |
3038 return false; | |
3039 } | |
3040 if (!sdkLibrary.isInternal) { | |
3041 return false; | |
3042 } | |
3043 // report problem | |
3044 _errorReporter.reportErrorForNode( | |
3045 CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY, directive, | |
3046 [directive.uri]); | |
3047 return true; | |
3048 } | |
3049 | |
3050 /** | |
3051 * Verify that the given extends [clause] does not extend a deferred class. | |
3052 * | |
3053 * See [CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS]. | |
3054 */ | |
3055 bool _checkForExtendsDeferredClass(ExtendsClause clause) { | |
3056 if (clause == null) { | |
3057 return false; | |
3058 } | |
3059 return _checkForExtendsOrImplementsDeferredClass( | |
3060 clause.superclass, CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS); | |
3061 } | |
3062 | |
3063 /** | |
3064 * Verify that the given type [alias] does not extend a deferred class. | |
3065 * | |
3066 * See [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]. | |
3067 */ | |
3068 bool _checkForExtendsDeferredClassInTypeAlias(ClassTypeAlias alias) { | |
3069 if (alias == null) { | |
3070 return false; | |
3071 } | |
3072 return _checkForExtendsOrImplementsDeferredClass( | |
3073 alias.superclass, CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS); | |
3074 } | |
3075 | |
3076 /** | |
3077 * Verify that the given extends [clause] does not extend classes such as | |
3078 * 'num' or 'String'. | |
3079 * | |
3080 * See [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]. | |
3081 */ | |
3082 bool _checkForExtendsDisallowedClass(ExtendsClause clause) { | |
3083 if (clause == null) { | |
3084 return false; | |
3085 } | |
3086 return _checkForExtendsOrImplementsDisallowedClass( | |
3087 clause.superclass, CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS); | |
3088 } | |
3089 | |
3090 /** | |
3091 * Verify that the given type [alias] does not extend classes such as 'num' or | |
3092 * 'String'. | |
3093 * | |
3094 * See [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]. | |
3095 */ | |
3096 bool _checkForExtendsDisallowedClassInTypeAlias(ClassTypeAlias alias) { | |
3097 if (alias == null) { | |
3098 return false; | |
3099 } | |
3100 return _checkForExtendsOrImplementsDisallowedClass( | |
3101 alias.superclass, CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS); | |
3102 } | |
3103 | |
3104 /** | |
3105 * Verify that the given [typeName] does not extend, implement or mixin | |
3106 * classes that are deferred. | |
3107 * | |
3108 * See [_checkForExtendsDeferredClass], | |
3109 * [_checkForExtendsDeferredClassInTypeAlias], | |
3110 * [_checkForImplementsDeferredClass], | |
3111 * [_checkForAllMixinErrorCodes], | |
3112 * [CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS], | |
3113 * [CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS], and | |
3114 * [CompileTimeErrorCode.MIXIN_DEFERRED_CLASS]. | |
3115 */ | |
3116 bool _checkForExtendsOrImplementsDeferredClass( | |
3117 TypeName typeName, ErrorCode errorCode) { | |
3118 if (typeName.isSynthetic) { | |
3119 return false; | |
3120 } | |
3121 if (typeName.isDeferred) { | |
3122 _errorReporter.reportErrorForNode( | |
3123 errorCode, typeName, [typeName.name.name]); | |
3124 return true; | |
3125 } | |
3126 return false; | |
3127 } | |
3128 | |
3129 /** | |
3130 * Verify that the given [typeName] does not extend, implement or mixin | |
3131 * classes such as 'num' or 'String'. | |
3132 * | |
3133 * See [_checkForExtendsDisallowedClass], | |
3134 * [_checkForExtendsDisallowedClassInTypeAlias], | |
3135 * [_checkForImplementsDisallowedClass], | |
3136 * [_checkForAllMixinErrorCodes], | |
3137 * [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS], | |
3138 * [CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS], and | |
3139 * [CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS]. | |
3140 */ | |
3141 bool _checkForExtendsOrImplementsDisallowedClass( | |
3142 TypeName typeName, ErrorCode errorCode) { | |
3143 if (typeName.isSynthetic) { | |
3144 return false; | |
3145 } | |
3146 DartType superType = typeName.type; | |
3147 for (InterfaceType disallowedType | |
3148 in _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT) { | |
3149 if (superType != null && superType == disallowedType) { | |
3150 // if the violating type happens to be 'num', we need to rule out the | |
3151 // case where the enclosing class is 'int' or 'double' | |
3152 if (superType == _typeProvider.numType) { | |
3153 AstNode grandParent = typeName.parent.parent; | |
3154 // Note: this is a corner case that won't happen often, so adding a | |
3155 // field currentClass (see currentFunction) to ErrorVerifier isn't | |
3156 // worth if for this case, but if the field currentClass is added, | |
3157 // then this message should become a todo to not lookup the | |
3158 // grandparent node. | |
3159 if (grandParent is ClassDeclaration) { | |
3160 ClassElement classElement = grandParent.element; | |
3161 DartType classType = classElement.type; | |
3162 if (classType != null && | |
3163 (classType == _intType || | |
3164 classType == _typeProvider.doubleType)) { | |
3165 return false; | |
3166 } | |
3167 } | |
3168 } | |
3169 // otherwise, report the error | |
3170 _errorReporter.reportErrorForNode( | |
3171 errorCode, typeName, [disallowedType.displayName]); | |
3172 return true; | |
3173 } | |
3174 } | |
3175 return false; | |
3176 } | |
3177 | |
3178 /** | |
3179 * Verify that the given constructor field [initializer] has compatible field | |
3180 * and initializer expression types. The [staticElement] is the static element | |
3181 * from the name in the [ConstructorFieldInitializer]. | |
3182 * | |
3183 * See [CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE], and | |
3184 * [StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE]. | |
3185 */ | |
3186 bool _checkForFieldInitializerNotAssignable( | |
3187 ConstructorFieldInitializer initializer, Element staticElement) { | |
3188 // prepare field element | |
3189 if (staticElement is! FieldElement) { | |
3190 return false; | |
3191 } | |
3192 FieldElement fieldElement = staticElement as FieldElement; | |
3193 // prepare field type | |
3194 DartType fieldType = fieldElement.type; | |
3195 // prepare expression type | |
3196 Expression expression = initializer.expression; | |
3197 if (expression == null) { | |
3198 return false; | |
3199 } | |
3200 // test the static type of the expression | |
3201 DartType staticType = getStaticType(expression); | |
3202 if (staticType == null) { | |
3203 return false; | |
3204 } | |
3205 if (staticType.isAssignableTo(fieldType)) { | |
3206 return false; | |
3207 } | |
3208 // report problem | |
3209 if (_isEnclosingConstructorConst) { | |
3210 // TODO(paulberry): this error should be based on the actual type of the | |
3211 // constant, not the static type. See dartbug.com/21119. | |
3212 _errorReporter.reportTypeErrorForNode( | |
3213 CheckedModeCompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE
, | |
3214 expression, [staticType, fieldType]); | |
3215 } | |
3216 _errorReporter.reportTypeErrorForNode( | |
3217 StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [ | |
3218 staticType, | |
3219 fieldType | |
3220 ]); | |
3221 return true; | |
3222 // TODO(brianwilkerson) Define a hint corresponding to these errors and | |
3223 // report it if appropriate. | |
3224 // // test the propagated type of the expression | |
3225 // Type propagatedType = expression.getPropagatedType(); | |
3226 // if (propagatedType != null && propagatedType.isAssignableTo(fieldType)
) { | |
3227 // return false; | |
3228 // } | |
3229 // // report problem | |
3230 // if (isEnclosingConstructorConst) { | |
3231 // errorReporter.reportTypeErrorForNode( | |
3232 // CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, | |
3233 // expression, | |
3234 // propagatedType == null ? staticType : propagatedType, | |
3235 // fieldType); | |
3236 // } else { | |
3237 // errorReporter.reportTypeErrorForNode( | |
3238 // StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, | |
3239 // expression, | |
3240 // propagatedType == null ? staticType : propagatedType, | |
3241 // fieldType); | |
3242 // } | |
3243 // return true; | |
3244 } | |
3245 | |
3246 /** | |
3247 * Verify that the given field formal [parameter] is in a constructor | |
3248 * declaration. | |
3249 * | |
3250 * See [CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR]. | |
3251 */ | |
3252 bool _checkForFieldInitializingFormalRedirectingConstructor( | |
3253 FieldFormalParameter parameter) { | |
3254 ConstructorDeclaration constructor = | |
3255 parameter.getAncestor((node) => node is ConstructorDeclaration); | |
3256 if (constructor == null) { | |
3257 _errorReporter.reportErrorForNode( | |
3258 CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, | |
3259 parameter); | |
3260 return true; | |
3261 } | |
3262 // constructor cannot be a factory | |
3263 if (constructor.factoryKeyword != null) { | |
3264 _errorReporter.reportErrorForNode( | |
3265 CompileTimeErrorCode.FIELD_INITIALIZER_FACTORY_CONSTRUCTOR, | |
3266 parameter); | |
3267 return true; | |
3268 } | |
3269 // constructor cannot have a redirection | |
3270 for (ConstructorInitializer initializer in constructor.initializers) { | |
3271 if (initializer is RedirectingConstructorInvocation) { | |
3272 _errorReporter.reportErrorForNode( | |
3273 CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR, | |
3274 parameter); | |
3275 return true; | |
3276 } | |
3277 } | |
3278 // OK | |
3279 return false; | |
3280 } | |
3281 | |
3282 /** | |
3283 * Verify that the given variable declaration [list] has only initialized | |
3284 * variables if the list is final or const. | |
3285 * | |
3286 * See [CompileTimeErrorCode.CONST_NOT_INITIALIZED], and | |
3287 * [StaticWarningCode.FINAL_NOT_INITIALIZED]. | |
3288 */ | |
3289 bool _checkForFinalNotInitialized(VariableDeclarationList list) { | |
3290 if (_isInNativeClass) { | |
3291 return false; | |
3292 } | |
3293 bool foundError = false; | |
3294 if (!list.isSynthetic) { | |
3295 NodeList<VariableDeclaration> variables = list.variables; | |
3296 for (VariableDeclaration variable in variables) { | |
3297 if (variable.initializer == null) { | |
3298 if (list.isConst) { | |
3299 _errorReporter.reportErrorForNode( | |
3300 CompileTimeErrorCode.CONST_NOT_INITIALIZED, variable.name, | |
3301 [variable.name.name]); | |
3302 } else if (list.isFinal) { | |
3303 _errorReporter.reportErrorForNode( | |
3304 StaticWarningCode.FINAL_NOT_INITIALIZED, variable.name, | |
3305 [variable.name.name]); | |
3306 } | |
3307 foundError = true; | |
3308 } | |
3309 } | |
3310 } | |
3311 return foundError; | |
3312 } | |
3313 | |
3314 /** | |
3315 * Verify that final fields in the given clas [declaration] that are declared, | |
3316 * without any constructors in the enclosing class, are initialized. Cases in | |
3317 * which there is at least one constructor are handled at the end of | |
3318 * [_checkForAllFinalInitializedErrorCodes]. | |
3319 * | |
3320 * See [CompileTimeErrorCode.CONST_NOT_INITIALIZED], and | |
3321 * [StaticWarningCode.FINAL_NOT_INITIALIZED]. | |
3322 */ | |
3323 bool _checkForFinalNotInitializedInClass(ClassDeclaration declaration) { | |
3324 NodeList<ClassMember> classMembers = declaration.members; | |
3325 for (ClassMember classMember in classMembers) { | |
3326 if (classMember is ConstructorDeclaration) { | |
3327 return false; | |
3328 } | |
3329 } | |
3330 bool foundError = false; | |
3331 for (ClassMember classMember in classMembers) { | |
3332 if (classMember is FieldDeclaration && | |
3333 _checkForFinalNotInitialized(classMember.fields)) { | |
3334 foundError = true; | |
3335 } | |
3336 } | |
3337 return foundError; | |
3338 } | |
3339 | |
3340 /** | |
3341 * If the current function is async, async*, or sync*, verify that its | |
3342 * declared return type is assignable to Future, Stream, or Iterable, | |
3343 * respectively. If not, report the error using [returnType]. | |
3344 */ | |
3345 void _checkForIllegalReturnType(TypeName returnType) { | |
3346 if (returnType == null) { | |
3347 // No declared return type, so the return type must be dynamic, which is | |
3348 // assignable to everything. | |
3349 return; | |
3350 } | |
3351 if (_enclosingFunction.isAsynchronous) { | |
3352 if (_enclosingFunction.isGenerator) { | |
3353 if (!_enclosingFunction.returnType | |
3354 .isAssignableTo(_typeProvider.streamDynamicType)) { | |
3355 _errorReporter.reportErrorForNode( | |
3356 StaticTypeWarningCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE, | |
3357 returnType); | |
3358 } | |
3359 } else { | |
3360 if (!_enclosingFunction.returnType | |
3361 .isAssignableTo(_typeProvider.futureDynamicType)) { | |
3362 _errorReporter.reportErrorForNode( | |
3363 StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE, returnType); | |
3364 } | |
3365 } | |
3366 } else if (_enclosingFunction.isGenerator) { | |
3367 if (!_enclosingFunction.returnType | |
3368 .isAssignableTo(_typeProvider.iterableDynamicType)) { | |
3369 _errorReporter.reportErrorForNode( | |
3370 StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE, | |
3371 returnType); | |
3372 } | |
3373 } | |
3374 } | |
3375 | |
3376 /** | |
3377 * Verify that the given implements [clause] does not implement classes that | |
3378 * are deferred. | |
3379 * | |
3380 * See [CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS]. | |
3381 */ | |
3382 bool _checkForImplementsDeferredClass(ImplementsClause clause) { | |
3383 if (clause == null) { | |
3384 return false; | |
3385 } | |
3386 bool foundError = false; | |
3387 for (TypeName type in clause.interfaces) { | |
3388 if (_checkForExtendsOrImplementsDeferredClass( | |
3389 type, CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS)) { | |
3390 foundError = true; | |
3391 } | |
3392 } | |
3393 return foundError; | |
3394 } | |
3395 | |
3396 /** | |
3397 * Verify that the given implements [clause] does not implement classes such | |
3398 * as 'num' or 'String'. | |
3399 * | |
3400 * See [CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS]. | |
3401 */ | |
3402 bool _checkForImplementsDisallowedClass(ImplementsClause clause) { | |
3403 if (clause == null) { | |
3404 return false; | |
3405 } | |
3406 bool foundError = false; | |
3407 for (TypeName type in clause.interfaces) { | |
3408 if (_checkForExtendsOrImplementsDisallowedClass( | |
3409 type, CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS)) { | |
3410 foundError = true; | |
3411 } | |
3412 } | |
3413 return foundError; | |
3414 } | |
3415 | |
3416 /** | |
3417 * Verify that if the given [identifier] is part of a constructor initializer, | |
3418 * then it does not implicitly reference 'this' expression. | |
3419 * | |
3420 * See [CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER], and | |
3421 * [CompileTimeErrorCode.INSTANCE_MEMBER_ACCESS_FROM_STATIC]. | |
3422 * TODO(scheglov) rename thid method | |
3423 */ | |
3424 bool _checkForImplicitThisReferenceInInitializer( | |
3425 SimpleIdentifier identifier) { | |
3426 if (!_isInConstructorInitializer && | |
3427 !_isInStaticMethod && | |
3428 !_isInFactory && | |
3429 !_isInInstanceVariableInitializer && | |
3430 !_isInStaticVariableDeclaration) { | |
3431 return false; | |
3432 } | |
3433 // prepare element | |
3434 Element element = identifier.staticElement; | |
3435 if (!(element is MethodElement || element is PropertyAccessorElement)) { | |
3436 return false; | |
3437 } | |
3438 // static element | |
3439 ExecutableElement executableElement = element as ExecutableElement; | |
3440 if (executableElement.isStatic) { | |
3441 return false; | |
3442 } | |
3443 // not a class member | |
3444 Element enclosingElement = element.enclosingElement; | |
3445 if (enclosingElement is! ClassElement) { | |
3446 return false; | |
3447 } | |
3448 // comment | |
3449 AstNode parent = identifier.parent; | |
3450 if (parent is CommentReference) { | |
3451 return false; | |
3452 } | |
3453 // qualified method invocation | |
3454 if (parent is MethodInvocation) { | |
3455 MethodInvocation invocation = parent; | |
3456 if (identical(invocation.methodName, identifier) && | |
3457 invocation.realTarget != null) { | |
3458 return false; | |
3459 } | |
3460 } | |
3461 // qualified property access | |
3462 if (parent is PropertyAccess) { | |
3463 PropertyAccess access = parent; | |
3464 if (identical(access.propertyName, identifier) && | |
3465 access.realTarget != null) { | |
3466 return false; | |
3467 } | |
3468 } | |
3469 if (parent is PrefixedIdentifier) { | |
3470 PrefixedIdentifier prefixed = parent; | |
3471 if (identical(prefixed.identifier, identifier)) { | |
3472 return false; | |
3473 } | |
3474 } | |
3475 // report problem | |
3476 if (_isInStaticMethod) { | |
3477 _errorReporter.reportErrorForNode( | |
3478 CompileTimeErrorCode.INSTANCE_MEMBER_ACCESS_FROM_STATIC, identifier); | |
3479 } else if (_isInFactory) { | |
3480 _errorReporter.reportErrorForNode( | |
3481 CompileTimeErrorCode.INSTANCE_MEMBER_ACCESS_FROM_FACTORY, identifier); | |
3482 } else { | |
3483 _errorReporter.reportErrorForNode( | |
3484 CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER, | |
3485 identifier); | |
3486 } | |
3487 return true; | |
3488 } | |
3489 | |
3490 /** | |
3491 * Verify that the given import [directive] has a unique name among other | |
3492 * imported libraries. The [importElement] is the [ImportElement] retrieved | |
3493 * from the node, if the element in the node was `null`, then this method is | |
3494 * not called. | |
3495 * | |
3496 * See [CompileTimeErrorCode.IMPORT_DUPLICATED_LIBRARY_NAME]. | |
3497 */ | |
3498 bool _checkForImportDuplicateLibraryName( | |
3499 ImportDirective directive, ImportElement importElement) { | |
3500 // prepare imported library | |
3501 LibraryElement nodeLibrary = importElement.importedLibrary; | |
3502 if (nodeLibrary == null) { | |
3503 return false; | |
3504 } | |
3505 String name = nodeLibrary.name; | |
3506 // check if there is another imported library with the same name | |
3507 LibraryElement prevLibrary = _nameToImportElement[name]; | |
3508 if (prevLibrary != null) { | |
3509 if (prevLibrary != nodeLibrary) { | |
3510 if (name.isEmpty) { | |
3511 _errorReporter.reportErrorForNode( | |
3512 StaticWarningCode.IMPORT_DUPLICATED_LIBRARY_UNNAMED, directive, [ | |
3513 prevLibrary.definingCompilationUnit.displayName, | |
3514 nodeLibrary.definingCompilationUnit.displayName | |
3515 ]); | |
3516 } else { | |
3517 _errorReporter.reportErrorForNode( | |
3518 StaticWarningCode.IMPORT_DUPLICATED_LIBRARY_NAMED, directive, [ | |
3519 prevLibrary.definingCompilationUnit.displayName, | |
3520 nodeLibrary.definingCompilationUnit.displayName, | |
3521 name | |
3522 ]); | |
3523 } | |
3524 return true; | |
3525 } | |
3526 } else { | |
3527 _nameToImportElement[name] = nodeLibrary; | |
3528 } | |
3529 // OK | |
3530 return false; | |
3531 } | |
3532 | |
3533 /** | |
3534 * Check that if the visiting library is not system, then any given library | |
3535 * should not be SDK internal library. The [importElement] is the | |
3536 * [ImportElement] retrieved from the node, if the element in the node was | |
3537 * `null`, then this method is not called | |
3538 * | |
3539 * See [CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY]. | |
3540 */ | |
3541 bool _checkForImportInternalLibrary( | |
3542 ImportDirective directive, ImportElement importElement) { | |
3543 if (_isInSystemLibrary) { | |
3544 return false; | |
3545 } | |
3546 // should be private | |
3547 DartSdk sdk = _currentLibrary.context.sourceFactory.dartSdk; | |
3548 String uri = importElement.uri; | |
3549 SdkLibrary sdkLibrary = sdk.getSdkLibrary(uri); | |
3550 if (sdkLibrary == null) { | |
3551 return false; | |
3552 } | |
3553 if (!sdkLibrary.isInternal) { | |
3554 return false; | |
3555 } | |
3556 // report problem | |
3557 _errorReporter.reportErrorForNode( | |
3558 CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY, directive, | |
3559 [directive.uri]); | |
3560 return true; | |
3561 } | |
3562 | |
3563 /** | |
3564 * For each class declaration, this method is called which verifies that all | |
3565 * inherited members are inherited consistently. | |
3566 * | |
3567 * See [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE]. | |
3568 */ | |
3569 bool _checkForInconsistentMethodInheritance() { | |
3570 // Ensure that the inheritance manager has a chance to generate all errors | |
3571 // we may care about, note that we ensure that the interfaces data since | |
3572 // there are no errors. | |
3573 _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass); | |
3574 HashSet<AnalysisError> errors = | |
3575 _inheritanceManager.getErrors(_enclosingClass); | |
3576 if (errors == null || errors.isEmpty) { | |
3577 return false; | |
3578 } | |
3579 for (AnalysisError error in errors) { | |
3580 _errorReporter.reportError(error); | |
3581 } | |
3582 return true; | |
3583 } | |
3584 | |
3585 /** | |
3586 * Check that the given [typeReference] is not a type reference and that then | |
3587 * the [name] is reference to an instance member. | |
3588 * | |
3589 * See [StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER]. | |
3590 */ | |
3591 bool _checkForInstanceAccessToStaticMember( | |
3592 ClassElement typeReference, SimpleIdentifier name) { | |
3593 // OK, in comment | |
3594 if (_isInComment) { | |
3595 return false; | |
3596 } | |
3597 // OK, target is a type | |
3598 if (typeReference != null) { | |
3599 return false; | |
3600 } | |
3601 // prepare member Element | |
3602 Element element = name.staticElement; | |
3603 if (element is! ExecutableElement) { | |
3604 return false; | |
3605 } | |
3606 ExecutableElement executableElement = element as ExecutableElement; | |
3607 // OK, top-level element | |
3608 if (executableElement.enclosingElement is! ClassElement) { | |
3609 return false; | |
3610 } | |
3611 // OK, instance member | |
3612 if (!executableElement.isStatic) { | |
3613 return false; | |
3614 } | |
3615 // report problem | |
3616 _errorReporter.reportErrorForNode( | |
3617 StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, name, | |
3618 [name.name]); | |
3619 return true; | |
3620 } | |
3621 | |
3622 /** | |
3623 * Check whether the given [executableElement] collides with the name of a | |
3624 * static method in one of its superclasses, and reports the appropriate | |
3625 * warning if it does. The [errorNameTarget] is the node to report problems | |
3626 * on. | |
3627 * | |
3628 * See [StaticTypeWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_ST
ATIC]. | |
3629 */ | |
3630 bool _checkForInstanceMethodNameCollidesWithSuperclassStatic( | |
3631 ExecutableElement executableElement, SimpleIdentifier errorNameTarget) { | |
3632 String executableElementName = executableElement.name; | |
3633 if (executableElement is! PropertyAccessorElement && | |
3634 !executableElement.isOperator) { | |
3635 HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>(); | |
3636 InterfaceType superclassType = _enclosingClass.supertype; | |
3637 ClassElement superclassElement = | |
3638 superclassType == null ? null : superclassType.element; | |
3639 bool executableElementPrivate = | |
3640 Identifier.isPrivateName(executableElementName); | |
3641 while (superclassElement != null && | |
3642 !visitedClasses.contains(superclassElement)) { | |
3643 visitedClasses.add(superclassElement); | |
3644 LibraryElement superclassLibrary = superclassElement.library; | |
3645 // Check fields. | |
3646 FieldElement fieldElt = | |
3647 superclassElement.getField(executableElementName); | |
3648 if (fieldElt != null) { | |
3649 // Ignore if private in a different library - cannot collide. | |
3650 if (executableElementPrivate && | |
3651 _currentLibrary != superclassLibrary) { | |
3652 continue; | |
3653 } | |
3654 // instance vs. static | |
3655 if (fieldElt.isStatic) { | |
3656 _errorReporter.reportErrorForNode( | |
3657 StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_
STATIC, | |
3658 errorNameTarget, [ | |
3659 executableElementName, | |
3660 fieldElt.enclosingElement.displayName | |
3661 ]); | |
3662 return true; | |
3663 } | |
3664 } | |
3665 // Check methods. | |
3666 List<MethodElement> methodElements = superclassElement.methods; | |
3667 for (MethodElement methodElement in methodElements) { | |
3668 // We need the same name. | |
3669 if (methodElement.name != executableElementName) { | |
3670 continue; | |
3671 } | |
3672 // Ignore if private in a different library - cannot collide. | |
3673 if (executableElementPrivate && | |
3674 _currentLibrary != superclassLibrary) { | |
3675 continue; | |
3676 } | |
3677 // instance vs. static | |
3678 if (methodElement.isStatic) { | |
3679 _errorReporter.reportErrorForNode( | |
3680 StaticWarningCode.INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_
STATIC, | |
3681 errorNameTarget, [ | |
3682 executableElementName, | |
3683 methodElement.enclosingElement.displayName | |
3684 ]); | |
3685 return true; | |
3686 } | |
3687 } | |
3688 superclassType = superclassElement.supertype; | |
3689 superclassElement = | |
3690 superclassType == null ? null : superclassType.element; | |
3691 } | |
3692 } | |
3693 return false; | |
3694 } | |
3695 | |
3696 /** | |
3697 * Verify that an 'int' can be assigned to the parameter corresponding to the | |
3698 * given [argument]. This is used for prefix and postfix expressions where | |
3699 * the argument value is implicit. | |
3700 * | |
3701 * See [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. | |
3702 */ | |
3703 bool _checkForIntNotAssignable(Expression argument) { | |
3704 if (argument == null) { | |
3705 return false; | |
3706 } | |
3707 ParameterElement staticParameterElement = argument.staticParameterElement; | |
3708 DartType staticParameterType = | |
3709 staticParameterElement == null ? null : staticParameterElement.type; | |
3710 return _checkForArgumentTypeNotAssignable(argument, staticParameterType, | |
3711 _intType, StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); | |
3712 } | |
3713 | |
3714 /** | |
3715 * Verify that the given [annotation] isn't defined in a deferred library. | |
3716 * | |
3717 * See [CompileTimeErrorCode.INVALID_ANNOTATION_FROM_DEFERRED_LIBRARY]. | |
3718 */ | |
3719 bool _checkForInvalidAnnotationFromDeferredLibrary(Annotation annotation) { | |
3720 Identifier nameIdentifier = annotation.name; | |
3721 if (nameIdentifier is PrefixedIdentifier) { | |
3722 if (nameIdentifier.isDeferred) { | |
3723 _errorReporter.reportErrorForNode( | |
3724 CompileTimeErrorCode.INVALID_ANNOTATION_FROM_DEFERRED_LIBRARY, | |
3725 annotation.name); | |
3726 return true; | |
3727 } | |
3728 } | |
3729 return false; | |
3730 } | |
3731 | |
3732 /** | |
3733 * Verify that the given left hand side ([lhs]) and right hand side ([rhs]) | |
3734 * represent a valid assignment. | |
3735 * | |
3736 * See [StaticTypeWarningCode.INVALID_ASSIGNMENT]. | |
3737 */ | |
3738 bool _checkForInvalidAssignment(Expression lhs, Expression rhs) { | |
3739 if (lhs == null || rhs == null) { | |
3740 return false; | |
3741 } | |
3742 VariableElement leftVariableElement = getVariableElement(lhs); | |
3743 DartType leftType = (leftVariableElement == null) | |
3744 ? getStaticType(lhs) | |
3745 : leftVariableElement.type; | |
3746 DartType staticRightType = getStaticType(rhs); | |
3747 if (!staticRightType.isAssignableTo(leftType)) { | |
3748 _errorReporter.reportTypeErrorForNode( | |
3749 StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [ | |
3750 staticRightType, | |
3751 leftType | |
3752 ]); | |
3753 return true; | |
3754 } | |
3755 return false; | |
3756 } | |
3757 | |
3758 /** | |
3759 * Given an [assignment] using a compound assignment operator, this verifies | |
3760 * that the given assignment is valid. The [lhs] is the left hand side | |
3761 * expression. The [rhs] is the right hand side expression. | |
3762 * | |
3763 * See [StaticTypeWarningCode.INVALID_ASSIGNMENT]. | |
3764 */ | |
3765 bool _checkForInvalidCompoundAssignment( | |
3766 AssignmentExpression assignment, Expression lhs, Expression rhs) { | |
3767 if (lhs == null) { | |
3768 return false; | |
3769 } | |
3770 VariableElement leftVariableElement = getVariableElement(lhs); | |
3771 DartType leftType = (leftVariableElement == null) | |
3772 ? getStaticType(lhs) | |
3773 : leftVariableElement.type; | |
3774 MethodElement invokedMethod = assignment.staticElement; | |
3775 if (invokedMethod == null) { | |
3776 return false; | |
3777 } | |
3778 DartType rightType = invokedMethod.type.returnType; | |
3779 if (leftType == null || rightType == null) { | |
3780 return false; | |
3781 } | |
3782 if (!rightType.isAssignableTo(leftType)) { | |
3783 _errorReporter.reportTypeErrorForNode( | |
3784 StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightType, leftType]); | |
3785 return true; | |
3786 } | |
3787 return false; | |
3788 } | |
3789 | |
3790 /** | |
3791 * Check the given [initializer] to ensure that the field being initialized is | |
3792 * a valid field. The [fieldName] is the field name from the | |
3793 * [ConstructorFieldInitializer]. The [staticElement] is the static element | |
3794 * from the name in the [ConstructorFieldInitializer]. | |
3795 */ | |
3796 void _checkForInvalidField(ConstructorFieldInitializer initializer, | |
3797 SimpleIdentifier fieldName, Element staticElement) { | |
3798 if (staticElement is FieldElement) { | |
3799 FieldElement fieldElement = staticElement; | |
3800 if (fieldElement.isSynthetic) { | |
3801 _errorReporter.reportErrorForNode( | |
3802 CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD, | |
3803 initializer, [fieldName]); | |
3804 } else if (fieldElement.isStatic) { | |
3805 _errorReporter.reportErrorForNode( | |
3806 CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, initializer, | |
3807 [fieldName]); | |
3808 } | |
3809 } else { | |
3810 _errorReporter.reportErrorForNode( | |
3811 CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD, initializer, | |
3812 [fieldName]); | |
3813 return; | |
3814 } | |
3815 } | |
3816 | |
3817 /** | |
3818 * Check to see whether the given function [body] has a modifier associated | |
3819 * with it, and report it as an error if it does. | |
3820 */ | |
3821 bool _checkForInvalidModifierOnBody( | |
3822 FunctionBody body, CompileTimeErrorCode errorCode) { | |
3823 sc.Token keyword = body.keyword; | |
3824 if (keyword != null) { | |
3825 _errorReporter.reportErrorForToken(errorCode, keyword, [keyword.lexeme]); | |
3826 return true; | |
3827 } | |
3828 return false; | |
3829 } | |
3830 | |
3831 /** | |
3832 * Verify that the usage of the given 'this' is valid. | |
3833 * | |
3834 * See [CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS]. | |
3835 */ | |
3836 bool _checkForInvalidReferenceToThis(ThisExpression expression) { | |
3837 if (!_isThisInValidContext(expression)) { | |
3838 _errorReporter.reportErrorForNode( | |
3839 CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS, expression); | |
3840 return true; | |
3841 } | |
3842 return false; | |
3843 } | |
3844 | |
3845 /** | |
3846 * Checks to ensure that the given list of type [arguments] does not have a | |
3847 * type parameter as a type argument. The [errorCode] is either | |
3848 * [CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_LIST] or | |
3849 * [CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_MAP]. | |
3850 */ | |
3851 bool _checkForInvalidTypeArgumentInConstTypedLiteral( | |
3852 NodeList<TypeName> arguments, ErrorCode errorCode) { | |
3853 bool foundError = false; | |
3854 for (TypeName typeName in arguments) { | |
3855 if (typeName.type is TypeParameterType) { | |
3856 _errorReporter.reportErrorForNode(errorCode, typeName, [typeName.name]); | |
3857 foundError = true; | |
3858 } | |
3859 } | |
3860 return foundError; | |
3861 } | |
3862 | |
3863 /** | |
3864 * Verify that the elements given list [literal] are subtypes of the specified | |
3865 * element type. The [typeArguments] are the type arguments. | |
3866 * | |
3867 * See [CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE], and | |
3868 * [StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE]. | |
3869 */ | |
3870 bool _checkForListElementTypeNotAssignable( | |
3871 ListLiteral literal, TypeArgumentList typeArguments) { | |
3872 NodeList<TypeName> typeNames = typeArguments.arguments; | |
3873 if (typeNames.length < 1) { | |
3874 return false; | |
3875 } | |
3876 DartType listElementType = typeNames[0].type; | |
3877 // Check every list element. | |
3878 bool hasProblems = false; | |
3879 for (Expression element in literal.elements) { | |
3880 if (literal.constKeyword != null) { | |
3881 // TODO(paulberry): this error should be based on the actual type of the | |
3882 // list element, not the static type. See dartbug.com/21119. | |
3883 if (_checkForArgumentTypeNotAssignableWithExpectedTypes(element, | |
3884 listElementType, | |
3885 CheckedModeCompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE)) { | |
3886 hasProblems = true; | |
3887 } | |
3888 } | |
3889 if (_checkForArgumentTypeNotAssignableWithExpectedTypes(element, | |
3890 listElementType, | |
3891 StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE)) { | |
3892 hasProblems = true; | |
3893 } | |
3894 } | |
3895 return hasProblems; | |
3896 } | |
3897 | |
3898 /** | |
3899 * Verify that the key/value of entries of the given map [literal] are | |
3900 * subtypes of the key/value types specified in the type arguments. The | |
3901 * [typeArguments] are the type arguments. | |
3902 * | |
3903 * See [CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE], | |
3904 * [CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE], | |
3905 * [StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE], and | |
3906 * [StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE]. | |
3907 */ | |
3908 bool _checkForMapTypeNotAssignable( | |
3909 MapLiteral literal, TypeArgumentList typeArguments) { | |
3910 // Prepare maps key/value types. | |
3911 NodeList<TypeName> typeNames = typeArguments.arguments; | |
3912 if (typeNames.length < 2) { | |
3913 return false; | |
3914 } | |
3915 DartType keyType = typeNames[0].type; | |
3916 DartType valueType = typeNames[1].type; | |
3917 // Check every map entry. | |
3918 bool hasProblems = false; | |
3919 NodeList<MapLiteralEntry> entries = literal.entries; | |
3920 for (MapLiteralEntry entry in entries) { | |
3921 Expression key = entry.key; | |
3922 Expression value = entry.value; | |
3923 if (literal.constKeyword != null) { | |
3924 // TODO(paulberry): this error should be based on the actual type of the | |
3925 // list element, not the static type. See dartbug.com/21119. | |
3926 if (_checkForArgumentTypeNotAssignableWithExpectedTypes(key, keyType, | |
3927 CheckedModeCompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE)) { | |
3928 hasProblems = true; | |
3929 } | |
3930 if (_checkForArgumentTypeNotAssignableWithExpectedTypes(value, | |
3931 valueType, | |
3932 CheckedModeCompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE)) { | |
3933 hasProblems = true; | |
3934 } | |
3935 } | |
3936 if (_checkForArgumentTypeNotAssignableWithExpectedTypes( | |
3937 key, keyType, StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE)) { | |
3938 hasProblems = true; | |
3939 } | |
3940 if (_checkForArgumentTypeNotAssignableWithExpectedTypes( | |
3941 value, valueType, StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE)) { | |
3942 hasProblems = true; | |
3943 } | |
3944 } | |
3945 return hasProblems; | |
3946 } | |
3947 | |
3948 /** | |
3949 * Verify that the [_enclosingClass] does not define members with the same nam
e | |
3950 * as the enclosing class. | |
3951 * | |
3952 * See [CompileTimeErrorCode.MEMBER_WITH_CLASS_NAME]. | |
3953 */ | |
3954 bool _checkForMemberWithClassName() { | |
3955 if (_enclosingClass == null) { | |
3956 return false; | |
3957 } | |
3958 String className = _enclosingClass.name; | |
3959 if (className == null) { | |
3960 return false; | |
3961 } | |
3962 bool problemReported = false; | |
3963 // check accessors | |
3964 for (PropertyAccessorElement accessor in _enclosingClass.accessors) { | |
3965 if (className == accessor.name) { | |
3966 _errorReporter.reportErrorForOffset( | |
3967 CompileTimeErrorCode.MEMBER_WITH_CLASS_NAME, accessor.nameOffset, | |
3968 className.length); | |
3969 problemReported = true; | |
3970 } | |
3971 } | |
3972 // don't check methods, they would be constructors | |
3973 // done | |
3974 return problemReported; | |
3975 } | |
3976 | |
3977 /** | |
3978 * Check to make sure that all similarly typed accessors are of the same type | |
3979 * (including inherited accessors). | |
3980 * | |
3981 * See [StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES], and | |
3982 * [StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE]. | |
3983 */ | |
3984 bool _checkForMismatchedAccessorTypes( | |
3985 Declaration accessorDeclaration, String accessorTextName) { | |
3986 ExecutableElement accessorElement = | |
3987 accessorDeclaration.element as ExecutableElement; | |
3988 if (accessorElement is! PropertyAccessorElement) { | |
3989 return false; | |
3990 } | |
3991 PropertyAccessorElement propertyAccessorElement = | |
3992 accessorElement as PropertyAccessorElement; | |
3993 PropertyAccessorElement counterpartAccessor = null; | |
3994 ClassElement enclosingClassForCounterpart = null; | |
3995 if (propertyAccessorElement.isGetter) { | |
3996 counterpartAccessor = propertyAccessorElement.correspondingSetter; | |
3997 } else { | |
3998 counterpartAccessor = propertyAccessorElement.correspondingGetter; | |
3999 // If the setter and getter are in the same enclosing element, return, | |
4000 // this prevents having MISMATCHED_GETTER_AND_SETTER_TYPES reported twice. | |
4001 if (counterpartAccessor != null && | |
4002 identical(counterpartAccessor.enclosingElement, | |
4003 propertyAccessorElement.enclosingElement)) { | |
4004 return false; | |
4005 } | |
4006 } | |
4007 if (counterpartAccessor == null) { | |
4008 // If the accessor is declared in a class, check the superclasses. | |
4009 if (_enclosingClass != null) { | |
4010 // Figure out the correct identifier to lookup in the inheritance graph, | |
4011 // if 'x', then 'x=', or if 'x=', then 'x'. | |
4012 String lookupIdentifier = propertyAccessorElement.name; | |
4013 if (StringUtilities.endsWithChar(lookupIdentifier, 0x3D)) { | |
4014 lookupIdentifier = | |
4015 lookupIdentifier.substring(0, lookupIdentifier.length - 1); | |
4016 } else { | |
4017 lookupIdentifier += "="; | |
4018 } | |
4019 // lookup with the identifier. | |
4020 ExecutableElement elementFromInheritance = _inheritanceManager | |
4021 .lookupInheritance(_enclosingClass, lookupIdentifier); | |
4022 // Verify that we found something, and that it is an accessor | |
4023 if (elementFromInheritance != null && | |
4024 elementFromInheritance is PropertyAccessorElement) { | |
4025 enclosingClassForCounterpart = | |
4026 elementFromInheritance.enclosingElement as ClassElement; | |
4027 counterpartAccessor = elementFromInheritance; | |
4028 } | |
4029 } | |
4030 if (counterpartAccessor == null) { | |
4031 return false; | |
4032 } | |
4033 } | |
4034 // Default of null == no accessor or no type (dynamic) | |
4035 DartType getterType = null; | |
4036 DartType setterType = null; | |
4037 // Get an existing counterpart accessor if any. | |
4038 if (propertyAccessorElement.isGetter) { | |
4039 getterType = _getGetterType(propertyAccessorElement); | |
4040 setterType = _getSetterType(counterpartAccessor); | |
4041 } else if (propertyAccessorElement.isSetter) { | |
4042 setterType = _getSetterType(propertyAccessorElement); | |
4043 getterType = _getGetterType(counterpartAccessor); | |
4044 } | |
4045 // If either types are not assignable to each other, report an error | |
4046 // (if the getter is null, it is dynamic which is assignable to everything). | |
4047 if (setterType != null && | |
4048 getterType != null && | |
4049 !getterType.isAssignableTo(setterType)) { | |
4050 if (enclosingClassForCounterpart == null) { | |
4051 _errorReporter.reportTypeErrorForNode( | |
4052 StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES, | |
4053 accessorDeclaration, [accessorTextName, setterType, getterType]); | |
4054 return true; | |
4055 } else { | |
4056 _errorReporter.reportTypeErrorForNode( | |
4057 StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, | |
4058 accessorDeclaration, [ | |
4059 accessorTextName, | |
4060 setterType, | |
4061 getterType, | |
4062 enclosingClassForCounterpart.displayName | |
4063 ]); | |
4064 } | |
4065 } | |
4066 return false; | |
4067 } | |
4068 | |
4069 /** | |
4070 * Check to make sure that the given switch [statement] whose static type is | |
4071 * an enum type either have a default case or include all of the enum | |
4072 * constants. | |
4073 */ | |
4074 bool _checkForMissingEnumConstantInSwitch(SwitchStatement statement) { | |
4075 // TODO(brianwilkerson) This needs to be checked after constant values have | |
4076 // been computed. | |
4077 Expression expression = statement.expression; | |
4078 DartType expressionType = getStaticType(expression); | |
4079 if (expressionType == null) { | |
4080 return false; | |
4081 } | |
4082 Element expressionElement = expressionType.element; | |
4083 if (expressionElement is! ClassElement) { | |
4084 return false; | |
4085 } | |
4086 ClassElement classElement = expressionElement as ClassElement; | |
4087 if (!classElement.isEnum) { | |
4088 return false; | |
4089 } | |
4090 List<String> constantNames = new List<String>(); | |
4091 List<FieldElement> fields = classElement.fields; | |
4092 int fieldCount = fields.length; | |
4093 for (int i = 0; i < fieldCount; i++) { | |
4094 FieldElement field = fields[i]; | |
4095 if (field.isStatic && !field.isSynthetic) { | |
4096 constantNames.add(field.name); | |
4097 } | |
4098 } | |
4099 NodeList<SwitchMember> members = statement.members; | |
4100 int memberCount = members.length; | |
4101 for (int i = 0; i < memberCount; i++) { | |
4102 SwitchMember member = members[i]; | |
4103 if (member is SwitchDefault) { | |
4104 return false; | |
4105 } | |
4106 String constantName = _getConstantName((member as SwitchCase).expression); | |
4107 if (constantName != null) { | |
4108 constantNames.remove(constantName); | |
4109 } | |
4110 } | |
4111 int nameCount = constantNames.length; | |
4112 if (nameCount == 0) { | |
4113 return false; | |
4114 } | |
4115 for (int i = 0; i < nameCount; i++) { | |
4116 _errorReporter.reportErrorForNode( | |
4117 CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH, statement, | |
4118 [constantNames[i]]); | |
4119 } | |
4120 return true; | |
4121 } | |
4122 | |
4123 /** | |
4124 * Verify that the given function [body] does not contain return statements | |
4125 * that both have and do not have return values. | |
4126 * | |
4127 * See [StaticWarningCode.MIXED_RETURN_TYPES]. | |
4128 */ | |
4129 bool _checkForMixedReturns(BlockFunctionBody body) { | |
4130 if (_hasReturnWithoutValue) { | |
4131 return false; | |
4132 } | |
4133 int withCount = _returnsWith.length; | |
4134 int withoutCount = _returnsWithout.length; | |
4135 if (withCount > 0 && withoutCount > 0) { | |
4136 for (int i = 0; i < withCount; i++) { | |
4137 _errorReporter.reportErrorForToken(StaticWarningCode.MIXED_RETURN_TYPES, | |
4138 _returnsWith[i].returnKeyword); | |
4139 } | |
4140 for (int i = 0; i < withoutCount; i++) { | |
4141 _errorReporter.reportErrorForToken(StaticWarningCode.MIXED_RETURN_TYPES, | |
4142 _returnsWithout[i].returnKeyword); | |
4143 } | |
4144 return true; | |
4145 } | |
4146 return false; | |
4147 } | |
4148 | |
4149 /** | |
4150 * Verify that the given mixin does not have an explicitly declared | |
4151 * constructor. The [mixinName] is the node to report problem on. The | |
4152 * [mixinElement] is the mixing to evaluate. | |
4153 * | |
4154 * See [CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR]. | |
4155 */ | |
4156 bool _checkForMixinDeclaresConstructor( | |
4157 TypeName mixinName, ClassElement mixinElement) { | |
4158 for (ConstructorElement constructor in mixinElement.constructors) { | |
4159 if (!constructor.isSynthetic && !constructor.isFactory) { | |
4160 _errorReporter.reportErrorForNode( | |
4161 CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR, mixinName, | |
4162 [mixinElement.name]); | |
4163 return true; | |
4164 } | |
4165 } | |
4166 return false; | |
4167 } | |
4168 | |
4169 /** | |
4170 * Report the error [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] if | |
4171 * appropriate. | |
4172 */ | |
4173 void _checkForMixinHasNoConstructors(AstNode node) { | |
4174 if ((_enclosingClass as ClassElementImpl).doesMixinLackConstructors) { | |
4175 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS; | |
4176 _errorReporter.reportErrorForNode( | |
4177 errorCode, node, [_enclosingClass.supertype]); | |
4178 } | |
4179 } | |
4180 | |
4181 /** | |
4182 * Verify that the given mixin has the 'Object' superclass. The [mixinName] is | |
4183 * the node to report problem on. The [mixinElement] is the mixing to | |
4184 * evaluate. | |
4185 * | |
4186 * See [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT]. | |
4187 */ | |
4188 bool _checkForMixinInheritsNotFromObject( | |
4189 TypeName mixinName, ClassElement mixinElement) { | |
4190 InterfaceType mixinSupertype = mixinElement.supertype; | |
4191 if (mixinSupertype != null) { | |
4192 if (!mixinSupertype.isObject || | |
4193 !mixinElement.isMixinApplication && mixinElement.mixins.length != 0) { | |
4194 _errorReporter.reportErrorForNode( | |
4195 CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, mixinName, | |
4196 [mixinElement.name]); | |
4197 return true; | |
4198 } | |
4199 } | |
4200 return false; | |
4201 } | |
4202 | |
4203 /** | |
4204 * Verify that the given mixin does not reference 'super'. The [mixinName] is | |
4205 * the node to report problem on. The [mixinElement] is the mixing to | |
4206 * evaluate. | |
4207 * | |
4208 * See [CompileTimeErrorCode.MIXIN_REFERENCES_SUPER]. | |
4209 */ | |
4210 bool _checkForMixinReferencesSuper( | |
4211 TypeName mixinName, ClassElement mixinElement) { | |
4212 if (mixinElement.hasReferenceToSuper) { | |
4213 _errorReporter.reportErrorForNode( | |
4214 CompileTimeErrorCode.MIXIN_REFERENCES_SUPER, mixinName, | |
4215 [mixinElement.name]); | |
4216 } | |
4217 return false; | |
4218 } | |
4219 | |
4220 /** | |
4221 * Verify that the given [constructor] has at most one 'super' initializer. | |
4222 * | |
4223 * See [CompileTimeErrorCode.MULTIPLE_SUPER_INITIALIZERS]. | |
4224 */ | |
4225 bool _checkForMultipleSuperInitializers(ConstructorDeclaration constructor) { | |
4226 int numSuperInitializers = 0; | |
4227 for (ConstructorInitializer initializer in constructor.initializers) { | |
4228 if (initializer is SuperConstructorInvocation) { | |
4229 numSuperInitializers++; | |
4230 if (numSuperInitializers > 1) { | |
4231 _errorReporter.reportErrorForNode( | |
4232 CompileTimeErrorCode.MULTIPLE_SUPER_INITIALIZERS, initializer); | |
4233 } | |
4234 } | |
4235 } | |
4236 return numSuperInitializers > 0; | |
4237 } | |
4238 | |
4239 /** | |
4240 * Checks to ensure that the given native function [body] is in SDK code. | |
4241 * | |
4242 * See [ParserErrorCode.NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE]. | |
4243 */ | |
4244 bool _checkForNativeFunctionBodyInNonSDKCode(NativeFunctionBody body) { | |
4245 if (!_isInSystemLibrary && !_hasExtUri) { | |
4246 _errorReporter.reportErrorForNode( | |
4247 ParserErrorCode.NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE, body); | |
4248 return true; | |
4249 } | |
4250 return false; | |
4251 } | |
4252 | |
4253 /** | |
4254 * Verify that the given instance creation [expression] invokes an existing | |
4255 * constructor. The [constructorName] is the constructor name. The [typeName] | |
4256 * is the name of the type defining the constructor. | |
4257 * | |
4258 * This method assumes that the instance creation was tested to be 'new' | |
4259 * before being called. | |
4260 * | |
4261 * See [StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR]. | |
4262 */ | |
4263 bool _checkForNewWithUndefinedConstructor( | |
4264 InstanceCreationExpression expression, ConstructorName constructorName, | |
4265 TypeName typeName) { | |
4266 // OK if resolved | |
4267 if (expression.staticElement != null) { | |
4268 return false; | |
4269 } | |
4270 DartType type = typeName.type; | |
4271 if (type is InterfaceType) { | |
4272 ClassElement element = type.element; | |
4273 if (element != null && element.isEnum) { | |
4274 // We have already reported the error. | |
4275 return false; | |
4276 } | |
4277 } | |
4278 // prepare class name | |
4279 Identifier className = typeName.name; | |
4280 // report as named or default constructor absence | |
4281 SimpleIdentifier name = constructorName.name; | |
4282 if (name != null) { | |
4283 _errorReporter.reportErrorForNode( | |
4284 StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR, name, [ | |
4285 className, | |
4286 name | |
4287 ]); | |
4288 } else { | |
4289 _errorReporter.reportErrorForNode( | |
4290 StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT, | |
4291 constructorName, [className]); | |
4292 } | |
4293 return true; | |
4294 } | |
4295 | |
4296 /** | |
4297 * Check that if the given class [declaration] implicitly calls default | |
4298 * constructor of its superclass, there should be such default constructor - | |
4299 * implicit or explicit. | |
4300 * | |
4301 * See [CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT]. | |
4302 */ | |
4303 bool _checkForNoDefaultSuperConstructorImplicit( | |
4304 ClassDeclaration declaration) { | |
4305 // do nothing if mixin errors have already been reported for this class. | |
4306 ClassElementImpl enclosingClass = _enclosingClass; | |
4307 if (enclosingClass.doesMixinLackConstructors) { | |
4308 return false; | |
4309 } | |
4310 // do nothing if there is explicit constructor | |
4311 List<ConstructorElement> constructors = _enclosingClass.constructors; | |
4312 if (!constructors[0].isSynthetic) { | |
4313 return false; | |
4314 } | |
4315 // prepare super | |
4316 InterfaceType superType = _enclosingClass.supertype; | |
4317 if (superType == null) { | |
4318 return false; | |
4319 } | |
4320 ClassElement superElement = superType.element; | |
4321 // try to find default generative super constructor | |
4322 ConstructorElement superUnnamedConstructor = | |
4323 superElement.unnamedConstructor; | |
4324 if (superUnnamedConstructor != null) { | |
4325 if (superUnnamedConstructor.isFactory) { | |
4326 _errorReporter.reportErrorForNode( | |
4327 CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, declaration.name, | |
4328 [superUnnamedConstructor]); | |
4329 return true; | |
4330 } | |
4331 if (superUnnamedConstructor.isDefaultConstructor && | |
4332 _enclosingClass | |
4333 .isSuperConstructorAccessible(superUnnamedConstructor)) { | |
4334 return true; | |
4335 } | |
4336 } | |
4337 // report problem | |
4338 _errorReporter.reportErrorForNode( | |
4339 CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT, | |
4340 declaration.name, [superType.displayName]); | |
4341 return true; | |
4342 } | |
4343 | |
4344 /** | |
4345 * Check that the given class declaration overrides all members required by | |
4346 * its superclasses and interfaces. The [classNameNode] is the | |
4347 * [SimpleIdentifier] to be used if there is a violation, this is either the | |
4348 * named from the [ClassDeclaration] or from the [ClassTypeAlias]. | |
4349 * | |
4350 * See [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE], | |
4351 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO], | |
4352 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE], | |
4353 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR], and | |
4354 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS]. | |
4355 */ | |
4356 bool _checkForNonAbstractClassInheritsAbstractMember( | |
4357 SimpleIdentifier classNameNode) { | |
4358 if (_enclosingClass.isAbstract) { | |
4359 return false; | |
4360 } | |
4361 // | |
4362 // Store in local sets the set of all method and accessor names | |
4363 // | |
4364 MethodElement method = | |
4365 _enclosingClass.getMethod(FunctionElement.NO_SUCH_METHOD_METHOD_NAME); | |
4366 if (method != null) { | |
4367 // If the enclosing class declares the method noSuchMethod(), then return. | |
4368 // From Spec: It is a static warning if a concrete class does not have an | |
4369 // implementation for a method in any of its superinterfaces unless it | |
4370 // declares its own noSuchMethod method (7.10). | |
4371 return false; | |
4372 } | |
4373 HashSet<ExecutableElement> missingOverrides = | |
4374 new HashSet<ExecutableElement>(); | |
4375 // | |
4376 // Loop through the set of all executable elements declared in the implicit | |
4377 // interface. | |
4378 // | |
4379 MemberMap membersInheritedFromInterfaces = _inheritanceManager | |
4380 .getMapOfMembersInheritedFromInterfaces(_enclosingClass); | |
4381 MemberMap membersInheritedFromSuperclasses = _inheritanceManager | |
4382 .getMapOfMembersInheritedFromClasses(_enclosingClass); | |
4383 for (int i = 0; i < membersInheritedFromInterfaces.size; i++) { | |
4384 String memberName = membersInheritedFromInterfaces.getKey(i); | |
4385 ExecutableElement executableElt = | |
4386 membersInheritedFromInterfaces.getValue(i); | |
4387 if (memberName == null) { | |
4388 break; | |
4389 } | |
4390 // If the element is not synthetic and can be determined to be defined in | |
4391 // Object, skip it. | |
4392 if (executableElt.enclosingElement != null && | |
4393 (executableElt.enclosingElement as ClassElement).type.isObject) { | |
4394 continue; | |
4395 } | |
4396 // Check to see if some element is in local enclosing class that matches | |
4397 // the name of the required member. | |
4398 if (_isMemberInClassOrMixin(executableElt, _enclosingClass)) { | |
4399 // We do not have to verify that this implementation of the found method | |
4400 // matches the required function type: the set of | |
4401 // StaticWarningCode.INVALID_METHOD_OVERRIDE_* warnings break out the | |
4402 // different specific situations. | |
4403 continue; | |
4404 } | |
4405 // First check to see if this element was declared in the superclass | |
4406 // chain, in which case there is already a concrete implementation. | |
4407 ExecutableElement elt = membersInheritedFromSuperclasses.get(memberName); | |
4408 // Check to see if an element was found in the superclass chain with the | |
4409 // correct name. | |
4410 if (elt != null) { | |
4411 // Reference the types, if any are null then continue. | |
4412 InterfaceType enclosingType = _enclosingClass.type; | |
4413 FunctionType concreteType = elt.type; | |
4414 FunctionType requiredMemberType = executableElt.type; | |
4415 if (enclosingType == null || | |
4416 concreteType == null || | |
4417 requiredMemberType == null) { | |
4418 continue; | |
4419 } | |
4420 // Some element was found in the superclass chain that matches the name | |
4421 // of the required member. | |
4422 // If it is not abstract and it is the correct one (types match- the | |
4423 // version of this method that we have has the correct number of | |
4424 // parameters, etc), then this class has a valid implementation of this | |
4425 // method, so skip it. | |
4426 if ((elt is MethodElement && !elt.isAbstract) || | |
4427 (elt is PropertyAccessorElement && !elt.isAbstract)) { | |
4428 // Since we are comparing two function types, we need to do the | |
4429 // appropriate type substitutions first (). | |
4430 FunctionType foundConcreteFT = _inheritanceManager | |
4431 .substituteTypeArgumentsInMemberFromInheritance( | |
4432 concreteType, memberName, enclosingType); | |
4433 FunctionType requiredMemberFT = _inheritanceManager | |
4434 .substituteTypeArgumentsInMemberFromInheritance( | |
4435 requiredMemberType, memberName, enclosingType); | |
4436 if (foundConcreteFT.isSubtypeOf(requiredMemberFT)) { | |
4437 continue; | |
4438 } | |
4439 } | |
4440 } | |
4441 // The not qualifying concrete executable element was found, add it to the | |
4442 // list. | |
4443 missingOverrides.add(executableElt); | |
4444 } | |
4445 // Now that we have the set of missing overrides, generate a warning on this | |
4446 // class. | |
4447 int missingOverridesSize = missingOverrides.length; | |
4448 if (missingOverridesSize == 0) { | |
4449 return false; | |
4450 } | |
4451 List<ExecutableElement> missingOverridesArray = | |
4452 new List.from(missingOverrides); | |
4453 List<String> stringMembersArrayListSet = new List<String>(); | |
4454 for (int i = 0; i < missingOverridesArray.length; i++) { | |
4455 String newStrMember; | |
4456 Element enclosingElement = missingOverridesArray[i].enclosingElement; | |
4457 String prefix = StringUtilities.EMPTY; | |
4458 if (missingOverridesArray[i] is PropertyAccessorElement) { | |
4459 PropertyAccessorElement propertyAccessorElement = | |
4460 missingOverridesArray[i] as PropertyAccessorElement; | |
4461 if (propertyAccessorElement.isGetter) { | |
4462 prefix = _GETTER_SPACE; | |
4463 // "getter " | |
4464 } else { | |
4465 prefix = _SETTER_SPACE; | |
4466 // "setter " | |
4467 } | |
4468 } | |
4469 if (enclosingElement != null) { | |
4470 newStrMember = | |
4471 "$prefix'${enclosingElement.displayName}.${missingOverridesArray[i].
displayName}'"; | |
4472 } else { | |
4473 newStrMember = "$prefix'${missingOverridesArray[i].displayName}'"; | |
4474 } | |
4475 stringMembersArrayListSet.add(newStrMember); | |
4476 } | |
4477 List<String> stringMembersArray = new List.from(stringMembersArrayListSet); | |
4478 AnalysisErrorWithProperties analysisError; | |
4479 if (stringMembersArray.length == 1) { | |
4480 analysisError = _errorReporter.newErrorWithProperties( | |
4481 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE, | |
4482 classNameNode, [stringMembersArray[0]]); | |
4483 } else if (stringMembersArray.length == 2) { | |
4484 analysisError = _errorReporter.newErrorWithProperties( | |
4485 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO, | |
4486 classNameNode, [stringMembersArray[0], stringMembersArray[1]]); | |
4487 } else if (stringMembersArray.length == 3) { | |
4488 analysisError = _errorReporter.newErrorWithProperties( | |
4489 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE, | |
4490 classNameNode, [ | |
4491 stringMembersArray[0], | |
4492 stringMembersArray[1], | |
4493 stringMembersArray[2] | |
4494 ]); | |
4495 } else if (stringMembersArray.length == 4) { | |
4496 analysisError = _errorReporter.newErrorWithProperties( | |
4497 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR, | |
4498 classNameNode, [ | |
4499 stringMembersArray[0], | |
4500 stringMembersArray[1], | |
4501 stringMembersArray[2], | |
4502 stringMembersArray[3] | |
4503 ]); | |
4504 } else { | |
4505 analysisError = _errorReporter.newErrorWithProperties( | |
4506 StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLU
S, | |
4507 classNameNode, [ | |
4508 stringMembersArray[0], | |
4509 stringMembersArray[1], | |
4510 stringMembersArray[2], | |
4511 stringMembersArray[3], | |
4512 stringMembersArray.length - 4 | |
4513 ]); | |
4514 } | |
4515 analysisError.setProperty( | |
4516 ErrorProperty.UNIMPLEMENTED_METHODS, missingOverridesArray); | |
4517 _errorReporter.reportError(analysisError); | |
4518 return true; | |
4519 } | |
4520 | |
4521 /** | |
4522 * Check to ensure that the [condition] is of type bool, are. Otherwise an | |
4523 * error is reported on the expression. | |
4524 * | |
4525 * See [StaticTypeWarningCode.NON_BOOL_CONDITION]. | |
4526 */ | |
4527 bool _checkForNonBoolCondition(Expression condition) { | |
4528 DartType conditionType = getStaticType(condition); | |
4529 if (conditionType != null && !conditionType.isAssignableTo(_boolType)) { | |
4530 _errorReporter.reportErrorForNode( | |
4531 StaticTypeWarningCode.NON_BOOL_CONDITION, condition); | |
4532 return true; | |
4533 } | |
4534 return false; | |
4535 } | |
4536 | |
4537 /** | |
4538 * Verify that the given assert [statement] has either a 'bool' or | |
4539 * '() -> bool' input. | |
4540 * | |
4541 * See [StaticTypeWarningCode.NON_BOOL_EXPRESSION]. | |
4542 */ | |
4543 bool _checkForNonBoolExpression(AssertStatement statement) { | |
4544 Expression expression = statement.condition; | |
4545 DartType type = getStaticType(expression); | |
4546 if (type is InterfaceType) { | |
4547 if (!type.isAssignableTo(_boolType)) { | |
4548 _errorReporter.reportErrorForNode( | |
4549 StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression); | |
4550 return true; | |
4551 } | |
4552 } else if (type is FunctionType) { | |
4553 FunctionType functionType = type; | |
4554 if (functionType.typeArguments.length == 0 && | |
4555 !functionType.returnType.isAssignableTo(_boolType)) { | |
4556 _errorReporter.reportErrorForNode( | |
4557 StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression); | |
4558 return true; | |
4559 } | |
4560 } | |
4561 return false; | |
4562 } | |
4563 | |
4564 /** | |
4565 * Checks to ensure that the given [expression] is assignable to bool. | |
4566 * | |
4567 * See [StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION]. | |
4568 */ | |
4569 bool _checkForNonBoolNegationExpression(Expression expression) { | |
4570 DartType conditionType = getStaticType(expression); | |
4571 if (conditionType != null && !conditionType.isAssignableTo(_boolType)) { | |
4572 _errorReporter.reportErrorForNode( | |
4573 StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION, expression); | |
4574 return true; | |
4575 } | |
4576 return false; | |
4577 } | |
4578 | |
4579 /** | |
4580 * Verify the given map [literal] either: | |
4581 * * has `const modifier` | |
4582 * * has explicit type arguments | |
4583 * * is not start of the statement | |
4584 * | |
4585 * See [CompileTimeErrorCode.NON_CONST_MAP_AS_EXPRESSION_STATEMENT]. | |
4586 */ | |
4587 bool _checkForNonConstMapAsExpressionStatement(MapLiteral literal) { | |
4588 // "const" | |
4589 if (literal.constKeyword != null) { | |
4590 return false; | |
4591 } | |
4592 // has type arguments | |
4593 if (literal.typeArguments != null) { | |
4594 return false; | |
4595 } | |
4596 // prepare statement | |
4597 Statement statement = | |
4598 literal.getAncestor((node) => node is ExpressionStatement); | |
4599 if (statement == null) { | |
4600 return false; | |
4601 } | |
4602 // OK, statement does not start with map | |
4603 if (!identical(statement.beginToken, literal.beginToken)) { | |
4604 return false; | |
4605 } | |
4606 // report problem | |
4607 _errorReporter.reportErrorForNode( | |
4608 CompileTimeErrorCode.NON_CONST_MAP_AS_EXPRESSION_STATEMENT, literal); | |
4609 return true; | |
4610 } | |
4611 | |
4612 /** | |
4613 * Verify that the given method [declaration] of operator `[]=`, has `void` | |
4614 * return type. | |
4615 * | |
4616 * See [StaticWarningCode.NON_VOID_RETURN_FOR_OPERATOR]. | |
4617 */ | |
4618 bool _checkForNonVoidReturnTypeForOperator(MethodDeclaration declaration) { | |
4619 // check that []= operator | |
4620 SimpleIdentifier name = declaration.name; | |
4621 if (name.name != "[]=") { | |
4622 return false; | |
4623 } | |
4624 // check return type | |
4625 TypeName typeName = declaration.returnType; | |
4626 if (typeName != null) { | |
4627 DartType type = typeName.type; | |
4628 if (type != null && !type.isVoid) { | |
4629 _errorReporter.reportErrorForNode( | |
4630 StaticWarningCode.NON_VOID_RETURN_FOR_OPERATOR, typeName); | |
4631 } | |
4632 } | |
4633 // no warning | |
4634 return false; | |
4635 } | |
4636 | |
4637 /** | |
4638 * Verify the [typeName], used as the return type of a setter, is valid | |
4639 * (either `null` or the type 'void'). | |
4640 * | |
4641 * See [StaticWarningCode.NON_VOID_RETURN_FOR_SETTER]. | |
4642 */ | |
4643 bool _checkForNonVoidReturnTypeForSetter(TypeName typeName) { | |
4644 if (typeName != null) { | |
4645 DartType type = typeName.type; | |
4646 if (type != null && !type.isVoid) { | |
4647 _errorReporter.reportErrorForNode( | |
4648 StaticWarningCode.NON_VOID_RETURN_FOR_SETTER, typeName); | |
4649 } | |
4650 } | |
4651 return false; | |
4652 } | |
4653 | |
4654 /** | |
4655 * Verify the given operator-method [declaration], does not have an optional | |
4656 * parameter. This method assumes that the method declaration was tested to be | |
4657 * an operator declaration before being called. | |
4658 * | |
4659 * See [CompileTimeErrorCode.OPTIONAL_PARAMETER_IN_OPERATOR]. | |
4660 */ | |
4661 bool _checkForOptionalParameterInOperator(MethodDeclaration declaration) { | |
4662 FormalParameterList parameterList = declaration.parameters; | |
4663 if (parameterList == null) { | |
4664 return false; | |
4665 } | |
4666 bool foundError = false; | |
4667 NodeList<FormalParameter> formalParameters = parameterList.parameters; | |
4668 for (FormalParameter formalParameter in formalParameters) { | |
4669 if (formalParameter.kind.isOptional) { | |
4670 _errorReporter.reportErrorForNode( | |
4671 CompileTimeErrorCode.OPTIONAL_PARAMETER_IN_OPERATOR, | |
4672 formalParameter); | |
4673 foundError = true; | |
4674 } | |
4675 } | |
4676 return foundError; | |
4677 } | |
4678 | |
4679 /** | |
4680 * Check that the given named optional [parameter] does not begin with '_'. | |
4681 * | |
4682 * See [CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER]. | |
4683 */ | |
4684 bool _checkForPrivateOptionalParameter(FormalParameter parameter) { | |
4685 // should be named parameter | |
4686 if (parameter.kind != ParameterKind.NAMED) { | |
4687 return false; | |
4688 } | |
4689 // name should start with '_' | |
4690 SimpleIdentifier name = parameter.identifier; | |
4691 if (name.isSynthetic || !StringUtilities.startsWithChar(name.name, 0x5F)) { | |
4692 return false; | |
4693 } | |
4694 // report problem | |
4695 _errorReporter.reportErrorForNode( | |
4696 CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER, parameter); | |
4697 return true; | |
4698 } | |
4699 | |
4700 /** | |
4701 * Check whether the given constructor [declaration] is the redirecting | |
4702 * generative constructor and references itself directly or indirectly. The | |
4703 * [constructorElement] is the constructor element. | |
4704 * | |
4705 * See [CompileTimeErrorCode.RECURSIVE_CONSTRUCTOR_REDIRECT]. | |
4706 */ | |
4707 bool _checkForRecursiveConstructorRedirect(ConstructorDeclaration declaration, | |
4708 ConstructorElement constructorElement) { | |
4709 // we check generative constructor here | |
4710 if (declaration.factoryKeyword != null) { | |
4711 return false; | |
4712 } | |
4713 // try to find redirecting constructor invocation and analyzer it for | |
4714 // recursion | |
4715 for (ConstructorInitializer initializer in declaration.initializers) { | |
4716 if (initializer is RedirectingConstructorInvocation) { | |
4717 // OK if no cycle | |
4718 if (!_hasRedirectingFactoryConstructorCycle(constructorElement)) { | |
4719 return false; | |
4720 } | |
4721 // report error | |
4722 _errorReporter.reportErrorForNode( | |
4723 CompileTimeErrorCode.RECURSIVE_CONSTRUCTOR_REDIRECT, initializer); | |
4724 return true; | |
4725 } | |
4726 } | |
4727 // OK, no redirecting constructor invocation | |
4728 return false; | |
4729 } | |
4730 | |
4731 /** | |
4732 * Check whether the given constructor [declaration] has redirected | |
4733 * constructor and references itself directly or indirectly. The | |
4734 * constructor [element] is the element introduced by the declaration. | |
4735 * | |
4736 * See [CompileTimeErrorCode.RECURSIVE_FACTORY_REDIRECT]. | |
4737 */ | |
4738 bool _checkForRecursiveFactoryRedirect( | |
4739 ConstructorDeclaration declaration, ConstructorElement element) { | |
4740 // prepare redirected constructor | |
4741 ConstructorName redirectedConstructorNode = | |
4742 declaration.redirectedConstructor; | |
4743 if (redirectedConstructorNode == null) { | |
4744 return false; | |
4745 } | |
4746 // OK if no cycle | |
4747 if (!_hasRedirectingFactoryConstructorCycle(element)) { | |
4748 return false; | |
4749 } | |
4750 // report error | |
4751 _errorReporter.reportErrorForNode( | |
4752 CompileTimeErrorCode.RECURSIVE_FACTORY_REDIRECT, | |
4753 redirectedConstructorNode); | |
4754 return true; | |
4755 } | |
4756 | |
4757 /** | |
4758 * Check that the class [element] is not a superinterface to itself. | |
4759 * | |
4760 * See [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE], | |
4761 * [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS], a
nd | |
4762 * [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS]
. | |
4763 */ | |
4764 bool _checkForRecursiveInterfaceInheritance(ClassElement element) { | |
4765 if (element == null) { | |
4766 return false; | |
4767 } | |
4768 return _safeCheckForRecursiveInterfaceInheritance( | |
4769 element, new List<ClassElement>()); | |
4770 } | |
4771 | |
4772 /** | |
4773 * Check that the given constructor [declaration] has a valid combination of | |
4774 * redirected constructor invocation(s), super constructor invocations and | |
4775 * field initializers. | |
4776 * | |
4777 * See [CompileTimeErrorCode.DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR]
, | |
4778 * [CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR], | |
4779 * [CompileTimeErrorCode.MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS], | |
4780 * [CompileTimeErrorCode.SUPER_IN_REDIRECTING_CONSTRUCTOR], and | |
4781 * [CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_NON_GENERATIVE_CONSTRUCTOR]. | |
4782 */ | |
4783 bool _checkForRedirectingConstructorErrorCodes( | |
4784 ConstructorDeclaration declaration) { | |
4785 bool errorReported = false; | |
4786 // | |
4787 // Check for default values in the parameters | |
4788 // | |
4789 ConstructorName redirectedConstructor = declaration.redirectedConstructor; | |
4790 if (redirectedConstructor != null) { | |
4791 for (FormalParameter parameter in declaration.parameters.parameters) { | |
4792 if (parameter is DefaultFormalParameter && | |
4793 parameter.defaultValue != null) { | |
4794 _errorReporter.reportErrorForNode( | |
4795 CompileTimeErrorCode.DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUC
TOR, | |
4796 parameter.identifier); | |
4797 errorReported = true; | |
4798 } | |
4799 } | |
4800 } | |
4801 // check if there are redirected invocations | |
4802 int numRedirections = 0; | |
4803 for (ConstructorInitializer initializer in declaration.initializers) { | |
4804 if (initializer is RedirectingConstructorInvocation) { | |
4805 if (numRedirections > 0) { | |
4806 _errorReporter.reportErrorForNode( | |
4807 CompileTimeErrorCode.MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS, | |
4808 initializer); | |
4809 errorReported = true; | |
4810 } | |
4811 if (declaration.factoryKeyword == null) { | |
4812 RedirectingConstructorInvocation invocation = initializer; | |
4813 ConstructorElement redirectingElement = invocation.staticElement; | |
4814 if (redirectingElement == null) { | |
4815 String enclosingTypeName = _enclosingClass.displayName; | |
4816 String constructorStrName = enclosingTypeName; | |
4817 if (invocation.constructorName != null) { | |
4818 constructorStrName += ".${invocation.constructorName.name}"; | |
4819 } | |
4820 _errorReporter.reportErrorForNode( | |
4821 CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR, | |
4822 invocation, [constructorStrName, enclosingTypeName]); | |
4823 } else { | |
4824 if (redirectingElement.isFactory) { | |
4825 _errorReporter.reportErrorForNode( | |
4826 CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_NON_GENERATIVE_CON
STRUCTOR, | |
4827 initializer); | |
4828 } | |
4829 } | |
4830 } | |
4831 numRedirections++; | |
4832 } | |
4833 } | |
4834 // check for other initializers | |
4835 if (numRedirections > 0) { | |
4836 for (ConstructorInitializer initializer in declaration.initializers) { | |
4837 if (initializer is SuperConstructorInvocation) { | |
4838 _errorReporter.reportErrorForNode( | |
4839 CompileTimeErrorCode.SUPER_IN_REDIRECTING_CONSTRUCTOR, | |
4840 initializer); | |
4841 errorReported = true; | |
4842 } | |
4843 if (initializer is ConstructorFieldInitializer) { | |
4844 _errorReporter.reportErrorForNode( | |
4845 CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR, | |
4846 initializer); | |
4847 errorReported = true; | |
4848 } | |
4849 } | |
4850 } | |
4851 // done | |
4852 return errorReported; | |
4853 } | |
4854 | |
4855 /** | |
4856 * Check whether the given constructor [declaration] has redirected | |
4857 * constructor and references itself directly or indirectly. The | |
4858 * constructor [element] is the element introduced by the declaration. | |
4859 * | |
4860 * See [CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR]. | |
4861 */ | |
4862 bool _checkForRedirectToNonConstConstructor( | |
4863 ConstructorDeclaration declaration, ConstructorElement element) { | |
4864 // prepare redirected constructor | |
4865 ConstructorName redirectedConstructorNode = | |
4866 declaration.redirectedConstructor; | |
4867 if (redirectedConstructorNode == null) { | |
4868 return false; | |
4869 } | |
4870 // prepare element | |
4871 if (element == null) { | |
4872 return false; | |
4873 } | |
4874 // OK, it is not 'const' | |
4875 if (!element.isConst) { | |
4876 return false; | |
4877 } | |
4878 // prepare redirected constructor | |
4879 ConstructorElement redirectedConstructor = element.redirectedConstructor; | |
4880 if (redirectedConstructor == null) { | |
4881 return false; | |
4882 } | |
4883 // OK, it is also 'const' | |
4884 if (redirectedConstructor.isConst) { | |
4885 return false; | |
4886 } | |
4887 // report error | |
4888 _errorReporter.reportErrorForNode( | |
4889 CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONSTRUCTOR, | |
4890 redirectedConstructorNode); | |
4891 return true; | |
4892 } | |
4893 | |
4894 /** | |
4895 * Check that the given rethrow [expression] is inside of a catch clause. | |
4896 * | |
4897 * See [CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH]. | |
4898 */ | |
4899 bool _checkForRethrowOutsideCatch(RethrowExpression expression) { | |
4900 if (!_isInCatchClause) { | |
4901 _errorReporter.reportErrorForNode( | |
4902 CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, expression); | |
4903 return true; | |
4904 } | |
4905 return false; | |
4906 } | |
4907 | |
4908 /** | |
4909 * Check that if the the given constructor [declaration] is generative, then | |
4910 * it does not have an expression function body. | |
4911 * | |
4912 * See [CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR]. | |
4913 */ | |
4914 bool _checkForReturnInGenerativeConstructor( | |
4915 ConstructorDeclaration declaration) { | |
4916 // ignore factory | |
4917 if (declaration.factoryKeyword != null) { | |
4918 return false; | |
4919 } | |
4920 // block body (with possible return statement) is checked elsewhere | |
4921 FunctionBody body = declaration.body; | |
4922 if (body is! ExpressionFunctionBody) { | |
4923 return false; | |
4924 } | |
4925 // report error | |
4926 _errorReporter.reportErrorForNode( | |
4927 CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR, body); | |
4928 return true; | |
4929 } | |
4930 | |
4931 /** | |
4932 * Check that a type mis-match between the type of the [returnExpression] and | |
4933 * the [expectedReturnType] by the enclosing method or function. | |
4934 * | |
4935 * This method is called both by [_checkForAllReturnStatementErrorCodes] | |
4936 * and [visitExpressionFunctionBody]. | |
4937 * | |
4938 * See [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]. | |
4939 */ | |
4940 bool _checkForReturnOfInvalidType( | |
4941 Expression returnExpression, DartType expectedReturnType) { | |
4942 if (_enclosingFunction == null) { | |
4943 return false; | |
4944 } | |
4945 if (_inGenerator) { | |
4946 // "return expression;" is disallowed in generators, but this is checked | |
4947 // elsewhere. Bare "return" is always allowed in generators regardless | |
4948 // of the return type. So no need to do any further checking. | |
4949 return false; | |
4950 } | |
4951 DartType staticReturnType = _computeReturnTypeForMethod(returnExpression); | |
4952 if (expectedReturnType.isVoid) { | |
4953 if (staticReturnType.isVoid || | |
4954 staticReturnType.isDynamic || | |
4955 staticReturnType.isBottom) { | |
4956 return false; | |
4957 } | |
4958 _errorReporter.reportTypeErrorForNode( | |
4959 StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [ | |
4960 staticReturnType, | |
4961 expectedReturnType, | |
4962 _enclosingFunction.displayName | |
4963 ]); | |
4964 return true; | |
4965 } | |
4966 if (staticReturnType.isAssignableTo(expectedReturnType)) { | |
4967 return false; | |
4968 } | |
4969 _errorReporter.reportTypeErrorForNode( | |
4970 StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [ | |
4971 staticReturnType, | |
4972 expectedReturnType, | |
4973 _enclosingFunction.displayName | |
4974 ]); | |
4975 return true; | |
4976 // TODO(brianwilkerson) Define a hint corresponding to the warning and | |
4977 // report it if appropriate. | |
4978 // Type propagatedReturnType = returnExpression.getPropagatedType(); | |
4979 // boolean isPropagatedAssignable = propagatedReturnType.isAssignableTo(e
xpectedReturnType); | |
4980 // if (isStaticAssignable || isPropagatedAssignable) { | |
4981 // return false; | |
4982 // } | |
4983 // errorReporter.reportTypeErrorForNode( | |
4984 // StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, | |
4985 // returnExpression, | |
4986 // staticReturnType, | |
4987 // expectedReturnType, | |
4988 // enclosingFunction.getDisplayName()); | |
4989 // return true; | |
4990 } | |
4991 | |
4992 /** | |
4993 * Check the given [typeReference] and that the [name] is not the reference to | |
4994 * an instance member. | |
4995 * | |
4996 * See [StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER]. | |
4997 */ | |
4998 bool _checkForStaticAccessToInstanceMember( | |
4999 ClassElement typeReference, SimpleIdentifier name) { | |
5000 // OK, target is not a type | |
5001 if (typeReference == null) { | |
5002 return false; | |
5003 } | |
5004 // prepare member Element | |
5005 Element element = name.staticElement; | |
5006 if (element is! ExecutableElement) { | |
5007 return false; | |
5008 } | |
5009 ExecutableElement memberElement = element as ExecutableElement; | |
5010 // OK, static | |
5011 if (memberElement.isStatic) { | |
5012 return false; | |
5013 } | |
5014 // report problem | |
5015 _errorReporter.reportErrorForNode( | |
5016 StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMBER, name, [name.name]); | |
5017 return true; | |
5018 } | |
5019 | |
5020 /** | |
5021 * Check that the type of the expression in the given 'switch' [statement] is | |
5022 * assignable to the type of the 'case' members. | |
5023 * | |
5024 * See [StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE]. | |
5025 */ | |
5026 bool _checkForSwitchExpressionNotAssignable(SwitchStatement statement) { | |
5027 // prepare 'switch' expression type | |
5028 Expression expression = statement.expression; | |
5029 DartType expressionType = getStaticType(expression); | |
5030 if (expressionType == null) { | |
5031 return false; | |
5032 } | |
5033 // compare with type of the first 'case' | |
5034 NodeList<SwitchMember> members = statement.members; | |
5035 for (SwitchMember switchMember in members) { | |
5036 if (switchMember is! SwitchCase) { | |
5037 continue; | |
5038 } | |
5039 SwitchCase switchCase = switchMember as SwitchCase; | |
5040 // prepare 'case' type | |
5041 Expression caseExpression = switchCase.expression; | |
5042 DartType caseType = getStaticType(caseExpression); | |
5043 // check types | |
5044 if (expressionType.isAssignableTo(caseType)) { | |
5045 return false; | |
5046 } | |
5047 // report problem | |
5048 _errorReporter.reportErrorForNode( | |
5049 StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE, expression, [ | |
5050 expressionType, | |
5051 caseType | |
5052 ]); | |
5053 return true; | |
5054 } | |
5055 return false; | |
5056 } | |
5057 | |
5058 /** | |
5059 * Verify that the given function type [alias] does not reference itself | |
5060 * directly. | |
5061 * | |
5062 * See [CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF]. | |
5063 */ | |
5064 bool _checkForTypeAliasCannotReferenceItself_function( | |
5065 FunctionTypeAlias alias) { | |
5066 FunctionTypeAliasElement element = alias.element; | |
5067 if (!_hasTypedefSelfReference(element)) { | |
5068 return false; | |
5069 } | |
5070 _errorReporter.reportErrorForNode( | |
5071 CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, alias); | |
5072 return true; | |
5073 } | |
5074 | |
5075 /** | |
5076 * Verify that the given type [name] is not a deferred type. | |
5077 * | |
5078 * See [StaticWarningCode.TYPE_ANNOTATION_DEFERRED_CLASS]. | |
5079 */ | |
5080 bool _checkForTypeAnnotationDeferredClass(TypeName name) { | |
5081 if (name != null && name.isDeferred) { | |
5082 _errorReporter.reportErrorForNode( | |
5083 StaticWarningCode.TYPE_ANNOTATION_DEFERRED_CLASS, name, [name.name]); | |
5084 } | |
5085 return false; | |
5086 } | |
5087 | |
5088 /** | |
5089 * Verify that the type arguments in the given [typeName] are all within | |
5090 * their bounds. | |
5091 * | |
5092 * See [StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS]. | |
5093 */ | |
5094 bool _checkForTypeArgumentNotMatchingBounds(TypeName typeName) { | |
5095 if (typeName.typeArguments == null) { | |
5096 return false; | |
5097 } | |
5098 // prepare Type | |
5099 DartType type = typeName.type; | |
5100 if (type == null) { | |
5101 return false; | |
5102 } | |
5103 // prepare ClassElement | |
5104 Element element = type.element; | |
5105 if (element is! ClassElement) { | |
5106 return false; | |
5107 } | |
5108 ClassElement classElement = element as ClassElement; | |
5109 // prepare type parameters | |
5110 List<DartType> typeParameters = classElement.type.typeArguments; | |
5111 List<TypeParameterElement> boundingElts = classElement.typeParameters; | |
5112 // iterate over each bounded type parameter and corresponding argument | |
5113 NodeList<TypeName> typeNameArgList = typeName.typeArguments.arguments; | |
5114 List<DartType> typeArguments = (type as InterfaceType).typeArguments; | |
5115 int loopThroughIndex = | |
5116 math.min(typeNameArgList.length, boundingElts.length); | |
5117 bool foundError = false; | |
5118 for (int i = 0; i < loopThroughIndex; i++) { | |
5119 TypeName argTypeName = typeNameArgList[i]; | |
5120 DartType argType = argTypeName.type; | |
5121 DartType boundType = boundingElts[i].bound; | |
5122 if (argType != null && boundType != null) { | |
5123 if (typeArguments.length != 0 && | |
5124 typeArguments.length == typeParameters.length) { | |
5125 boundType = boundType.substitute2(typeArguments, typeParameters); | |
5126 } | |
5127 if (!argType.isSubtypeOf(boundType)) { | |
5128 ErrorCode errorCode; | |
5129 if (_isInConstInstanceCreation) { | |
5130 errorCode = CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; | |
5131 } else { | |
5132 errorCode = StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; | |
5133 } | |
5134 _errorReporter.reportTypeErrorForNode( | |
5135 errorCode, argTypeName, [argType, boundType]); | |
5136 foundError = true; | |
5137 } | |
5138 } | |
5139 } | |
5140 return foundError; | |
5141 } | |
5142 | |
5143 /** | |
5144 * Check whether the given type [name] is a type parameter being used to | |
5145 * define a static member. | |
5146 * | |
5147 * See [StaticWarningCode.TYPE_PARAMETER_REFERENCED_BY_STATIC]. | |
5148 */ | |
5149 bool _checkForTypeParameterReferencedByStatic(TypeName name) { | |
5150 if (_isInStaticMethod || _isInStaticVariableDeclaration) { | |
5151 DartType type = name.type; | |
5152 if (type is TypeParameterType) { | |
5153 _errorReporter.reportErrorForNode( | |
5154 StaticWarningCode.TYPE_PARAMETER_REFERENCED_BY_STATIC, name); | |
5155 return true; | |
5156 } | |
5157 } | |
5158 return false; | |
5159 } | |
5160 | |
5161 /** | |
5162 * Check whether the given type [parameter] is a supertype of its bound. | |
5163 * | |
5164 * See [StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND]. | |
5165 */ | |
5166 bool _checkForTypeParameterSupertypeOfItsBound(TypeParameter parameter) { | |
5167 TypeParameterElement element = parameter.element; | |
5168 // prepare bound | |
5169 DartType bound = element.bound; | |
5170 if (bound == null) { | |
5171 return false; | |
5172 } | |
5173 // OK, type parameter is not supertype of its bound | |
5174 if (!bound.isMoreSpecificThan(element.type)) { | |
5175 return false; | |
5176 } | |
5177 // report problem | |
5178 _errorReporter.reportErrorForNode( | |
5179 StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND, parameter, | |
5180 [element.displayName]); | |
5181 return true; | |
5182 } | |
5183 | |
5184 /** | |
5185 * Check that if the given generative [constructor] has neither an explicit | |
5186 * super constructor invocation nor a redirecting constructor invocation, that | |
5187 * the superclass has a default generative constructor. | |
5188 * | |
5189 * See [CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT], | |
5190 * [CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR], and | |
5191 * [StaticWarningCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT]. | |
5192 */ | |
5193 bool _checkForUndefinedConstructorInInitializerImplicit( | |
5194 ConstructorDeclaration constructor) { | |
5195 if (_enclosingClass == null) { | |
5196 return false; | |
5197 } | |
5198 // do nothing if mixin errors have already been reported for this class. | |
5199 ClassElementImpl enclosingClass = _enclosingClass; | |
5200 if (enclosingClass.doesMixinLackConstructors) { | |
5201 return false; | |
5202 } | |
5203 // | |
5204 // Ignore if the constructor is not generative. | |
5205 // | |
5206 if (constructor.factoryKeyword != null) { | |
5207 return false; | |
5208 } | |
5209 // | |
5210 // Ignore if the constructor has either an implicit super constructor | |
5211 // invocation or a redirecting constructor invocation. | |
5212 // | |
5213 for (ConstructorInitializer constructorInitializer | |
5214 in constructor.initializers) { | |
5215 if (constructorInitializer is SuperConstructorInvocation || | |
5216 constructorInitializer is RedirectingConstructorInvocation) { | |
5217 return false; | |
5218 } | |
5219 } | |
5220 // | |
5221 // Check to see whether the superclass has a non-factory unnamed | |
5222 // constructor. | |
5223 // | |
5224 InterfaceType superType = _enclosingClass.supertype; | |
5225 if (superType == null) { | |
5226 return false; | |
5227 } | |
5228 ClassElement superElement = superType.element; | |
5229 ConstructorElement superUnnamedConstructor = | |
5230 superElement.unnamedConstructor; | |
5231 if (superUnnamedConstructor != null) { | |
5232 if (superUnnamedConstructor.isFactory) { | |
5233 _errorReporter.reportErrorForNode( | |
5234 CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, | |
5235 constructor.returnType, [superUnnamedConstructor]); | |
5236 return true; | |
5237 } | |
5238 if (!superUnnamedConstructor.isDefaultConstructor || | |
5239 !_enclosingClass | |
5240 .isSuperConstructorAccessible(superUnnamedConstructor)) { | |
5241 int offset; | |
5242 int length; | |
5243 { | |
5244 Identifier returnType = constructor.returnType; | |
5245 SimpleIdentifier name = constructor.name; | |
5246 offset = returnType.offset; | |
5247 length = (name != null ? name.end : returnType.end) - offset; | |
5248 } | |
5249 _errorReporter.reportErrorForOffset( | |
5250 CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT, offset, | |
5251 length, [superType.displayName]); | |
5252 } | |
5253 return false; | |
5254 } | |
5255 _errorReporter.reportErrorForNode( | |
5256 CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, | |
5257 constructor.returnType, [superElement.name]); | |
5258 return true; | |
5259 } | |
5260 | |
5261 /** | |
5262 * Check that if the given [name] is a reference to a static member it is | |
5263 * defined in the enclosing class rather than in a superclass. | |
5264 * | |
5265 * See [StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER
]. | |
5266 */ | |
5267 bool _checkForUnqualifiedReferenceToNonLocalStaticMember( | |
5268 SimpleIdentifier name) { | |
5269 Element element = name.staticElement; | |
5270 if (element == null || element is TypeParameterElement) { | |
5271 return false; | |
5272 } | |
5273 Element enclosingElement = element.enclosingElement; | |
5274 if (enclosingElement is! ClassElement) { | |
5275 return false; | |
5276 } | |
5277 if ((element is MethodElement && !element.isStatic) || | |
5278 (element is PropertyAccessorElement && !element.isStatic)) { | |
5279 return false; | |
5280 } | |
5281 if (identical(enclosingElement, _enclosingClass)) { | |
5282 return false; | |
5283 } | |
5284 _errorReporter.reportErrorForNode( | |
5285 StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER, | |
5286 name, [name.name]); | |
5287 return true; | |
5288 } | |
5289 | |
5290 void _checkForValidField(FieldFormalParameter parameter) { | |
5291 ParameterElement element = parameter.element; | |
5292 if (element is FieldFormalParameterElement) { | |
5293 FieldElement fieldElement = element.field; | |
5294 if (fieldElement == null || fieldElement.isSynthetic) { | |
5295 _errorReporter.reportErrorForNode( | |
5296 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD, | |
5297 parameter, [parameter.identifier.name]); | |
5298 } else { | |
5299 ParameterElement parameterElement = parameter.element; | |
5300 if (parameterElement is FieldFormalParameterElementImpl) { | |
5301 FieldFormalParameterElementImpl fieldFormal = parameterElement; | |
5302 DartType declaredType = fieldFormal.type; | |
5303 DartType fieldType = fieldElement.type; | |
5304 if (fieldElement.isSynthetic) { | |
5305 _errorReporter.reportErrorForNode( | |
5306 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD, | |
5307 parameter, [parameter.identifier.name]); | |
5308 } else if (fieldElement.isStatic) { | |
5309 _errorReporter.reportErrorForNode( | |
5310 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, | |
5311 parameter, [parameter.identifier.name]); | |
5312 } else if (declaredType != null && | |
5313 fieldType != null && | |
5314 !declaredType.isAssignableTo(fieldType)) { | |
5315 _errorReporter.reportTypeErrorForNode( | |
5316 StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, | |
5317 parameter, [declaredType, fieldType]); | |
5318 } | |
5319 } else { | |
5320 if (fieldElement.isSynthetic) { | |
5321 _errorReporter.reportErrorForNode( | |
5322 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD, | |
5323 parameter, [parameter.identifier.name]); | |
5324 } else if (fieldElement.isStatic) { | |
5325 _errorReporter.reportErrorForNode( | |
5326 CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, | |
5327 parameter, [parameter.identifier.name]); | |
5328 } | |
5329 } | |
5330 } | |
5331 } | |
5332 // else { | |
5333 // // TODO(jwren) Report error, constructor initializer variable is a top
level element | |
5334 // // (Either here or in ErrorVerifier.checkForAllFinalInitializedErrorCo
des) | |
5335 // } | |
5336 } | |
5337 | |
5338 /** | |
5339 * Verify that the given [getter] does not have a return type of 'void'. | |
5340 * | |
5341 * See [StaticWarningCode.VOID_RETURN_FOR_GETTER]. | |
5342 */ | |
5343 bool _checkForVoidReturnType(MethodDeclaration getter) { | |
5344 TypeName returnType = getter.returnType; | |
5345 if (returnType == null || returnType.name.name != "void") { | |
5346 return false; | |
5347 } | |
5348 _errorReporter.reportErrorForNode( | |
5349 StaticWarningCode.VOID_RETURN_FOR_GETTER, returnType); | |
5350 return true; | |
5351 } | |
5352 | |
5353 /** | |
5354 * Verify the given operator-method [declaration], has correct number of | |
5355 * parameters. | |
5356 * | |
5357 * This method assumes that the method declaration was tested to be an | |
5358 * operator declaration before being called. | |
5359 * | |
5360 * See [CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR]. | |
5361 */ | |
5362 bool _checkForWrongNumberOfParametersForOperator( | |
5363 MethodDeclaration declaration) { | |
5364 // prepare number of parameters | |
5365 FormalParameterList parameterList = declaration.parameters; | |
5366 if (parameterList == null) { | |
5367 return false; | |
5368 } | |
5369 int numParameters = parameterList.parameters.length; | |
5370 // prepare operator name | |
5371 SimpleIdentifier nameNode = declaration.name; | |
5372 if (nameNode == null) { | |
5373 return false; | |
5374 } | |
5375 String name = nameNode.name; | |
5376 // check for exact number of parameters | |
5377 int expected = -1; | |
5378 if ("[]=" == name) { | |
5379 expected = 2; | |
5380 } else if ("<" == name || | |
5381 ">" == name || | |
5382 "<=" == name || | |
5383 ">=" == name || | |
5384 "==" == name || | |
5385 "+" == name || | |
5386 "/" == name || | |
5387 "~/" == name || | |
5388 "*" == name || | |
5389 "%" == name || | |
5390 "|" == name || | |
5391 "^" == name || | |
5392 "&" == name || | |
5393 "<<" == name || | |
5394 ">>" == name || | |
5395 "[]" == name) { | |
5396 expected = 1; | |
5397 } else if ("~" == name) { | |
5398 expected = 0; | |
5399 } | |
5400 if (expected != -1 && numParameters != expected) { | |
5401 _errorReporter.reportErrorForNode( | |
5402 CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR, | |
5403 nameNode, [name, expected, numParameters]); | |
5404 return true; | |
5405 } | |
5406 // check for operator "-" | |
5407 if ("-" == name && numParameters > 1) { | |
5408 _errorReporter.reportErrorForNode( | |
5409 CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS, | |
5410 nameNode, [numParameters]); | |
5411 return true; | |
5412 } | |
5413 // OK | |
5414 return false; | |
5415 } | |
5416 | |
5417 /** | |
5418 * Verify that the given setter [parameterList] has only one required | |
5419 * parameter. The [setterName] is the name of the setter to report problems | |
5420 * on. | |
5421 * | |
5422 * This method assumes that the method declaration was tested to be a setter | |
5423 * before being called. | |
5424 * | |
5425 * See [CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER]. | |
5426 */ | |
5427 bool _checkForWrongNumberOfParametersForSetter( | |
5428 SimpleIdentifier setterName, FormalParameterList parameterList) { | |
5429 if (setterName == null) { | |
5430 return false; | |
5431 } | |
5432 if (parameterList == null) { | |
5433 return false; | |
5434 } | |
5435 NodeList<FormalParameter> parameters = parameterList.parameters; | |
5436 if (parameters.length != 1 || | |
5437 parameters[0].kind != ParameterKind.REQUIRED) { | |
5438 _errorReporter.reportErrorForNode( | |
5439 CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER, | |
5440 setterName); | |
5441 return true; | |
5442 } | |
5443 return false; | |
5444 } | |
5445 | |
5446 /** | |
5447 * Check for a type mis-match between the yielded type and the declared | |
5448 * return type of a generator function. | |
5449 * | |
5450 * This method should only be called in generator functions. | |
5451 */ | |
5452 bool _checkForYieldOfInvalidType( | |
5453 Expression yieldExpression, bool isYieldEach) { | |
5454 assert(_inGenerator); | |
5455 if (_enclosingFunction == null) { | |
5456 return false; | |
5457 } | |
5458 DartType declaredReturnType = _enclosingFunction.returnType; | |
5459 DartType staticYieldedType = getStaticType(yieldExpression); | |
5460 DartType impliedReturnType; | |
5461 if (isYieldEach) { | |
5462 impliedReturnType = staticYieldedType; | |
5463 } else if (_enclosingFunction.isAsynchronous) { | |
5464 impliedReturnType = | |
5465 _typeProvider.streamType.substitute4(<DartType>[staticYieldedType]); | |
5466 } else { | |
5467 impliedReturnType = | |
5468 _typeProvider.iterableType.substitute4(<DartType>[staticYieldedType]); | |
5469 } | |
5470 if (!impliedReturnType.isAssignableTo(declaredReturnType)) { | |
5471 _errorReporter.reportTypeErrorForNode( | |
5472 StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, yieldExpression, [ | |
5473 impliedReturnType, | |
5474 declaredReturnType | |
5475 ]); | |
5476 return true; | |
5477 } | |
5478 if (isYieldEach) { | |
5479 // Since the declared return type might have been "dynamic", we need to | |
5480 // also check that the implied return type is assignable to generic | |
5481 // Stream/Iterable. | |
5482 DartType requiredReturnType; | |
5483 if (_enclosingFunction.isAsynchronous) { | |
5484 requiredReturnType = _typeProvider.streamDynamicType; | |
5485 } else { | |
5486 requiredReturnType = _typeProvider.iterableDynamicType; | |
5487 } | |
5488 if (!impliedReturnType.isAssignableTo(requiredReturnType)) { | |
5489 _errorReporter.reportTypeErrorForNode( | |
5490 StaticTypeWarningCode.YIELD_OF_INVALID_TYPE, yieldExpression, [ | |
5491 impliedReturnType, | |
5492 requiredReturnType | |
5493 ]); | |
5494 return true; | |
5495 } | |
5496 } | |
5497 return false; | |
5498 } | |
5499 | |
5500 /** | |
5501 * Verify that if the given class [declaration] implements the class Function | |
5502 * that it has a concrete implementation of the call method. | |
5503 * | |
5504 * See [StaticWarningCode.FUNCTION_WITHOUT_CALL]. | |
5505 */ | |
5506 bool _checkImplementsFunctionWithoutCall(ClassDeclaration declaration) { | |
5507 if (declaration.isAbstract) { | |
5508 return false; | |
5509 } | |
5510 ClassElement classElement = declaration.element; | |
5511 if (classElement == null) { | |
5512 return false; | |
5513 } | |
5514 if (!classElement.type.isSubtypeOf(_typeProvider.functionType)) { | |
5515 return false; | |
5516 } | |
5517 // If there is a noSuchMethod method, then don't report the warning, | |
5518 // see dartbug.com/16078 | |
5519 if (classElement.getMethod(FunctionElement.NO_SUCH_METHOD_METHOD_NAME) != | |
5520 null) { | |
5521 return false; | |
5522 } | |
5523 ExecutableElement callMethod = _inheritanceManager.lookupMember( | |
5524 classElement, FunctionElement.CALL_METHOD_NAME); | |
5525 if (callMethod == null || | |
5526 callMethod is! MethodElement || | |
5527 (callMethod as MethodElement).isAbstract) { | |
5528 _errorReporter.reportErrorForNode( | |
5529 StaticWarningCode.FUNCTION_WITHOUT_CALL, declaration.name); | |
5530 return true; | |
5531 } | |
5532 return false; | |
5533 } | |
5534 | |
5535 /** | |
5536 * Verify that the given class [declaration] does not have the same class in | |
5537 * the 'extends' and 'implements' clauses. | |
5538 * | |
5539 * See [CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS]. | |
5540 */ | |
5541 bool _checkImplementsSuperClass(ClassDeclaration declaration) { | |
5542 // prepare super type | |
5543 InterfaceType superType = _enclosingClass.supertype; | |
5544 if (superType == null) { | |
5545 return false; | |
5546 } | |
5547 // prepare interfaces | |
5548 ImplementsClause implementsClause = declaration.implementsClause; | |
5549 if (implementsClause == null) { | |
5550 return false; | |
5551 } | |
5552 // check interfaces | |
5553 bool hasProblem = false; | |
5554 for (TypeName interfaceNode in implementsClause.interfaces) { | |
5555 if (interfaceNode.type == superType) { | |
5556 hasProblem = true; | |
5557 _errorReporter.reportErrorForNode( | |
5558 CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS, interfaceNode, | |
5559 [superType.displayName]); | |
5560 } | |
5561 } | |
5562 // done | |
5563 return hasProblem; | |
5564 } | |
5565 | |
5566 DartType _computeReturnTypeForMethod(Expression returnExpression) { | |
5567 // This method should never be called for generators, since generators are | |
5568 // never allowed to contain return statements with expressions. | |
5569 assert(!_inGenerator); | |
5570 if (returnExpression == null) { | |
5571 if (_enclosingFunction.isAsynchronous) { | |
5572 return _typeProvider.futureNullType; | |
5573 } else { | |
5574 return VoidTypeImpl.instance; | |
5575 } | |
5576 } | |
5577 DartType staticReturnType = getStaticType(returnExpression); | |
5578 if (staticReturnType != null && _enclosingFunction.isAsynchronous) { | |
5579 return _typeProvider.futureType.substitute4(<DartType>[ | |
5580 StaticTypeAnalyzer.flattenFutures(_typeProvider, staticReturnType) | |
5581 ]); | |
5582 } | |
5583 return staticReturnType; | |
5584 } | |
5585 | |
5586 /** | |
5587 * Return the error code that should be used when the given class [element] | |
5588 * references itself directly. | |
5589 */ | |
5590 ErrorCode _getBaseCaseErrorCode(ClassElement element) { | |
5591 InterfaceType supertype = element.supertype; | |
5592 if (supertype != null && _enclosingClass == supertype.element) { | |
5593 return CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTE
NDS; | |
5594 } | |
5595 List<InterfaceType> mixins = element.mixins; | |
5596 for (int i = 0; i < mixins.length; i++) { | |
5597 if (_enclosingClass == mixins[i].element) { | |
5598 return CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_WI
TH; | |
5599 } | |
5600 } | |
5601 return CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEM
ENTS; | |
5602 } | |
5603 | |
5604 /** | |
5605 * Given an [expression] in a switch case whose value is expected to be an | |
5606 * enum constant, return the name of the constant. | |
5607 */ | |
5608 String _getConstantName(Expression expression) { | |
5609 // TODO(brianwilkerson) Convert this to return the element representing the | |
5610 // constant. | |
5611 if (expression is SimpleIdentifier) { | |
5612 return expression.name; | |
5613 } else if (expression is PrefixedIdentifier) { | |
5614 return expression.identifier.name; | |
5615 } else if (expression is PropertyAccess) { | |
5616 return expression.propertyName.name; | |
5617 } | |
5618 return null; | |
5619 } | |
5620 | |
5621 /** | |
5622 * Return the return type of the given [getter]. | |
5623 */ | |
5624 DartType _getGetterType(PropertyAccessorElement getter) { | |
5625 FunctionType functionType = getter.type; | |
5626 if (functionType != null) { | |
5627 return functionType.returnType; | |
5628 } else { | |
5629 return null; | |
5630 } | |
5631 } | |
5632 | |
5633 /** | |
5634 * Return the type of the first and only parameter of the given [setter]. | |
5635 */ | |
5636 DartType _getSetterType(PropertyAccessorElement setter) { | |
5637 // Get the parameters for MethodDeclaration or FunctionDeclaration | |
5638 List<ParameterElement> setterParameters = setter.parameters; | |
5639 // If there are no setter parameters, return no type. | |
5640 if (setterParameters.length == 0) { | |
5641 return null; | |
5642 } | |
5643 return setterParameters[0].type; | |
5644 } | |
5645 | |
5646 /** | |
5647 * Given a list of [directives] that have the same prefix, generate an error | |
5648 * if there is more than one import and any of those imports is deferred. | |
5649 * | |
5650 * See [CompileTimeErrorCode.SHARED_DEFERRED_PREFIX]. | |
5651 */ | |
5652 bool _hasDeferredPrefixCollision(List<ImportDirective> directives) { | |
5653 bool foundError = false; | |
5654 int count = directives.length; | |
5655 if (count > 1) { | |
5656 for (int i = 0; i < count; i++) { | |
5657 sc.Token deferredToken = directives[i].deferredKeyword; | |
5658 if (deferredToken != null) { | |
5659 _errorReporter.reportErrorForToken( | |
5660 CompileTimeErrorCode.SHARED_DEFERRED_PREFIX, deferredToken); | |
5661 foundError = true; | |
5662 } | |
5663 } | |
5664 } | |
5665 return foundError; | |
5666 } | |
5667 | |
5668 /** | |
5669 * Return `true` if the given [constructor] redirects to itself, directly or | |
5670 * indirectly. | |
5671 */ | |
5672 bool _hasRedirectingFactoryConstructorCycle(ConstructorElement constructor) { | |
5673 Set<ConstructorElement> constructors = new HashSet<ConstructorElement>(); | |
5674 ConstructorElement current = constructor; | |
5675 while (current != null) { | |
5676 if (constructors.contains(current)) { | |
5677 return identical(current, constructor); | |
5678 } | |
5679 constructors.add(current); | |
5680 current = current.redirectedConstructor; | |
5681 if (current is ConstructorMember) { | |
5682 current = (current as ConstructorMember).baseElement; | |
5683 } | |
5684 } | |
5685 return false; | |
5686 } | |
5687 | |
5688 /** | |
5689 * Return `true` if the given [element] has direct or indirect reference to | |
5690 * itself from anywhere except a class element or type parameter bounds. | |
5691 */ | |
5692 bool _hasTypedefSelfReference(Element element) { | |
5693 Set<Element> checked = new HashSet<Element>(); | |
5694 List<Element> toCheck = new List<Element>(); | |
5695 GeneralizingElementVisitor_ErrorVerifier_hasTypedefSelfReference elementVisi
tor = | |
5696 new GeneralizingElementVisitor_ErrorVerifier_hasTypedefSelfReference( | |
5697 toCheck); | |
5698 toCheck.add(element); | |
5699 bool firstIteration = true; | |
5700 while (true) { | |
5701 Element current; | |
5702 // get next element | |
5703 while (true) { | |
5704 // may be no more elements to check | |
5705 if (toCheck.isEmpty) { | |
5706 return false; | |
5707 } | |
5708 // try to get next element | |
5709 current = toCheck.removeAt(toCheck.length - 1); | |
5710 if (element == current) { | |
5711 if (firstIteration) { | |
5712 firstIteration = false; | |
5713 break; | |
5714 } else { | |
5715 return true; | |
5716 } | |
5717 } | |
5718 if (current != null && !checked.contains(current)) { | |
5719 break; | |
5720 } | |
5721 } | |
5722 // check current element | |
5723 current.accept(elementVisitor); | |
5724 checked.add(current); | |
5725 } | |
5726 } | |
5727 | |
5728 bool _isFunctionType(DartType type) { | |
5729 if (type.isDynamic || type.isBottom) { | |
5730 return true; | |
5731 } else if (type is FunctionType || type.isDartCoreFunction) { | |
5732 return true; | |
5733 } else if (type is InterfaceType) { | |
5734 MethodElement callMethod = | |
5735 type.lookUpMethod(FunctionElement.CALL_METHOD_NAME, _currentLibrary); | |
5736 return callMethod != null; | |
5737 } | |
5738 return false; | |
5739 } | |
5740 | |
5741 /** | |
5742 * Return `true` iff the given [classElement] has a concrete method, getter or | |
5743 * setter that matches the name of the given [executableElement] in either the | |
5744 * class itself, or one of its' mixins. | |
5745 * | |
5746 * By "match", only the name of the member is tested to match, it does not | |
5747 * have to equal or be a subtype of the given executable element, this is due | |
5748 * to the specific use where this method is used in | |
5749 * [_checkForNonAbstractClassInheritsAbstractMember]. | |
5750 */ | |
5751 bool _isMemberInClassOrMixin( | |
5752 ExecutableElement executableElement, ClassElement classElement) { | |
5753 ExecutableElement foundElt = null; | |
5754 String executableName = executableElement.name; | |
5755 if (executableElement is MethodElement) { | |
5756 foundElt = classElement.getMethod(executableName); | |
5757 if (foundElt != null && !(foundElt as MethodElement).isAbstract) { | |
5758 return true; | |
5759 } | |
5760 List<InterfaceType> mixins = classElement.mixins; | |
5761 for (int i = 0; i < mixins.length && foundElt == null; i++) { | |
5762 foundElt = mixins[i].getMethod(executableName); | |
5763 } | |
5764 if (foundElt != null && !(foundElt as MethodElement).isAbstract) { | |
5765 return true; | |
5766 } | |
5767 } else if (executableElement is PropertyAccessorElement) { | |
5768 PropertyAccessorElement propertyAccessorElement = executableElement; | |
5769 if (propertyAccessorElement.isGetter) { | |
5770 foundElt = classElement.getGetter(executableName); | |
5771 } | |
5772 if (foundElt == null && propertyAccessorElement.isSetter) { | |
5773 foundElt = classElement.getSetter(executableName); | |
5774 } | |
5775 if (foundElt != null && | |
5776 !(foundElt as PropertyAccessorElement).isAbstract) { | |
5777 return true; | |
5778 } | |
5779 List<InterfaceType> mixins = classElement.mixins; | |
5780 for (int i = 0; i < mixins.length && foundElt == null; i++) { | |
5781 foundElt = mixins[i].getGetter(executableName); | |
5782 if (foundElt == null) { | |
5783 foundElt = mixins[i].getSetter(executableName); | |
5784 } | |
5785 } | |
5786 if (foundElt != null && | |
5787 !(foundElt as PropertyAccessorElement).isAbstract) { | |
5788 return true; | |
5789 } | |
5790 } | |
5791 return false; | |
5792 } | |
5793 | |
5794 /** | |
5795 * Return `true` if the given 'this' [expression] is in a valid context. | |
5796 */ | |
5797 bool _isThisInValidContext(ThisExpression expression) { | |
5798 for (AstNode node = expression.parent; node != null; node = node.parent) { | |
5799 if (node is CompilationUnit) { | |
5800 return false; | |
5801 } | |
5802 if (node is ConstructorDeclaration) { | |
5803 return node.factoryKeyword == null; | |
5804 } | |
5805 if (node is ConstructorInitializer) { | |
5806 return false; | |
5807 } | |
5808 if (node is MethodDeclaration) { | |
5809 return !node.isStatic; | |
5810 } | |
5811 } | |
5812 return false; | |
5813 } | |
5814 | |
5815 /** | |
5816 * Return `true` if the given [identifier] is in a location where it is | |
5817 * allowed to resolve to a static member of a supertype. | |
5818 */ | |
5819 bool _isUnqualifiedReferenceToNonLocalStaticMemberAllowed( | |
5820 SimpleIdentifier identifier) { | |
5821 if (identifier.inDeclarationContext()) { | |
5822 return true; | |
5823 } | |
5824 AstNode parent = identifier.parent; | |
5825 if (parent is ConstructorName || | |
5826 parent is MethodInvocation || | |
5827 parent is PropertyAccess || | |
5828 parent is SuperConstructorInvocation) { | |
5829 return true; | |
5830 } | |
5831 if (parent is PrefixedIdentifier && | |
5832 identical(parent.identifier, identifier)) { | |
5833 return true; | |
5834 } | |
5835 if (parent is Annotation && identical(parent.constructorName, identifier)) { | |
5836 return true; | |
5837 } | |
5838 if (parent is CommentReference) { | |
5839 CommentReference commentReference = parent; | |
5840 if (commentReference.newKeyword != null) { | |
5841 return true; | |
5842 } | |
5843 } | |
5844 return false; | |
5845 } | |
5846 | |
5847 bool _isUserDefinedObject(EvaluationResultImpl result) => result == null || | |
5848 (result.value != null && result.value.isUserDefinedObject); | |
5849 | |
5850 /** | |
5851 * Check that the given class [element] is not a superinterface to itself. The | |
5852 * [path] is a list containing the potentially cyclic implements path. | |
5853 * | |
5854 * See [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE], | |
5855 * [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS], | |
5856 * [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS]
, | |
5857 * and [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_WITH]. | |
5858 */ | |
5859 bool _safeCheckForRecursiveInterfaceInheritance( | |
5860 ClassElement element, List<ClassElement> path) { | |
5861 // Detect error condition. | |
5862 int size = path.length; | |
5863 // If this is not the base case (size > 0), and the enclosing class is the | |
5864 // given class element then an error an error. | |
5865 if (size > 0 && _enclosingClass == element) { | |
5866 String enclosingClassName = _enclosingClass.displayName; | |
5867 if (size > 1) { | |
5868 // Construct a string showing the cyclic implements path: | |
5869 // "A, B, C, D, A" | |
5870 String separator = ", "; | |
5871 StringBuffer buffer = new StringBuffer(); | |
5872 for (int i = 0; i < size; i++) { | |
5873 buffer.write(path[i].displayName); | |
5874 buffer.write(separator); | |
5875 } | |
5876 buffer.write(element.displayName); | |
5877 _errorReporter.reportErrorForOffset( | |
5878 CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE, | |
5879 _enclosingClass.nameOffset, enclosingClassName.length, [ | |
5880 enclosingClassName, | |
5881 buffer.toString() | |
5882 ]); | |
5883 return true; | |
5884 } else { | |
5885 // RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS or | |
5886 // RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS or | |
5887 // RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_WITH | |
5888 _errorReporter.reportErrorForOffset(_getBaseCaseErrorCode(element), | |
5889 _enclosingClass.nameOffset, enclosingClassName.length, | |
5890 [enclosingClassName]); | |
5891 return true; | |
5892 } | |
5893 } | |
5894 if (path.indexOf(element) > 0) { | |
5895 return false; | |
5896 } | |
5897 path.add(element); | |
5898 // n-case | |
5899 InterfaceType supertype = element.supertype; | |
5900 if (supertype != null && | |
5901 _safeCheckForRecursiveInterfaceInheritance(supertype.element, path)) { | |
5902 return true; | |
5903 } | |
5904 List<InterfaceType> interfaceTypes = element.interfaces; | |
5905 for (InterfaceType interfaceType in interfaceTypes) { | |
5906 if (_safeCheckForRecursiveInterfaceInheritance( | |
5907 interfaceType.element, path)) { | |
5908 return true; | |
5909 } | |
5910 } | |
5911 List<InterfaceType> mixinTypes = element.mixins; | |
5912 for (InterfaceType mixinType in mixinTypes) { | |
5913 if (_safeCheckForRecursiveInterfaceInheritance(mixinType.element, path)) { | |
5914 return true; | |
5915 } | |
5916 } | |
5917 path.removeAt(path.length - 1); | |
5918 return false; | |
5919 } | |
5920 | |
5921 /** | |
5922 * Return the static type of the given [expression] that is to be used for | |
5923 * type analysis. | |
5924 */ | |
5925 static DartType getStaticType(Expression expression) { | |
5926 DartType type = expression.staticType; | |
5927 if (type == null) { | |
5928 // TODO(brianwilkerson) This should never happen. | |
5929 return DynamicTypeImpl.instance; | |
5930 } | |
5931 return type; | |
5932 } | |
5933 | |
5934 /** | |
5935 * Return the variable element represented by the given [expression], or | |
5936 * `null` if there is no such element. | |
5937 */ | |
5938 static VariableElement getVariableElement(Expression expression) { | |
5939 if (expression is Identifier) { | |
5940 Element element = expression.staticElement; | |
5941 if (element is VariableElement) { | |
5942 return element; | |
5943 } | |
5944 } | |
5945 return null; | |
5946 } | |
5947 } | |
5948 | |
5949 class GeneralizingElementVisitor_ErrorVerifier_hasTypedefSelfReference | |
5950 extends GeneralizingElementVisitor<Object> { | |
5951 List<Element> toCheck; | |
5952 | |
5953 GeneralizingElementVisitor_ErrorVerifier_hasTypedefSelfReference(this.toCheck) | |
5954 : super(); | |
5955 | |
5956 @override | |
5957 Object visitClassElement(ClassElement element) { | |
5958 // Typedefs are allowed to reference themselves via classes. | |
5959 return null; | |
5960 } | |
5961 | |
5962 @override | |
5963 Object visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { | |
5964 _addTypeToCheck(element.returnType); | |
5965 return super.visitFunctionTypeAliasElement(element); | |
5966 } | |
5967 | |
5968 @override | |
5969 Object visitParameterElement(ParameterElement element) { | |
5970 _addTypeToCheck(element.type); | |
5971 return super.visitParameterElement(element); | |
5972 } | |
5973 | |
5974 @override | |
5975 Object visitTypeParameterElement(TypeParameterElement element) { | |
5976 _addTypeToCheck(element.bound); | |
5977 return super.visitTypeParameterElement(element); | |
5978 } | |
5979 | |
5980 void _addTypeToCheck(DartType type) { | |
5981 if (type == null) { | |
5982 return; | |
5983 } | |
5984 // schedule for checking | |
5985 toCheck.add(type.element); | |
5986 // type arguments | |
5987 if (type is InterfaceType) { | |
5988 InterfaceType interfaceType = type; | |
5989 for (DartType typeArgument in interfaceType.typeArguments) { | |
5990 _addTypeToCheck(typeArgument); | |
5991 } | |
5992 } | |
5993 } | |
5994 } | |
OLD | NEW |