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