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

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

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

Powered by Google App Engine
This is Rietveld 408576698