| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library engine.resolver; | 5 library analyzer.src.generated.resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'constant.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
| 11 import 'element.dart'; | 11 import 'package:analyzer/dart/ast/visitor.dart'; |
| 12 import 'element_resolver.dart'; | 12 import 'package:analyzer/dart/element/element.dart'; |
| 13 import 'engine.dart'; | 13 import 'package:analyzer/dart/element/type.dart'; |
| 14 import 'error.dart'; | 14 import 'package:analyzer/dart/element/visitor.dart'; |
| 15 import 'error_verifier.dart'; | 15 import 'package:analyzer/error/error.dart'; |
| 16 import 'html.dart' as ht; | 16 import 'package:analyzer/error/listener.dart'; |
| 17 import 'java_core.dart'; | 17 import 'package:analyzer/exception/exception.dart'; |
| 18 import 'java_engine.dart'; | 18 import 'package:analyzer/src/dart/ast/ast.dart'; |
| 19 import 'scanner.dart' as sc; | 19 import 'package:analyzer/src/dart/ast/utilities.dart'; |
| 20 import 'sdk.dart' show DartSdk, SdkLibrary; | 20 import 'package:analyzer/src/dart/element/element.dart'; |
| 21 import 'source.dart'; | 21 import 'package:analyzer/src/dart/element/type.dart'; |
| 22 import 'static_type_analyzer.dart'; | 22 import 'package:analyzer/src/dart/element/utilities.dart'; |
| 23 import 'utilities_dart.dart'; | 23 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; |
| 24 import 'package:analyzer/src/dart/resolver/scope.dart'; |
| 25 import 'package:analyzer/src/error/codes.dart'; |
| 26 import 'package:analyzer/src/generated/constant.dart'; |
| 27 import 'package:analyzer/src/generated/element_resolver.dart'; |
| 28 import 'package:analyzer/src/generated/engine.dart'; |
| 29 import 'package:analyzer/src/generated/error_verifier.dart'; |
| 30 import 'package:analyzer/src/generated/source.dart'; |
| 31 import 'package:analyzer/src/generated/static_type_analyzer.dart'; |
| 32 import 'package:analyzer/src/generated/type_system.dart'; |
| 33 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 24 | 34 |
| 25 /** | 35 export 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; |
| 26 * Callback signature used by ImplicitConstructorBuilder to register | 36 export 'package:analyzer/src/dart/resolver/scope.dart'; |
| 27 * computations to be performed, and their dependencies. A call to this | 37 export 'package:analyzer/src/generated/type_system.dart'; |
| 28 * callback indicates that [computation] may be used to compute implicit | |
| 29 * constructors for [classElement], but that the computation may not be invoked | |
| 30 * until after implicit constructors have been built for [superclassElement]. | |
| 31 */ | |
| 32 typedef void ImplicitConstructorBuilderCallback(ClassElement classElement, | |
| 33 ClassElement superclassElement, void computation()); | |
| 34 | |
| 35 typedef LibraryResolver LibraryResolverFactory(AnalysisContext context); | |
| 36 | |
| 37 typedef ResolverVisitor ResolverVisitorFactory( | |
| 38 Library library, Source source, TypeProvider typeProvider); | |
| 39 | |
| 40 typedef StaticTypeAnalyzer StaticTypeAnalyzerFactory(ResolverVisitor visitor); | |
| 41 | |
| 42 typedef TypeResolverVisitor TypeResolverVisitorFactory( | |
| 43 Library library, Source source, TypeProvider typeProvider); | |
| 44 | |
| 45 typedef void VoidFunction(); | |
| 46 | |
| 47 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); | |
| 48 | |
| 49 typedef bool _SubtypeChecker<T>(T t1, T t2); | |
| 50 | 38 |
| 51 /** | 39 /** |
| 52 * Instances of the class `BestPracticesVerifier` traverse an AST structure look
ing for | 40 * Instances of the class `BestPracticesVerifier` traverse an AST structure look
ing for |
| 53 * violations of Dart best practices. | 41 * violations of Dart best practices. |
| 54 */ | 42 */ |
| 55 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { | 43 class BestPracticesVerifier extends RecursiveAstVisitor<Object> { |
| 56 // static String _HASHCODE_GETTER_NAME = "hashCode"; | 44 // static String _HASHCODE_GETTER_NAME = "hashCode"; |
| 57 | 45 |
| 58 static String _NULL_TYPE_NAME = "Null"; | 46 static String _NULL_TYPE_NAME = "Null"; |
| 59 | 47 |
| 60 static String _TO_INT_METHOD_NAME = "toInt"; | 48 static String _TO_INT_METHOD_NAME = "toInt"; |
| 61 | 49 |
| 62 /** | 50 /** |
| 63 * The class containing the AST nodes being visited, or `null` if we are not i
n the scope of | 51 * The class containing the AST nodes being visited, or `null` if we are not i
n the scope of |
| 64 * a class. | 52 * a class. |
| 65 */ | 53 */ |
| 66 ClassElement _enclosingClass; | 54 ClassElementImpl _enclosingClass; |
| 55 |
| 56 /** |
| 57 * A flag indicating whether a surrounding member (compilation unit or class) |
| 58 * is deprecated. |
| 59 */ |
| 60 bool inDeprecatedMember; |
| 67 | 61 |
| 68 /** | 62 /** |
| 69 * The error reporter by which errors will be reported. | 63 * The error reporter by which errors will be reported. |
| 70 */ | 64 */ |
| 71 final ErrorReporter _errorReporter; | 65 final ErrorReporter _errorReporter; |
| 72 | 66 |
| 73 /** | 67 /** |
| 68 * The type [Null]. |
| 69 */ |
| 70 final InterfaceType _nullType; |
| 71 |
| 72 /** |
| 74 * The type Future<Null>, which is needed for determining whether it is safe | 73 * The type Future<Null>, which is needed for determining whether it is safe |
| 75 * to have a bare "return;" in an async method. | 74 * to have a bare "return;" in an async method. |
| 76 */ | 75 */ |
| 77 final InterfaceType _futureNullType; | 76 final InterfaceType _futureNullType; |
| 78 | 77 |
| 79 /** | 78 /** |
| 80 * The type system primitives | 79 * The type system primitives |
| 81 */ | 80 */ |
| 82 TypeSystem _typeSystem; | 81 TypeSystem _typeSystem; |
| 83 | 82 |
| 84 /** | 83 /** |
| 84 * The current library |
| 85 */ |
| 86 LibraryElement _currentLibrary; |
| 87 |
| 88 /** |
| 89 * The inheritance manager used to find overridden methods. |
| 90 */ |
| 91 InheritanceManager _manager; |
| 92 |
| 93 /** |
| 85 * Create a new instance of the [BestPracticesVerifier]. | 94 * Create a new instance of the [BestPracticesVerifier]. |
| 86 * | 95 * |
| 87 * @param errorReporter the error reporter | 96 * @param errorReporter the error reporter |
| 88 */ | 97 */ |
| 89 BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider, | 98 BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider, |
| 99 this._currentLibrary, this._manager, |
| 90 {TypeSystem typeSystem}) | 100 {TypeSystem typeSystem}) |
| 91 : _futureNullType = typeProvider.futureNullType, | 101 : _nullType = typeProvider.nullType, |
| 92 _typeSystem = (typeSystem != null) ? typeSystem : new TypeSystemImpl(); | 102 _futureNullType = typeProvider.futureNullType, |
| 103 _typeSystem = typeSystem ?? new TypeSystemImpl() { |
| 104 inDeprecatedMember = _currentLibrary.isDeprecated; |
| 105 } |
| 106 |
| 107 @override |
| 108 Object visitAnnotation(Annotation node) { |
| 109 if (node.elementAnnotation?.isFactory == true) { |
| 110 AstNode parent = node.parent; |
| 111 if (parent is MethodDeclaration) { |
| 112 _checkForInvalidFactory(parent); |
| 113 } else { |
| 114 _errorReporter |
| 115 .reportErrorForNode(HintCode.INVALID_FACTORY_ANNOTATION, node, []); |
| 116 } |
| 117 } |
| 118 return super.visitAnnotation(node); |
| 119 } |
| 93 | 120 |
| 94 @override | 121 @override |
| 95 Object visitArgumentList(ArgumentList node) { | 122 Object visitArgumentList(ArgumentList node) { |
| 123 for (Expression argument in node.arguments) { |
| 124 ParameterElement parameter = argument.bestParameterElement; |
| 125 if (parameter?.parameterKind == ParameterKind.POSITIONAL) { |
| 126 _checkForDeprecatedMemberUse(parameter, argument); |
| 127 } |
| 128 } |
| 96 _checkForArgumentTypesNotAssignableInList(node); | 129 _checkForArgumentTypesNotAssignableInList(node); |
| 97 return super.visitArgumentList(node); | 130 return super.visitArgumentList(node); |
| 98 } | 131 } |
| 99 | 132 |
| 100 @override | 133 @override |
| 101 Object visitAsExpression(AsExpression node) { | 134 Object visitAsExpression(AsExpression node) { |
| 102 _checkForUnnecessaryCast(node); | 135 _checkForUnnecessaryCast(node); |
| 103 return super.visitAsExpression(node); | 136 return super.visitAsExpression(node); |
| 104 } | 137 } |
| 105 | 138 |
| 106 @override | 139 @override |
| 140 Object visitAssertStatement(AssertStatement node) { |
| 141 _checkForPossibleNullCondition(node.condition); |
| 142 return super.visitAssertStatement(node); |
| 143 } |
| 144 |
| 145 @override |
| 107 Object visitAssignmentExpression(AssignmentExpression node) { | 146 Object visitAssignmentExpression(AssignmentExpression node) { |
| 108 sc.TokenType operatorType = node.operator.type; | 147 TokenType operatorType = node.operator.type; |
| 109 if (operatorType == sc.TokenType.EQ) { | 148 if (operatorType == TokenType.EQ) { |
| 110 _checkForUseOfVoidResult(node.rightHandSide); | 149 _checkForUseOfVoidResult(node.rightHandSide); |
| 111 _checkForInvalidAssignment(node.leftHandSide, node.rightHandSide); | 150 _checkForInvalidAssignment(node.leftHandSide, node.rightHandSide); |
| 112 } else { | 151 } else { |
| 113 _checkForDeprecatedMemberUse(node.bestElement, node); | 152 _checkForDeprecatedMemberUse(node.bestElement, node); |
| 114 } | 153 } |
| 115 return super.visitAssignmentExpression(node); | 154 return super.visitAssignmentExpression(node); |
| 116 } | 155 } |
| 117 | 156 |
| 118 @override | 157 @override |
| 119 Object visitBinaryExpression(BinaryExpression node) { | 158 Object visitBinaryExpression(BinaryExpression node) { |
| 120 _checkForDivisionOptimizationHint(node); | 159 _checkForDivisionOptimizationHint(node); |
| 121 _checkForDeprecatedMemberUse(node.bestElement, node); | 160 _checkForDeprecatedMemberUse(node.bestElement, node); |
| 122 return super.visitBinaryExpression(node); | 161 return super.visitBinaryExpression(node); |
| 123 } | 162 } |
| 124 | 163 |
| 125 @override | 164 @override |
| 126 Object visitClassDeclaration(ClassDeclaration node) { | 165 Object visitClassDeclaration(ClassDeclaration node) { |
| 127 ClassElement outerClass = _enclosingClass; | 166 ClassElementImpl outerClass = _enclosingClass; |
| 167 bool wasInDeprecatedMember = inDeprecatedMember; |
| 168 ClassElement element = AbstractClassElementImpl.getImpl(node.element); |
| 169 if (element != null && element.isDeprecated) { |
| 170 inDeprecatedMember = true; |
| 171 } |
| 128 try { | 172 try { |
| 129 _enclosingClass = node.element; | 173 _enclosingClass = element; |
| 130 // Commented out until we decide that we want this hint in the analyzer | 174 // Commented out until we decide that we want this hint in the analyzer |
| 131 // checkForOverrideEqualsButNotHashCode(node); | 175 // checkForOverrideEqualsButNotHashCode(node); |
| 132 return super.visitClassDeclaration(node); | 176 return super.visitClassDeclaration(node); |
| 133 } finally { | 177 } finally { |
| 134 _enclosingClass = outerClass; | 178 _enclosingClass = outerClass; |
| 179 inDeprecatedMember = wasInDeprecatedMember; |
| 135 } | 180 } |
| 136 } | 181 } |
| 137 | 182 |
| 138 @override | 183 @override |
| 184 Object visitConditionalExpression(ConditionalExpression node) { |
| 185 _checkForPossibleNullCondition(node.condition); |
| 186 return super.visitConditionalExpression(node); |
| 187 } |
| 188 |
| 189 @override |
| 190 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 191 if (node.element.isFactory) { |
| 192 if (node.body is BlockFunctionBody) { |
| 193 // Check the block for a return statement, if not, create the hint. |
| 194 if (!ExitDetector.exits(node.body)) { |
| 195 _errorReporter.reportErrorForNode( |
| 196 HintCode.MISSING_RETURN, node, [node.returnType.name]); |
| 197 } |
| 198 } |
| 199 } |
| 200 return super.visitConstructorDeclaration(node); |
| 201 } |
| 202 |
| 203 @override |
| 204 Object visitDoStatement(DoStatement node) { |
| 205 _checkForPossibleNullCondition(node.condition); |
| 206 return super.visitDoStatement(node); |
| 207 } |
| 208 |
| 209 @override |
| 139 Object visitExportDirective(ExportDirective node) { | 210 Object visitExportDirective(ExportDirective node) { |
| 140 _checkForDeprecatedMemberUse(node.uriElement, node); | 211 _checkForDeprecatedMemberUse(node.uriElement, node); |
| 141 return super.visitExportDirective(node); | 212 return super.visitExportDirective(node); |
| 142 } | 213 } |
| 143 | 214 |
| 144 @override | 215 @override |
| 216 Object visitForStatement(ForStatement node) { |
| 217 _checkForPossibleNullCondition(node.condition); |
| 218 return super.visitForStatement(node); |
| 219 } |
| 220 |
| 221 @override |
| 145 Object visitFunctionDeclaration(FunctionDeclaration node) { | 222 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 146 _checkForMissingReturn(node.returnType, node.functionExpression.body); | 223 bool wasInDeprecatedMember = inDeprecatedMember; |
| 147 return super.visitFunctionDeclaration(node); | 224 ExecutableElement element = node.element; |
| 225 if (element != null && element.isDeprecated) { |
| 226 inDeprecatedMember = true; |
| 227 } |
| 228 try { |
| 229 _checkForMissingReturn(node.returnType, node.functionExpression.body); |
| 230 return super.visitFunctionDeclaration(node); |
| 231 } finally { |
| 232 inDeprecatedMember = wasInDeprecatedMember; |
| 233 } |
| 234 } |
| 235 |
| 236 @override |
| 237 Object visitIfStatement(IfStatement node) { |
| 238 _checkForPossibleNullCondition(node.condition); |
| 239 return super.visitIfStatement(node); |
| 148 } | 240 } |
| 149 | 241 |
| 150 @override | 242 @override |
| 151 Object visitImportDirective(ImportDirective node) { | 243 Object visitImportDirective(ImportDirective node) { |
| 152 _checkForDeprecatedMemberUse(node.uriElement, node); | 244 _checkForDeprecatedMemberUse(node.uriElement, node); |
| 153 ImportElement importElement = node.element; | 245 ImportElement importElement = node.element; |
| 154 if (importElement != null) { | 246 if (importElement != null && importElement.isDeferred) { |
| 155 if (importElement.isDeferred) { | 247 _checkForLoadLibraryFunction(node, importElement); |
| 156 _checkForLoadLibraryFunction(node, importElement); | |
| 157 } | |
| 158 } | 248 } |
| 159 return super.visitImportDirective(node); | 249 return super.visitImportDirective(node); |
| 160 } | 250 } |
| 161 | 251 |
| 162 @override | 252 @override |
| 163 Object visitIndexExpression(IndexExpression node) { | 253 Object visitIndexExpression(IndexExpression node) { |
| 164 _checkForDeprecatedMemberUse(node.bestElement, node); | 254 _checkForDeprecatedMemberUse(node.bestElement, node); |
| 165 return super.visitIndexExpression(node); | 255 return super.visitIndexExpression(node); |
| 166 } | 256 } |
| 167 | 257 |
| 168 @override | 258 @override |
| 169 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | 259 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 170 _checkForDeprecatedMemberUse(node.staticElement, node); | 260 _checkForDeprecatedMemberUse(node.staticElement, node); |
| 171 return super.visitInstanceCreationExpression(node); | 261 return super.visitInstanceCreationExpression(node); |
| 172 } | 262 } |
| 173 | 263 |
| 174 @override | 264 @override |
| 175 Object visitIsExpression(IsExpression node) { | 265 Object visitIsExpression(IsExpression node) { |
| 176 _checkAllTypeChecks(node); | 266 _checkAllTypeChecks(node); |
| 177 return super.visitIsExpression(node); | 267 return super.visitIsExpression(node); |
| 178 } | 268 } |
| 179 | 269 |
| 180 @override | 270 @override |
| 181 Object visitMethodDeclaration(MethodDeclaration node) { | 271 Object visitMethodDeclaration(MethodDeclaration node) { |
| 182 // This was determined to not be a good hint, see: dartbug.com/16029 | 272 bool wasInDeprecatedMember = inDeprecatedMember; |
| 183 //checkForOverridingPrivateMember(node); | 273 ExecutableElement element = node.element; |
| 184 _checkForMissingReturn(node.returnType, node.body); | 274 if (element != null && element.isDeprecated) { |
| 185 return super.visitMethodDeclaration(node); | 275 inDeprecatedMember = true; |
| 276 } |
| 277 try { |
| 278 // This was determined to not be a good hint, see: dartbug.com/16029 |
| 279 //checkForOverridingPrivateMember(node); |
| 280 _checkForMissingReturn(node.returnType, node.body); |
| 281 _checkForUnnecessaryNoSuchMethod(node); |
| 282 return super.visitMethodDeclaration(node); |
| 283 } finally { |
| 284 inDeprecatedMember = wasInDeprecatedMember; |
| 285 } |
| 186 } | 286 } |
| 187 | 287 |
| 188 @override | 288 @override |
| 289 Object visitMethodInvocation(MethodInvocation node) { |
| 290 Expression realTarget = node.realTarget; |
| 291 _checkForAbstractSuperMemberReference(realTarget, node.methodName); |
| 292 _checkForCanBeNullAfterNullAware( |
| 293 realTarget, node.operator, null, node.methodName); |
| 294 DartType staticInvokeType = node.staticInvokeType; |
| 295 if (staticInvokeType is InterfaceType) { |
| 296 MethodElement methodElement = staticInvokeType.lookUpMethod( |
| 297 FunctionElement.CALL_METHOD_NAME, _currentLibrary); |
| 298 _checkForDeprecatedMemberUse(methodElement, node); |
| 299 } |
| 300 return super.visitMethodInvocation(node); |
| 301 } |
| 302 |
| 303 @override |
| 189 Object visitPostfixExpression(PostfixExpression node) { | 304 Object visitPostfixExpression(PostfixExpression node) { |
| 190 _checkForDeprecatedMemberUse(node.bestElement, node); | 305 _checkForDeprecatedMemberUse(node.bestElement, node); |
| 191 return super.visitPostfixExpression(node); | 306 return super.visitPostfixExpression(node); |
| 192 } | 307 } |
| 193 | 308 |
| 194 @override | 309 @override |
| 195 Object visitPrefixExpression(PrefixExpression node) { | 310 Object visitPrefixExpression(PrefixExpression node) { |
| 196 _checkForDeprecatedMemberUse(node.bestElement, node); | 311 _checkForDeprecatedMemberUse(node.bestElement, node); |
| 197 return super.visitPrefixExpression(node); | 312 return super.visitPrefixExpression(node); |
| 198 } | 313 } |
| 199 | 314 |
| 200 @override | 315 @override |
| 316 Object visitPropertyAccess(PropertyAccess node) { |
| 317 Expression realTarget = node.realTarget; |
| 318 _checkForAbstractSuperMemberReference(realTarget, node.propertyName); |
| 319 _checkForCanBeNullAfterNullAware( |
| 320 realTarget, node.operator, node.propertyName, null); |
| 321 return super.visitPropertyAccess(node); |
| 322 } |
| 323 |
| 324 @override |
| 201 Object visitRedirectingConstructorInvocation( | 325 Object visitRedirectingConstructorInvocation( |
| 202 RedirectingConstructorInvocation node) { | 326 RedirectingConstructorInvocation node) { |
| 203 _checkForDeprecatedMemberUse(node.staticElement, node); | 327 _checkForDeprecatedMemberUse(node.staticElement, node); |
| 204 return super.visitRedirectingConstructorInvocation(node); | 328 return super.visitRedirectingConstructorInvocation(node); |
| 205 } | 329 } |
| 206 | 330 |
| 207 @override | 331 @override |
| 208 Object visitSimpleIdentifier(SimpleIdentifier node) { | 332 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 209 _checkForDeprecatedMemberUseAtIdentifier(node); | 333 _checkForDeprecatedMemberUseAtIdentifier(node); |
| 334 _checkForInvalidProtectedMemberAccess(node); |
| 210 return super.visitSimpleIdentifier(node); | 335 return super.visitSimpleIdentifier(node); |
| 211 } | 336 } |
| 212 | 337 |
| 213 @override | 338 @override |
| 214 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | 339 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 215 _checkForDeprecatedMemberUse(node.staticElement, node); | 340 _checkForDeprecatedMemberUse(node.staticElement, node); |
| 216 return super.visitSuperConstructorInvocation(node); | 341 return super.visitSuperConstructorInvocation(node); |
| 217 } | 342 } |
| 218 | 343 |
| 219 @override | 344 @override |
| 220 Object visitVariableDeclaration(VariableDeclaration node) { | 345 Object visitVariableDeclaration(VariableDeclaration node) { |
| 221 _checkForUseOfVoidResult(node.initializer); | 346 _checkForUseOfVoidResult(node.initializer); |
| 222 _checkForInvalidAssignment(node.name, node.initializer); | 347 _checkForInvalidAssignment(node.name, node.initializer); |
| 223 return super.visitVariableDeclaration(node); | 348 return super.visitVariableDeclaration(node); |
| 224 } | 349 } |
| 225 | 350 |
| 351 @override |
| 352 Object visitWhileStatement(WhileStatement node) { |
| 353 _checkForPossibleNullCondition(node.condition); |
| 354 return super.visitWhileStatement(node); |
| 355 } |
| 356 |
| 226 /** | 357 /** |
| 227 * Check for the passed is expression for the unnecessary type check hint code
s as well as null | 358 * Check for the passed is expression for the unnecessary type check hint code
s as well as null |
| 228 * checks expressed using an is expression. | 359 * checks expressed using an is expression. |
| 229 * | 360 * |
| 230 * @param node the is expression to check | 361 * @param node the is expression to check |
| 231 * @return `true` if and only if a hint code is generated on the passed node | 362 * @return `true` if and only if a hint code is generated on the passed node |
| 232 * See [HintCode.TYPE_CHECK_IS_NOT_NULL], [HintCode.TYPE_CHECK_IS_NULL], | 363 * See [HintCode.TYPE_CHECK_IS_NOT_NULL], [HintCode.TYPE_CHECK_IS_NULL], |
| 233 * [HintCode.UNNECESSARY_TYPE_CHECK_TRUE], and | 364 * [HintCode.UNNECESSARY_TYPE_CHECK_TRUE], and |
| 234 * [HintCode.UNNECESSARY_TYPE_CHECK_FALSE]. | 365 * [HintCode.UNNECESSARY_TYPE_CHECK_FALSE]. |
| 235 */ | 366 */ |
| 236 bool _checkAllTypeChecks(IsExpression node) { | 367 bool _checkAllTypeChecks(IsExpression node) { |
| 237 Expression expression = node.expression; | 368 Expression expression = node.expression; |
| 238 TypeName typeName = node.type; | 369 TypeName typeName = node.type; |
| 239 DartType lhsType = expression.staticType; | 370 DartType lhsType = expression.staticType; |
| 240 DartType rhsType = typeName.type; | 371 DartType rhsType = typeName.type; |
| 241 if (lhsType == null || rhsType == null) { | 372 if (lhsType == null || rhsType == null) { |
| 242 return false; | 373 return false; |
| 243 } | 374 } |
| 244 String rhsNameStr = typeName.name.name; | 375 String rhsNameStr = typeName.name.name; |
| 245 // if x is dynamic | 376 // if x is dynamic |
| 246 if (rhsType.isDynamic && rhsNameStr == sc.Keyword.DYNAMIC.syntax) { | 377 if (rhsType.isDynamic && rhsNameStr == Keyword.DYNAMIC.syntax) { |
| 247 if (node.notOperator == null) { | 378 if (node.notOperator == null) { |
| 248 // the is case | 379 // the is case |
| 249 _errorReporter.reportErrorForNode( | 380 _errorReporter.reportErrorForNode( |
| 250 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node); | 381 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node); |
| 251 } else { | 382 } else { |
| 252 // the is not case | 383 // the is not case |
| 253 _errorReporter.reportErrorForNode( | 384 _errorReporter.reportErrorForNode( |
| 254 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node); | 385 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node); |
| 255 } | 386 } |
| 256 return true; | 387 return true; |
| 257 } | 388 } |
| 258 Element rhsElement = rhsType.element; | 389 Element rhsElement = rhsType.element; |
| 259 LibraryElement libraryElement = | 390 LibraryElement libraryElement = rhsElement?.library; |
| 260 rhsElement != null ? rhsElement.library : null; | |
| 261 if (libraryElement != null && libraryElement.isDartCore) { | 391 if (libraryElement != null && libraryElement.isDartCore) { |
| 262 // if x is Object or null is Null | 392 // if x is Object or null is Null |
| 263 if (rhsType.isObject || | 393 if (rhsType.isObject || |
| 264 (expression is NullLiteral && rhsNameStr == _NULL_TYPE_NAME)) { | 394 (expression is NullLiteral && rhsNameStr == _NULL_TYPE_NAME)) { |
| 265 if (node.notOperator == null) { | 395 if (node.notOperator == null) { |
| 266 // the is case | 396 // the is case |
| 267 _errorReporter.reportErrorForNode( | 397 _errorReporter.reportErrorForNode( |
| 268 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node); | 398 HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node); |
| 269 } else { | 399 } else { |
| 270 // the is not case | 400 // the is not case |
| 271 _errorReporter.reportErrorForNode( | 401 _errorReporter.reportErrorForNode( |
| 272 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node); | 402 HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node); |
| 273 } | 403 } |
| 274 return true; | 404 return true; |
| 275 } else if (rhsNameStr == _NULL_TYPE_NAME) { | 405 } else if (rhsNameStr == _NULL_TYPE_NAME) { |
| 276 if (node.notOperator == null) { | 406 if (node.notOperator == null) { |
| 277 // the is case | 407 // the is case |
| 278 _errorReporter.reportErrorForNode(HintCode.TYPE_CHECK_IS_NULL, node); | 408 _errorReporter.reportErrorForNode(HintCode.TYPE_CHECK_IS_NULL, node); |
| 279 } else { | 409 } else { |
| 280 // the is not case | 410 // the is not case |
| 281 _errorReporter.reportErrorForNode( | 411 _errorReporter.reportErrorForNode( |
| 282 HintCode.TYPE_CHECK_IS_NOT_NULL, node); | 412 HintCode.TYPE_CHECK_IS_NOT_NULL, node); |
| 283 } | 413 } |
| 284 return true; | 414 return true; |
| 285 } | 415 } |
| 286 } | 416 } |
| 287 return false; | 417 return false; |
| 288 } | 418 } |
| 289 | 419 |
| 420 void _checkForAbstractSuperMemberReference( |
| 421 Expression target, SimpleIdentifier name) { |
| 422 if (target is SuperExpression) { |
| 423 Element element = name.staticElement; |
| 424 if (element is ExecutableElement && element.isAbstract) { |
| 425 if (!_enclosingClass.hasNoSuchMethod) { |
| 426 ExecutableElement concrete = null; |
| 427 if (element.kind == ElementKind.METHOD) { |
| 428 concrete = _enclosingClass.lookUpInheritedConcreteMethod( |
| 429 element.displayName, _currentLibrary); |
| 430 } else if (element.kind == ElementKind.GETTER) { |
| 431 concrete = _enclosingClass.lookUpInheritedConcreteGetter( |
| 432 element.displayName, _currentLibrary); |
| 433 } else if (element.kind == ElementKind.SETTER) { |
| 434 concrete = _enclosingClass.lookUpInheritedConcreteSetter( |
| 435 element.displayName, _currentLibrary); |
| 436 } |
| 437 if (concrete == null) { |
| 438 _errorReporter.reportTypeErrorForNode( |
| 439 HintCode.ABSTRACT_SUPER_MEMBER_REFERENCE, |
| 440 name, |
| 441 [element.kind.displayName, name.name]); |
| 442 } |
| 443 } |
| 444 } |
| 445 } |
| 446 } |
| 447 |
| 290 /** | 448 /** |
| 291 * This verifies that the passed expression can be assigned to its correspondi
ng parameters. | 449 * This verifies that the passed expression can be assigned to its correspondi
ng parameters. |
| 292 * | 450 * |
| 293 * This method corresponds to ErrorVerifier.checkForArgumentTypeNotAssignable. | 451 * This method corresponds to ErrorVerifier.checkForArgumentTypeNotAssignable. |
| 294 * | 452 * |
| 295 * TODO (jwren) In the ErrorVerifier there are other warnings that we could ha
ve a corresponding | 453 * TODO (jwren) In the ErrorVerifier there are other warnings that we could ha
ve a corresponding |
| 296 * hint for: see other callers of ErrorVerifier.checkForArgumentTypeNotAssigna
ble(..). | 454 * hint for: see other callers of ErrorVerifier.checkForArgumentTypeNotAssigna
ble(..). |
| 297 * | 455 * |
| 298 * @param expression the expression to evaluate | 456 * @param expression the expression to evaluate |
| 299 * @param expectedStaticType the expected static type of the parameter | 457 * @param expectedStaticType the expected static type of the parameter |
| (...skipping 18 matching lines...) Expand all Loading... |
| 318 if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) { | 476 if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) { |
| 319 // A warning was created in the ErrorVerifier, return false, don't | 477 // A warning was created in the ErrorVerifier, return false, don't |
| 320 // create a hint when a warning has already been created. | 478 // create a hint when a warning has already been created. |
| 321 return false; | 479 return false; |
| 322 } | 480 } |
| 323 } | 481 } |
| 324 // | 482 // |
| 325 // Hint case: test propagated type information | 483 // Hint case: test propagated type information |
| 326 // | 484 // |
| 327 // Compute the best types to use. | 485 // Compute the best types to use. |
| 328 DartType expectedBestType = expectedPropagatedType != null | 486 DartType expectedBestType = expectedPropagatedType ?? expectedStaticType; |
| 329 ? expectedPropagatedType | 487 DartType actualBestType = actualPropagatedType ?? actualStaticType; |
| 330 : expectedStaticType; | |
| 331 DartType actualBestType = | |
| 332 actualPropagatedType != null ? actualPropagatedType : actualStaticType; | |
| 333 if (actualBestType != null && expectedBestType != null) { | 488 if (actualBestType != null && expectedBestType != null) { |
| 334 if (!_typeSystem.isAssignableTo(actualBestType, expectedBestType)) { | 489 if (!_typeSystem.isAssignableTo(actualBestType, expectedBestType)) { |
| 335 _errorReporter.reportTypeErrorForNode( | 490 _errorReporter.reportTypeErrorForNode( |
| 336 hintCode, expression, [actualBestType, expectedBestType]); | 491 hintCode, expression, [actualBestType, expectedBestType]); |
| 337 return true; | 492 return true; |
| 338 } | 493 } |
| 339 } | 494 } |
| 340 return false; | 495 return false; |
| 341 } | 496 } |
| 342 | 497 |
| 343 /** | 498 /** |
| 344 * This verifies that the passed argument can be assigned to its corresponding
parameter. | 499 * This verifies that the passed argument can be assigned to its corresponding
parameter. |
| 345 * | 500 * |
| 346 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableForAr
gument. | 501 * This method corresponds to ErrorCode.checkForArgumentTypeNotAssignableForAr
gument. |
| 347 * | 502 * |
| 348 * @param argument the argument to evaluate | 503 * @param argument the argument to evaluate |
| 349 * @return `true` if and only if an hint code is generated on the passed node | 504 * @return `true` if and only if an hint code is generated on the passed node |
| 350 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. | 505 * See [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]. |
| 351 */ | 506 */ |
| 352 bool _checkForArgumentTypeNotAssignableForArgument(Expression argument) { | 507 bool _checkForArgumentTypeNotAssignableForArgument(Expression argument) { |
| 353 if (argument == null) { | 508 if (argument == null) { |
| 354 return false; | 509 return false; |
| 355 } | 510 } |
| 356 ParameterElement staticParameterElement = argument.staticParameterElement; | 511 ParameterElement staticParameterElement = argument.staticParameterElement; |
| 357 DartType staticParameterType = | 512 DartType staticParameterType = staticParameterElement?.type; |
| 358 staticParameterElement == null ? null : staticParameterElement.type; | |
| 359 ParameterElement propagatedParameterElement = | 513 ParameterElement propagatedParameterElement = |
| 360 argument.propagatedParameterElement; | 514 argument.propagatedParameterElement; |
| 361 DartType propagatedParameterType = propagatedParameterElement == null | 515 DartType propagatedParameterType = propagatedParameterElement?.type; |
| 362 ? null | |
| 363 : propagatedParameterElement.type; | |
| 364 return _checkForArgumentTypeNotAssignableWithExpectedTypes( | 516 return _checkForArgumentTypeNotAssignableWithExpectedTypes( |
| 365 argument, | 517 argument, |
| 366 staticParameterType, | 518 staticParameterType, |
| 367 propagatedParameterType, | 519 propagatedParameterType, |
| 368 HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); | 520 HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); |
| 369 } | 521 } |
| 370 | 522 |
| 371 /** | 523 /** |
| 372 * This verifies that the passed expression can be assigned to its correspondi
ng parameters. | 524 * This verifies that the passed expression can be assigned to its correspondi
ng parameters. |
| 373 * | 525 * |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 bool problemReported = false; | 560 bool problemReported = false; |
| 409 for (Expression argument in argumentList.arguments) { | 561 for (Expression argument in argumentList.arguments) { |
| 410 if (_checkForArgumentTypeNotAssignableForArgument(argument)) { | 562 if (_checkForArgumentTypeNotAssignableForArgument(argument)) { |
| 411 problemReported = true; | 563 problemReported = true; |
| 412 } | 564 } |
| 413 } | 565 } |
| 414 return problemReported; | 566 return problemReported; |
| 415 } | 567 } |
| 416 | 568 |
| 417 /** | 569 /** |
| 570 * Produce a hint if the given [target] could have a value of `null`, and |
| 571 * [identifier] is not a name of a getter or a method that exists in the |
| 572 * class [Null]. |
| 573 */ |
| 574 void _checkForCanBeNullAfterNullAware(Expression target, Token operator, |
| 575 SimpleIdentifier propertyName, SimpleIdentifier methodName) { |
| 576 if (operator?.type == TokenType.QUESTION_PERIOD) { |
| 577 return; |
| 578 } |
| 579 bool isNullTypeMember() { |
| 580 if (propertyName != null) { |
| 581 String name = propertyName.name; |
| 582 return _nullType.lookUpGetter(name, _currentLibrary) != null; |
| 583 } |
| 584 if (methodName != null) { |
| 585 String name = methodName.name; |
| 586 return _nullType.lookUpMethod(name, _currentLibrary) != null; |
| 587 } |
| 588 return false; |
| 589 } |
| 590 |
| 591 target = target?.unParenthesized; |
| 592 if (target is MethodInvocation) { |
| 593 if (target.operator?.type == TokenType.QUESTION_PERIOD && |
| 594 !isNullTypeMember()) { |
| 595 _errorReporter.reportErrorForNode( |
| 596 HintCode.CAN_BE_NULL_AFTER_NULL_AWARE, target); |
| 597 } |
| 598 } else if (target is PropertyAccess) { |
| 599 if (target.operator.type == TokenType.QUESTION_PERIOD && |
| 600 !isNullTypeMember()) { |
| 601 _errorReporter.reportErrorForNode( |
| 602 HintCode.CAN_BE_NULL_AFTER_NULL_AWARE, target); |
| 603 } |
| 604 } |
| 605 } |
| 606 |
| 607 /** |
| 418 * Given some [Element], look at the associated metadata and report the use of
the member if | 608 * Given some [Element], look at the associated metadata and report the use of
the member if |
| 419 * it is declared as deprecated. | 609 * it is declared as deprecated. |
| 420 * | 610 * |
| 421 * @param element some element to check for deprecated use of | 611 * @param element some element to check for deprecated use of |
| 422 * @param node the node use for the location of the error | 612 * @param node the node use for the location of the error |
| 423 * @return `true` if and only if a hint code is generated on the passed node | 613 * @return `true` if and only if a hint code is generated on the passed node |
| 424 * See [HintCode.DEPRECATED_MEMBER_USE]. | 614 * See [HintCode.DEPRECATED_MEMBER_USE]. |
| 425 */ | 615 */ |
| 426 bool _checkForDeprecatedMemberUse(Element element, AstNode node) { | 616 void _checkForDeprecatedMemberUse(Element element, AstNode node) { |
| 427 if (element != null && element.isDeprecated) { | 617 bool isDeprecated(Element element) { |
| 618 if (element == null) { |
| 619 return false; |
| 620 } else if (element is PropertyAccessorElement && element.isSynthetic) { |
| 621 // TODO(brianwilkerson) Why isn't this the implementation for PropertyAc
cessorElement? |
| 622 Element variable = element.variable; |
| 623 if (variable == null) { |
| 624 return false; |
| 625 } |
| 626 return variable.isDeprecated; |
| 627 } |
| 628 return element.isDeprecated; |
| 629 } |
| 630 |
| 631 if (!inDeprecatedMember && isDeprecated(element)) { |
| 428 String displayName = element.displayName; | 632 String displayName = element.displayName; |
| 429 if (element is ConstructorElement) { | 633 if (element is ConstructorElement) { |
| 430 // TODO(jwren) We should modify ConstructorElement.getDisplayName(), | 634 // TODO(jwren) We should modify ConstructorElement.getDisplayName(), |
| 431 // or have the logic centralized elsewhere, instead of doing this logic | 635 // or have the logic centralized elsewhere, instead of doing this logic |
| 432 // here. | 636 // here. |
| 433 ConstructorElement constructorElement = element; | 637 displayName = element.enclosingElement.displayName; |
| 434 displayName = constructorElement.enclosingElement.displayName; | 638 if (!element.displayName.isEmpty) { |
| 435 if (!constructorElement.displayName.isEmpty) { | 639 displayName = "$displayName.${element.displayName}"; |
| 436 displayName = "$displayName.${constructorElement.displayName}"; | |
| 437 } | 640 } |
| 641 } else if (displayName == FunctionElement.CALL_METHOD_NAME && |
| 642 node is MethodInvocation && |
| 643 node.staticInvokeType is InterfaceType) { |
| 644 displayName = |
| 645 "${node.staticInvokeType.displayName}.${element.displayName}"; |
| 438 } | 646 } |
| 439 _errorReporter.reportErrorForNode( | 647 _errorReporter.reportErrorForNode( |
| 440 HintCode.DEPRECATED_MEMBER_USE, node, [displayName]); | 648 HintCode.DEPRECATED_MEMBER_USE, node, [displayName]); |
| 441 return true; | |
| 442 } | 649 } |
| 443 return false; | |
| 444 } | 650 } |
| 445 | 651 |
| 446 /** | 652 /** |
| 447 * For [SimpleIdentifier]s, only call [checkForDeprecatedMemberUse] | 653 * For [SimpleIdentifier]s, only call [checkForDeprecatedMemberUse] |
| 448 * if the node is not in a declaration context. | 654 * if the node is not in a declaration context. |
| 449 * | 655 * |
| 450 * Also, if the identifier is a constructor name in a constructor invocation,
then calls to the | 656 * Also, if the identifier is a constructor name in a constructor invocation,
then calls to the |
| 451 * deprecated constructor will be caught by | 657 * deprecated constructor will be caught by |
| 452 * [visitInstanceCreationExpression] and | 658 * [visitInstanceCreationExpression] and |
| 453 * [visitSuperConstructorInvocation], and can be ignored by | 659 * [visitSuperConstructorInvocation], and can be ignored by |
| 454 * this visit method. | 660 * this visit method. |
| 455 * | 661 * |
| 456 * @param identifier some simple identifier to check for deprecated use of | 662 * @param identifier some simple identifier to check for deprecated use of |
| 457 * @return `true` if and only if a hint code is generated on the passed node | 663 * @return `true` if and only if a hint code is generated on the passed node |
| 458 * See [HintCode.DEPRECATED_MEMBER_USE]. | 664 * See [HintCode.DEPRECATED_MEMBER_USE]. |
| 459 */ | 665 */ |
| 460 bool _checkForDeprecatedMemberUseAtIdentifier(SimpleIdentifier identifier) { | 666 void _checkForDeprecatedMemberUseAtIdentifier(SimpleIdentifier identifier) { |
| 461 if (identifier.inDeclarationContext()) { | 667 if (identifier.inDeclarationContext()) { |
| 462 return false; | 668 return; |
| 463 } | 669 } |
| 464 AstNode parent = identifier.parent; | 670 AstNode parent = identifier.parent; |
| 465 if ((parent is ConstructorName && identical(identifier, parent.name)) || | 671 if ((parent is ConstructorName && identical(identifier, parent.name)) || |
| 672 (parent is ConstructorDeclaration && |
| 673 identical(identifier, parent.returnType)) || |
| 466 (parent is SuperConstructorInvocation && | 674 (parent is SuperConstructorInvocation && |
| 467 identical(identifier, parent.constructorName)) || | 675 identical(identifier, parent.constructorName)) || |
| 468 parent is HideCombinator) { | 676 parent is HideCombinator) { |
| 469 return false; | 677 return; |
| 470 } | 678 } |
| 471 return _checkForDeprecatedMemberUse(identifier.bestElement, identifier); | 679 _checkForDeprecatedMemberUse(identifier.bestElement, identifier); |
| 472 } | 680 } |
| 473 | 681 |
| 474 /** | 682 /** |
| 475 * Check for the passed binary expression for the [HintCode.DIVISION_OPTIMIZAT
ION]. | 683 * Check for the passed binary expression for the [HintCode.DIVISION_OPTIMIZAT
ION]. |
| 476 * | 684 * |
| 477 * @param node the binary expression to check | 685 * @param node the binary expression to check |
| 478 * @return `true` if and only if a hint code is generated on the passed node | 686 * @return `true` if and only if a hint code is generated on the passed node |
| 479 * See [HintCode.DIVISION_OPTIMIZATION]. | 687 * See [HintCode.DIVISION_OPTIMIZATION]. |
| 480 */ | 688 */ |
| 481 bool _checkForDivisionOptimizationHint(BinaryExpression node) { | 689 bool _checkForDivisionOptimizationHint(BinaryExpression node) { |
| 482 // Return if the operator is not '/' | 690 // Return if the operator is not '/' |
| 483 if (node.operator.type != sc.TokenType.SLASH) { | 691 if (node.operator.type != TokenType.SLASH) { |
| 484 return false; | 692 return false; |
| 485 } | 693 } |
| 486 // Return if the '/' operator is not defined in core, or if we don't know | 694 // Return if the '/' operator is not defined in core, or if we don't know |
| 487 // its static or propagated type | 695 // its static or propagated type |
| 488 MethodElement methodElement = node.bestElement; | 696 MethodElement methodElement = node.bestElement; |
| 489 if (methodElement == null) { | 697 if (methodElement == null) { |
| 490 return false; | 698 return false; |
| 491 } | 699 } |
| 492 LibraryElement libraryElement = methodElement.library; | 700 LibraryElement libraryElement = methodElement.library; |
| 493 if (libraryElement != null && !libraryElement.isDartCore) { | 701 if (libraryElement != null && !libraryElement.isDartCore) { |
| 494 return false; | 702 return false; |
| 495 } | 703 } |
| 496 // Report error if the (x/y) has toInt() invoked on it | 704 // Report error if the (x/y) has toInt() invoked on it |
| 497 if (node.parent is ParenthesizedExpression) { | 705 AstNode parent = node.parent; |
| 706 if (parent is ParenthesizedExpression) { |
| 498 ParenthesizedExpression parenthesizedExpression = | 707 ParenthesizedExpression parenthesizedExpression = |
| 499 _wrapParenthesizedExpression(node.parent as ParenthesizedExpression); | 708 _wrapParenthesizedExpression(parent); |
| 500 if (parenthesizedExpression.parent is MethodInvocation) { | 709 AstNode grandParent = parenthesizedExpression.parent; |
| 501 MethodInvocation methodInvocation = | 710 if (grandParent is MethodInvocation) { |
| 502 parenthesizedExpression.parent as MethodInvocation; | 711 if (_TO_INT_METHOD_NAME == grandParent.methodName.name && |
| 503 if (_TO_INT_METHOD_NAME == methodInvocation.methodName.name && | 712 grandParent.argumentList.arguments.isEmpty) { |
| 504 methodInvocation.argumentList.arguments.isEmpty) { | |
| 505 _errorReporter.reportErrorForNode( | 713 _errorReporter.reportErrorForNode( |
| 506 HintCode.DIVISION_OPTIMIZATION, methodInvocation); | 714 HintCode.DIVISION_OPTIMIZATION, grandParent); |
| 507 return true; | 715 return true; |
| 508 } | 716 } |
| 509 } | 717 } |
| 510 } | 718 } |
| 511 return false; | 719 return false; |
| 512 } | 720 } |
| 513 | 721 |
| 514 /** | 722 /** |
| 515 * This verifies that the passed left hand side and right hand side represent
a valid assignment. | 723 * This verifies that the passed left hand side and right hand side represent
a valid assignment. |
| 516 * | 724 * |
| (...skipping 22 matching lines...) Expand all Loading... |
| 539 if (leftType != null && bestRightType != null) { | 747 if (leftType != null && bestRightType != null) { |
| 540 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) { | 748 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) { |
| 541 _errorReporter.reportTypeErrorForNode( | 749 _errorReporter.reportTypeErrorForNode( |
| 542 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]); | 750 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]); |
| 543 return true; | 751 return true; |
| 544 } | 752 } |
| 545 } | 753 } |
| 546 return false; | 754 return false; |
| 547 } | 755 } |
| 548 | 756 |
| 757 void _checkForInvalidFactory(MethodDeclaration decl) { |
| 758 // Check declaration. |
| 759 // Note that null return types are expected to be flagged by other analyses. |
| 760 DartType returnType = decl.returnType?.type; |
| 761 if (returnType is VoidType) { |
| 762 _errorReporter.reportErrorForNode(HintCode.INVALID_FACTORY_METHOD_DECL, |
| 763 decl.name, [decl.name.toString()]); |
| 764 return; |
| 765 } |
| 766 |
| 767 // Check implementation. |
| 768 |
| 769 FunctionBody body = decl.body; |
| 770 if (body is EmptyFunctionBody) { |
| 771 // Abstract methods are OK. |
| 772 return; |
| 773 } |
| 774 |
| 775 // `new Foo()` or `null`. |
| 776 bool factoryExpression(Expression expression) => |
| 777 expression is InstanceCreationExpression || expression is NullLiteral; |
| 778 |
| 779 if (body is ExpressionFunctionBody && factoryExpression(body.expression)) { |
| 780 return; |
| 781 } else if (body is BlockFunctionBody) { |
| 782 NodeList<Statement> statements = body.block.statements; |
| 783 if (statements.isNotEmpty) { |
| 784 Statement last = statements.last; |
| 785 if (last is ReturnStatement && factoryExpression(last.expression)) { |
| 786 return; |
| 787 } |
| 788 } |
| 789 } |
| 790 |
| 791 _errorReporter.reportErrorForNode(HintCode.INVALID_FACTORY_METHOD_IMPL, |
| 792 decl.name, [decl.name.toString()]); |
| 793 } |
| 794 |
| 795 /** |
| 796 * Produces a hint if the given identifier is a protected closure, field or |
| 797 * getter/setter, method closure or invocation accessed outside a subclass. |
| 798 */ |
| 799 void _checkForInvalidProtectedMemberAccess(SimpleIdentifier identifier) { |
| 800 if (identifier.inDeclarationContext()) { |
| 801 return; |
| 802 } |
| 803 |
| 804 bool isProtected(Element element) { |
| 805 if (element is PropertyAccessorElement && |
| 806 element.enclosingElement is ClassElement && |
| 807 (element.isProtected || element.variable.isProtected)) { |
| 808 return true; |
| 809 } |
| 810 if (element is MethodElement && |
| 811 element.enclosingElement is ClassElement && |
| 812 element.isProtected) { |
| 813 return true; |
| 814 } |
| 815 return false; |
| 816 } |
| 817 |
| 818 bool inCommentReference(SimpleIdentifier identifier) => |
| 819 identifier.getAncestor((AstNode node) => node is CommentReference) != |
| 820 null; |
| 821 |
| 822 bool inCurrentLibrary(Element element) => |
| 823 element.library == _currentLibrary; |
| 824 |
| 825 Element element = identifier.bestElement; |
| 826 if (isProtected(element) && |
| 827 !inCurrentLibrary(element) && |
| 828 !inCommentReference(identifier)) { |
| 829 ClassElement definingClass = element.enclosingElement; |
| 830 ClassDeclaration accessingClass = |
| 831 identifier.getAncestor((AstNode node) => node is ClassDeclaration); |
| 832 if (accessingClass == null || |
| 833 !_hasTypeOrSuperType(accessingClass.element, definingClass.type)) { |
| 834 _errorReporter.reportErrorForNode( |
| 835 HintCode.INVALID_USE_OF_PROTECTED_MEMBER, |
| 836 identifier, |
| 837 [identifier.name.toString(), definingClass.name]); |
| 838 } |
| 839 } |
| 840 } |
| 841 |
| 549 /** | 842 /** |
| 550 * Check that the imported library does not define a loadLibrary function. The
import has already | 843 * Check that the imported library does not define a loadLibrary function. The
import has already |
| 551 * been determined to be deferred when this is called. | 844 * been determined to be deferred when this is called. |
| 552 * | 845 * |
| 553 * @param node the import directive to evaluate | 846 * @param node the import directive to evaluate |
| 554 * @param importElement the [ImportElement] retrieved from the node | 847 * @param importElement the [ImportElement] retrieved from the node |
| 555 * @return `true` if and only if an error code is generated on the passed node | 848 * @return `true` if and only if an error code is generated on the passed node |
| 556 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION]. | 849 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION]. |
| 557 */ | 850 */ |
| 558 bool _checkForLoadLibraryFunction( | 851 bool _checkForLoadLibraryFunction( |
| (...skipping 18 matching lines...) Expand all Loading... |
| 577 * `null`, avoiding these implicit returns is considered a best practice. | 870 * `null`, avoiding these implicit returns is considered a best practice. |
| 578 * | 871 * |
| 579 * Note: for async functions/methods, this hint only applies when the | 872 * Note: for async functions/methods, this hint only applies when the |
| 580 * function has a return type that Future<Null> is not assignable to. | 873 * function has a return type that Future<Null> is not assignable to. |
| 581 * | 874 * |
| 582 * @param node the binary expression to check | 875 * @param node the binary expression to check |
| 583 * @param body the function body | 876 * @param body the function body |
| 584 * @return `true` if and only if a hint code is generated on the passed node | 877 * @return `true` if and only if a hint code is generated on the passed node |
| 585 * See [HintCode.MISSING_RETURN]. | 878 * See [HintCode.MISSING_RETURN]. |
| 586 */ | 879 */ |
| 587 bool _checkForMissingReturn(TypeName returnType, FunctionBody body) { | 880 void _checkForMissingReturn(TypeName returnType, FunctionBody body) { |
| 588 // Check that the method or function has a return type, and a function body | 881 // Check that the method or function has a return type, and a function body |
| 589 if (returnType == null || body == null) { | 882 if (returnType == null || body == null) { |
| 590 return false; | 883 return; |
| 591 } | 884 } |
| 592 // Check that the body is a BlockFunctionBody | 885 // Check that the body is a BlockFunctionBody |
| 593 if (body is! BlockFunctionBody) { | 886 if (body is BlockFunctionBody) { |
| 594 return false; | 887 // Generators are never required to have a return statement. |
| 888 if (body.isGenerator) { |
| 889 return; |
| 890 } |
| 891 // Check that the type is resolvable, and is not "void" |
| 892 DartType returnTypeType = returnType.type; |
| 893 if (returnTypeType == null || returnTypeType.isVoid) { |
| 894 return; |
| 895 } |
| 896 // For async, give no hint if Future<Null> is assignable to the return |
| 897 // type. |
| 898 if (body.isAsynchronous && |
| 899 _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) { |
| 900 return; |
| 901 } |
| 902 // Check the block for a return statement, if not, create the hint |
| 903 if (!ExitDetector.exits(body)) { |
| 904 _errorReporter.reportErrorForNode( |
| 905 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]); |
| 906 } |
| 595 } | 907 } |
| 596 // Generators are never required to have a return statement. | |
| 597 if (body.isGenerator) { | |
| 598 return false; | |
| 599 } | |
| 600 // Check that the type is resolvable, and is not "void" | |
| 601 DartType returnTypeType = returnType.type; | |
| 602 if (returnTypeType == null || returnTypeType.isVoid) { | |
| 603 return false; | |
| 604 } | |
| 605 // For async, give no hint if Future<Null> is assignable to the return | |
| 606 // type. | |
| 607 if (body.isAsynchronous && | |
| 608 _typeSystem.isAssignableTo(_futureNullType, returnTypeType)) { | |
| 609 return false; | |
| 610 } | |
| 611 // Check the block for a return statement, if not, create the hint | |
| 612 BlockFunctionBody blockFunctionBody = body as BlockFunctionBody; | |
| 613 if (!ExitDetector.exits(blockFunctionBody)) { | |
| 614 _errorReporter.reportErrorForNode( | |
| 615 HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]); | |
| 616 return true; | |
| 617 } | |
| 618 return false; | |
| 619 } | 908 } |
| 620 | 909 |
| 621 /** | 910 /** |
| 622 * Check for the passed class declaration for the | 911 * Produce a hint if the given [condition] could have a value of `null`. |
| 623 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. | |
| 624 * | |
| 625 * @param node the class declaration to check | |
| 626 * @return `true` if and only if a hint code is generated on the passed node | |
| 627 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE]. | |
| 628 */ | 912 */ |
| 629 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { | 913 void _checkForPossibleNullCondition(Expression condition) { |
| 630 // ClassElement classElement = node.element; | 914 condition = condition?.unParenthesized; |
| 631 // if (classElement == null) { | 915 if (condition is BinaryExpression) { |
| 632 // return false; | 916 _checkForPossibleNullConditionInBinaryExpression(condition); |
| 633 // } | 917 } else if (condition is PrefixExpression) { |
| 634 // MethodElement equalsOperatorMethodElement = | 918 _checkForPossibleNullConditionInPrefixExpression(condition); |
| 635 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme); | 919 } else { |
| 636 // if (equalsOperatorMethodElement != null) { | 920 _checkForPossibleNullConditionInSimpleExpression(condition); |
| 637 // PropertyAccessorElement hashCodeElement = | 921 } |
| 638 // classElement.getGetter(_HASHCODE_GETTER_NAME); | 922 } |
| 639 // if (hashCodeElement == null) { | 923 |
| 640 // _errorReporter.reportErrorForNode( | 924 /** |
| 641 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, | 925 * Produce a hint if any of the parts of the given binary [condition] could |
| 642 // node.name, | 926 * have a value of `null`. |
| 643 // [classElement.displayName]); | 927 */ |
| 644 // return true; | 928 void _checkForPossibleNullConditionInBinaryExpression( |
| 645 // } | 929 BinaryExpression condition) { |
| 646 // } | 930 TokenType type = condition.operator?.type; |
| 647 // return false; | 931 if (type == TokenType.AMPERSAND_AMPERSAND || type == TokenType.BAR_BAR) { |
| 648 // } | 932 _checkForPossibleNullCondition(condition.leftOperand); |
| 933 _checkForPossibleNullCondition(condition.rightOperand); |
| 934 } |
| 935 } |
| 936 |
| 937 /** |
| 938 * Produce a hint if the operand of the given prefix [condition] could |
| 939 * have a value of `null`. |
| 940 */ |
| 941 void _checkForPossibleNullConditionInPrefixExpression( |
| 942 PrefixExpression condition) { |
| 943 if (condition.operator?.type == TokenType.BANG) { |
| 944 _checkForPossibleNullCondition(condition.operand); |
| 945 } |
| 946 } |
| 947 |
| 948 /** |
| 949 * Produce a hint if the given [condition] could have a value of `null`. |
| 950 */ |
| 951 void _checkForPossibleNullConditionInSimpleExpression(Expression condition) { |
| 952 if (condition is MethodInvocation) { |
| 953 if (condition.operator?.type == TokenType.QUESTION_PERIOD) { |
| 954 _errorReporter.reportErrorForNode( |
| 955 HintCode.NULL_AWARE_IN_CONDITION, condition); |
| 956 } |
| 957 } else if (condition is PropertyAccess) { |
| 958 if (condition.operator?.type == TokenType.QUESTION_PERIOD) { |
| 959 _errorReporter.reportErrorForNode( |
| 960 HintCode.NULL_AWARE_IN_CONDITION, condition); |
| 961 } |
| 962 } |
| 963 } |
| 649 | 964 |
| 650 /** | 965 /** |
| 651 * Check for the passed as expression for the [HintCode.UNNECESSARY_CAST] hint
code. | 966 * Check for the passed as expression for the [HintCode.UNNECESSARY_CAST] hint
code. |
| 652 * | 967 * |
| 653 * @param node the as expression to check | 968 * @param node the as expression to check |
| 654 * @return `true` if and only if a hint code is generated on the passed node | 969 * @return `true` if and only if a hint code is generated on the passed node |
| 655 * See [HintCode.UNNECESSARY_CAST]. | 970 * See [HintCode.UNNECESSARY_CAST]. |
| 656 */ | 971 */ |
| 657 bool _checkForUnnecessaryCast(AsExpression node) { | 972 bool _checkForUnnecessaryCast(AsExpression node) { |
| 658 // TODO(jwren) After dartbug.com/13732, revisit this, we should be able to | 973 // TODO(jwren) After dartbug.com/13732, revisit this, we should be able to |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 690 !lhsType.isDynamic && | 1005 !lhsType.isDynamic && |
| 691 !rhsType.isDynamic && | 1006 !rhsType.isDynamic && |
| 692 lhsType.isMoreSpecificThan(rhsType)) { | 1007 lhsType.isMoreSpecificThan(rhsType)) { |
| 693 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node); | 1008 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node); |
| 694 return true; | 1009 return true; |
| 695 } | 1010 } |
| 696 return false; | 1011 return false; |
| 697 } | 1012 } |
| 698 | 1013 |
| 699 /** | 1014 /** |
| 700 * Check for situations where the result of a method or function is used, when
it returns 'void'. | 1015 * Generate a hint for `noSuchMethod` methods that do nothing except of |
| 1016 * calling another `noSuchMethod` that is not defined by `Object`. |
| 701 * | 1017 * |
| 702 * TODO(jwren) Many other situations of use could be covered. We currently cov
er the cases var x = | 1018 * @return `true` if and only if a hint code is generated on the passed node |
| 703 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m
(), f(m()), return | 1019 * See [HintCode.UNNECESSARY_NO_SUCH_METHOD]. |
| 704 * m(). | 1020 */ |
| 1021 bool _checkForUnnecessaryNoSuchMethod(MethodDeclaration node) { |
| 1022 if (node.name.name != FunctionElement.NO_SUCH_METHOD_METHOD_NAME) { |
| 1023 return false; |
| 1024 } |
| 1025 bool isNonObjectNoSuchMethodInvocation(Expression invocation) { |
| 1026 if (invocation is MethodInvocation && |
| 1027 invocation.target is SuperExpression && |
| 1028 invocation.argumentList.arguments.length == 1) { |
| 1029 SimpleIdentifier name = invocation.methodName; |
| 1030 if (name.name == FunctionElement.NO_SUCH_METHOD_METHOD_NAME) { |
| 1031 Element methodElement = name.staticElement; |
| 1032 Element classElement = methodElement?.enclosingElement; |
| 1033 return methodElement is MethodElement && |
| 1034 classElement is ClassElement && |
| 1035 !classElement.type.isObject; |
| 1036 } |
| 1037 } |
| 1038 return false; |
| 1039 } |
| 1040 |
| 1041 FunctionBody body = node.body; |
| 1042 if (body is ExpressionFunctionBody) { |
| 1043 if (isNonObjectNoSuchMethodInvocation(body.expression)) { |
| 1044 _errorReporter.reportErrorForNode( |
| 1045 HintCode.UNNECESSARY_NO_SUCH_METHOD, node); |
| 1046 return true; |
| 1047 } |
| 1048 } else if (body is BlockFunctionBody) { |
| 1049 List<Statement> statements = body.block.statements; |
| 1050 if (statements.length == 1) { |
| 1051 Statement returnStatement = statements.first; |
| 1052 if (returnStatement is ReturnStatement && |
| 1053 isNonObjectNoSuchMethodInvocation(returnStatement.expression)) { |
| 1054 _errorReporter.reportErrorForNode( |
| 1055 HintCode.UNNECESSARY_NO_SUCH_METHOD, node); |
| 1056 return true; |
| 1057 } |
| 1058 } |
| 1059 } |
| 1060 return false; |
| 1061 } |
| 1062 |
| 1063 /** |
| 1064 * Check for situations where the result of a method or function is used, when |
| 1065 * it returns 'void'. |
| 705 * | 1066 * |
| 706 * @param node expression on the RHS of some assignment | |
| 707 * @return `true` if and only if a hint code is generated on the passed node | |
| 708 * See [HintCode.USE_OF_VOID_RESULT]. | 1067 * See [HintCode.USE_OF_VOID_RESULT]. |
| 709 */ | 1068 */ |
| 710 bool _checkForUseOfVoidResult(Expression expression) { | 1069 void _checkForUseOfVoidResult(Expression expression) { |
| 711 if (expression == null || expression is! MethodInvocation) { | 1070 // TODO(jwren) Many other situations of use could be covered. We currently |
| 1071 // cover the cases var x = m() and x = m(), but we could also cover cases |
| 1072 // such as m().x, m()[k], a + m(), f(m()), return m(). |
| 1073 if (expression is MethodInvocation) { |
| 1074 if (identical(expression.staticType, VoidTypeImpl.instance)) { |
| 1075 SimpleIdentifier methodName = expression.methodName; |
| 1076 _errorReporter.reportErrorForNode( |
| 1077 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); |
| 1078 } |
| 1079 } |
| 1080 } |
| 1081 |
| 1082 /** |
| 1083 * Check for the passed class declaration for the |
| 1084 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. |
| 1085 * |
| 1086 * @param node the class declaration to check |
| 1087 * @return `true` if and only if a hint code is generated on the passed node |
| 1088 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE]. |
| 1089 */ |
| 1090 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { |
| 1091 // ClassElement classElement = node.element; |
| 1092 // if (classElement == null) { |
| 1093 // return false; |
| 1094 // } |
| 1095 // MethodElement equalsOperatorMethodElement = |
| 1096 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme); |
| 1097 // if (equalsOperatorMethodElement != null) { |
| 1098 // PropertyAccessorElement hashCodeElement = |
| 1099 // classElement.getGetter(_HASHCODE_GETTER_NAME); |
| 1100 // if (hashCodeElement == null) { |
| 1101 // _errorReporter.reportErrorForNode( |
| 1102 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE, |
| 1103 // node.name, |
| 1104 // [classElement.displayName]); |
| 1105 // return true; |
| 1106 // } |
| 1107 // } |
| 1108 // return false; |
| 1109 // } |
| 1110 |
| 1111 bool _hasTypeOrSuperType(ClassElement element, InterfaceType type) { |
| 1112 if (element == null) { |
| 712 return false; | 1113 return false; |
| 713 } | 1114 } |
| 714 MethodInvocation methodInvocation = expression as MethodInvocation; | 1115 ClassElement typeElement = type.element; |
| 715 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) { | 1116 return element == typeElement || |
| 716 SimpleIdentifier methodName = methodInvocation.methodName; | 1117 element.allSupertypes |
| 717 _errorReporter.reportErrorForNode( | 1118 .any((InterfaceType t) => t.element == typeElement); |
| 718 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); | |
| 719 return true; | |
| 720 } | |
| 721 return false; | |
| 722 } | 1119 } |
| 723 | 1120 |
| 724 /** | 1121 /** |
| 725 * Given a parenthesized expression, this returns the parent (or recursively g
rand-parent) of the | 1122 * Given a parenthesized expression, this returns the parent (or recursively g
rand-parent) of the |
| 726 * expression that is a parenthesized expression, but whose parent is not a pa
renthesized | 1123 * expression that is a parenthesized expression, but whose parent is not a pa
renthesized |
| 727 * expression. | 1124 * expression. |
| 728 * | 1125 * |
| 729 * For example given the code `(((e)))`: `(e) -> (((e)))`. | 1126 * For example given the code `(((e)))`: `(e) -> (((e)))`. |
| 730 * | 1127 * |
| 731 * @param parenthesizedExpression some expression whose parent is a parenthesi
zed expression | 1128 * @param parenthesizedExpression some expression whose parent is a parenthesi
zed expression |
| 732 * @return the first parent or grand-parent that is a parenthesized expression
, that does not have | 1129 * @return the first parent or grand-parent that is a parenthesized expression
, that does not have |
| 733 * a parenthesized expression parent | 1130 * a parenthesized expression parent |
| 734 */ | 1131 */ |
| 735 static ParenthesizedExpression _wrapParenthesizedExpression( | 1132 static ParenthesizedExpression _wrapParenthesizedExpression( |
| 736 ParenthesizedExpression parenthesizedExpression) { | 1133 ParenthesizedExpression parenthesizedExpression) { |
| 737 if (parenthesizedExpression.parent is ParenthesizedExpression) { | 1134 AstNode parent = parenthesizedExpression.parent; |
| 738 return _wrapParenthesizedExpression( | 1135 if (parent is ParenthesizedExpression) { |
| 739 parenthesizedExpression.parent as ParenthesizedExpression); | 1136 return _wrapParenthesizedExpression(parent); |
| 740 } | 1137 } |
| 741 return parenthesizedExpression; | 1138 return parenthesizedExpression; |
| 742 } | 1139 } |
| 743 } | 1140 } |
| 744 | 1141 |
| 745 /** | 1142 /** |
| 746 * Instances of the class `ClassScope` implement the scope defined by a class. | 1143 * Utilities for [LibraryElementImpl] building. |
| 747 */ | 1144 */ |
| 748 class ClassScope extends EnclosedScope { | 1145 class BuildLibraryElementUtils { |
| 749 /** | 1146 /** |
| 750 * Initialize a newly created scope enclosed within another scope. | 1147 * Look through all of the compilation units defined for the given [library], |
| 751 * | 1148 * looking for getters and setters that are defined in different compilation |
| 752 * @param enclosingScope the scope in which this scope is lexically enclosed | 1149 * units but that have the same names. If any are found, make sure that they |
| 753 * @param typeElement the element representing the type represented by this sc
ope | 1150 * have the same variable element. |
| 754 */ | 1151 */ |
| 755 ClassScope(Scope enclosingScope, ClassElement typeElement) | 1152 static void patchTopLevelAccessors(LibraryElementImpl library) { |
| 756 : super(enclosingScope) { | 1153 // Without parts getters/setters already share the same variable element. |
| 757 if (typeElement == null) { | 1154 List<CompilationUnitElement> parts = library.parts; |
| 758 throw new IllegalArgumentException("class element cannot be null"); | 1155 if (parts.isEmpty) { |
| 1156 return; |
| 759 } | 1157 } |
| 760 _defineMembers(typeElement); | 1158 // Collect getters and setters. |
| 761 } | 1159 HashMap<String, PropertyAccessorElement> getters = |
| 762 | 1160 new HashMap<String, PropertyAccessorElement>(); |
| 763 @override | 1161 List<PropertyAccessorElement> setters = <PropertyAccessorElement>[]; |
| 764 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { | 1162 _collectAccessors(getters, setters, library.definingCompilationUnit); |
| 765 if (existing is PropertyAccessorElement && duplicate is MethodElement) { | 1163 int partLength = parts.length; |
| 766 if (existing.nameOffset < duplicate.nameOffset) { | 1164 for (int i = 0; i < partLength; i++) { |
| 767 return new AnalysisError( | 1165 CompilationUnitElement unit = parts[i]; |
| 768 duplicate.source, | 1166 _collectAccessors(getters, setters, unit); |
| 769 duplicate.nameOffset, | 1167 } |
| 770 duplicate.nameLength, | 1168 // Move every setter to the corresponding getter's variable (if exists). |
| 771 CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME, | 1169 int setterLength = setters.length; |
| 772 [existing.displayName]); | 1170 for (int j = 0; j < setterLength; j++) { |
| 773 } else { | 1171 PropertyAccessorElement setter = setters[j]; |
| 774 return new AnalysisError( | 1172 PropertyAccessorElement getter = getters[setter.displayName]; |
| 775 existing.source, | 1173 if (getter != null) { |
| 776 existing.nameOffset, | 1174 TopLevelVariableElementImpl variable = getter.variable; |
| 777 existing.nameLength, | 1175 TopLevelVariableElementImpl setterVariable = setter.variable; |
| 778 CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME, | 1176 CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement; |
| 779 [existing.displayName]); | 1177 setterUnit.replaceTopLevelVariable(setterVariable, variable); |
| 1178 variable.setter = setter; |
| 1179 (setter as PropertyAccessorElementImpl).variable = variable; |
| 780 } | 1180 } |
| 781 } | 1181 } |
| 782 return super.getErrorForDuplicate(existing, duplicate); | |
| 783 } | 1182 } |
| 784 | 1183 |
| 785 /** | 1184 /** |
| 786 * Define the instance members defined by the class. | 1185 * Add all of the non-synthetic [getters] and [setters] defined in the given |
| 787 * | 1186 * [unit] that have no corresponding accessor to one of the given collections. |
| 788 * @param typeElement the element representing the type represented by this sc
ope | |
| 789 */ | 1187 */ |
| 790 void _defineMembers(ClassElement typeElement) { | 1188 static void _collectAccessors(Map<String, PropertyAccessorElement> getters, |
| 791 for (PropertyAccessorElement accessor in typeElement.accessors) { | 1189 List<PropertyAccessorElement> setters, CompilationUnitElement unit) { |
| 792 define(accessor); | 1190 List<PropertyAccessorElement> accessors = unit.accessors; |
| 793 } | 1191 int length = accessors.length; |
| 794 for (MethodElement method in typeElement.methods) { | 1192 for (int i = 0; i < length; i++) { |
| 795 define(method); | 1193 PropertyAccessorElement accessor = accessors[i]; |
| 1194 if (accessor.isGetter) { |
| 1195 if (!accessor.isSynthetic && accessor.correspondingSetter == null) { |
| 1196 getters[accessor.displayName] = accessor; |
| 1197 } |
| 1198 } else { |
| 1199 if (!accessor.isSynthetic && accessor.correspondingGetter == null) { |
| 1200 setters.add(accessor); |
| 1201 } |
| 1202 } |
| 796 } | 1203 } |
| 797 } | 1204 } |
| 798 } | 1205 } |
| 799 | 1206 |
| 800 /** | |
| 801 * A `CompilationUnitBuilder` builds an element model for a single compilation | |
| 802 * unit. | |
| 803 */ | |
| 804 class CompilationUnitBuilder { | |
| 805 /** | |
| 806 * Build the compilation unit element for the given [source] based on the | |
| 807 * compilation [unit] associated with the source. Throw an AnalysisException | |
| 808 * if the element could not be built. [librarySource] is the source for the | |
| 809 * containing library. | |
| 810 */ | |
| 811 CompilationUnitElementImpl buildCompilationUnit( | |
| 812 Source source, CompilationUnit unit, Source librarySource) { | |
| 813 return PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 814 if (unit == null) { | |
| 815 return null; | |
| 816 } | |
| 817 ElementHolder holder = new ElementHolder(); | |
| 818 ElementBuilder builder = new ElementBuilder(holder); | |
| 819 unit.accept(builder); | |
| 820 CompilationUnitElementImpl element = | |
| 821 new CompilationUnitElementImpl(source.shortName); | |
| 822 element.accessors = holder.accessors; | |
| 823 element.enums = holder.enums; | |
| 824 element.functions = holder.functions; | |
| 825 element.source = source; | |
| 826 element.librarySource = librarySource; | |
| 827 element.typeAliases = holder.typeAliases; | |
| 828 element.types = holder.types; | |
| 829 element.topLevelVariables = holder.topLevelVariables; | |
| 830 unit.element = element; | |
| 831 holder.validate(); | |
| 832 return element; | |
| 833 }); | |
| 834 } | |
| 835 } | |
| 836 | |
| 837 /** | 1207 /** |
| 838 * Instances of the class `ConstantVerifier` traverse an AST structure looking f
or additional | 1208 * Instances of the class `ConstantVerifier` traverse an AST structure looking f
or additional |
| 839 * errors and warnings not covered by the parser and resolver. In particular, it
looks for errors | 1209 * errors and warnings not covered by the parser and resolver. In particular, it
looks for errors |
| 840 * and warnings related to constant expressions. | 1210 * and warnings related to constant expressions. |
| 841 */ | 1211 */ |
| 842 class ConstantVerifier extends RecursiveAstVisitor<Object> { | 1212 class ConstantVerifier extends RecursiveAstVisitor<Object> { |
| 843 /** | 1213 /** |
| 844 * The error reporter by which errors will be reported. | 1214 * The error reporter by which errors will be reported. |
| 845 */ | 1215 */ |
| 846 final ErrorReporter _errorReporter; | 1216 final ErrorReporter _errorReporter; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 899 this._numType = _typeProvider.numType; | 1269 this._numType = _typeProvider.numType; |
| 900 this._stringType = _typeProvider.stringType; | 1270 this._stringType = _typeProvider.stringType; |
| 901 } | 1271 } |
| 902 | 1272 |
| 903 @override | 1273 @override |
| 904 Object visitAnnotation(Annotation node) { | 1274 Object visitAnnotation(Annotation node) { |
| 905 super.visitAnnotation(node); | 1275 super.visitAnnotation(node); |
| 906 // check annotation creation | 1276 // check annotation creation |
| 907 Element element = node.element; | 1277 Element element = node.element; |
| 908 if (element is ConstructorElement) { | 1278 if (element is ConstructorElement) { |
| 909 ConstructorElement constructorElement = element; | 1279 // should be 'const' constructor |
| 910 // should 'const' constructor | 1280 if (!element.isConst) { |
| 911 if (!constructorElement.isConst) { | |
| 912 _errorReporter.reportErrorForNode( | 1281 _errorReporter.reportErrorForNode( |
| 913 CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node); | 1282 CompileTimeErrorCode.NON_CONSTANT_ANNOTATION_CONSTRUCTOR, node); |
| 914 return null; | 1283 return null; |
| 915 } | 1284 } |
| 916 // should have arguments | 1285 // should have arguments |
| 917 ArgumentList argumentList = node.arguments; | 1286 ArgumentList argumentList = node.arguments; |
| 918 if (argumentList == null) { | 1287 if (argumentList == null) { |
| 919 _errorReporter.reportErrorForNode( | 1288 _errorReporter.reportErrorForNode( |
| 920 CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node); | 1289 CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS, node); |
| 921 return null; | 1290 return null; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 969 | 1338 |
| 970 @override | 1339 @override |
| 971 Object visitListLiteral(ListLiteral node) { | 1340 Object visitListLiteral(ListLiteral node) { |
| 972 super.visitListLiteral(node); | 1341 super.visitListLiteral(node); |
| 973 if (node.constKeyword != null) { | 1342 if (node.constKeyword != null) { |
| 974 DartObjectImpl result; | 1343 DartObjectImpl result; |
| 975 for (Expression element in node.elements) { | 1344 for (Expression element in node.elements) { |
| 976 result = | 1345 result = |
| 977 _validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT); | 1346 _validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT); |
| 978 if (result != null) { | 1347 if (result != null) { |
| 979 _reportErrorIfFromDeferredLibrary(element, | 1348 _reportErrorIfFromDeferredLibrary( |
| 980 CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRA
RY); | 1349 element, |
| 1350 CompileTimeErrorCode |
| 1351 .NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY); |
| 981 } | 1352 } |
| 982 } | 1353 } |
| 983 } | 1354 } |
| 984 return null; | 1355 return null; |
| 985 } | 1356 } |
| 986 | 1357 |
| 987 @override | 1358 @override |
| 988 Object visitMapLiteral(MapLiteral node) { | 1359 Object visitMapLiteral(MapLiteral node) { |
| 989 super.visitMapLiteral(node); | 1360 super.visitMapLiteral(node); |
| 990 bool isConst = node.constKeyword != null; | 1361 bool isConst = node.constKeyword != null; |
| 991 bool reportEqualKeys = true; | 1362 bool reportEqualKeys = true; |
| 992 HashSet<DartObject> keys = new HashSet<DartObject>(); | 1363 HashSet<DartObject> keys = new HashSet<DartObject>(); |
| 993 List<Expression> invalidKeys = new List<Expression>(); | 1364 List<Expression> invalidKeys = new List<Expression>(); |
| 994 for (MapLiteralEntry entry in node.entries) { | 1365 for (MapLiteralEntry entry in node.entries) { |
| 995 Expression key = entry.key; | 1366 Expression key = entry.key; |
| 996 if (isConst) { | 1367 if (isConst) { |
| 997 DartObjectImpl keyResult = | 1368 DartObjectImpl keyResult = |
| 998 _validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY); | 1369 _validate(key, CompileTimeErrorCode.NON_CONSTANT_MAP_KEY); |
| 999 Expression valueExpression = entry.value; | 1370 Expression valueExpression = entry.value; |
| 1000 DartObjectImpl valueResult = _validate( | 1371 DartObjectImpl valueResult = _validate( |
| 1001 valueExpression, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE); | 1372 valueExpression, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE); |
| 1002 if (valueResult != null) { | 1373 if (valueResult != null) { |
| 1003 _reportErrorIfFromDeferredLibrary(valueExpression, | 1374 _reportErrorIfFromDeferredLibrary( |
| 1004 CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY)
; | 1375 valueExpression, |
| 1376 CompileTimeErrorCode |
| 1377 .NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY); |
| 1005 } | 1378 } |
| 1006 if (keyResult != null) { | 1379 if (keyResult != null) { |
| 1007 _reportErrorIfFromDeferredLibrary(key, | 1380 _reportErrorIfFromDeferredLibrary(key, |
| 1008 CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY); | 1381 CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY); |
| 1009 if (keys.contains(keyResult)) { | 1382 if (keys.contains(keyResult)) { |
| 1010 invalidKeys.add(key); | 1383 invalidKeys.add(key); |
| 1011 } else { | 1384 } else { |
| 1012 keys.add(keyResult); | 1385 keys.add(keyResult); |
| 1013 } | 1386 } |
| 1014 DartType type = keyResult.type; | 1387 DartType type = keyResult.type; |
| 1015 if (_implementsEqualsWhenNotAllowed(type)) { | 1388 if (_implementsEqualsWhenNotAllowed(type)) { |
| 1016 _errorReporter.reportErrorForNode( | 1389 _errorReporter.reportErrorForNode( |
| 1017 CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQ
UALS, | 1390 CompileTimeErrorCode |
| 1391 .CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS, |
| 1018 key, | 1392 key, |
| 1019 [type.displayName]); | 1393 [type.displayName]); |
| 1020 } | 1394 } |
| 1021 } | 1395 } |
| 1022 } else { | 1396 } else { |
| 1023 // Note: we throw the errors away because this isn't actually a const. | 1397 // Note: we throw the errors away because this isn't actually a const. |
| 1024 AnalysisErrorListener errorListener = | 1398 AnalysisErrorListener errorListener = |
| 1025 AnalysisErrorListener.NULL_LISTENER; | 1399 AnalysisErrorListener.NULL_LISTENER; |
| 1026 ErrorReporter subErrorReporter = | 1400 ErrorReporter subErrorReporter = |
| 1027 new ErrorReporter(errorListener, _errorReporter.source); | 1401 new ErrorReporter(errorListener, _errorReporter.source); |
| 1028 DartObjectImpl result = key.accept(new ConstantVisitor( | 1402 DartObjectImpl result = key.accept(new ConstantVisitor( |
| 1029 new ConstantEvaluationEngine(_typeProvider, declaredVariables, | 1403 new ConstantEvaluationEngine(_typeProvider, declaredVariables, |
| 1030 typeSystem: _typeSystem), | 1404 typeSystem: _typeSystem), |
| 1031 subErrorReporter)); | 1405 subErrorReporter)); |
| 1032 if (result != null) { | 1406 if (result != null) { |
| 1033 if (keys.contains(result)) { | 1407 if (keys.contains(result)) { |
| 1034 invalidKeys.add(key); | 1408 invalidKeys.add(key); |
| 1035 } else { | 1409 } else { |
| 1036 keys.add(result); | 1410 keys.add(result); |
| 1037 } | 1411 } |
| 1038 } else { | 1412 } else { |
| 1039 reportEqualKeys = false; | 1413 reportEqualKeys = false; |
| 1040 } | 1414 } |
| 1041 } | 1415 } |
| 1042 } | 1416 } |
| 1043 if (reportEqualKeys) { | 1417 if (reportEqualKeys) { |
| 1044 for (Expression key in invalidKeys) { | 1418 int length = invalidKeys.length; |
| 1419 for (int i = 0; i < length; i++) { |
| 1045 _errorReporter.reportErrorForNode( | 1420 _errorReporter.reportErrorForNode( |
| 1046 StaticWarningCode.EQUAL_KEYS_IN_MAP, key); | 1421 StaticWarningCode.EQUAL_KEYS_IN_MAP, invalidKeys[i]); |
| 1047 } | 1422 } |
| 1048 } | 1423 } |
| 1049 return null; | 1424 return null; |
| 1050 } | 1425 } |
| 1051 | 1426 |
| 1052 @override | 1427 @override |
| 1053 Object visitMethodDeclaration(MethodDeclaration node) { | 1428 Object visitMethodDeclaration(MethodDeclaration node) { |
| 1054 super.visitMethodDeclaration(node); | 1429 super.visitMethodDeclaration(node); |
| 1055 _validateDefaultValues(node.parameters); | 1430 _validateDefaultValues(node.parameters); |
| 1056 return null; | 1431 return null; |
| 1057 } | 1432 } |
| 1058 | 1433 |
| 1059 @override | 1434 @override |
| 1060 Object visitSwitchStatement(SwitchStatement node) { | 1435 Object visitSwitchStatement(SwitchStatement node) { |
| 1061 // TODO(paulberry): to minimize error messages, it would be nice to | 1436 // TODO(paulberry): to minimize error messages, it would be nice to |
| 1062 // compare all types with the most popular type rather than the first | 1437 // compare all types with the most popular type rather than the first |
| 1063 // type. | 1438 // type. |
| 1064 NodeList<SwitchMember> switchMembers = node.members; | 1439 NodeList<SwitchMember> switchMembers = node.members; |
| 1065 bool foundError = false; | 1440 bool foundError = false; |
| 1066 DartType firstType = null; | 1441 DartType firstType = null; |
| 1067 for (SwitchMember switchMember in switchMembers) { | 1442 for (SwitchMember switchMember in switchMembers) { |
| 1068 if (switchMember is SwitchCase) { | 1443 if (switchMember is SwitchCase) { |
| 1069 SwitchCase switchCase = switchMember; | 1444 Expression expression = switchMember.expression; |
| 1070 Expression expression = switchCase.expression; | |
| 1071 DartObjectImpl caseResult = _validate( | 1445 DartObjectImpl caseResult = _validate( |
| 1072 expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION); | 1446 expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION); |
| 1073 if (caseResult != null) { | 1447 if (caseResult != null) { |
| 1074 _reportErrorIfFromDeferredLibrary(expression, | 1448 _reportErrorIfFromDeferredLibrary( |
| 1075 CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LI
BRARY); | 1449 expression, |
| 1450 CompileTimeErrorCode |
| 1451 .NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LIBRARY); |
| 1076 DartObject value = caseResult; | 1452 DartObject value = caseResult; |
| 1077 if (firstType == null) { | 1453 if (firstType == null) { |
| 1078 firstType = value.type; | 1454 firstType = value.type; |
| 1079 } else { | 1455 } else { |
| 1080 DartType nType = value.type; | 1456 DartType nType = value.type; |
| 1081 if (firstType != nType) { | 1457 if (firstType != nType) { |
| 1082 _errorReporter.reportErrorForNode( | 1458 _errorReporter.reportErrorForNode( |
| 1083 CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, | 1459 CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, |
| 1084 expression, | 1460 expression, |
| 1085 [expression.toSource(), firstType.displayName]); | 1461 [expression.toSource(), firstType.displayName]); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1105 if (result == null) { | 1481 if (result == null) { |
| 1106 // Variables marked "const" should have had their values computed by | 1482 // Variables marked "const" should have had their values computed by |
| 1107 // ConstantValueComputer. Other variables will only have had their | 1483 // ConstantValueComputer. Other variables will only have had their |
| 1108 // values computed if the value was needed (e.g. final variables in a | 1484 // values computed if the value was needed (e.g. final variables in a |
| 1109 // class containing const constructors). | 1485 // class containing const constructors). |
| 1110 assert(!node.isConst); | 1486 assert(!node.isConst); |
| 1111 return null; | 1487 return null; |
| 1112 } | 1488 } |
| 1113 _reportErrors(result.errors, | 1489 _reportErrors(result.errors, |
| 1114 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE); | 1490 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE); |
| 1115 _reportErrorIfFromDeferredLibrary(initializer, | 1491 _reportErrorIfFromDeferredLibrary( |
| 1116 CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DE
FERRED_LIBRARY); | 1492 initializer, |
| 1493 CompileTimeErrorCode |
| 1494 .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY); |
| 1117 } | 1495 } |
| 1118 return null; | 1496 return null; |
| 1119 } | 1497 } |
| 1120 | 1498 |
| 1121 /** | 1499 /** |
| 1122 * This verifies that the passed switch statement does not have a case express
ion with the | 1500 * This verifies that the passed switch statement does not have a case express
ion with the |
| 1123 * operator '==' overridden. | 1501 * operator '==' overridden. |
| 1124 * | 1502 * |
| 1125 * @param node the switch statement to evaluate | 1503 * @param node the switch statement to evaluate |
| 1126 * @param type the common type of all 'case' expressions | 1504 * @param type the common type of all 'case' expressions |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1146 */ | 1524 */ |
| 1147 bool _implementsEqualsWhenNotAllowed(DartType type) { | 1525 bool _implementsEqualsWhenNotAllowed(DartType type) { |
| 1148 // ignore int or String | 1526 // ignore int or String |
| 1149 if (type == null || type == _intType || type == _typeProvider.stringType) { | 1527 if (type == null || type == _intType || type == _typeProvider.stringType) { |
| 1150 return false; | 1528 return false; |
| 1151 } else if (type == _typeProvider.doubleType) { | 1529 } else if (type == _typeProvider.doubleType) { |
| 1152 return true; | 1530 return true; |
| 1153 } | 1531 } |
| 1154 // prepare ClassElement | 1532 // prepare ClassElement |
| 1155 Element element = type.element; | 1533 Element element = type.element; |
| 1156 if (element is! ClassElement) { | 1534 if (element is ClassElement) { |
| 1157 return false; | 1535 // lookup for == |
| 1536 MethodElement method = |
| 1537 element.lookUpConcreteMethod("==", _currentLibrary); |
| 1538 if (method == null || method.enclosingElement.type.isObject) { |
| 1539 return false; |
| 1540 } |
| 1541 // there is == that we don't like |
| 1542 return true; |
| 1158 } | 1543 } |
| 1159 ClassElement classElement = element as ClassElement; | 1544 return false; |
| 1160 // lookup for == | |
| 1161 MethodElement method = | |
| 1162 classElement.lookUpConcreteMethod("==", _currentLibrary); | |
| 1163 if (method == null || method.enclosingElement.type.isObject) { | |
| 1164 return false; | |
| 1165 } | |
| 1166 // there is == that we don't like | |
| 1167 return true; | |
| 1168 } | 1545 } |
| 1169 | 1546 |
| 1170 /** | 1547 /** |
| 1171 * Given some computed [Expression], this method generates the passed [ErrorCo
de] on | 1548 * Given some computed [Expression], this method generates the passed [ErrorCo
de] on |
| 1172 * the node if its' value consists of information from a deferred library. | 1549 * the node if its' value consists of information from a deferred library. |
| 1173 * | 1550 * |
| 1174 * @param expression the expression to be tested for a deferred library refere
nce | 1551 * @param expression the expression to be tested for a deferred library refere
nce |
| 1175 * @param errorCode the error code to be used if the expression is or consists
of a reference to a | 1552 * @param errorCode the error code to be used if the expression is or consists
of a reference to a |
| 1176 * deferred library | 1553 * deferred library |
| 1177 */ | 1554 */ |
| 1178 void _reportErrorIfFromDeferredLibrary( | 1555 void _reportErrorIfFromDeferredLibrary( |
| 1179 Expression expression, ErrorCode errorCode) { | 1556 Expression expression, ErrorCode errorCode) { |
| 1180 DeferredLibraryReferenceDetector referenceDetector = | 1557 DeferredLibraryReferenceDetector referenceDetector = |
| 1181 new DeferredLibraryReferenceDetector(); | 1558 new DeferredLibraryReferenceDetector(); |
| 1182 expression.accept(referenceDetector); | 1559 expression.accept(referenceDetector); |
| 1183 if (referenceDetector.result) { | 1560 if (referenceDetector.result) { |
| 1184 _errorReporter.reportErrorForNode(errorCode, expression); | 1561 _errorReporter.reportErrorForNode(errorCode, expression); |
| 1185 } | 1562 } |
| 1186 } | 1563 } |
| 1187 | 1564 |
| 1188 /** | 1565 /** |
| 1189 * Report any errors in the given list. Except for special cases, use the give
n error code rather | 1566 * Report any errors in the given list. Except for special cases, use the give
n error code rather |
| 1190 * than the one reported in the error. | 1567 * than the one reported in the error. |
| 1191 * | 1568 * |
| 1192 * @param errors the errors that need to be reported | 1569 * @param errors the errors that need to be reported |
| 1193 * @param errorCode the error code to be used | 1570 * @param errorCode the error code to be used |
| 1194 */ | 1571 */ |
| 1195 void _reportErrors(List<AnalysisError> errors, ErrorCode errorCode) { | 1572 void _reportErrors(List<AnalysisError> errors, ErrorCode errorCode) { |
| 1196 for (AnalysisError data in errors) { | 1573 int length = errors.length; |
| 1574 for (int i = 0; i < length; i++) { |
| 1575 AnalysisError data = errors[i]; |
| 1197 ErrorCode dataErrorCode = data.errorCode; | 1576 ErrorCode dataErrorCode = data.errorCode; |
| 1198 if (identical(dataErrorCode, | 1577 if (identical(dataErrorCode, |
| 1199 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) || | 1578 CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) || |
| 1200 identical( | 1579 identical( |
| 1201 dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) || | 1580 dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) || |
| 1202 identical(dataErrorCode, | 1581 identical(dataErrorCode, |
| 1203 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) || | 1582 CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) || |
| 1204 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) || | 1583 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) || |
| 1205 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) || | 1584 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) || |
| 1206 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) || | 1585 identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) || |
| 1207 identical(dataErrorCode, | 1586 identical(dataErrorCode, |
| 1208 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) || | 1587 CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) || |
| 1209 identical(dataErrorCode, | 1588 identical( |
| 1210 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMA
TCH) || | 1589 dataErrorCode, |
| 1211 identical(dataErrorCode, | 1590 CheckedModeCompileTimeErrorCode |
| 1212 CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMA
TCH) || | 1591 .CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH) || |
| 1592 identical( |
| 1593 dataErrorCode, |
| 1594 CheckedModeCompileTimeErrorCode |
| 1595 .CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH) || |
| 1213 identical(dataErrorCode, | 1596 identical(dataErrorCode, |
| 1214 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH)) { | 1597 CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH)) { |
| 1215 _errorReporter.reportError(data); | 1598 _errorReporter.reportError(data); |
| 1216 } else if (errorCode != null) { | 1599 } else if (errorCode != null) { |
| 1217 _errorReporter.reportError(new AnalysisError( | 1600 _errorReporter.reportError(new AnalysisError( |
| 1218 data.source, data.offset, data.length, errorCode)); | 1601 data.source, data.offset, data.length, errorCode)); |
| 1219 } | 1602 } |
| 1220 } | 1603 } |
| 1221 } | 1604 } |
| 1222 | 1605 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1240 return result; | 1623 return result; |
| 1241 } | 1624 } |
| 1242 | 1625 |
| 1243 /** | 1626 /** |
| 1244 * Validate that if the passed arguments are constant expressions. | 1627 * Validate that if the passed arguments are constant expressions. |
| 1245 * | 1628 * |
| 1246 * @param argumentList the argument list to evaluate | 1629 * @param argumentList the argument list to evaluate |
| 1247 */ | 1630 */ |
| 1248 void _validateConstantArguments(ArgumentList argumentList) { | 1631 void _validateConstantArguments(ArgumentList argumentList) { |
| 1249 for (Expression argument in argumentList.arguments) { | 1632 for (Expression argument in argumentList.arguments) { |
| 1250 if (argument is NamedExpression) { | 1633 Expression realArgument = |
| 1251 argument = (argument as NamedExpression).expression; | 1634 argument is NamedExpression ? argument.expression : argument; |
| 1252 } | |
| 1253 _validate( | 1635 _validate( |
| 1254 argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT); | 1636 realArgument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT); |
| 1255 } | 1637 } |
| 1256 } | 1638 } |
| 1257 | 1639 |
| 1258 /** | 1640 /** |
| 1259 * Validates that the expressions of the given initializers (of a constant con
structor) are all | 1641 * Validates that the expressions of the given initializers (of a constant con
structor) are all |
| 1260 * compile time constants. | 1642 * compile time constants. |
| 1261 * | 1643 * |
| 1262 * @param constructor the constant constructor declaration to validate | 1644 * @param constructor the constant constructor declaration to validate |
| 1263 */ | 1645 */ |
| 1264 void _validateConstructorInitializers(ConstructorDeclaration constructor) { | 1646 void _validateConstructorInitializers(ConstructorDeclaration constructor) { |
| 1265 List<ParameterElement> parameterElements = | 1647 List<ParameterElement> parameterElements = |
| 1266 constructor.parameters.parameterElements; | 1648 constructor.parameters.parameterElements; |
| 1267 NodeList<ConstructorInitializer> initializers = constructor.initializers; | 1649 NodeList<ConstructorInitializer> initializers = constructor.initializers; |
| 1268 for (ConstructorInitializer initializer in initializers) { | 1650 for (ConstructorInitializer initializer in initializers) { |
| 1269 if (initializer is ConstructorFieldInitializer) { | 1651 if (initializer is ConstructorFieldInitializer) { |
| 1270 ConstructorFieldInitializer fieldInitializer = initializer; | |
| 1271 _validateInitializerExpression( | 1652 _validateInitializerExpression( |
| 1272 parameterElements, fieldInitializer.expression); | 1653 parameterElements, initializer.expression); |
| 1273 } | 1654 } |
| 1274 if (initializer is RedirectingConstructorInvocation) { | 1655 if (initializer is RedirectingConstructorInvocation) { |
| 1275 RedirectingConstructorInvocation invocation = initializer; | |
| 1276 _validateInitializerInvocationArguments( | 1656 _validateInitializerInvocationArguments( |
| 1277 parameterElements, invocation.argumentList); | 1657 parameterElements, initializer.argumentList); |
| 1278 } | 1658 } |
| 1279 if (initializer is SuperConstructorInvocation) { | 1659 if (initializer is SuperConstructorInvocation) { |
| 1280 SuperConstructorInvocation invocation = initializer; | |
| 1281 _validateInitializerInvocationArguments( | 1660 _validateInitializerInvocationArguments( |
| 1282 parameterElements, invocation.argumentList); | 1661 parameterElements, initializer.argumentList); |
| 1283 } | 1662 } |
| 1284 } | 1663 } |
| 1285 } | 1664 } |
| 1286 | 1665 |
| 1287 /** | 1666 /** |
| 1288 * Validate that the default value associated with each of the parameters in t
he given list is a | 1667 * Validate that the default value associated with each of the parameters in t
he given list is a |
| 1289 * compile time constant. | 1668 * compile time constant. |
| 1290 * | 1669 * |
| 1291 * @param parameters the list of parameters to be validated | 1670 * @param parameters the list of parameters to be validated |
| 1292 */ | 1671 */ |
| 1293 void _validateDefaultValues(FormalParameterList parameters) { | 1672 void _validateDefaultValues(FormalParameterList parameters) { |
| 1294 if (parameters == null) { | 1673 if (parameters == null) { |
| 1295 return; | 1674 return; |
| 1296 } | 1675 } |
| 1297 for (FormalParameter parameter in parameters.parameters) { | 1676 for (FormalParameter parameter in parameters.parameters) { |
| 1298 if (parameter is DefaultFormalParameter) { | 1677 if (parameter is DefaultFormalParameter) { |
| 1299 DefaultFormalParameter defaultParameter = parameter; | 1678 Expression defaultValue = parameter.defaultValue; |
| 1300 Expression defaultValue = defaultParameter.defaultValue; | |
| 1301 DartObjectImpl result; | 1679 DartObjectImpl result; |
| 1302 if (defaultValue == null) { | 1680 if (defaultValue == null) { |
| 1303 result = | 1681 result = |
| 1304 new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE); | 1682 new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE); |
| 1305 } else { | 1683 } else { |
| 1306 result = _validate( | 1684 result = _validate( |
| 1307 defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE); | 1685 defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE); |
| 1308 if (result != null) { | 1686 if (result != null) { |
| 1309 _reportErrorIfFromDeferredLibrary(defaultValue, | 1687 _reportErrorIfFromDeferredLibrary( |
| 1310 CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LI
BRARY); | 1688 defaultValue, |
| 1689 CompileTimeErrorCode |
| 1690 .NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LIBRARY); |
| 1311 } | 1691 } |
| 1312 } | 1692 } |
| 1313 VariableElementImpl element = parameter.element as VariableElementImpl; | 1693 VariableElementImpl element = parameter.element as VariableElementImpl; |
| 1314 element.evaluationResult = new EvaluationResultImpl(result); | 1694 element.evaluationResult = new EvaluationResultImpl(result); |
| 1315 } | 1695 } |
| 1316 } | 1696 } |
| 1317 } | 1697 } |
| 1318 | 1698 |
| 1319 /** | 1699 /** |
| 1320 * Validates that the expressions of any field initializers in the class decla
ration are all | 1700 * Validates that the expressions of any field initializers in the class decla
ration are all |
| 1321 * compile time constants. Since this is only required if the class has a cons
tant constructor, | 1701 * compile time constants. Since this is only required if the class has a cons
tant constructor, |
| 1322 * the error is reported at the constructor site. | 1702 * the error is reported at the constructor site. |
| 1323 * | 1703 * |
| 1324 * @param classDeclaration the class which should be validated | 1704 * @param classDeclaration the class which should be validated |
| 1325 * @param errorSite the site at which errors should be reported. | 1705 * @param errorSite the site at which errors should be reported. |
| 1326 */ | 1706 */ |
| 1327 void _validateFieldInitializers( | 1707 void _validateFieldInitializers( |
| 1328 ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) { | 1708 ClassDeclaration classDeclaration, ConstructorDeclaration errorSite) { |
| 1329 NodeList<ClassMember> members = classDeclaration.members; | 1709 NodeList<ClassMember> members = classDeclaration.members; |
| 1330 for (ClassMember member in members) { | 1710 for (ClassMember member in members) { |
| 1331 if (member is FieldDeclaration) { | 1711 if (member is FieldDeclaration && !member.isStatic) { |
| 1332 FieldDeclaration fieldDeclaration = member; | 1712 for (VariableDeclaration variableDeclaration |
| 1333 if (!fieldDeclaration.isStatic) { | 1713 in member.fields.variables) { |
| 1334 for (VariableDeclaration variableDeclaration | 1714 Expression initializer = variableDeclaration.initializer; |
| 1335 in fieldDeclaration.fields.variables) { | 1715 if (initializer != null) { |
| 1336 Expression initializer = variableDeclaration.initializer; | 1716 // Ignore any errors produced during validation--if the constant |
| 1337 if (initializer != null) { | 1717 // can't be eavluated we'll just report a single error. |
| 1338 // Ignore any errors produced during validation--if the constant | 1718 AnalysisErrorListener errorListener = |
| 1339 // can't be eavluated we'll just report a single error. | 1719 AnalysisErrorListener.NULL_LISTENER; |
| 1340 AnalysisErrorListener errorListener = | 1720 ErrorReporter subErrorReporter = |
| 1341 AnalysisErrorListener.NULL_LISTENER; | 1721 new ErrorReporter(errorListener, _errorReporter.source); |
| 1342 ErrorReporter subErrorReporter = | 1722 DartObjectImpl result = initializer.accept(new ConstantVisitor( |
| 1343 new ErrorReporter(errorListener, _errorReporter.source); | 1723 new ConstantEvaluationEngine(_typeProvider, declaredVariables, |
| 1344 DartObjectImpl result = initializer.accept(new ConstantVisitor( | 1724 typeSystem: _typeSystem), |
| 1345 new ConstantEvaluationEngine(_typeProvider, declaredVariables, | 1725 subErrorReporter)); |
| 1346 typeSystem: _typeSystem), | 1726 if (result == null) { |
| 1347 subErrorReporter)); | 1727 _errorReporter.reportErrorForNode( |
| 1348 if (result == null) { | 1728 CompileTimeErrorCode |
| 1349 _errorReporter.reportErrorForNode( | 1729 .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST, |
| 1350 CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZE
D_BY_NON_CONST, | 1730 errorSite, |
| 1351 errorSite, | 1731 [variableDeclaration.name.name]); |
| 1352 [variableDeclaration.name.name]); | |
| 1353 } | |
| 1354 } | 1732 } |
| 1355 } | 1733 } |
| 1356 } | 1734 } |
| 1357 } | 1735 } |
| 1358 } | 1736 } |
| 1359 } | 1737 } |
| 1360 | 1738 |
| 1361 /** | 1739 /** |
| 1362 * Validates that the given expression is a compile time constant. | 1740 * Validates that the given expression is a compile time constant. |
| 1363 * | 1741 * |
| 1364 * @param parameterElements the elements of parameters of constant constructor
, they are | 1742 * @param parameterElements the elements of parameters of constant constructor
, they are |
| 1365 * considered as a valid potentially constant expressions | 1743 * considered as a valid potentially constant expressions |
| 1366 * @param expression the expression to validate | 1744 * @param expression the expression to validate |
| 1367 */ | 1745 */ |
| 1368 void _validateInitializerExpression( | 1746 void _validateInitializerExpression( |
| 1369 List<ParameterElement> parameterElements, Expression expression) { | 1747 List<ParameterElement> parameterElements, Expression expression) { |
| 1370 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1748 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 1371 ErrorReporter subErrorReporter = | 1749 ErrorReporter subErrorReporter = |
| 1372 new ErrorReporter(errorListener, _errorReporter.source); | 1750 new ErrorReporter(errorListener, _errorReporter.source); |
| 1373 DartObjectImpl result = expression.accept( | 1751 DartObjectImpl result = expression.accept( |
| 1374 new _ConstantVerifier_validateInitializerExpression(_typeProvider, | 1752 new _ConstantVerifier_validateInitializerExpression(_typeProvider, |
| 1375 subErrorReporter, this, parameterElements, declaredVariables, | 1753 subErrorReporter, this, parameterElements, declaredVariables, |
| 1376 typeSystem: _typeSystem)); | 1754 typeSystem: _typeSystem)); |
| 1377 _reportErrors(errorListener.errors, | 1755 _reportErrors(errorListener.errors, |
| 1378 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER); | 1756 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER); |
| 1379 if (result != null) { | 1757 if (result != null) { |
| 1380 _reportErrorIfFromDeferredLibrary(expression, | 1758 _reportErrorIfFromDeferredLibrary( |
| 1381 CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_L
IBRARY); | 1759 expression, |
| 1760 CompileTimeErrorCode |
| 1761 .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY); |
| 1382 } | 1762 } |
| 1383 } | 1763 } |
| 1384 | 1764 |
| 1385 /** | 1765 /** |
| 1386 * Validates that all of the arguments of a constructor initializer are compil
e time constants. | 1766 * Validates that all of the arguments of a constructor initializer are compil
e time constants. |
| 1387 * | 1767 * |
| 1388 * @param parameterElements the elements of parameters of constant constructor
, they are | 1768 * @param parameterElements the elements of parameters of constant constructor
, they are |
| 1389 * considered as a valid potentially constant expressions | 1769 * considered as a valid potentially constant expressions |
| 1390 * @param argumentList the argument list to validate | 1770 * @param argumentList the argument list to validate |
| 1391 */ | 1771 */ |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1452 * @param node the is expression to check | 1832 * @param node the is expression to check |
| 1453 * @return `true` if and only if a hint code is generated on the passed node | 1833 * @return `true` if and only if a hint code is generated on the passed node |
| 1454 * See [HintCode.IS_DOUBLE], | 1834 * See [HintCode.IS_DOUBLE], |
| 1455 * [HintCode.IS_INT], | 1835 * [HintCode.IS_INT], |
| 1456 * [HintCode.IS_NOT_DOUBLE], and | 1836 * [HintCode.IS_NOT_DOUBLE], and |
| 1457 * [HintCode.IS_NOT_INT]. | 1837 * [HintCode.IS_NOT_INT]. |
| 1458 */ | 1838 */ |
| 1459 bool _checkForIsDoubleHints(IsExpression node) { | 1839 bool _checkForIsDoubleHints(IsExpression node) { |
| 1460 TypeName typeName = node.type; | 1840 TypeName typeName = node.type; |
| 1461 DartType type = typeName.type; | 1841 DartType type = typeName.type; |
| 1462 if (type != null && type.element != null) { | 1842 Element element = type?.element; |
| 1463 Element element = type.element; | 1843 if (element != null) { |
| 1464 String typeNameStr = element.name; | 1844 String typeNameStr = element.name; |
| 1465 LibraryElement libraryElement = element.library; | 1845 LibraryElement libraryElement = element.library; |
| 1466 // if (typeNameStr.equals(INT_TYPE_NAME) && libraryElement != null | 1846 // if (typeNameStr.equals(INT_TYPE_NAME) && libraryElement != null |
| 1467 // && libraryElement.isDartCore()) { | 1847 // && libraryElement.isDartCore()) { |
| 1468 // if (node.getNotOperator() == null) { | 1848 // if (node.getNotOperator() == null) { |
| 1469 // errorReporter.reportError(HintCode.IS_INT, node); | 1849 // errorReporter.reportError(HintCode.IS_INT, node); |
| 1470 // } else { | 1850 // } else { |
| 1471 // errorReporter.reportError(HintCode.IS_NOT_INT, node); | 1851 // errorReporter.reportError(HintCode.IS_NOT_INT, node); |
| 1472 // } | 1852 // } |
| 1473 // return true; | 1853 // return true; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1501 * The type system for this visitor | 1881 * The type system for this visitor |
| 1502 */ | 1882 */ |
| 1503 final TypeSystem _typeSystem; | 1883 final TypeSystem _typeSystem; |
| 1504 | 1884 |
| 1505 /** | 1885 /** |
| 1506 * Create a new instance of the [DeadCodeVerifier]. | 1886 * Create a new instance of the [DeadCodeVerifier]. |
| 1507 * | 1887 * |
| 1508 * @param errorReporter the error reporter | 1888 * @param errorReporter the error reporter |
| 1509 */ | 1889 */ |
| 1510 DeadCodeVerifier(this._errorReporter, {TypeSystem typeSystem}) | 1890 DeadCodeVerifier(this._errorReporter, {TypeSystem typeSystem}) |
| 1511 : this._typeSystem = | 1891 : this._typeSystem = typeSystem ?? new TypeSystemImpl(); |
| 1512 (typeSystem != null) ? typeSystem : new TypeSystemImpl(); | |
| 1513 | 1892 |
| 1514 @override | 1893 @override |
| 1515 Object visitBinaryExpression(BinaryExpression node) { | 1894 Object visitBinaryExpression(BinaryExpression node) { |
| 1516 sc.Token operator = node.operator; | 1895 Token operator = node.operator; |
| 1517 bool isAmpAmp = operator.type == sc.TokenType.AMPERSAND_AMPERSAND; | 1896 bool isAmpAmp = operator.type == TokenType.AMPERSAND_AMPERSAND; |
| 1518 bool isBarBar = operator.type == sc.TokenType.BAR_BAR; | 1897 bool isBarBar = operator.type == TokenType.BAR_BAR; |
| 1519 if (isAmpAmp || isBarBar) { | 1898 if (isAmpAmp || isBarBar) { |
| 1520 Expression lhsCondition = node.leftOperand; | 1899 Expression lhsCondition = node.leftOperand; |
| 1521 if (!_isDebugConstant(lhsCondition)) { | 1900 if (!_isDebugConstant(lhsCondition)) { |
| 1522 EvaluationResultImpl lhsResult = _getConstantBooleanValue(lhsCondition); | 1901 EvaluationResultImpl lhsResult = _getConstantBooleanValue(lhsCondition); |
| 1523 if (lhsResult != null) { | 1902 if (lhsResult != null) { |
| 1524 if (lhsResult.value.toBoolValue() == true && isBarBar) { | 1903 bool value = lhsResult.value.toBoolValue(); |
| 1904 if (value == true && isBarBar) { |
| 1525 // report error on else block: true || !e! | 1905 // report error on else block: true || !e! |
| 1526 _errorReporter.reportErrorForNode( | 1906 _errorReporter.reportErrorForNode( |
| 1527 HintCode.DEAD_CODE, node.rightOperand); | 1907 HintCode.DEAD_CODE, node.rightOperand); |
| 1528 // only visit the LHS: | 1908 // only visit the LHS: |
| 1529 _safelyVisit(lhsCondition); | 1909 lhsCondition?.accept(this); |
| 1530 return null; | 1910 return null; |
| 1531 } else if (lhsResult.value.toBoolValue() == false && isAmpAmp) { | 1911 } else if (value == false && isAmpAmp) { |
| 1532 // report error on if block: false && !e! | 1912 // report error on if block: false && !e! |
| 1533 _errorReporter.reportErrorForNode( | 1913 _errorReporter.reportErrorForNode( |
| 1534 HintCode.DEAD_CODE, node.rightOperand); | 1914 HintCode.DEAD_CODE, node.rightOperand); |
| 1535 // only visit the LHS: | 1915 // only visit the LHS: |
| 1536 _safelyVisit(lhsCondition); | 1916 lhsCondition?.accept(this); |
| 1537 return null; | 1917 return null; |
| 1538 } | 1918 } |
| 1539 } | 1919 } |
| 1540 } | 1920 } |
| 1541 // How do we want to handle the RHS? It isn't dead code, but "pointless" | 1921 // How do we want to handle the RHS? It isn't dead code, but "pointless" |
| 1542 // or "obscure"... | 1922 // or "obscure"... |
| 1543 // Expression rhsCondition = node.getRightOperand(); | 1923 // Expression rhsCondition = node.getRightOperand(); |
| 1544 // ValidResult rhsResult = getConstantBooleanValue(rhsCondition); | 1924 // ValidResult rhsResult = getConstantBooleanValue(rhsCondition); |
| 1545 // if (rhsResult != null) { | 1925 // if (rhsResult != null) { |
| 1546 // if (rhsResult == ValidResult.RESULT_TRUE && isBarBar) { | 1926 // if (rhsResult == ValidResult.RESULT_TRUE && isBarBar) { |
| 1547 // // report error on else block: !e! || true | 1927 // // report error on else block: !e! || true |
| 1548 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe
rand()); | 1928 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe
rand()); |
| 1549 // // only visit the RHS: | 1929 // // only visit the RHS: |
| 1550 // safelyVisit(rhsCondition); | 1930 // rhsCondition?.accept(this); |
| 1551 // return null; | 1931 // return null; |
| 1552 // } else if (rhsResult == ValidResult.RESULT_FALSE && isAmpAmp) { | 1932 // } else if (rhsResult == ValidResult.RESULT_FALSE && isAmpAmp) { |
| 1553 // // report error on if block: !e! && false | 1933 // // report error on if block: !e! && false |
| 1554 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe
rand()); | 1934 // errorReporter.reportError(HintCode.DEAD_CODE, node.getRightOpe
rand()); |
| 1555 // // only visit the RHS: | 1935 // // only visit the RHS: |
| 1556 // safelyVisit(rhsCondition); | 1936 // rhsCondition?.accept(this); |
| 1557 // return null; | 1937 // return null; |
| 1558 // } | 1938 // } |
| 1559 // } | 1939 // } |
| 1560 } | 1940 } |
| 1561 return super.visitBinaryExpression(node); | 1941 return super.visitBinaryExpression(node); |
| 1562 } | 1942 } |
| 1563 | 1943 |
| 1564 /** | 1944 /** |
| 1565 * For each [Block], this method reports and error on all statements between t
he end of the | 1945 * For each [Block], this method reports and error on all statements between t
he end of the |
| 1566 * block and the first return statement (assuming there it is not at the end o
f the block.) | 1946 * block and the first return statement (assuming there it is not at the end o
f the block.) |
| 1567 * | 1947 * |
| 1568 * @param node the block to evaluate | 1948 * @param node the block to evaluate |
| 1569 */ | 1949 */ |
| 1570 @override | 1950 @override |
| 1571 Object visitBlock(Block node) { | 1951 Object visitBlock(Block node) { |
| 1572 NodeList<Statement> statements = node.statements; | 1952 NodeList<Statement> statements = node.statements; |
| 1573 _checkForDeadStatementsInNodeList(statements); | 1953 _checkForDeadStatementsInNodeList(statements); |
| 1574 return null; | 1954 return null; |
| 1575 } | 1955 } |
| 1576 | 1956 |
| 1577 @override | 1957 @override |
| 1578 Object visitConditionalExpression(ConditionalExpression node) { | 1958 Object visitConditionalExpression(ConditionalExpression node) { |
| 1579 Expression conditionExpression = node.condition; | 1959 Expression conditionExpression = node.condition; |
| 1580 _safelyVisit(conditionExpression); | 1960 conditionExpression?.accept(this); |
| 1581 if (!_isDebugConstant(conditionExpression)) { | 1961 if (!_isDebugConstant(conditionExpression)) { |
| 1582 EvaluationResultImpl result = | 1962 EvaluationResultImpl result = |
| 1583 _getConstantBooleanValue(conditionExpression); | 1963 _getConstantBooleanValue(conditionExpression); |
| 1584 if (result != null) { | 1964 if (result != null) { |
| 1585 if (result.value.toBoolValue() == true) { | 1965 if (result.value.toBoolValue() == true) { |
| 1586 // report error on else block: true ? 1 : !2! | 1966 // report error on else block: true ? 1 : !2! |
| 1587 _errorReporter.reportErrorForNode( | 1967 _errorReporter.reportErrorForNode( |
| 1588 HintCode.DEAD_CODE, node.elseExpression); | 1968 HintCode.DEAD_CODE, node.elseExpression); |
| 1589 _safelyVisit(node.thenExpression); | 1969 node.thenExpression?.accept(this); |
| 1590 return null; | 1970 return null; |
| 1591 } else { | 1971 } else { |
| 1592 // report error on if block: false ? !1! : 2 | 1972 // report error on if block: false ? !1! : 2 |
| 1593 _errorReporter.reportErrorForNode( | 1973 _errorReporter.reportErrorForNode( |
| 1594 HintCode.DEAD_CODE, node.thenExpression); | 1974 HintCode.DEAD_CODE, node.thenExpression); |
| 1595 _safelyVisit(node.elseExpression); | 1975 node.elseExpression?.accept(this); |
| 1596 return null; | 1976 return null; |
| 1597 } | 1977 } |
| 1598 } | 1978 } |
| 1599 } | 1979 } |
| 1600 return super.visitConditionalExpression(node); | 1980 return super.visitConditionalExpression(node); |
| 1601 } | 1981 } |
| 1602 | 1982 |
| 1603 @override | 1983 @override |
| 1984 Object visitExportDirective(ExportDirective node) { |
| 1985 ExportElement exportElement = node.element; |
| 1986 if (exportElement != null) { |
| 1987 // The element is null when the URI is invalid |
| 1988 LibraryElement library = exportElement.exportedLibrary; |
| 1989 if (library != null && !library.isSynthetic) { |
| 1990 for (Combinator combinator in node.combinators) { |
| 1991 _checkCombinator(exportElement.exportedLibrary, combinator); |
| 1992 } |
| 1993 } |
| 1994 } |
| 1995 return super.visitExportDirective(node); |
| 1996 } |
| 1997 |
| 1998 @override |
| 1604 Object visitIfStatement(IfStatement node) { | 1999 Object visitIfStatement(IfStatement node) { |
| 1605 Expression conditionExpression = node.condition; | 2000 Expression conditionExpression = node.condition; |
| 1606 _safelyVisit(conditionExpression); | 2001 conditionExpression?.accept(this); |
| 1607 if (!_isDebugConstant(conditionExpression)) { | 2002 if (!_isDebugConstant(conditionExpression)) { |
| 1608 EvaluationResultImpl result = | 2003 EvaluationResultImpl result = |
| 1609 _getConstantBooleanValue(conditionExpression); | 2004 _getConstantBooleanValue(conditionExpression); |
| 1610 if (result != null) { | 2005 if (result != null) { |
| 1611 if (result.value.toBoolValue() == true) { | 2006 if (result.value.toBoolValue() == true) { |
| 1612 // report error on else block: if(true) {} else {!} | 2007 // report error on else block: if(true) {} else {!} |
| 1613 Statement elseStatement = node.elseStatement; | 2008 Statement elseStatement = node.elseStatement; |
| 1614 if (elseStatement != null) { | 2009 if (elseStatement != null) { |
| 1615 _errorReporter.reportErrorForNode( | 2010 _errorReporter.reportErrorForNode( |
| 1616 HintCode.DEAD_CODE, elseStatement); | 2011 HintCode.DEAD_CODE, elseStatement); |
| 1617 _safelyVisit(node.thenStatement); | 2012 node.thenStatement?.accept(this); |
| 1618 return null; | 2013 return null; |
| 1619 } | 2014 } |
| 1620 } else { | 2015 } else { |
| 1621 // report error on if block: if (false) {!} else {} | 2016 // report error on if block: if (false) {!} else {} |
| 1622 _errorReporter.reportErrorForNode( | 2017 _errorReporter.reportErrorForNode( |
| 1623 HintCode.DEAD_CODE, node.thenStatement); | 2018 HintCode.DEAD_CODE, node.thenStatement); |
| 1624 _safelyVisit(node.elseStatement); | 2019 node.elseStatement?.accept(this); |
| 1625 return null; | 2020 return null; |
| 1626 } | 2021 } |
| 1627 } | 2022 } |
| 1628 } | 2023 } |
| 1629 return super.visitIfStatement(node); | 2024 return super.visitIfStatement(node); |
| 1630 } | 2025 } |
| 1631 | 2026 |
| 1632 @override | 2027 @override |
| 2028 Object visitImportDirective(ImportDirective node) { |
| 2029 ImportElement importElement = node.element; |
| 2030 if (importElement != null) { |
| 2031 // The element is null when the URI is invalid, but not when the URI is |
| 2032 // valid but refers to a non-existent file. |
| 2033 LibraryElement library = importElement.importedLibrary; |
| 2034 if (library != null && !library.isSynthetic) { |
| 2035 for (Combinator combinator in node.combinators) { |
| 2036 _checkCombinator(library, combinator); |
| 2037 } |
| 2038 } |
| 2039 } |
| 2040 return super.visitImportDirective(node); |
| 2041 } |
| 2042 |
| 2043 @override |
| 1633 Object visitSwitchCase(SwitchCase node) { | 2044 Object visitSwitchCase(SwitchCase node) { |
| 1634 _checkForDeadStatementsInNodeList(node.statements); | 2045 _checkForDeadStatementsInNodeList(node.statements, allowMandated: true); |
| 1635 return super.visitSwitchCase(node); | 2046 return super.visitSwitchCase(node); |
| 1636 } | 2047 } |
| 1637 | 2048 |
| 1638 @override | 2049 @override |
| 1639 Object visitSwitchDefault(SwitchDefault node) { | 2050 Object visitSwitchDefault(SwitchDefault node) { |
| 1640 _checkForDeadStatementsInNodeList(node.statements); | 2051 _checkForDeadStatementsInNodeList(node.statements, allowMandated: true); |
| 1641 return super.visitSwitchDefault(node); | 2052 return super.visitSwitchDefault(node); |
| 1642 } | 2053 } |
| 1643 | 2054 |
| 1644 @override | 2055 @override |
| 1645 Object visitTryStatement(TryStatement node) { | 2056 Object visitTryStatement(TryStatement node) { |
| 1646 _safelyVisit(node.body); | 2057 node.body?.accept(this); |
| 1647 _safelyVisit(node.finallyBlock); | 2058 node.finallyBlock?.accept(this); |
| 1648 NodeList<CatchClause> catchClauses = node.catchClauses; | 2059 NodeList<CatchClause> catchClauses = node.catchClauses; |
| 1649 int numOfCatchClauses = catchClauses.length; | 2060 int numOfCatchClauses = catchClauses.length; |
| 1650 List<DartType> visitedTypes = new List<DartType>(); | 2061 List<DartType> visitedTypes = new List<DartType>(); |
| 1651 for (int i = 0; i < numOfCatchClauses; i++) { | 2062 for (int i = 0; i < numOfCatchClauses; i++) { |
| 1652 CatchClause catchClause = catchClauses[i]; | 2063 CatchClause catchClause = catchClauses[i]; |
| 1653 if (catchClause.onKeyword != null) { | 2064 if (catchClause.onKeyword != null) { |
| 1654 // on-catch clause found, verify that the exception type is not a | 2065 // on-catch clause found, verify that the exception type is not a |
| 1655 // subtype of a previous on-catch exception type | 2066 // subtype of a previous on-catch exception type |
| 1656 TypeName typeName = catchClause.exceptionType; | 2067 DartType currentType = catchClause.exceptionType?.type; |
| 1657 if (typeName != null && typeName.type != null) { | 2068 if (currentType != null) { |
| 1658 DartType currentType = typeName.type; | |
| 1659 if (currentType.isObject) { | 2069 if (currentType.isObject) { |
| 1660 // Found catch clause clause that has Object as an exception type, | 2070 // Found catch clause clause that has Object as an exception type, |
| 1661 // this is equivalent to having a catch clause that doesn't have an | 2071 // this is equivalent to having a catch clause that doesn't have an |
| 1662 // exception type, visit the block, but generate an error on any | 2072 // exception type, visit the block, but generate an error on any |
| 1663 // following catch clauses (and don't visit them). | 2073 // following catch clauses (and don't visit them). |
| 1664 _safelyVisit(catchClause); | 2074 catchClause?.accept(this); |
| 1665 if (i + 1 != numOfCatchClauses) { | 2075 if (i + 1 != numOfCatchClauses) { |
| 1666 // this catch clause is not the last in the try statement | 2076 // this catch clause is not the last in the try statement |
| 1667 CatchClause nextCatchClause = catchClauses[i + 1]; | 2077 CatchClause nextCatchClause = catchClauses[i + 1]; |
| 1668 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; | 2078 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; |
| 1669 int offset = nextCatchClause.offset; | 2079 int offset = nextCatchClause.offset; |
| 1670 int length = lastCatchClause.end - offset; | 2080 int length = lastCatchClause.end - offset; |
| 1671 _errorReporter.reportErrorForOffset( | 2081 _errorReporter.reportErrorForOffset( |
| 1672 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length); | 2082 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length); |
| 1673 return null; | 2083 return null; |
| 1674 } | 2084 } |
| 1675 } | 2085 } |
| 1676 for (DartType type in visitedTypes) { | 2086 int length = visitedTypes.length; |
| 2087 for (int j = 0; j < length; j++) { |
| 2088 DartType type = visitedTypes[j]; |
| 1677 if (_typeSystem.isSubtypeOf(currentType, type)) { | 2089 if (_typeSystem.isSubtypeOf(currentType, type)) { |
| 1678 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; | 2090 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; |
| 1679 int offset = catchClause.offset; | 2091 int offset = catchClause.offset; |
| 1680 int length = lastCatchClause.end - offset; | 2092 int length = lastCatchClause.end - offset; |
| 1681 _errorReporter.reportErrorForOffset( | 2093 _errorReporter.reportErrorForOffset( |
| 1682 HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, | 2094 HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, |
| 1683 offset, | 2095 offset, |
| 1684 length, | 2096 length, |
| 1685 [currentType.displayName, type.displayName]); | 2097 [currentType.displayName, type.displayName]); |
| 1686 return null; | 2098 return null; |
| 1687 } | 2099 } |
| 1688 } | 2100 } |
| 1689 visitedTypes.add(currentType); | 2101 visitedTypes.add(currentType); |
| 1690 } | 2102 } |
| 1691 _safelyVisit(catchClause); | 2103 catchClause?.accept(this); |
| 1692 } else { | 2104 } else { |
| 1693 // Found catch clause clause that doesn't have an exception type, | 2105 // Found catch clause clause that doesn't have an exception type, |
| 1694 // visit the block, but generate an error on any following catch clauses | 2106 // visit the block, but generate an error on any following catch clauses |
| 1695 // (and don't visit them). | 2107 // (and don't visit them). |
| 1696 _safelyVisit(catchClause); | 2108 catchClause?.accept(this); |
| 1697 if (i + 1 != numOfCatchClauses) { | 2109 if (i + 1 != numOfCatchClauses) { |
| 1698 // this catch clause is not the last in the try statement | 2110 // this catch clause is not the last in the try statement |
| 1699 CatchClause nextCatchClause = catchClauses[i + 1]; | 2111 CatchClause nextCatchClause = catchClauses[i + 1]; |
| 1700 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; | 2112 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; |
| 1701 int offset = nextCatchClause.offset; | 2113 int offset = nextCatchClause.offset; |
| 1702 int length = lastCatchClause.end - offset; | 2114 int length = lastCatchClause.end - offset; |
| 1703 _errorReporter.reportErrorForOffset( | 2115 _errorReporter.reportErrorForOffset( |
| 1704 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length); | 2116 HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH, offset, length); |
| 1705 return null; | 2117 return null; |
| 1706 } | 2118 } |
| 1707 } | 2119 } |
| 1708 } | 2120 } |
| 1709 return null; | 2121 return null; |
| 1710 } | 2122 } |
| 1711 | 2123 |
| 1712 @override | 2124 @override |
| 1713 Object visitWhileStatement(WhileStatement node) { | 2125 Object visitWhileStatement(WhileStatement node) { |
| 1714 Expression conditionExpression = node.condition; | 2126 Expression conditionExpression = node.condition; |
| 1715 _safelyVisit(conditionExpression); | 2127 conditionExpression?.accept(this); |
| 1716 if (!_isDebugConstant(conditionExpression)) { | 2128 if (!_isDebugConstant(conditionExpression)) { |
| 1717 EvaluationResultImpl result = | 2129 EvaluationResultImpl result = |
| 1718 _getConstantBooleanValue(conditionExpression); | 2130 _getConstantBooleanValue(conditionExpression); |
| 1719 if (result != null) { | 2131 if (result != null) { |
| 1720 if (result.value.toBoolValue() == false) { | 2132 if (result.value.toBoolValue() == false) { |
| 1721 // report error on if block: while (false) {!} | 2133 // report error on if block: while (false) {!} |
| 1722 _errorReporter.reportErrorForNode(HintCode.DEAD_CODE, node.body); | 2134 _errorReporter.reportErrorForNode(HintCode.DEAD_CODE, node.body); |
| 1723 return null; | 2135 return null; |
| 1724 } | 2136 } |
| 1725 } | 2137 } |
| 1726 } | 2138 } |
| 1727 _safelyVisit(node.body); | 2139 node.body?.accept(this); |
| 1728 return null; | 2140 return null; |
| 1729 } | 2141 } |
| 1730 | 2142 |
| 1731 /** | 2143 /** |
| 2144 * Resolve the names in the given [combinator] in the scope of the given |
| 2145 * [library]. |
| 2146 */ |
| 2147 void _checkCombinator(LibraryElement library, Combinator combinator) { |
| 2148 Namespace namespace = |
| 2149 new NamespaceBuilder().createExportNamespaceForLibrary(library); |
| 2150 NodeList<SimpleIdentifier> names; |
| 2151 ErrorCode hintCode; |
| 2152 if (combinator is HideCombinator) { |
| 2153 names = combinator.hiddenNames; |
| 2154 hintCode = HintCode.UNDEFINED_HIDDEN_NAME; |
| 2155 } else { |
| 2156 names = (combinator as ShowCombinator).shownNames; |
| 2157 hintCode = HintCode.UNDEFINED_SHOWN_NAME; |
| 2158 } |
| 2159 for (SimpleIdentifier name in names) { |
| 2160 String nameStr = name.name; |
| 2161 Element element = namespace.get(nameStr); |
| 2162 if (element == null) { |
| 2163 element = namespace.get("$nameStr="); |
| 2164 } |
| 2165 if (element == null) { |
| 2166 _errorReporter |
| 2167 .reportErrorForNode(hintCode, name, [library.identifier, nameStr]); |
| 2168 } |
| 2169 } |
| 2170 } |
| 2171 |
| 2172 /** |
| 1732 * Given some [NodeList] of [Statement]s, from either a [Block] or | 2173 * Given some [NodeList] of [Statement]s, from either a [Block] or |
| 1733 * [SwitchMember], this loops through the list in reverse order searching for
statements | 2174 * [SwitchMember], this loops through the list searching for dead statements. |
| 1734 * after a return, unlabeled break or unlabeled continue statement to mark the
m as dead code. | |
| 1735 * | 2175 * |
| 1736 * @param statements some ordered list of statements in a [Block] or [SwitchMe
mber] | 2176 * @param statements some ordered list of statements in a [Block] or [SwitchMe
mber] |
| 2177 * @param allowMandated allow dead statements mandated by the language spec. |
| 2178 * This allows for a final break, continue, return, or throw statem
ent |
| 2179 * at the end of a switch case, that are mandated by the language s
pec. |
| 1737 */ | 2180 */ |
| 1738 void _checkForDeadStatementsInNodeList(NodeList<Statement> statements) { | 2181 void _checkForDeadStatementsInNodeList(NodeList<Statement> statements, |
| 2182 {bool allowMandated: false}) { |
| 2183 bool statementExits(Statement statement) { |
| 2184 if (statement is BreakStatement) { |
| 2185 return statement.label == null; |
| 2186 } else if (statement is ContinueStatement) { |
| 2187 return statement.label == null; |
| 2188 } |
| 2189 return ExitDetector.exits(statement); |
| 2190 } |
| 2191 |
| 1739 int size = statements.length; | 2192 int size = statements.length; |
| 1740 for (int i = 0; i < size; i++) { | 2193 for (int i = 0; i < size; i++) { |
| 1741 Statement currentStatement = statements[i]; | 2194 Statement currentStatement = statements[i]; |
| 1742 _safelyVisit(currentStatement); | 2195 currentStatement?.accept(this); |
| 1743 bool returnOrBreakingStatement = currentStatement is ReturnStatement || | 2196 if (statementExits(currentStatement) && i != size - 1) { |
| 1744 (currentStatement is BreakStatement && | |
| 1745 currentStatement.label == null) || | |
| 1746 (currentStatement is ContinueStatement && | |
| 1747 currentStatement.label == null); | |
| 1748 if (returnOrBreakingStatement && i != size - 1) { | |
| 1749 Statement nextStatement = statements[i + 1]; | 2197 Statement nextStatement = statements[i + 1]; |
| 1750 Statement lastStatement = statements[size - 1]; | 2198 Statement lastStatement = statements[size - 1]; |
| 2199 // If mandated statements are allowed, and only the last statement is |
| 2200 // dead, and it's a BreakStatement, then assume it is a statement |
| 2201 // mandated by the language spec, there to avoid a |
| 2202 // CASE_BLOCK_NOT_TERMINATED error. |
| 2203 if (allowMandated && i == size - 2 && nextStatement is BreakStatement) { |
| 2204 return; |
| 2205 } |
| 1751 int offset = nextStatement.offset; | 2206 int offset = nextStatement.offset; |
| 1752 int length = lastStatement.end - offset; | 2207 int length = lastStatement.end - offset; |
| 1753 _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length); | 2208 _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length); |
| 1754 return; | 2209 return; |
| 1755 } | 2210 } |
| 1756 } | 2211 } |
| 1757 } | 2212 } |
| 1758 | 2213 |
| 1759 /** | 2214 /** |
| 1760 * Given some [Expression], this method returns [ValidResult.RESULT_TRUE] if i
t is | 2215 * Given some [Expression], this method returns [ValidResult.RESULT_TRUE] if i
t is |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1792 | 2247 |
| 1793 /** | 2248 /** |
| 1794 * Return `true` if and only if the passed expression is resolved to a constan
t variable. | 2249 * Return `true` if and only if the passed expression is resolved to a constan
t variable. |
| 1795 * | 2250 * |
| 1796 * @param expression some conditional expression | 2251 * @param expression some conditional expression |
| 1797 * @return `true` if and only if the passed expression is resolved to a consta
nt variable | 2252 * @return `true` if and only if the passed expression is resolved to a consta
nt variable |
| 1798 */ | 2253 */ |
| 1799 bool _isDebugConstant(Expression expression) { | 2254 bool _isDebugConstant(Expression expression) { |
| 1800 Element element = null; | 2255 Element element = null; |
| 1801 if (expression is Identifier) { | 2256 if (expression is Identifier) { |
| 1802 Identifier identifier = expression; | 2257 element = expression.staticElement; |
| 1803 element = identifier.staticElement; | |
| 1804 } else if (expression is PropertyAccess) { | 2258 } else if (expression is PropertyAccess) { |
| 1805 PropertyAccess propertyAccess = expression; | 2259 element = expression.propertyName.staticElement; |
| 1806 element = propertyAccess.propertyName.staticElement; | |
| 1807 } | 2260 } |
| 1808 if (element is PropertyAccessorElement) { | 2261 if (element is PropertyAccessorElement) { |
| 1809 PropertyInducingElement variable = element.variable; | 2262 PropertyInducingElement variable = element.variable; |
| 1810 return variable != null && variable.isConst; | 2263 return variable != null && variable.isConst; |
| 1811 } | 2264 } |
| 1812 return false; | 2265 return false; |
| 1813 } | 2266 } |
| 1814 | |
| 1815 /** | |
| 1816 * If the given node is not `null`, visit this instance of the dead code verif
ier. | |
| 1817 * | |
| 1818 * @param node the node to be visited | |
| 1819 */ | |
| 1820 void _safelyVisit(AstNode node) { | |
| 1821 if (node != null) { | |
| 1822 node.accept(this); | |
| 1823 } | |
| 1824 } | |
| 1825 } | 2267 } |
| 1826 | 2268 |
| 1827 /** | 2269 /** |
| 1828 * Instances of the class `DeclarationResolver` are used to resolve declarations
in an AST | 2270 * A visitor that resolves declarations in an AST structure to already built |
| 1829 * structure to already built elements. | 2271 * elements. |
| 2272 * |
| 2273 * The resulting AST must have everything resolved that would have been resolved |
| 2274 * by a [CompilationUnitBuilder] (that is, must be a valid [RESOLVED_UNIT1]). |
| 2275 * This class must not assume that the [CompilationUnitElement] passed to it is |
| 2276 * any more complete than a [COMPILATION_UNIT_ELEMENT]. |
| 1830 */ | 2277 */ |
| 1831 class DeclarationResolver extends RecursiveAstVisitor<Object> { | 2278 class DeclarationResolver extends RecursiveAstVisitor<Object> |
| 2279 with ExistingElementResolver { |
| 1832 /** | 2280 /** |
| 1833 * The compilation unit containing the AST nodes being visited. | 2281 * The analysis context containing the sources to be analyzed. |
| 1834 */ | 2282 */ |
| 1835 CompilationUnitElement _enclosingUnit; | 2283 AnalysisContext _context; |
| 1836 | 2284 |
| 1837 /** | 2285 /** |
| 1838 * The function type alias containing the AST nodes being visited, or `null` i
f we are not | 2286 * The elements that are reachable from the compilation unit element. When a |
| 1839 * in the scope of a function type alias. | 2287 * compilation unit has been resolved, this set should be empty. |
| 2288 */ |
| 2289 Set<Element> _expectedElements; |
| 2290 |
| 2291 /** |
| 2292 * The function type alias containing the AST nodes being visited, or `null` |
| 2293 * if we are not in the scope of a function type alias. |
| 1840 */ | 2294 */ |
| 1841 FunctionTypeAliasElement _enclosingAlias; | 2295 FunctionTypeAliasElement _enclosingAlias; |
| 1842 | 2296 |
| 1843 /** | 2297 /** |
| 1844 * The class containing the AST nodes being visited, or `null` if we are not i
n the scope of | 2298 * The class containing the AST nodes being visited, or `null` if we are not |
| 1845 * a class. | 2299 * in the scope of a class. |
| 1846 */ | 2300 */ |
| 1847 ClassElement _enclosingClass; | 2301 ClassElement _enclosingClass; |
| 1848 | 2302 |
| 1849 /** | 2303 /** |
| 1850 * The method or function containing the AST nodes being visited, or `null` if
we are not in | 2304 * The method or function containing the AST nodes being visited, or `null` if |
| 1851 * the scope of a method or function. | 2305 * we are not in the scope of a method or function. |
| 1852 */ | 2306 */ |
| 1853 ExecutableElement _enclosingExecutable; | 2307 ExecutableElement _enclosingExecutable; |
| 1854 | 2308 |
| 1855 /** | 2309 /** |
| 1856 * The parameter containing the AST nodes being visited, or `null` if we are n
ot in the | 2310 * The parameter containing the AST nodes being visited, or `null` if we are |
| 1857 * scope of a parameter. | 2311 * not in the scope of a parameter. |
| 1858 */ | 2312 */ |
| 1859 ParameterElement _enclosingParameter; | 2313 ParameterElement _enclosingParameter; |
| 1860 | 2314 |
| 1861 /** | 2315 /** |
| 1862 * Resolve the declarations within the given compilation unit to the elements
rooted at the given | 2316 * Resolve the declarations within the given compilation [unit] to the |
| 1863 * element. | 2317 * elements rooted at the given [element]. Throw an [ElementMismatchException] |
| 1864 * | 2318 * if the element model and compilation unit do not match each other. |
| 1865 * @param unit the compilation unit to be resolved | |
| 1866 * @param element the root of the element model used to resolve the AST nodes | |
| 1867 */ | 2319 */ |
| 1868 void resolve(CompilationUnit unit, CompilationUnitElement element) { | 2320 void resolve(CompilationUnit unit, CompilationUnitElement element) { |
| 2321 _context = element.context; |
| 2322 ElementGatherer gatherer = new ElementGatherer(); |
| 2323 element.accept(gatherer); |
| 2324 _expectedElements = gatherer.elements; |
| 1869 _enclosingUnit = element; | 2325 _enclosingUnit = element; |
| 2326 _expectedElements.remove(element); |
| 1870 unit.element = element; | 2327 unit.element = element; |
| 1871 unit.accept(this); | 2328 unit.accept(this); |
| 2329 _validateResolution(); |
| 1872 } | 2330 } |
| 1873 | 2331 |
| 1874 @override | 2332 @override |
| 1875 Object visitCatchClause(CatchClause node) { | 2333 Object visitCatchClause(CatchClause node) { |
| 1876 SimpleIdentifier exceptionParameter = node.exceptionParameter; | 2334 SimpleIdentifier exceptionParameter = node.exceptionParameter; |
| 1877 if (exceptionParameter != null) { | 2335 if (exceptionParameter != null) { |
| 1878 List<LocalVariableElement> localVariables = | 2336 List<LocalVariableElement> localVariables = |
| 1879 _enclosingExecutable.localVariables; | 2337 _enclosingExecutable.localVariables; |
| 1880 _findIdentifier(localVariables, exceptionParameter); | 2338 _findIdentifier(localVariables, exceptionParameter); |
| 1881 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; | 2339 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; |
| 1882 if (stackTraceParameter != null) { | 2340 if (stackTraceParameter != null) { |
| 1883 _findIdentifier(localVariables, stackTraceParameter); | 2341 _findIdentifier(localVariables, stackTraceParameter); |
| 1884 } | 2342 } |
| 1885 } | 2343 } |
| 1886 return super.visitCatchClause(node); | 2344 return super.visitCatchClause(node); |
| 1887 } | 2345 } |
| 1888 | 2346 |
| 1889 @override | 2347 @override |
| 1890 Object visitClassDeclaration(ClassDeclaration node) { | 2348 Object visitClassDeclaration(ClassDeclaration node) { |
| 1891 ClassElement outerClass = _enclosingClass; | 2349 ClassElement outerClass = _enclosingClass; |
| 1892 try { | 2350 try { |
| 1893 SimpleIdentifier className = node.name; | 2351 SimpleIdentifier className = node.name; |
| 1894 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); | 2352 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); |
| 1895 return super.visitClassDeclaration(node); | 2353 super.visitClassDeclaration(node); |
| 2354 _resolveMetadata(node, node.metadata, _enclosingClass); |
| 2355 return null; |
| 1896 } finally { | 2356 } finally { |
| 1897 _enclosingClass = outerClass; | 2357 _enclosingClass = outerClass; |
| 1898 } | 2358 } |
| 1899 } | 2359 } |
| 1900 | 2360 |
| 1901 @override | 2361 @override |
| 1902 Object visitClassTypeAlias(ClassTypeAlias node) { | 2362 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 1903 ClassElement outerClass = _enclosingClass; | 2363 ClassElement outerClass = _enclosingClass; |
| 1904 try { | 2364 try { |
| 1905 SimpleIdentifier className = node.name; | 2365 SimpleIdentifier className = node.name; |
| 1906 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); | 2366 _enclosingClass = _findIdentifier(_enclosingUnit.types, className); |
| 1907 return super.visitClassTypeAlias(node); | 2367 super.visitClassTypeAlias(node); |
| 2368 _resolveMetadata(node, node.metadata, _enclosingClass); |
| 2369 return null; |
| 1908 } finally { | 2370 } finally { |
| 1909 _enclosingClass = outerClass; | 2371 _enclosingClass = outerClass; |
| 1910 } | 2372 } |
| 1911 } | 2373 } |
| 1912 | 2374 |
| 1913 @override | 2375 @override |
| 1914 Object visitConstructorDeclaration(ConstructorDeclaration node) { | 2376 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 1915 ExecutableElement outerExecutable = _enclosingExecutable; | 2377 ExecutableElement outerExecutable = _enclosingExecutable; |
| 1916 try { | 2378 try { |
| 1917 SimpleIdentifier constructorName = node.name; | 2379 SimpleIdentifier constructorName = node.name; |
| 1918 if (constructorName == null) { | 2380 if (constructorName == null) { |
| 1919 _enclosingExecutable = _enclosingClass.unnamedConstructor; | 2381 _enclosingExecutable = _enclosingClass.unnamedConstructor; |
| 2382 if (_enclosingExecutable == null) { |
| 2383 _mismatch('Could not find default constructor', node); |
| 2384 } |
| 1920 } else { | 2385 } else { |
| 1921 _enclosingExecutable = | 2386 _enclosingExecutable = |
| 1922 _enclosingClass.getNamedConstructor(constructorName.name); | 2387 _enclosingClass.getNamedConstructor(constructorName.name); |
| 2388 if (_enclosingExecutable == null) { |
| 2389 _mismatch( |
| 2390 'Could not find constructor element with name "${constructorName.n
ame}', |
| 2391 node); |
| 2392 } |
| 1923 constructorName.staticElement = _enclosingExecutable; | 2393 constructorName.staticElement = _enclosingExecutable; |
| 1924 } | 2394 } |
| 2395 _expectedElements.remove(_enclosingExecutable); |
| 1925 node.element = _enclosingExecutable as ConstructorElement; | 2396 node.element = _enclosingExecutable as ConstructorElement; |
| 1926 return super.visitConstructorDeclaration(node); | 2397 super.visitConstructorDeclaration(node); |
| 2398 _resolveMetadata(node, node.metadata, _enclosingExecutable); |
| 2399 return null; |
| 1927 } finally { | 2400 } finally { |
| 1928 _enclosingExecutable = outerExecutable; | 2401 _enclosingExecutable = outerExecutable; |
| 1929 } | 2402 } |
| 1930 } | 2403 } |
| 1931 | 2404 |
| 1932 @override | 2405 @override |
| 1933 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | 2406 Object visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 1934 SimpleIdentifier variableName = node.identifier; | 2407 SimpleIdentifier variableName = node.identifier; |
| 1935 _findIdentifier(_enclosingExecutable.localVariables, variableName); | 2408 Element element = |
| 1936 return super.visitDeclaredIdentifier(node); | 2409 _findIdentifier(_enclosingExecutable.localVariables, variableName); |
| 2410 super.visitDeclaredIdentifier(node); |
| 2411 _resolveMetadata(node, node.metadata, element); |
| 2412 return null; |
| 1937 } | 2413 } |
| 1938 | 2414 |
| 1939 @override | 2415 @override |
| 1940 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | 2416 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 1941 SimpleIdentifier parameterName = node.parameter.identifier; | 2417 SimpleIdentifier parameterName = node.parameter.identifier; |
| 1942 ParameterElement element = _getElementForParameter(node, parameterName); | 2418 ParameterElement element = _getElementForParameter(node, parameterName); |
| 1943 Expression defaultValue = node.defaultValue; | 2419 Expression defaultValue = node.defaultValue; |
| 1944 if (defaultValue != null) { | 2420 if (defaultValue != null) { |
| 1945 ExecutableElement outerExecutable = _enclosingExecutable; | 2421 ExecutableElement outerExecutable = _enclosingExecutable; |
| 1946 try { | 2422 try { |
| 1947 if (element == null) { | 2423 _enclosingExecutable = element.initializer; |
| 1948 // TODO(brianwilkerson) Report this internal error. | |
| 1949 } else { | |
| 1950 _enclosingExecutable = element.initializer; | |
| 1951 } | |
| 1952 defaultValue.accept(this); | 2424 defaultValue.accept(this); |
| 1953 } finally { | 2425 } finally { |
| 1954 _enclosingExecutable = outerExecutable; | 2426 _enclosingExecutable = outerExecutable; |
| 1955 } | 2427 } |
| 1956 } | 2428 } |
| 1957 ParameterElement outerParameter = _enclosingParameter; | 2429 ParameterElement outerParameter = _enclosingParameter; |
| 1958 try { | 2430 try { |
| 1959 _enclosingParameter = element; | 2431 _enclosingParameter = element; |
| 1960 return super.visitDefaultFormalParameter(node); | 2432 super.visitDefaultFormalParameter(node); |
| 2433 _resolveMetadata(node, node.metadata, element); |
| 2434 return null; |
| 1961 } finally { | 2435 } finally { |
| 1962 _enclosingParameter = outerParameter; | 2436 _enclosingParameter = outerParameter; |
| 1963 } | 2437 } |
| 1964 } | 2438 } |
| 1965 | 2439 |
| 1966 @override | 2440 @override |
| 1967 Object visitEnumDeclaration(EnumDeclaration node) { | 2441 Object visitEnumDeclaration(EnumDeclaration node) { |
| 1968 ClassElement enclosingEnum = | 2442 ClassElement enclosingEnum = |
| 1969 _findIdentifier(_enclosingUnit.enums, node.name); | 2443 _findIdentifier(_enclosingUnit.enums, node.name); |
| 1970 List<FieldElement> constants = enclosingEnum.fields; | 2444 List<FieldElement> constants = enclosingEnum.fields; |
| 1971 for (EnumConstantDeclaration constant in node.constants) { | 2445 for (EnumConstantDeclaration constant in node.constants) { |
| 1972 _findIdentifier(constants, constant.name); | 2446 _findIdentifier(constants, constant.name); |
| 1973 } | 2447 } |
| 1974 return super.visitEnumDeclaration(node); | 2448 super.visitEnumDeclaration(node); |
| 2449 _resolveMetadata(node, node.metadata, enclosingEnum); |
| 2450 return null; |
| 1975 } | 2451 } |
| 1976 | 2452 |
| 1977 @override | 2453 @override |
| 1978 Object visitExportDirective(ExportDirective node) { | 2454 Object visitExportDirective(ExportDirective node) { |
| 1979 String uri = _getStringValue(node.uri); | 2455 super.visitExportDirective(node); |
| 1980 if (uri != null) { | 2456 _resolveAnnotations( |
| 1981 LibraryElement library = _enclosingUnit.library; | 2457 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 1982 ExportElement exportElement = _findExport( | 2458 return null; |
| 1983 library.exports, | |
| 1984 _enclosingUnit.context.sourceFactory | |
| 1985 .resolveUri(_enclosingUnit.source, uri)); | |
| 1986 node.element = exportElement; | |
| 1987 } | |
| 1988 return super.visitExportDirective(node); | |
| 1989 } | 2459 } |
| 1990 | 2460 |
| 1991 @override | 2461 @override |
| 2462 Object visitFieldDeclaration(FieldDeclaration node) { |
| 2463 super.visitFieldDeclaration(node); |
| 2464 _resolveMetadata(node, node.metadata, node.fields.variables[0].element); |
| 2465 return null; |
| 2466 } |
| 2467 |
| 2468 @override |
| 1992 Object visitFieldFormalParameter(FieldFormalParameter node) { | 2469 Object visitFieldFormalParameter(FieldFormalParameter node) { |
| 1993 if (node.parent is! DefaultFormalParameter) { | 2470 if (node.parent is! DefaultFormalParameter) { |
| 1994 SimpleIdentifier parameterName = node.identifier; | 2471 SimpleIdentifier parameterName = node.identifier; |
| 1995 ParameterElement element = _getElementForParameter(node, parameterName); | 2472 ParameterElement element = _getElementForParameter(node, parameterName); |
| 1996 ParameterElement outerParameter = _enclosingParameter; | 2473 ParameterElement outerParameter = _enclosingParameter; |
| 1997 try { | 2474 try { |
| 1998 _enclosingParameter = element; | 2475 _enclosingParameter = element; |
| 1999 return super.visitFieldFormalParameter(node); | 2476 super.visitFieldFormalParameter(node); |
| 2477 _resolveMetadata(node, node.metadata, element); |
| 2478 return null; |
| 2000 } finally { | 2479 } finally { |
| 2001 _enclosingParameter = outerParameter; | 2480 _enclosingParameter = outerParameter; |
| 2002 } | 2481 } |
| 2003 } else { | 2482 } else { |
| 2004 return super.visitFieldFormalParameter(node); | 2483 return super.visitFieldFormalParameter(node); |
| 2005 } | 2484 } |
| 2006 } | 2485 } |
| 2007 | 2486 |
| 2008 @override | 2487 @override |
| 2009 Object visitFunctionDeclaration(FunctionDeclaration node) { | 2488 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 2010 ExecutableElement outerExecutable = _enclosingExecutable; | 2489 ExecutableElement outerExecutable = _enclosingExecutable; |
| 2011 try { | 2490 try { |
| 2012 SimpleIdentifier functionName = node.name; | 2491 SimpleIdentifier functionName = node.name; |
| 2013 sc.Token property = node.propertyKeyword; | 2492 Token property = node.propertyKeyword; |
| 2014 if (property == null) { | 2493 if (property == null) { |
| 2015 if (_enclosingExecutable != null) { | 2494 if (_enclosingExecutable != null) { |
| 2016 _enclosingExecutable = | 2495 _enclosingExecutable = |
| 2017 _findIdentifier(_enclosingExecutable.functions, functionName); | 2496 _findIdentifier(_enclosingExecutable.functions, functionName); |
| 2018 } else { | 2497 } else { |
| 2019 _enclosingExecutable = | 2498 _enclosingExecutable = |
| 2020 _findIdentifier(_enclosingUnit.functions, functionName); | 2499 _findIdentifier(_enclosingUnit.functions, functionName); |
| 2021 } | 2500 } |
| 2022 } else { | 2501 } else { |
| 2023 PropertyAccessorElement accessor = | 2502 if (_enclosingExecutable != null) { |
| 2024 _findIdentifier(_enclosingUnit.accessors, functionName); | 2503 _enclosingExecutable = |
| 2025 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) { | 2504 _findIdentifier(_enclosingExecutable.functions, functionName); |
| 2026 accessor = accessor.variable.setter; | 2505 } else { |
| 2027 functionName.staticElement = accessor; | 2506 List<PropertyAccessorElement> accessors; |
| 2507 if (_enclosingClass != null) { |
| 2508 accessors = _enclosingClass.accessors; |
| 2509 } else { |
| 2510 accessors = _enclosingUnit.accessors; |
| 2511 } |
| 2512 PropertyAccessorElement accessor; |
| 2513 if (property.keyword == Keyword.GET) { |
| 2514 accessor = _findIdentifier(accessors, functionName); |
| 2515 } else if (property.keyword == Keyword.SET) { |
| 2516 accessor = _findWithNameAndOffset(accessors, functionName, |
| 2517 functionName.name + '=', functionName.offset); |
| 2518 _expectedElements.remove(accessor); |
| 2519 functionName.staticElement = accessor; |
| 2520 } |
| 2521 _enclosingExecutable = accessor; |
| 2028 } | 2522 } |
| 2029 _enclosingExecutable = accessor; | |
| 2030 } | 2523 } |
| 2031 node.functionExpression.element = _enclosingExecutable; | 2524 node.functionExpression.element = _enclosingExecutable; |
| 2032 return super.visitFunctionDeclaration(node); | 2525 super.visitFunctionDeclaration(node); |
| 2526 _resolveMetadata(node, node.metadata, _enclosingExecutable); |
| 2527 return null; |
| 2033 } finally { | 2528 } finally { |
| 2034 _enclosingExecutable = outerExecutable; | 2529 _enclosingExecutable = outerExecutable; |
| 2035 } | 2530 } |
| 2036 } | 2531 } |
| 2037 | 2532 |
| 2038 @override | 2533 @override |
| 2039 Object visitFunctionExpression(FunctionExpression node) { | 2534 Object visitFunctionExpression(FunctionExpression node) { |
| 2040 if (node.parent is! FunctionDeclaration) { | 2535 if (node.parent is! FunctionDeclaration) { |
| 2041 FunctionElement element = | 2536 FunctionElement element = _findAtOffset( |
| 2042 _findAtOffset(_enclosingExecutable.functions, node.beginToken.offset); | 2537 _enclosingExecutable.functions, node, node.beginToken.offset); |
| 2538 _expectedElements.remove(element); |
| 2043 node.element = element; | 2539 node.element = element; |
| 2044 } | 2540 } |
| 2045 ExecutableElement outerExecutable = _enclosingExecutable; | 2541 ExecutableElement outerExecutable = _enclosingExecutable; |
| 2046 try { | 2542 try { |
| 2047 _enclosingExecutable = node.element; | 2543 _enclosingExecutable = node.element; |
| 2048 return super.visitFunctionExpression(node); | 2544 return super.visitFunctionExpression(node); |
| 2049 } finally { | 2545 } finally { |
| 2050 _enclosingExecutable = outerExecutable; | 2546 _enclosingExecutable = outerExecutable; |
| 2051 } | 2547 } |
| 2052 } | 2548 } |
| 2053 | 2549 |
| 2054 @override | 2550 @override |
| 2055 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 2551 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 2056 FunctionTypeAliasElement outerAlias = _enclosingAlias; | 2552 FunctionTypeAliasElement outerAlias = _enclosingAlias; |
| 2057 try { | 2553 try { |
| 2058 SimpleIdentifier aliasName = node.name; | 2554 SimpleIdentifier aliasName = node.name; |
| 2059 _enclosingAlias = | 2555 _enclosingAlias = |
| 2060 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName); | 2556 _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName); |
| 2061 return super.visitFunctionTypeAlias(node); | 2557 super.visitFunctionTypeAlias(node); |
| 2558 _resolveMetadata(node, node.metadata, _enclosingAlias); |
| 2559 return null; |
| 2062 } finally { | 2560 } finally { |
| 2063 _enclosingAlias = outerAlias; | 2561 _enclosingAlias = outerAlias; |
| 2064 } | 2562 } |
| 2065 } | 2563 } |
| 2066 | 2564 |
| 2067 @override | 2565 @override |
| 2068 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | 2566 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 2069 if (node.parent is! DefaultFormalParameter) { | 2567 if (node.parent is! DefaultFormalParameter) { |
| 2070 SimpleIdentifier parameterName = node.identifier; | 2568 SimpleIdentifier parameterName = node.identifier; |
| 2071 ParameterElement element = _getElementForParameter(node, parameterName); | 2569 ParameterElement element = _getElementForParameter(node, parameterName); |
| 2072 ParameterElement outerParameter = _enclosingParameter; | 2570 ParameterElement outerParameter = _enclosingParameter; |
| 2073 try { | 2571 try { |
| 2074 _enclosingParameter = element; | 2572 _enclosingParameter = element; |
| 2075 return super.visitFunctionTypedFormalParameter(node); | 2573 super.visitFunctionTypedFormalParameter(node); |
| 2574 _resolveMetadata(node, node.metadata, _enclosingParameter); |
| 2575 return null; |
| 2076 } finally { | 2576 } finally { |
| 2077 _enclosingParameter = outerParameter; | 2577 _enclosingParameter = outerParameter; |
| 2078 } | 2578 } |
| 2079 } else { | 2579 } else { |
| 2080 return super.visitFunctionTypedFormalParameter(node); | 2580 return super.visitFunctionTypedFormalParameter(node); |
| 2081 } | 2581 } |
| 2082 } | 2582 } |
| 2083 | 2583 |
| 2084 @override | 2584 @override |
| 2085 Object visitImportDirective(ImportDirective node) { | 2585 Object visitImportDirective(ImportDirective node) { |
| 2086 String uri = _getStringValue(node.uri); | 2586 super.visitImportDirective(node); |
| 2087 if (uri != null) { | 2587 _resolveAnnotations( |
| 2088 LibraryElement library = _enclosingUnit.library; | 2588 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 2089 ImportElement importElement = _findImport( | 2589 return null; |
| 2090 library.imports, | |
| 2091 _enclosingUnit.context.sourceFactory | |
| 2092 .resolveUri(_enclosingUnit.source, uri), | |
| 2093 node.prefix); | |
| 2094 node.element = importElement; | |
| 2095 } | |
| 2096 return super.visitImportDirective(node); | |
| 2097 } | 2590 } |
| 2098 | 2591 |
| 2099 @override | 2592 @override |
| 2100 Object visitLabeledStatement(LabeledStatement node) { | 2593 Object visitLabeledStatement(LabeledStatement node) { |
| 2101 for (Label label in node.labels) { | 2594 for (Label label in node.labels) { |
| 2102 SimpleIdentifier labelName = label.label; | 2595 SimpleIdentifier labelName = label.label; |
| 2103 _findIdentifier(_enclosingExecutable.labels, labelName); | 2596 _findIdentifier(_enclosingExecutable.labels, labelName); |
| 2104 } | 2597 } |
| 2105 return super.visitLabeledStatement(node); | 2598 return super.visitLabeledStatement(node); |
| 2106 } | 2599 } |
| 2107 | 2600 |
| 2108 @override | 2601 @override |
| 2109 Object visitLibraryDirective(LibraryDirective node) { | 2602 Object visitLibraryDirective(LibraryDirective node) { |
| 2110 node.element = _enclosingUnit.library; | 2603 super.visitLibraryDirective(node); |
| 2111 return super.visitLibraryDirective(node); | 2604 _resolveAnnotations( |
| 2605 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 2606 return null; |
| 2112 } | 2607 } |
| 2113 | 2608 |
| 2114 @override | 2609 @override |
| 2115 Object visitMethodDeclaration(MethodDeclaration node) { | 2610 Object visitMethodDeclaration(MethodDeclaration node) { |
| 2116 ExecutableElement outerExecutable = _enclosingExecutable; | 2611 ExecutableElement outerExecutable = _enclosingExecutable; |
| 2117 try { | 2612 try { |
| 2118 sc.Token property = node.propertyKeyword; | 2613 Token property = node.propertyKeyword; |
| 2119 SimpleIdentifier methodName = node.name; | 2614 SimpleIdentifier methodName = node.name; |
| 2120 String nameOfMethod = methodName.name; | 2615 String nameOfMethod = methodName.name; |
| 2121 if (property == null) { | 2616 if (property == null) { |
| 2122 _enclosingExecutable = _findWithNameAndOffset( | 2617 String elementName = nameOfMethod == '-' && |
| 2123 _enclosingClass.methods, nameOfMethod, methodName.offset); | 2618 node.parameters != null && |
| 2619 node.parameters.parameters.isEmpty |
| 2620 ? 'unary-' |
| 2621 : nameOfMethod; |
| 2622 _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods, |
| 2623 methodName, elementName, methodName.offset); |
| 2624 _expectedElements.remove(_enclosingExecutable); |
| 2124 methodName.staticElement = _enclosingExecutable; | 2625 methodName.staticElement = _enclosingExecutable; |
| 2125 } else { | 2626 } else { |
| 2126 PropertyAccessorElement accessor = | 2627 PropertyAccessorElement accessor; |
| 2127 _findIdentifier(_enclosingClass.accessors, methodName); | 2628 if (property.keyword == Keyword.GET) { |
| 2128 if ((property as sc.KeywordToken).keyword == sc.Keyword.SET) { | 2629 accessor = _findIdentifier(_enclosingClass.accessors, methodName); |
| 2129 accessor = accessor.variable.setter; | 2630 } else if (property.keyword == Keyword.SET) { |
| 2631 accessor = _findWithNameAndOffset(_enclosingClass.accessors, |
| 2632 methodName, nameOfMethod + '=', methodName.offset); |
| 2633 _expectedElements.remove(accessor); |
| 2130 methodName.staticElement = accessor; | 2634 methodName.staticElement = accessor; |
| 2131 } | 2635 } |
| 2132 _enclosingExecutable = accessor; | 2636 _enclosingExecutable = accessor; |
| 2133 } | 2637 } |
| 2134 return super.visitMethodDeclaration(node); | 2638 super.visitMethodDeclaration(node); |
| 2639 _resolveMetadata(node, node.metadata, _enclosingExecutable); |
| 2640 return null; |
| 2135 } finally { | 2641 } finally { |
| 2136 _enclosingExecutable = outerExecutable; | 2642 _enclosingExecutable = outerExecutable; |
| 2137 } | 2643 } |
| 2138 } | 2644 } |
| 2139 | 2645 |
| 2140 @override | 2646 @override |
| 2141 Object visitPartDirective(PartDirective node) { | 2647 Object visitPartDirective(PartDirective node) { |
| 2142 String uri = _getStringValue(node.uri); | 2648 super.visitPartDirective(node); |
| 2143 if (uri != null) { | 2649 _resolveAnnotations( |
| 2144 Source partSource = _enclosingUnit.context.sourceFactory | 2650 node, node.metadata, _enclosingUnit.getAnnotations(node.offset)); |
| 2145 .resolveUri(_enclosingUnit.source, uri); | 2651 return null; |
| 2146 node.element = _findPart(_enclosingUnit.library.parts, partSource); | |
| 2147 } | |
| 2148 return super.visitPartDirective(node); | |
| 2149 } | 2652 } |
| 2150 | 2653 |
| 2151 @override | 2654 @override |
| 2152 Object visitPartOfDirective(PartOfDirective node) { | 2655 Object visitPartOfDirective(PartOfDirective node) { |
| 2153 node.element = _enclosingUnit.library; | 2656 node.element = _enclosingUnit.library; |
| 2154 return super.visitPartOfDirective(node); | 2657 return super.visitPartOfDirective(node); |
| 2155 } | 2658 } |
| 2156 | 2659 |
| 2157 @override | 2660 @override |
| 2158 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | 2661 Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 2159 if (node.parent is! DefaultFormalParameter) { | 2662 if (node.parent is! DefaultFormalParameter) { |
| 2160 SimpleIdentifier parameterName = node.identifier; | 2663 SimpleIdentifier parameterName = node.identifier; |
| 2161 ParameterElement element = _getElementForParameter(node, parameterName); | 2664 ParameterElement element = _getElementForParameter(node, parameterName); |
| 2162 ParameterElement outerParameter = _enclosingParameter; | 2665 ParameterElement outerParameter = _enclosingParameter; |
| 2163 try { | 2666 try { |
| 2164 _enclosingParameter = element; | 2667 _enclosingParameter = element; |
| 2165 return super.visitSimpleFormalParameter(node); | 2668 super.visitSimpleFormalParameter(node); |
| 2669 _resolveMetadata(node, node.metadata, element); |
| 2670 return null; |
| 2166 } finally { | 2671 } finally { |
| 2167 _enclosingParameter = outerParameter; | 2672 _enclosingParameter = outerParameter; |
| 2168 } | 2673 } |
| 2169 } else {} | 2674 } else {} |
| 2170 return super.visitSimpleFormalParameter(node); | 2675 return super.visitSimpleFormalParameter(node); |
| 2171 } | 2676 } |
| 2172 | 2677 |
| 2173 @override | 2678 @override |
| 2174 Object visitSwitchCase(SwitchCase node) { | 2679 Object visitSwitchCase(SwitchCase node) { |
| 2175 for (Label label in node.labels) { | 2680 for (Label label in node.labels) { |
| 2176 SimpleIdentifier labelName = label.label; | 2681 SimpleIdentifier labelName = label.label; |
| 2177 _findIdentifier(_enclosingExecutable.labels, labelName); | 2682 _findIdentifier(_enclosingExecutable.labels, labelName); |
| 2178 } | 2683 } |
| 2179 return super.visitSwitchCase(node); | 2684 return super.visitSwitchCase(node); |
| 2180 } | 2685 } |
| 2181 | 2686 |
| 2182 @override | 2687 @override |
| 2183 Object visitSwitchDefault(SwitchDefault node) { | 2688 Object visitSwitchDefault(SwitchDefault node) { |
| 2184 for (Label label in node.labels) { | 2689 for (Label label in node.labels) { |
| 2185 SimpleIdentifier labelName = label.label; | 2690 SimpleIdentifier labelName = label.label; |
| 2186 _findIdentifier(_enclosingExecutable.labels, labelName); | 2691 _findIdentifier(_enclosingExecutable.labels, labelName); |
| 2187 } | 2692 } |
| 2188 return super.visitSwitchDefault(node); | 2693 return super.visitSwitchDefault(node); |
| 2189 } | 2694 } |
| 2190 | 2695 |
| 2191 @override | 2696 @override |
| 2697 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 2698 super.visitTopLevelVariableDeclaration(node); |
| 2699 _resolveMetadata(node, node.metadata, node.variables.variables[0].element); |
| 2700 return null; |
| 2701 } |
| 2702 |
| 2703 @override |
| 2192 Object visitTypeParameter(TypeParameter node) { | 2704 Object visitTypeParameter(TypeParameter node) { |
| 2193 SimpleIdentifier parameterName = node.name; | 2705 SimpleIdentifier parameterName = node.name; |
| 2194 if (_enclosingClass != null) { | 2706 Element element = null; |
| 2195 _findIdentifier(_enclosingClass.typeParameters, parameterName); | 2707 if (_enclosingExecutable != null) { |
| 2196 } else if (_enclosingAlias != null) { | 2708 element = _findIdentifier( |
| 2197 _findIdentifier(_enclosingAlias.typeParameters, parameterName); | 2709 _enclosingExecutable.typeParameters, parameterName, |
| 2710 required: false); |
| 2198 } | 2711 } |
| 2199 return super.visitTypeParameter(node); | 2712 if (element == null) { |
| 2713 if (_enclosingClass != null) { |
| 2714 element = |
| 2715 _findIdentifier(_enclosingClass.typeParameters, parameterName); |
| 2716 } else if (_enclosingAlias != null) { |
| 2717 element = |
| 2718 _findIdentifier(_enclosingAlias.typeParameters, parameterName); |
| 2719 } |
| 2720 } |
| 2721 if (element == null) { |
| 2722 String name = parameterName.name; |
| 2723 int offset = parameterName.offset; |
| 2724 _mismatch( |
| 2725 'Could not find type parameter with name "$name" at $offset', node); |
| 2726 } |
| 2727 super.visitTypeParameter(node); |
| 2728 _resolveMetadata(node, node.metadata, element); |
| 2729 return null; |
| 2200 } | 2730 } |
| 2201 | 2731 |
| 2202 @override | 2732 @override |
| 2203 Object visitVariableDeclaration(VariableDeclaration node) { | 2733 Object visitVariableDeclaration(VariableDeclaration node) { |
| 2204 VariableElement element = null; | 2734 VariableElement element = null; |
| 2205 SimpleIdentifier variableName = node.name; | 2735 SimpleIdentifier variableName = node.name; |
| 2206 if (_enclosingExecutable != null) { | 2736 if (_enclosingExecutable != null) { |
| 2207 element = | 2737 element = _findIdentifier( |
| 2208 _findIdentifier(_enclosingExecutable.localVariables, variableName); | 2738 _enclosingExecutable.localVariables, variableName, |
| 2739 required: false); |
| 2209 } | 2740 } |
| 2210 if (element == null && _enclosingClass != null) { | 2741 if (element == null && _enclosingClass != null) { |
| 2211 element = _findIdentifier(_enclosingClass.fields, variableName); | 2742 element = _findIdentifier(_enclosingClass.fields, variableName, |
| 2743 required: false); |
| 2212 } | 2744 } |
| 2213 if (element == null && _enclosingUnit != null) { | 2745 if (element == null && _enclosingUnit != null) { |
| 2214 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName); | 2746 element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName); |
| 2215 } | 2747 } |
| 2216 Expression initializer = node.initializer; | 2748 Expression initializer = node.initializer; |
| 2217 if (initializer != null) { | 2749 if (initializer != null) { |
| 2218 ExecutableElement outerExecutable = _enclosingExecutable; | 2750 ExecutableElement outerExecutable = _enclosingExecutable; |
| 2219 try { | 2751 try { |
| 2220 if (element == null) { | 2752 _enclosingExecutable = element.initializer; |
| 2221 // TODO(brianwilkerson) Report this internal error. | |
| 2222 } else { | |
| 2223 _enclosingExecutable = element.initializer; | |
| 2224 } | |
| 2225 return super.visitVariableDeclaration(node); | 2753 return super.visitVariableDeclaration(node); |
| 2226 } finally { | 2754 } finally { |
| 2227 _enclosingExecutable = outerExecutable; | 2755 _enclosingExecutable = outerExecutable; |
| 2228 } | 2756 } |
| 2229 } | 2757 } |
| 2230 return super.visitVariableDeclaration(node); | 2758 return super.visitVariableDeclaration(node); |
| 2231 } | 2759 } |
| 2232 | 2760 |
| 2233 /** | 2761 @override |
| 2234 * Return the element in the given array of elements that was created for the
declaration at the | 2762 Object visitVariableDeclarationList(VariableDeclarationList node) { |
| 2235 * given offset. This method should only be used when there is no name | 2763 super.visitVariableDeclarationList(node); |
| 2236 * | 2764 if (node.parent is! FieldDeclaration && |
| 2237 * @param elements the elements of the appropriate kind that exist in the curr
ent context | 2765 node.parent is! TopLevelVariableDeclaration) { |
| 2238 * @param offset the offset of the name of the element to be returned | 2766 _resolveMetadata(node, node.metadata, node.variables[0].element); |
| 2239 * @return the element at the given offset | |
| 2240 */ | |
| 2241 Element _findAtOffset(List<Element> elements, int offset) => | |
| 2242 _findWithNameAndOffset(elements, "", offset); | |
| 2243 | |
| 2244 /** | |
| 2245 * Return the export element from the given array whose library has the given
source, or | |
| 2246 * `null` if there is no such export. | |
| 2247 * | |
| 2248 * @param exports the export elements being searched | |
| 2249 * @param source the source of the library associated with the export element
to being searched | |
| 2250 * for | |
| 2251 * @return the export element whose library has the given source | |
| 2252 */ | |
| 2253 ExportElement _findExport(List<ExportElement> exports, Source source) { | |
| 2254 for (ExportElement export in exports) { | |
| 2255 if (export.exportedLibrary.source == source) { | |
| 2256 return export; | |
| 2257 } | |
| 2258 } | 2767 } |
| 2259 return null; | 2768 return null; |
| 2260 } | 2769 } |
| 2261 | 2770 |
| 2262 /** | 2771 /** |
| 2263 * Return the element in the given array of elements that was created for the
declaration with the | 2772 * Return the element in the given list of [elements] that was created for the |
| 2264 * given name. | 2773 * declaration at the given [offset]. Throw an [ElementMismatchException] if |
| 2774 * an element at that offset cannot be found. |
| 2265 * | 2775 * |
| 2266 * @param elements the elements of the appropriate kind that exist in the curr
ent context | 2776 * This method should only be used when there is no name associated with the |
| 2267 * @param identifier the name node in the declaration of the element to be ret
urned | 2777 * node. |
| 2268 * @return the element created for the declaration with the given name | |
| 2269 */ | 2778 */ |
| 2270 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier) { | 2779 Element _findAtOffset(List<Element> elements, AstNode node, int offset) => |
| 2271 Element element = | 2780 _findWithNameAndOffset(elements, node, '', offset); |
| 2272 _findWithNameAndOffset(elements, identifier.name, identifier.offset); | 2781 |
| 2782 /** |
| 2783 * Return the element in the given list of [elements] that was created for the |
| 2784 * declaration with the given [identifier]. As a side-effect, associate the |
| 2785 * returned element with the identifier. Throw an [ElementMismatchException] |
| 2786 * if an element corresponding to the identifier cannot be found unless |
| 2787 * [required] is `false`, in which case return `null`. |
| 2788 */ |
| 2789 Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier, |
| 2790 {bool required: true}) { |
| 2791 Element element = _findWithNameAndOffset( |
| 2792 elements, identifier, identifier.name, identifier.offset, |
| 2793 required: required); |
| 2794 _expectedElements.remove(element); |
| 2273 identifier.staticElement = element; | 2795 identifier.staticElement = element; |
| 2274 return element; | 2796 return element; |
| 2275 } | 2797 } |
| 2276 | 2798 |
| 2277 /** | 2799 /** |
| 2278 * Return the import element from the given array whose library has the given
source and that has | 2800 * Return the element in the given list of [elements] that was created for the |
| 2279 * the given prefix, or `null` if there is no such import. | 2801 * declaration with the given [name] at the given [offset]. Throw an |
| 2280 * | 2802 * [ElementMismatchException] if an element corresponding to the identifier |
| 2281 * @param imports the import elements being searched | 2803 * cannot be found unless [required] is `false`, in which case return `null`. |
| 2282 * @param source the source of the library associated with the import element
to being searched | |
| 2283 * for | |
| 2284 * @param prefix the prefix with which the library was imported | |
| 2285 * @return the import element whose library has the given source and prefix | |
| 2286 */ | 2804 */ |
| 2287 ImportElement _findImport( | 2805 Element _findWithNameAndOffset( |
| 2288 List<ImportElement> imports, Source source, SimpleIdentifier prefix) { | 2806 List<Element> elements, AstNode node, String name, int offset, |
| 2289 for (ImportElement element in imports) { | 2807 {bool required: true}) { |
| 2290 if (element.importedLibrary.source == source) { | 2808 int length = elements.length; |
| 2291 PrefixElement prefixElement = element.prefix; | 2809 for (int i = 0; i < length; i++) { |
| 2292 if (prefix == null) { | 2810 Element element = elements[i]; |
| 2293 if (prefixElement == null) { | 2811 if (element.nameOffset == offset && element.name == name) { |
| 2294 return element; | 2812 return element; |
| 2295 } | |
| 2296 } else { | |
| 2297 if (prefixElement != null && | |
| 2298 prefix.name == prefixElement.displayName) { | |
| 2299 return element; | |
| 2300 } | |
| 2301 } | |
| 2302 } | 2813 } |
| 2303 } | 2814 } |
| 2304 return null; | 2815 if (!required) { |
| 2816 return null; |
| 2817 } |
| 2818 for (int i = 0; i < length; i++) { |
| 2819 Element element = elements[i]; |
| 2820 if (element.name == name) { |
| 2821 _mismatch( |
| 2822 'Found element with name "$name" at ${element.nameOffset}, ' |
| 2823 'but expected offset of $offset', |
| 2824 node); |
| 2825 } |
| 2826 if (element.nameOffset == offset) { |
| 2827 _mismatch( |
| 2828 'Found element with name "${element.name}" at $offset, ' |
| 2829 'but expected element with name "$name"', |
| 2830 node); |
| 2831 } |
| 2832 } |
| 2833 _mismatch('Could not find element with name "$name" at $offset', node); |
| 2834 return null; // Never reached |
| 2305 } | 2835 } |
| 2306 | 2836 |
| 2307 /** | 2837 /** |
| 2308 * Return the element for the part with the given source, or `null` if there i
s no element | 2838 * Search the most closely enclosing list of parameter elements for a |
| 2309 * for the given source. | 2839 * parameter, defined by the given [node], with the given [parameterName]. |
| 2310 * | 2840 * Return the element that was found, or throw an [ElementMismatchException] |
| 2311 * @param parts the elements for the parts | 2841 * if an element corresponding to the identifier cannot be found. |
| 2312 * @param partSource the source for the part whose element is to be returned | |
| 2313 * @return the element for the part with the given source | |
| 2314 */ | |
| 2315 CompilationUnitElement _findPart( | |
| 2316 List<CompilationUnitElement> parts, Source partSource) { | |
| 2317 for (CompilationUnitElement part in parts) { | |
| 2318 if (part.source == partSource) { | |
| 2319 return part; | |
| 2320 } | |
| 2321 } | |
| 2322 return null; | |
| 2323 } | |
| 2324 | |
| 2325 /** | |
| 2326 * Return the element in the given array of elements that was created for the
declaration with the | |
| 2327 * given name at the given offset. | |
| 2328 * | |
| 2329 * @param elements the elements of the appropriate kind that exist in the curr
ent context | |
| 2330 * @param name the name of the element to be returned | |
| 2331 * @param offset the offset of the name of the element to be returned | |
| 2332 * @return the element with the given name and offset | |
| 2333 */ | |
| 2334 Element _findWithNameAndOffset( | |
| 2335 List<Element> elements, String name, int offset) { | |
| 2336 for (Element element in elements) { | |
| 2337 if (element.nameOffset == offset && element.displayName == name) { | |
| 2338 return element; | |
| 2339 } | |
| 2340 } | |
| 2341 return null; | |
| 2342 } | |
| 2343 | |
| 2344 /** | |
| 2345 * Search the most closely enclosing list of parameters for a parameter with t
he given name. | |
| 2346 * | |
| 2347 * @param node the node defining the parameter with the given name | |
| 2348 * @param parameterName the name of the parameter being searched for | |
| 2349 * @return the element representing the parameter with that name | |
| 2350 */ | 2842 */ |
| 2351 ParameterElement _getElementForParameter( | 2843 ParameterElement _getElementForParameter( |
| 2352 FormalParameter node, SimpleIdentifier parameterName) { | 2844 FormalParameter node, SimpleIdentifier parameterName) { |
| 2353 List<ParameterElement> parameters = null; | 2845 List<ParameterElement> parameters = null; |
| 2354 if (_enclosingParameter != null) { | 2846 if (_enclosingParameter != null) { |
| 2355 parameters = _enclosingParameter.parameters; | 2847 parameters = _enclosingParameter.parameters; |
| 2356 } | 2848 } |
| 2357 if (parameters == null && _enclosingExecutable != null) { | 2849 if (parameters == null && _enclosingExecutable != null) { |
| 2358 parameters = _enclosingExecutable.parameters; | 2850 parameters = _enclosingExecutable.parameters; |
| 2359 } | 2851 } |
| 2360 if (parameters == null && _enclosingAlias != null) { | 2852 if (parameters == null && _enclosingAlias != null) { |
| 2361 parameters = _enclosingAlias.parameters; | 2853 parameters = _enclosingAlias.parameters; |
| 2362 } | 2854 } |
| 2363 ParameterElement element = | 2855 if (parameters == null) { |
| 2364 parameters == null ? null : _findIdentifier(parameters, parameterName); | |
| 2365 if (element == null) { | |
| 2366 StringBuffer buffer = new StringBuffer(); | 2856 StringBuffer buffer = new StringBuffer(); |
| 2367 buffer.writeln("Invalid state found in the Analysis Engine:"); | 2857 buffer.writeln('Could not find parameter in enclosing scope'); |
| 2368 buffer.writeln( | 2858 buffer.writeln( |
| 2369 "DeclarationResolver.getElementForParameter() is visiting a parameter
that does not appear to be in a method or function."); | 2859 '(_enclosingParameter == null) == ${_enclosingParameter == null}'); |
| 2370 buffer.writeln("Ancestors:"); | 2860 buffer.writeln( |
| 2371 AstNode parent = node.parent; | 2861 '(_enclosingExecutable == null) == ${_enclosingExecutable == null}'); |
| 2372 while (parent != null) { | 2862 buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}'); |
| 2373 buffer.writeln(parent.runtimeType.toString()); | 2863 _mismatch(buffer.toString(), parameterName); |
| 2374 buffer.writeln("---------"); | 2864 } |
| 2375 parent = parent.parent; | 2865 return _findIdentifier(parameters, parameterName); |
| 2866 } |
| 2867 |
| 2868 /** |
| 2869 * Associate each of the annotation [nodes] with the corresponding |
| 2870 * [ElementAnnotation] in [annotations]. If there is a problem, report it |
| 2871 * against the given [parent] node. |
| 2872 */ |
| 2873 void _resolveAnnotations(AstNode parent, NodeList<Annotation> nodes, |
| 2874 List<ElementAnnotation> annotations) { |
| 2875 int nodeCount = nodes.length; |
| 2876 if (nodeCount != annotations.length) { |
| 2877 _mismatch( |
| 2878 'Found $nodeCount annotation nodes and ' |
| 2879 '${annotations.length} element annotations', |
| 2880 parent); |
| 2881 } |
| 2882 for (int i = 0; i < nodeCount; i++) { |
| 2883 nodes[i].elementAnnotation = annotations[i]; |
| 2884 } |
| 2885 } |
| 2886 |
| 2887 /** |
| 2888 * If [element] is not `null`, associate each of the annotation [nodes] with |
| 2889 * the corresponding [ElementAnnotation] in [element.metadata]. If there is a |
| 2890 * problem, report it against the given [parent] node. |
| 2891 * |
| 2892 * If [element] is `null`, do nothing--this allows us to be robust in the |
| 2893 * case where we are operating on an element model that hasn't been fully |
| 2894 * built. |
| 2895 */ |
| 2896 void _resolveMetadata( |
| 2897 AstNode parent, NodeList<Annotation> nodes, Element element) { |
| 2898 if (element != null) { |
| 2899 _resolveAnnotations(parent, nodes, element.metadata); |
| 2900 } |
| 2901 } |
| 2902 |
| 2903 /** |
| 2904 * Throw an exception if there are non-synthetic elements in the element model |
| 2905 * that were not associated with an AST node. |
| 2906 */ |
| 2907 void _validateResolution() { |
| 2908 if (_expectedElements.isNotEmpty) { |
| 2909 StringBuffer buffer = new StringBuffer(); |
| 2910 buffer.write(_expectedElements.length); |
| 2911 buffer.writeln(' unmatched elements found:'); |
| 2912 for (Element element in _expectedElements) { |
| 2913 buffer.write(' '); |
| 2914 buffer.writeln(element); |
| 2376 } | 2915 } |
| 2377 AnalysisEngine.instance.logger.logError(buffer.toString(), | 2916 throw new ElementMismatchException(buffer.toString()); |
| 2378 new CaughtException(new AnalysisException(), null)); | 2917 } |
| 2379 } | |
| 2380 return element; | |
| 2381 } | |
| 2382 | |
| 2383 /** | |
| 2384 * Return the value of the given string literal, or `null` if the string is no
t a constant | |
| 2385 * string without any string interpolation. | |
| 2386 * | |
| 2387 * @param literal the string literal whose value is to be returned | |
| 2388 * @return the value of the given string literal | |
| 2389 */ | |
| 2390 String _getStringValue(StringLiteral literal) { | |
| 2391 if (literal is StringInterpolation) { | |
| 2392 return null; | |
| 2393 } | |
| 2394 return literal.stringValue; | |
| 2395 } | 2918 } |
| 2396 } | 2919 } |
| 2397 | 2920 |
| 2398 /** | 2921 /** |
| 2399 * Instances of the class `ElementBuilder` traverse an AST structure and build t
he element | 2922 * A visitor that resolves directives in an AST structure to already built |
| 2400 * model representing the AST structure. | 2923 * elements. |
| 2924 * |
| 2925 * The resulting AST must have everything resolved that would have been resolved |
| 2926 * by a [DirectiveElementBuilder]. |
| 2401 */ | 2927 */ |
| 2402 class ElementBuilder extends RecursiveAstVisitor<Object> { | 2928 class DirectiveResolver extends SimpleAstVisitor { |
| 2403 /** | 2929 LibraryElement _enclosingLibrary; |
| 2404 * The element holder associated with the element that is currently being buil
t. | |
| 2405 */ | |
| 2406 ElementHolder _currentHolder; | |
| 2407 | |
| 2408 /** | |
| 2409 * A flag indicating whether a variable declaration is in the context of a fie
ld declaration. | |
| 2410 */ | |
| 2411 bool _inFieldContext = false; | |
| 2412 | |
| 2413 /** | |
| 2414 * A flag indicating whether a variable declaration is within the body of a me
thod or function. | |
| 2415 */ | |
| 2416 bool _inFunction = false; | |
| 2417 | |
| 2418 /** | |
| 2419 * A flag indicating whether the class currently being visited can be used as
a mixin. | |
| 2420 */ | |
| 2421 bool _isValidMixin = false; | |
| 2422 | |
| 2423 /** | |
| 2424 * A collection holding the function types defined in a class that need to hav
e their type | |
| 2425 * arguments set to the types of the type parameters for the class, or `null`
if we are not | |
| 2426 * currently processing nodes within a class. | |
| 2427 */ | |
| 2428 List<FunctionTypeImpl> _functionTypesToFix = null; | |
| 2429 | |
| 2430 /** | |
| 2431 * A table mapping field names to field elements for the fields defined in the
current class, or | |
| 2432 * `null` if we are not in the scope of a class. | |
| 2433 */ | |
| 2434 HashMap<String, FieldElement> _fieldMap; | |
| 2435 | |
| 2436 /** | |
| 2437 * Initialize a newly created element builder to build the elements for a comp
ilation unit. | |
| 2438 * | |
| 2439 * @param initialHolder the element holder associated with the compilation uni
t being built | |
| 2440 */ | |
| 2441 ElementBuilder(ElementHolder initialHolder) { | |
| 2442 _currentHolder = initialHolder; | |
| 2443 } | |
| 2444 | 2930 |
| 2445 @override | 2931 @override |
| 2446 Object visitBlock(Block node) { | 2932 void visitCompilationUnit(CompilationUnit node) { |
| 2447 bool wasInField = _inFieldContext; | 2933 _enclosingLibrary = node.element.library; |
| 2448 _inFieldContext = false; | 2934 for (Directive directive in node.directives) { |
| 2449 try { | 2935 directive.accept(this); |
| 2450 node.visitChildren(this); | 2936 } |
| 2451 } finally { | |
| 2452 _inFieldContext = wasInField; | |
| 2453 } | |
| 2454 return null; | |
| 2455 } | 2937 } |
| 2456 | 2938 |
| 2457 @override | 2939 @override |
| 2458 Object visitCatchClause(CatchClause node) { | 2940 void visitExportDirective(ExportDirective node) { |
| 2459 SimpleIdentifier exceptionParameter = node.exceptionParameter; | 2941 int nodeOffset = node.offset; |
| 2460 if (exceptionParameter != null) { | 2942 node.element = null; |
| 2461 // exception | 2943 for (ExportElement element in _enclosingLibrary.exports) { |
| 2462 LocalVariableElementImpl exception = | 2944 if (element.nameOffset == nodeOffset) { |
| 2463 new LocalVariableElementImpl.forNode(exceptionParameter); | 2945 node.element = element; |
| 2464 if (node.exceptionType == null) { | 2946 break; |
| 2465 exception.hasImplicitType = true; | |
| 2466 } | 2947 } |
| 2467 _currentHolder.addLocalVariable(exception); | 2948 } |
| 2468 exceptionParameter.staticElement = exception; | 2949 } |
| 2469 // stack trace | 2950 |
| 2470 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; | 2951 @override |
| 2471 if (stackTraceParameter != null) { | 2952 void visitImportDirective(ImportDirective node) { |
| 2472 LocalVariableElementImpl stackTrace = | 2953 int nodeOffset = node.offset; |
| 2473 new LocalVariableElementImpl.forNode(stackTraceParameter); | 2954 node.element = null; |
| 2474 _currentHolder.addLocalVariable(stackTrace); | 2955 for (ImportElement element in _enclosingLibrary.imports) { |
| 2475 stackTraceParameter.staticElement = stackTrace; | 2956 if (element.nameOffset == nodeOffset) { |
| 2957 node.element = element; |
| 2958 break; |
| 2476 } | 2959 } |
| 2477 } | 2960 } |
| 2478 return super.visitCatchClause(node); | |
| 2479 } | 2961 } |
| 2480 | 2962 |
| 2481 @override | 2963 @override |
| 2482 Object visitClassDeclaration(ClassDeclaration node) { | 2964 void visitLibraryDirective(LibraryDirective node) { |
| 2483 ElementHolder holder = new ElementHolder(); | 2965 node.element = _enclosingLibrary; |
| 2484 _isValidMixin = true; | |
| 2485 _functionTypesToFix = new List<FunctionTypeImpl>(); | |
| 2486 // | |
| 2487 // Process field declarations before constructors and methods so that field | |
| 2488 // formal parameters can be correctly resolved to their fields. | |
| 2489 // | |
| 2490 ElementHolder previousHolder = _currentHolder; | |
| 2491 _currentHolder = holder; | |
| 2492 try { | |
| 2493 List<ClassMember> nonFields = new List<ClassMember>(); | |
| 2494 node.visitChildren( | |
| 2495 new _ElementBuilder_visitClassDeclaration(this, nonFields)); | |
| 2496 _buildFieldMap(holder.fieldsWithoutFlushing); | |
| 2497 int count = nonFields.length; | |
| 2498 for (int i = 0; i < count; i++) { | |
| 2499 nonFields[i].accept(this); | |
| 2500 } | |
| 2501 } finally { | |
| 2502 _currentHolder = previousHolder; | |
| 2503 } | |
| 2504 SimpleIdentifier className = node.name; | |
| 2505 ClassElementImpl element = new ClassElementImpl.forNode(className); | |
| 2506 List<TypeParameterElement> typeParameters = holder.typeParameters; | |
| 2507 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters); | |
| 2508 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element); | |
| 2509 interfaceType.typeArguments = typeArguments; | |
| 2510 element.type = interfaceType; | |
| 2511 List<ConstructorElement> constructors = holder.constructors; | |
| 2512 if (constructors.length == 0) { | |
| 2513 // | |
| 2514 // Create the default constructor. | |
| 2515 // | |
| 2516 constructors = _createDefaultConstructors(interfaceType); | |
| 2517 } | |
| 2518 _setDocRange(element, node); | |
| 2519 element.abstract = node.isAbstract; | |
| 2520 element.accessors = holder.accessors; | |
| 2521 element.constructors = constructors; | |
| 2522 element.fields = holder.fields; | |
| 2523 element.methods = holder.methods; | |
| 2524 element.typeParameters = typeParameters; | |
| 2525 element.validMixin = _isValidMixin; | |
| 2526 int functionTypeCount = _functionTypesToFix.length; | |
| 2527 for (int i = 0; i < functionTypeCount; i++) { | |
| 2528 _functionTypesToFix[i].typeArguments = typeArguments; | |
| 2529 } | |
| 2530 _functionTypesToFix = null; | |
| 2531 _currentHolder.addType(element); | |
| 2532 className.staticElement = element; | |
| 2533 _fieldMap = null; | |
| 2534 holder.validate(); | |
| 2535 return null; | |
| 2536 } | |
| 2537 | |
| 2538 /** | |
| 2539 * Implementation of this method should be synchronized with | |
| 2540 * [visitClassDeclaration]. | |
| 2541 */ | |
| 2542 void visitClassDeclarationIncrementally(ClassDeclaration node) { | |
| 2543 // | |
| 2544 // Process field declarations before constructors and methods so that field | |
| 2545 // formal parameters can be correctly resolved to their fields. | |
| 2546 // | |
| 2547 ClassElement classElement = node.element; | |
| 2548 _buildFieldMap(classElement.fields); | |
| 2549 } | |
| 2550 | |
| 2551 @override | |
| 2552 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 2553 ElementHolder holder = new ElementHolder(); | |
| 2554 _functionTypesToFix = new List<FunctionTypeImpl>(); | |
| 2555 _visitChildren(holder, node); | |
| 2556 SimpleIdentifier className = node.name; | |
| 2557 ClassElementImpl element = new ClassElementImpl.forNode(className); | |
| 2558 element.abstract = node.abstractKeyword != null; | |
| 2559 element.mixinApplication = true; | |
| 2560 List<TypeParameterElement> typeParameters = holder.typeParameters; | |
| 2561 element.typeParameters = typeParameters; | |
| 2562 List<DartType> typeArguments = _createTypeParameterTypes(typeParameters); | |
| 2563 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element); | |
| 2564 interfaceType.typeArguments = typeArguments; | |
| 2565 element.type = interfaceType; | |
| 2566 // set default constructor | |
| 2567 for (FunctionTypeImpl functionType in _functionTypesToFix) { | |
| 2568 functionType.typeArguments = typeArguments; | |
| 2569 } | |
| 2570 _functionTypesToFix = null; | |
| 2571 _currentHolder.addType(element); | |
| 2572 className.staticElement = element; | |
| 2573 holder.validate(); | |
| 2574 return null; | |
| 2575 } | |
| 2576 | |
| 2577 @override | |
| 2578 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 2579 _isValidMixin = false; | |
| 2580 ElementHolder holder = new ElementHolder(); | |
| 2581 bool wasInFunction = _inFunction; | |
| 2582 _inFunction = true; | |
| 2583 try { | |
| 2584 _visitChildren(holder, node); | |
| 2585 } finally { | |
| 2586 _inFunction = wasInFunction; | |
| 2587 } | |
| 2588 FunctionBody body = node.body; | |
| 2589 SimpleIdentifier constructorName = node.name; | |
| 2590 ConstructorElementImpl element = | |
| 2591 new ConstructorElementImpl.forNode(constructorName); | |
| 2592 _setDocRange(element, node); | |
| 2593 if (node.externalKeyword != null) { | |
| 2594 element.external = true; | |
| 2595 } | |
| 2596 if (node.factoryKeyword != null) { | |
| 2597 element.factory = true; | |
| 2598 } | |
| 2599 element.functions = holder.functions; | |
| 2600 element.labels = holder.labels; | |
| 2601 element.localVariables = holder.localVariables; | |
| 2602 element.parameters = holder.parameters; | |
| 2603 element.const2 = node.constKeyword != null; | |
| 2604 if (body.isAsynchronous) { | |
| 2605 element.asynchronous = true; | |
| 2606 } | |
| 2607 if (body.isGenerator) { | |
| 2608 element.generator = true; | |
| 2609 } | |
| 2610 _currentHolder.addConstructor(element); | |
| 2611 node.element = element; | |
| 2612 if (constructorName == null) { | |
| 2613 Identifier returnType = node.returnType; | |
| 2614 if (returnType != null) { | |
| 2615 element.nameOffset = returnType.offset; | |
| 2616 element.nameEnd = returnType.end; | |
| 2617 } | |
| 2618 } else { | |
| 2619 constructorName.staticElement = element; | |
| 2620 element.periodOffset = node.period.offset; | |
| 2621 element.nameEnd = constructorName.end; | |
| 2622 } | |
| 2623 holder.validate(); | |
| 2624 return null; | |
| 2625 } | |
| 2626 | |
| 2627 @override | |
| 2628 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 2629 SimpleIdentifier variableName = node.identifier; | |
| 2630 LocalVariableElementImpl element = | |
| 2631 new LocalVariableElementImpl.forNode(variableName); | |
| 2632 ForEachStatement statement = node.parent as ForEachStatement; | |
| 2633 int declarationEnd = node.offset + node.length; | |
| 2634 int statementEnd = statement.offset + statement.length; | |
| 2635 element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1); | |
| 2636 element.const3 = node.isConst; | |
| 2637 element.final2 = node.isFinal; | |
| 2638 if (node.type == null) { | |
| 2639 element.hasImplicitType = true; | |
| 2640 } | |
| 2641 _currentHolder.addLocalVariable(element); | |
| 2642 variableName.staticElement = element; | |
| 2643 return super.visitDeclaredIdentifier(node); | |
| 2644 } | |
| 2645 | |
| 2646 @override | |
| 2647 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 2648 ElementHolder holder = new ElementHolder(); | |
| 2649 NormalFormalParameter normalParameter = node.parameter; | |
| 2650 SimpleIdentifier parameterName = normalParameter.identifier; | |
| 2651 ParameterElementImpl parameter; | |
| 2652 if (normalParameter is FieldFormalParameter) { | |
| 2653 parameter = new DefaultFieldFormalParameterElementImpl(parameterName); | |
| 2654 FieldElement field = | |
| 2655 _fieldMap == null ? null : _fieldMap[parameterName.name]; | |
| 2656 if (field != null) { | |
| 2657 (parameter as DefaultFieldFormalParameterElementImpl).field = field; | |
| 2658 } | |
| 2659 } else { | |
| 2660 parameter = new DefaultParameterElementImpl(parameterName); | |
| 2661 } | |
| 2662 parameter.const3 = node.isConst; | |
| 2663 parameter.final2 = node.isFinal; | |
| 2664 parameter.parameterKind = node.kind; | |
| 2665 // set initializer, default value range | |
| 2666 Expression defaultValue = node.defaultValue; | |
| 2667 if (defaultValue != null) { | |
| 2668 _visit(holder, defaultValue); | |
| 2669 FunctionElementImpl initializer = | |
| 2670 new FunctionElementImpl.forOffset(defaultValue.beginToken.offset); | |
| 2671 initializer.functions = holder.functions; | |
| 2672 initializer.labels = holder.labels; | |
| 2673 initializer.localVariables = holder.localVariables; | |
| 2674 initializer.parameters = holder.parameters; | |
| 2675 initializer.synthetic = true; | |
| 2676 parameter.initializer = initializer; | |
| 2677 parameter.defaultValueCode = defaultValue.toSource(); | |
| 2678 } | |
| 2679 // visible range | |
| 2680 _setParameterVisibleRange(node, parameter); | |
| 2681 if (normalParameter is SimpleFormalParameter && | |
| 2682 normalParameter.type == null) { | |
| 2683 parameter.hasImplicitType = true; | |
| 2684 } | |
| 2685 _currentHolder.addParameter(parameter); | |
| 2686 parameterName.staticElement = parameter; | |
| 2687 normalParameter.accept(this); | |
| 2688 holder.validate(); | |
| 2689 return null; | |
| 2690 } | |
| 2691 | |
| 2692 @override | |
| 2693 Object visitEnumDeclaration(EnumDeclaration node) { | |
| 2694 SimpleIdentifier enumName = node.name; | |
| 2695 ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName); | |
| 2696 enumElement.enum2 = true; | |
| 2697 _setDocRange(enumElement, node); | |
| 2698 InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement); | |
| 2699 enumElement.type = enumType; | |
| 2700 // The equivalent code for enums in the spec shows a single constructor, | |
| 2701 // but that constructor is not callable (since it is a compile-time error | |
| 2702 // to subclass, mix-in, implement, or explicitly instantiate an enum). So | |
| 2703 // we represent this as having no constructors. | |
| 2704 enumElement.constructors = ConstructorElement.EMPTY_LIST; | |
| 2705 _currentHolder.addEnum(enumElement); | |
| 2706 enumName.staticElement = enumElement; | |
| 2707 return super.visitEnumDeclaration(node); | |
| 2708 } | |
| 2709 | |
| 2710 @override | |
| 2711 Object visitFieldDeclaration(FieldDeclaration node) { | |
| 2712 bool wasInField = _inFieldContext; | |
| 2713 _inFieldContext = true; | |
| 2714 try { | |
| 2715 node.visitChildren(this); | |
| 2716 } finally { | |
| 2717 _inFieldContext = wasInField; | |
| 2718 } | |
| 2719 return null; | |
| 2720 } | |
| 2721 | |
| 2722 @override | |
| 2723 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 2724 if (node.parent is! DefaultFormalParameter) { | |
| 2725 SimpleIdentifier parameterName = node.identifier; | |
| 2726 FieldElement field = | |
| 2727 _fieldMap == null ? null : _fieldMap[parameterName.name]; | |
| 2728 FieldFormalParameterElementImpl parameter = | |
| 2729 new FieldFormalParameterElementImpl(parameterName); | |
| 2730 parameter.const3 = node.isConst; | |
| 2731 parameter.final2 = node.isFinal; | |
| 2732 parameter.parameterKind = node.kind; | |
| 2733 if (field != null) { | |
| 2734 parameter.field = field; | |
| 2735 } | |
| 2736 _currentHolder.addParameter(parameter); | |
| 2737 parameterName.staticElement = parameter; | |
| 2738 } | |
| 2739 // | |
| 2740 // The children of this parameter include any parameters defined on the type | |
| 2741 // of this parameter. | |
| 2742 // | |
| 2743 ElementHolder holder = new ElementHolder(); | |
| 2744 _visitChildren(holder, node); | |
| 2745 ParameterElementImpl element = node.element; | |
| 2746 element.parameters = holder.parameters; | |
| 2747 element.typeParameters = holder.typeParameters; | |
| 2748 holder.validate(); | |
| 2749 return null; | |
| 2750 } | |
| 2751 | |
| 2752 @override | |
| 2753 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 2754 FunctionExpression expression = node.functionExpression; | |
| 2755 if (expression != null) { | |
| 2756 ElementHolder holder = new ElementHolder(); | |
| 2757 bool wasInFunction = _inFunction; | |
| 2758 _inFunction = true; | |
| 2759 try { | |
| 2760 _visitChildren(holder, node); | |
| 2761 } finally { | |
| 2762 _inFunction = wasInFunction; | |
| 2763 } | |
| 2764 FunctionBody body = expression.body; | |
| 2765 sc.Token property = node.propertyKeyword; | |
| 2766 if (property == null || _inFunction) { | |
| 2767 SimpleIdentifier functionName = node.name; | |
| 2768 FunctionElementImpl element = | |
| 2769 new FunctionElementImpl.forNode(functionName); | |
| 2770 _setDocRange(element, node); | |
| 2771 if (node.externalKeyword != null) { | |
| 2772 element.external = true; | |
| 2773 } | |
| 2774 element.functions = holder.functions; | |
| 2775 element.labels = holder.labels; | |
| 2776 element.localVariables = holder.localVariables; | |
| 2777 element.parameters = holder.parameters; | |
| 2778 element.typeParameters = holder.typeParameters; | |
| 2779 if (body.isAsynchronous) { | |
| 2780 element.asynchronous = true; | |
| 2781 } | |
| 2782 if (body.isGenerator) { | |
| 2783 element.generator = true; | |
| 2784 } | |
| 2785 if (_inFunction) { | |
| 2786 Block enclosingBlock = node.getAncestor((node) => node is Block); | |
| 2787 if (enclosingBlock != null) { | |
| 2788 int functionEnd = node.offset + node.length; | |
| 2789 int blockEnd = enclosingBlock.offset + enclosingBlock.length; | |
| 2790 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1); | |
| 2791 } | |
| 2792 } | |
| 2793 if (node.returnType == null) { | |
| 2794 element.hasImplicitReturnType = true; | |
| 2795 } | |
| 2796 _currentHolder.addFunction(element); | |
| 2797 expression.element = element; | |
| 2798 functionName.staticElement = element; | |
| 2799 } else { | |
| 2800 SimpleIdentifier propertyNameNode = node.name; | |
| 2801 if (propertyNameNode == null) { | |
| 2802 // TODO(brianwilkerson) Report this internal error. | |
| 2803 return null; | |
| 2804 } | |
| 2805 String propertyName = propertyNameNode.name; | |
| 2806 TopLevelVariableElementImpl variable = _currentHolder | |
| 2807 .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl; | |
| 2808 if (variable == null) { | |
| 2809 variable = new TopLevelVariableElementImpl(node.name.name, -1); | |
| 2810 variable.final2 = true; | |
| 2811 variable.synthetic = true; | |
| 2812 _currentHolder.addTopLevelVariable(variable); | |
| 2813 } | |
| 2814 if (node.isGetter) { | |
| 2815 PropertyAccessorElementImpl getter = | |
| 2816 new PropertyAccessorElementImpl.forNode(propertyNameNode); | |
| 2817 _setDocRange(getter, node); | |
| 2818 if (node.externalKeyword != null) { | |
| 2819 getter.external = true; | |
| 2820 } | |
| 2821 getter.functions = holder.functions; | |
| 2822 getter.labels = holder.labels; | |
| 2823 getter.localVariables = holder.localVariables; | |
| 2824 if (body.isAsynchronous) { | |
| 2825 getter.asynchronous = true; | |
| 2826 } | |
| 2827 if (body.isGenerator) { | |
| 2828 getter.generator = true; | |
| 2829 } | |
| 2830 getter.variable = variable; | |
| 2831 getter.getter = true; | |
| 2832 getter.static = true; | |
| 2833 variable.getter = getter; | |
| 2834 if (node.returnType == null) { | |
| 2835 getter.hasImplicitReturnType = true; | |
| 2836 } | |
| 2837 _currentHolder.addAccessor(getter); | |
| 2838 expression.element = getter; | |
| 2839 propertyNameNode.staticElement = getter; | |
| 2840 } else { | |
| 2841 PropertyAccessorElementImpl setter = | |
| 2842 new PropertyAccessorElementImpl.forNode(propertyNameNode); | |
| 2843 _setDocRange(setter, node); | |
| 2844 if (node.externalKeyword != null) { | |
| 2845 setter.external = true; | |
| 2846 } | |
| 2847 setter.functions = holder.functions; | |
| 2848 setter.labels = holder.labels; | |
| 2849 setter.localVariables = holder.localVariables; | |
| 2850 setter.parameters = holder.parameters; | |
| 2851 if (body.isAsynchronous) { | |
| 2852 setter.asynchronous = true; | |
| 2853 } | |
| 2854 if (body.isGenerator) { | |
| 2855 setter.generator = true; | |
| 2856 } | |
| 2857 setter.variable = variable; | |
| 2858 setter.setter = true; | |
| 2859 setter.static = true; | |
| 2860 variable.setter = setter; | |
| 2861 variable.final2 = false; | |
| 2862 _currentHolder.addAccessor(setter); | |
| 2863 expression.element = setter; | |
| 2864 propertyNameNode.staticElement = setter; | |
| 2865 } | |
| 2866 } | |
| 2867 holder.validate(); | |
| 2868 } | |
| 2869 return null; | |
| 2870 } | |
| 2871 | |
| 2872 @override | |
| 2873 Object visitFunctionExpression(FunctionExpression node) { | |
| 2874 if (node.parent is FunctionDeclaration) { | |
| 2875 // visitFunctionDeclaration has already created the element for the | |
| 2876 // declaration. We just need to visit children. | |
| 2877 return super.visitFunctionExpression(node); | |
| 2878 } | |
| 2879 ElementHolder holder = new ElementHolder(); | |
| 2880 bool wasInFunction = _inFunction; | |
| 2881 _inFunction = true; | |
| 2882 try { | |
| 2883 _visitChildren(holder, node); | |
| 2884 } finally { | |
| 2885 _inFunction = wasInFunction; | |
| 2886 } | |
| 2887 FunctionBody body = node.body; | |
| 2888 FunctionElementImpl element = | |
| 2889 new FunctionElementImpl.forOffset(node.beginToken.offset); | |
| 2890 element.functions = holder.functions; | |
| 2891 element.labels = holder.labels; | |
| 2892 element.localVariables = holder.localVariables; | |
| 2893 element.parameters = holder.parameters; | |
| 2894 element.typeParameters = holder.typeParameters; | |
| 2895 if (body.isAsynchronous) { | |
| 2896 element.asynchronous = true; | |
| 2897 } | |
| 2898 if (body.isGenerator) { | |
| 2899 element.generator = true; | |
| 2900 } | |
| 2901 if (_inFunction) { | |
| 2902 Block enclosingBlock = node.getAncestor((node) => node is Block); | |
| 2903 if (enclosingBlock != null) { | |
| 2904 int functionEnd = node.offset + node.length; | |
| 2905 int blockEnd = enclosingBlock.offset + enclosingBlock.length; | |
| 2906 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1); | |
| 2907 } | |
| 2908 } | |
| 2909 FunctionTypeImpl type = new FunctionTypeImpl(element); | |
| 2910 if (_functionTypesToFix != null) { | |
| 2911 _functionTypesToFix.add(type); | |
| 2912 } | |
| 2913 element.type = type; | |
| 2914 element.hasImplicitReturnType = true; | |
| 2915 _currentHolder.addFunction(element); | |
| 2916 node.element = element; | |
| 2917 holder.validate(); | |
| 2918 return null; | |
| 2919 } | |
| 2920 | |
| 2921 @override | |
| 2922 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 2923 ElementHolder holder = new ElementHolder(); | |
| 2924 _visitChildren(holder, node); | |
| 2925 SimpleIdentifier aliasName = node.name; | |
| 2926 List<ParameterElement> parameters = holder.parameters; | |
| 2927 List<TypeParameterElement> typeParameters = holder.typeParameters; | |
| 2928 FunctionTypeAliasElementImpl element = | |
| 2929 new FunctionTypeAliasElementImpl.forNode(aliasName); | |
| 2930 _setDocRange(element, node); | |
| 2931 element.parameters = parameters; | |
| 2932 element.typeParameters = typeParameters; | |
| 2933 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element); | |
| 2934 type.typeArguments = _createTypeParameterTypes(typeParameters); | |
| 2935 element.type = type; | |
| 2936 _currentHolder.addTypeAlias(element); | |
| 2937 aliasName.staticElement = element; | |
| 2938 holder.validate(); | |
| 2939 return null; | |
| 2940 } | |
| 2941 | |
| 2942 @override | |
| 2943 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 2944 if (node.parent is! DefaultFormalParameter) { | |
| 2945 SimpleIdentifier parameterName = node.identifier; | |
| 2946 ParameterElementImpl parameter = | |
| 2947 new ParameterElementImpl.forNode(parameterName); | |
| 2948 parameter.parameterKind = node.kind; | |
| 2949 _setParameterVisibleRange(node, parameter); | |
| 2950 _currentHolder.addParameter(parameter); | |
| 2951 parameterName.staticElement = parameter; | |
| 2952 } | |
| 2953 // | |
| 2954 // The children of this parameter include any parameters defined on the type | |
| 2955 //of this parameter. | |
| 2956 // | |
| 2957 ElementHolder holder = new ElementHolder(); | |
| 2958 _visitChildren(holder, node); | |
| 2959 ParameterElementImpl element = node.element; | |
| 2960 element.parameters = holder.parameters; | |
| 2961 element.typeParameters = holder.typeParameters; | |
| 2962 holder.validate(); | |
| 2963 return null; | |
| 2964 } | |
| 2965 | |
| 2966 @override | |
| 2967 Object visitLabeledStatement(LabeledStatement node) { | |
| 2968 bool onSwitchStatement = node.statement is SwitchStatement; | |
| 2969 for (Label label in node.labels) { | |
| 2970 SimpleIdentifier labelName = label.label; | |
| 2971 LabelElementImpl element = | |
| 2972 new LabelElementImpl(labelName, onSwitchStatement, false); | |
| 2973 _currentHolder.addLabel(element); | |
| 2974 labelName.staticElement = element; | |
| 2975 } | |
| 2976 return super.visitLabeledStatement(node); | |
| 2977 } | |
| 2978 | |
| 2979 @override | |
| 2980 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 2981 try { | |
| 2982 ElementHolder holder = new ElementHolder(); | |
| 2983 bool wasInFunction = _inFunction; | |
| 2984 _inFunction = true; | |
| 2985 try { | |
| 2986 _visitChildren(holder, node); | |
| 2987 } finally { | |
| 2988 _inFunction = wasInFunction; | |
| 2989 } | |
| 2990 bool isStatic = node.isStatic; | |
| 2991 sc.Token property = node.propertyKeyword; | |
| 2992 FunctionBody body = node.body; | |
| 2993 if (property == null) { | |
| 2994 SimpleIdentifier methodName = node.name; | |
| 2995 String nameOfMethod = methodName.name; | |
| 2996 if (nameOfMethod == sc.TokenType.MINUS.lexeme && | |
| 2997 node.parameters.parameters.length == 0) { | |
| 2998 nameOfMethod = "unary-"; | |
| 2999 } | |
| 3000 MethodElementImpl element = | |
| 3001 new MethodElementImpl(nameOfMethod, methodName.offset); | |
| 3002 _setDocRange(element, node); | |
| 3003 element.abstract = node.isAbstract; | |
| 3004 if (node.externalKeyword != null) { | |
| 3005 element.external = true; | |
| 3006 } | |
| 3007 element.functions = holder.functions; | |
| 3008 element.labels = holder.labels; | |
| 3009 element.localVariables = holder.localVariables; | |
| 3010 element.parameters = holder.parameters; | |
| 3011 element.static = isStatic; | |
| 3012 element.typeParameters = holder.typeParameters; | |
| 3013 if (body.isAsynchronous) { | |
| 3014 element.asynchronous = true; | |
| 3015 } | |
| 3016 if (body.isGenerator) { | |
| 3017 element.generator = true; | |
| 3018 } | |
| 3019 if (node.returnType == null) { | |
| 3020 element.hasImplicitReturnType = true; | |
| 3021 } | |
| 3022 _currentHolder.addMethod(element); | |
| 3023 methodName.staticElement = element; | |
| 3024 } else { | |
| 3025 SimpleIdentifier propertyNameNode = node.name; | |
| 3026 String propertyName = propertyNameNode.name; | |
| 3027 FieldElementImpl field = | |
| 3028 _currentHolder.getField(propertyName) as FieldElementImpl; | |
| 3029 if (field == null) { | |
| 3030 field = new FieldElementImpl(node.name.name, -1); | |
| 3031 field.final2 = true; | |
| 3032 field.static = isStatic; | |
| 3033 field.synthetic = true; | |
| 3034 _currentHolder.addField(field); | |
| 3035 } | |
| 3036 if (node.isGetter) { | |
| 3037 PropertyAccessorElementImpl getter = | |
| 3038 new PropertyAccessorElementImpl.forNode(propertyNameNode); | |
| 3039 _setDocRange(getter, node); | |
| 3040 if (node.externalKeyword != null) { | |
| 3041 getter.external = true; | |
| 3042 } | |
| 3043 getter.functions = holder.functions; | |
| 3044 getter.labels = holder.labels; | |
| 3045 getter.localVariables = holder.localVariables; | |
| 3046 if (body.isAsynchronous) { | |
| 3047 getter.asynchronous = true; | |
| 3048 } | |
| 3049 if (body.isGenerator) { | |
| 3050 getter.generator = true; | |
| 3051 } | |
| 3052 getter.variable = field; | |
| 3053 getter.abstract = node.isAbstract; | |
| 3054 getter.getter = true; | |
| 3055 getter.static = isStatic; | |
| 3056 field.getter = getter; | |
| 3057 if (node.returnType == null) { | |
| 3058 getter.hasImplicitReturnType = true; | |
| 3059 } | |
| 3060 _currentHolder.addAccessor(getter); | |
| 3061 propertyNameNode.staticElement = getter; | |
| 3062 } else { | |
| 3063 PropertyAccessorElementImpl setter = | |
| 3064 new PropertyAccessorElementImpl.forNode(propertyNameNode); | |
| 3065 _setDocRange(setter, node); | |
| 3066 if (node.externalKeyword != null) { | |
| 3067 setter.external = true; | |
| 3068 } | |
| 3069 setter.functions = holder.functions; | |
| 3070 setter.labels = holder.labels; | |
| 3071 setter.localVariables = holder.localVariables; | |
| 3072 setter.parameters = holder.parameters; | |
| 3073 if (body.isAsynchronous) { | |
| 3074 setter.asynchronous = true; | |
| 3075 } | |
| 3076 if (body.isGenerator) { | |
| 3077 setter.generator = true; | |
| 3078 } | |
| 3079 setter.variable = field; | |
| 3080 setter.abstract = node.isAbstract; | |
| 3081 setter.setter = true; | |
| 3082 setter.static = isStatic; | |
| 3083 field.setter = setter; | |
| 3084 field.final2 = false; | |
| 3085 _currentHolder.addAccessor(setter); | |
| 3086 propertyNameNode.staticElement = setter; | |
| 3087 } | |
| 3088 } | |
| 3089 holder.validate(); | |
| 3090 } catch (exception, stackTrace) { | |
| 3091 if (node.name.staticElement == null) { | |
| 3092 ClassDeclaration classNode = | |
| 3093 node.getAncestor((node) => node is ClassDeclaration); | |
| 3094 StringBuffer buffer = new StringBuffer(); | |
| 3095 buffer.write("The element for the method "); | |
| 3096 buffer.write(node.name); | |
| 3097 buffer.write(" in "); | |
| 3098 buffer.write(classNode.name); | |
| 3099 buffer.write(" was not set while trying to build the element model."); | |
| 3100 AnalysisEngine.instance.logger.logError( | |
| 3101 buffer.toString(), new CaughtException(exception, stackTrace)); | |
| 3102 } else { | |
| 3103 String message = | |
| 3104 "Exception caught in ElementBuilder.visitMethodDeclaration()"; | |
| 3105 AnalysisEngine.instance.logger | |
| 3106 .logError(message, new CaughtException(exception, stackTrace)); | |
| 3107 } | |
| 3108 } finally { | |
| 3109 if (node.name.staticElement == null) { | |
| 3110 ClassDeclaration classNode = | |
| 3111 node.getAncestor((node) => node is ClassDeclaration); | |
| 3112 StringBuffer buffer = new StringBuffer(); | |
| 3113 buffer.write("The element for the method "); | |
| 3114 buffer.write(node.name); | |
| 3115 buffer.write(" in "); | |
| 3116 buffer.write(classNode.name); | |
| 3117 buffer.write(" was not set while trying to resolve types."); | |
| 3118 AnalysisEngine.instance.logger.logError( | |
| 3119 buffer.toString(), | |
| 3120 new CaughtException( | |
| 3121 new AnalysisException(buffer.toString()), null)); | |
| 3122 } | |
| 3123 } | |
| 3124 return null; | |
| 3125 } | |
| 3126 | |
| 3127 @override | |
| 3128 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 3129 if (node.parent is! DefaultFormalParameter) { | |
| 3130 SimpleIdentifier parameterName = node.identifier; | |
| 3131 ParameterElementImpl parameter = | |
| 3132 new ParameterElementImpl.forNode(parameterName); | |
| 3133 parameter.const3 = node.isConst; | |
| 3134 parameter.final2 = node.isFinal; | |
| 3135 parameter.parameterKind = node.kind; | |
| 3136 _setParameterVisibleRange(node, parameter); | |
| 3137 if (node.type == null) { | |
| 3138 parameter.hasImplicitType = true; | |
| 3139 } | |
| 3140 _currentHolder.addParameter(parameter); | |
| 3141 parameterName.staticElement = parameter; | |
| 3142 } | |
| 3143 return super.visitSimpleFormalParameter(node); | |
| 3144 } | |
| 3145 | |
| 3146 @override | |
| 3147 Object visitSuperExpression(SuperExpression node) { | |
| 3148 _isValidMixin = false; | |
| 3149 return super.visitSuperExpression(node); | |
| 3150 } | |
| 3151 | |
| 3152 @override | |
| 3153 Object visitSwitchCase(SwitchCase node) { | |
| 3154 for (Label label in node.labels) { | |
| 3155 SimpleIdentifier labelName = label.label; | |
| 3156 LabelElementImpl element = new LabelElementImpl(labelName, false, true); | |
| 3157 _currentHolder.addLabel(element); | |
| 3158 labelName.staticElement = element; | |
| 3159 } | |
| 3160 return super.visitSwitchCase(node); | |
| 3161 } | |
| 3162 | |
| 3163 @override | |
| 3164 Object visitSwitchDefault(SwitchDefault node) { | |
| 3165 for (Label label in node.labels) { | |
| 3166 SimpleIdentifier labelName = label.label; | |
| 3167 LabelElementImpl element = new LabelElementImpl(labelName, false, true); | |
| 3168 _currentHolder.addLabel(element); | |
| 3169 labelName.staticElement = element; | |
| 3170 } | |
| 3171 return super.visitSwitchDefault(node); | |
| 3172 } | |
| 3173 | |
| 3174 @override | |
| 3175 Object visitTypeParameter(TypeParameter node) { | |
| 3176 SimpleIdentifier parameterName = node.name; | |
| 3177 TypeParameterElementImpl typeParameter = | |
| 3178 new TypeParameterElementImpl.forNode(parameterName); | |
| 3179 TypeParameterTypeImpl typeParameterType = | |
| 3180 new TypeParameterTypeImpl(typeParameter); | |
| 3181 typeParameter.type = typeParameterType; | |
| 3182 _currentHolder.addTypeParameter(typeParameter); | |
| 3183 parameterName.staticElement = typeParameter; | |
| 3184 return super.visitTypeParameter(node); | |
| 3185 } | |
| 3186 | |
| 3187 @override | |
| 3188 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 3189 bool isConst = node.isConst; | |
| 3190 bool isFinal = node.isFinal; | |
| 3191 bool hasInitializer = node.initializer != null; | |
| 3192 VariableElementImpl element; | |
| 3193 if (_inFieldContext) { | |
| 3194 SimpleIdentifier fieldName = node.name; | |
| 3195 FieldElementImpl field; | |
| 3196 if ((isConst || isFinal) && hasInitializer) { | |
| 3197 field = new ConstFieldElementImpl.forNode(fieldName); | |
| 3198 } else { | |
| 3199 field = new FieldElementImpl.forNode(fieldName); | |
| 3200 } | |
| 3201 element = field; | |
| 3202 if (node.parent.parent is FieldDeclaration) { | |
| 3203 _setDocRange(element, node.parent.parent); | |
| 3204 } | |
| 3205 if ((node.parent as VariableDeclarationList).type == null) { | |
| 3206 field.hasImplicitType = true; | |
| 3207 } | |
| 3208 _currentHolder.addField(field); | |
| 3209 fieldName.staticElement = field; | |
| 3210 } else if (_inFunction) { | |
| 3211 SimpleIdentifier variableName = node.name; | |
| 3212 LocalVariableElementImpl variable; | |
| 3213 if (isConst && hasInitializer) { | |
| 3214 variable = new ConstLocalVariableElementImpl.forNode(variableName); | |
| 3215 } else { | |
| 3216 variable = new LocalVariableElementImpl.forNode(variableName); | |
| 3217 } | |
| 3218 element = variable; | |
| 3219 Block enclosingBlock = node.getAncestor((node) => node is Block); | |
| 3220 // TODO(brianwilkerson) This isn't right for variables declared in a for | |
| 3221 // loop. | |
| 3222 variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length); | |
| 3223 if ((node.parent as VariableDeclarationList).type == null) { | |
| 3224 variable.hasImplicitType = true; | |
| 3225 } | |
| 3226 _currentHolder.addLocalVariable(variable); | |
| 3227 variableName.staticElement = element; | |
| 3228 } else { | |
| 3229 SimpleIdentifier variableName = node.name; | |
| 3230 TopLevelVariableElementImpl variable; | |
| 3231 if (isConst && hasInitializer) { | |
| 3232 variable = new ConstTopLevelVariableElementImpl(variableName); | |
| 3233 } else { | |
| 3234 variable = new TopLevelVariableElementImpl.forNode(variableName); | |
| 3235 } | |
| 3236 element = variable; | |
| 3237 if (node.parent.parent is TopLevelVariableDeclaration) { | |
| 3238 _setDocRange(element, node.parent.parent); | |
| 3239 } | |
| 3240 if ((node.parent as VariableDeclarationList).type == null) { | |
| 3241 variable.hasImplicitType = true; | |
| 3242 } | |
| 3243 _currentHolder.addTopLevelVariable(variable); | |
| 3244 variableName.staticElement = element; | |
| 3245 } | |
| 3246 element.const3 = isConst; | |
| 3247 element.final2 = isFinal; | |
| 3248 if (hasInitializer) { | |
| 3249 ElementHolder holder = new ElementHolder(); | |
| 3250 bool wasInFieldContext = _inFieldContext; | |
| 3251 _inFieldContext = false; | |
| 3252 try { | |
| 3253 _visit(holder, node.initializer); | |
| 3254 } finally { | |
| 3255 _inFieldContext = wasInFieldContext; | |
| 3256 } | |
| 3257 FunctionElementImpl initializer = | |
| 3258 new FunctionElementImpl.forOffset(node.initializer.beginToken.offset); | |
| 3259 initializer.functions = holder.functions; | |
| 3260 initializer.labels = holder.labels; | |
| 3261 initializer.localVariables = holder.localVariables; | |
| 3262 initializer.synthetic = true; | |
| 3263 element.initializer = initializer; | |
| 3264 holder.validate(); | |
| 3265 } | |
| 3266 if (element is PropertyInducingElementImpl) { | |
| 3267 if (_inFieldContext) { | |
| 3268 (element as FieldElementImpl).static = | |
| 3269 (node.parent.parent as FieldDeclaration).isStatic; | |
| 3270 } | |
| 3271 PropertyAccessorElementImpl getter = | |
| 3272 new PropertyAccessorElementImpl.forVariable(element); | |
| 3273 getter.getter = true; | |
| 3274 if (element.hasImplicitType) { | |
| 3275 getter.hasImplicitReturnType = true; | |
| 3276 } | |
| 3277 _currentHolder.addAccessor(getter); | |
| 3278 element.getter = getter; | |
| 3279 if (!isConst && !isFinal) { | |
| 3280 PropertyAccessorElementImpl setter = | |
| 3281 new PropertyAccessorElementImpl.forVariable(element); | |
| 3282 setter.setter = true; | |
| 3283 ParameterElementImpl parameter = | |
| 3284 new ParameterElementImpl("_${element.name}", element.nameOffset); | |
| 3285 parameter.synthetic = true; | |
| 3286 parameter.parameterKind = ParameterKind.REQUIRED; | |
| 3287 setter.parameters = <ParameterElement>[parameter]; | |
| 3288 _currentHolder.addAccessor(setter); | |
| 3289 element.setter = setter; | |
| 3290 } | |
| 3291 } | |
| 3292 return null; | |
| 3293 } | |
| 3294 | |
| 3295 /** | |
| 3296 * Build the table mapping field names to field elements for the fields define
d in the current | |
| 3297 * class. | |
| 3298 * | |
| 3299 * @param fields the field elements defined in the current class | |
| 3300 */ | |
| 3301 void _buildFieldMap(List<FieldElement> fields) { | |
| 3302 _fieldMap = new HashMap<String, FieldElement>(); | |
| 3303 int count = fields.length; | |
| 3304 for (int i = 0; i < count; i++) { | |
| 3305 FieldElement field = fields[i]; | |
| 3306 _fieldMap[field.name] = field; | |
| 3307 } | |
| 3308 } | |
| 3309 | |
| 3310 /** | |
| 3311 * Creates the [ConstructorElement]s array with the single default constructor
element. | |
| 3312 * | |
| 3313 * @param interfaceType the interface type for which to create a default const
ructor | |
| 3314 * @return the [ConstructorElement]s array with the single default constructor
element | |
| 3315 */ | |
| 3316 List<ConstructorElement> _createDefaultConstructors( | |
| 3317 InterfaceTypeImpl interfaceType) { | |
| 3318 ConstructorElementImpl constructor = | |
| 3319 new ConstructorElementImpl.forNode(null); | |
| 3320 constructor.synthetic = true; | |
| 3321 constructor.returnType = interfaceType; | |
| 3322 FunctionTypeImpl type = new FunctionTypeImpl(constructor); | |
| 3323 _functionTypesToFix.add(type); | |
| 3324 constructor.type = type; | |
| 3325 return <ConstructorElement>[constructor]; | |
| 3326 } | |
| 3327 | |
| 3328 /** | |
| 3329 * Create the types associated with the given type parameters, setting the typ
e of each type | |
| 3330 * parameter, and return an array of types corresponding to the given paramete
rs. | |
| 3331 * | |
| 3332 * @param typeParameters the type parameters for which types are to be created | |
| 3333 * @return an array of types corresponding to the given parameters | |
| 3334 */ | |
| 3335 List<DartType> _createTypeParameterTypes( | |
| 3336 List<TypeParameterElement> typeParameters) { | |
| 3337 int typeParameterCount = typeParameters.length; | |
| 3338 List<DartType> typeArguments = new List<DartType>(typeParameterCount); | |
| 3339 for (int i = 0; i < typeParameterCount; i++) { | |
| 3340 TypeParameterElementImpl typeParameter = | |
| 3341 typeParameters[i] as TypeParameterElementImpl; | |
| 3342 TypeParameterTypeImpl typeParameterType = | |
| 3343 new TypeParameterTypeImpl(typeParameter); | |
| 3344 typeParameter.type = typeParameterType; | |
| 3345 typeArguments[i] = typeParameterType; | |
| 3346 } | |
| 3347 return typeArguments; | |
| 3348 } | |
| 3349 | |
| 3350 /** | |
| 3351 * Return the body of the function that contains the given parameter, or `null
` if no | |
| 3352 * function body could be found. | |
| 3353 * | |
| 3354 * @param node the parameter contained in the function whose body is to be ret
urned | |
| 3355 * @return the body of the function that contains the given parameter | |
| 3356 */ | |
| 3357 FunctionBody _getFunctionBody(FormalParameter node) { | |
| 3358 AstNode parent = node.parent; | |
| 3359 while (parent != null) { | |
| 3360 if (parent is ConstructorDeclaration) { | |
| 3361 return parent.body; | |
| 3362 } else if (parent is FunctionExpression) { | |
| 3363 return parent.body; | |
| 3364 } else if (parent is MethodDeclaration) { | |
| 3365 return parent.body; | |
| 3366 } | |
| 3367 parent = parent.parent; | |
| 3368 } | |
| 3369 return null; | |
| 3370 } | |
| 3371 | |
| 3372 /** | |
| 3373 * If the given [node] has a documentation comment, remember its range | |
| 3374 * into the given [element]. | |
| 3375 */ | |
| 3376 void _setDocRange(ElementImpl element, AnnotatedNode node) { | |
| 3377 Comment comment = node.documentationComment; | |
| 3378 if (comment != null && comment.isDocumentation) { | |
| 3379 element.setDocRange(comment.offset, comment.length); | |
| 3380 } | |
| 3381 } | |
| 3382 | |
| 3383 /** | |
| 3384 * Sets the visible source range for formal parameter. | |
| 3385 */ | |
| 3386 void _setParameterVisibleRange( | |
| 3387 FormalParameter node, ParameterElementImpl element) { | |
| 3388 FunctionBody body = _getFunctionBody(node); | |
| 3389 if (body != null) { | |
| 3390 element.setVisibleRange(body.offset, body.length); | |
| 3391 } | |
| 3392 } | |
| 3393 | |
| 3394 /** | |
| 3395 * Make the given holder be the current holder while visiting the given node. | |
| 3396 * | |
| 3397 * @param holder the holder that will gather elements that are built while vis
iting the children | |
| 3398 * @param node the node to be visited | |
| 3399 */ | |
| 3400 void _visit(ElementHolder holder, AstNode node) { | |
| 3401 if (node != null) { | |
| 3402 ElementHolder previousHolder = _currentHolder; | |
| 3403 _currentHolder = holder; | |
| 3404 try { | |
| 3405 node.accept(this); | |
| 3406 } finally { | |
| 3407 _currentHolder = previousHolder; | |
| 3408 } | |
| 3409 } | |
| 3410 } | |
| 3411 | |
| 3412 /** | |
| 3413 * Make the given holder be the current holder while visiting the children of
the given node. | |
| 3414 * | |
| 3415 * @param holder the holder that will gather elements that are built while vis
iting the children | |
| 3416 * @param node the node whose children are to be visited | |
| 3417 */ | |
| 3418 void _visitChildren(ElementHolder holder, AstNode node) { | |
| 3419 if (node != null) { | |
| 3420 ElementHolder previousHolder = _currentHolder; | |
| 3421 _currentHolder = holder; | |
| 3422 try { | |
| 3423 node.visitChildren(this); | |
| 3424 } finally { | |
| 3425 _currentHolder = previousHolder; | |
| 3426 } | |
| 3427 } | |
| 3428 } | 2966 } |
| 3429 } | 2967 } |
| 3430 | 2968 |
| 3431 /** | 2969 /** |
| 3432 * Instances of the class `ElementHolder` hold on to elements created while trav
ersing an AST | 2970 * Instances of the class `ElementHolder` hold on to elements created while trav
ersing an AST |
| 3433 * structure so that they can be accessed when creating their enclosing element. | 2971 * structure so that they can be accessed when creating their enclosing element. |
| 3434 */ | 2972 */ |
| 3435 class ElementHolder { | 2973 class ElementHolder { |
| 3436 List<PropertyAccessorElement> _accessors; | 2974 List<PropertyAccessorElement> _accessors; |
| 3437 | 2975 |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3668 _typeAliases.add(element); | 3206 _typeAliases.add(element); |
| 3669 } | 3207 } |
| 3670 | 3208 |
| 3671 void addTypeParameter(TypeParameterElement element) { | 3209 void addTypeParameter(TypeParameterElement element) { |
| 3672 if (_typeParameters == null) { | 3210 if (_typeParameters == null) { |
| 3673 _typeParameters = new List<TypeParameterElement>(); | 3211 _typeParameters = new List<TypeParameterElement>(); |
| 3674 } | 3212 } |
| 3675 _typeParameters.add(element); | 3213 _typeParameters.add(element); |
| 3676 } | 3214 } |
| 3677 | 3215 |
| 3678 FieldElement getField(String fieldName) { | 3216 FieldElement getField(String fieldName, {bool synthetic: false}) { |
| 3679 if (_fields == null) { | 3217 if (_fields == null) { |
| 3680 return null; | 3218 return null; |
| 3681 } | 3219 } |
| 3682 for (FieldElement field in _fields) { | 3220 int length = _fields.length; |
| 3683 if (field.name == fieldName) { | 3221 for (int i = 0; i < length; i++) { |
| 3222 FieldElement field = _fields[i]; |
| 3223 if (field.name == fieldName && field.isSynthetic == synthetic) { |
| 3684 return field; | 3224 return field; |
| 3685 } | 3225 } |
| 3686 } | 3226 } |
| 3687 return null; | 3227 return null; |
| 3688 } | 3228 } |
| 3689 | 3229 |
| 3690 TopLevelVariableElement getTopLevelVariable(String variableName) { | 3230 TopLevelVariableElement getTopLevelVariable(String variableName) { |
| 3691 if (_topLevelVariables == null) { | 3231 if (_topLevelVariables == null) { |
| 3692 return null; | 3232 return null; |
| 3693 } | 3233 } |
| 3694 for (TopLevelVariableElement variable in _topLevelVariables) { | 3234 int length = _topLevelVariables.length; |
| 3235 for (int i = 0; i < length; i++) { |
| 3236 TopLevelVariableElement variable = _topLevelVariables[i]; |
| 3695 if (variable.name == variableName) { | 3237 if (variable.name == variableName) { |
| 3696 return variable; | 3238 return variable; |
| 3697 } | 3239 } |
| 3698 } | 3240 } |
| 3699 return null; | 3241 return null; |
| 3700 } | 3242 } |
| 3701 | 3243 |
| 3702 void validate() { | 3244 void validate() { |
| 3703 StringBuffer buffer = new StringBuffer(); | 3245 StringBuffer buffer = new StringBuffer(); |
| 3704 if (_accessors != null) { | 3246 if (_accessors != null) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3782 buffer.write(_typeParameters.length); | 3324 buffer.write(_typeParameters.length); |
| 3783 buffer.write(" type parameters"); | 3325 buffer.write(" type parameters"); |
| 3784 } | 3326 } |
| 3785 if (buffer.length > 0) { | 3327 if (buffer.length > 0) { |
| 3786 AnalysisEngine.instance.logger | 3328 AnalysisEngine.instance.logger |
| 3787 .logError("Failed to capture elements: $buffer"); | 3329 .logError("Failed to capture elements: $buffer"); |
| 3788 } | 3330 } |
| 3789 } | 3331 } |
| 3790 } | 3332 } |
| 3791 | 3333 |
| 3792 /** | 3334 class ElementMismatchException extends AnalysisException { |
| 3793 * Instances of the class `EnclosedScope` implement a scope that is lexically en
closed in | |
| 3794 * another scope. | |
| 3795 */ | |
| 3796 class EnclosedScope extends Scope { | |
| 3797 /** | 3335 /** |
| 3798 * The scope in which this scope is lexically enclosed. | 3336 * Initialize a newly created exception to have the given [message] and |
| 3337 * [cause]. |
| 3799 */ | 3338 */ |
| 3800 final Scope enclosingScope; | 3339 ElementMismatchException(String message, [CaughtException cause = null]) |
| 3801 | 3340 : super(message, cause); |
| 3802 /** | |
| 3803 * A table mapping names that will be defined in this scope, but right now are
not initialized. | |
| 3804 * According to the scoping rules these names are hidden, even if they were de
fined in an outer | |
| 3805 * scope. | |
| 3806 */ | |
| 3807 HashMap<String, Element> _hiddenElements = new HashMap<String, Element>(); | |
| 3808 | |
| 3809 /** | |
| 3810 * A flag indicating whether there are any names defined in this scope. | |
| 3811 */ | |
| 3812 bool _hasHiddenName = false; | |
| 3813 | |
| 3814 /** | |
| 3815 * Initialize a newly created scope enclosed within another scope. | |
| 3816 * | |
| 3817 * @param enclosingScope the scope in which this scope is lexically enclosed | |
| 3818 */ | |
| 3819 EnclosedScope(this.enclosingScope); | |
| 3820 | |
| 3821 @override | |
| 3822 AnalysisErrorListener get errorListener => enclosingScope.errorListener; | |
| 3823 | |
| 3824 /** | |
| 3825 * Record that given element is declared in this scope, but hasn't been initia
lized yet, so it is | |
| 3826 * error to use. If there is already an element with the given name defined in
an outer scope, | |
| 3827 * then it will become unavailable. | |
| 3828 * | |
| 3829 * @param element the element declared, but not initialized in this scope | |
| 3830 */ | |
| 3831 void hide(Element element) { | |
| 3832 if (element != null) { | |
| 3833 String name = element.name; | |
| 3834 if (name != null && !name.isEmpty) { | |
| 3835 _hiddenElements[name] = element; | |
| 3836 _hasHiddenName = true; | |
| 3837 } | |
| 3838 } | |
| 3839 } | |
| 3840 | |
| 3841 @override | |
| 3842 Element internalLookup( | |
| 3843 Identifier identifier, String name, LibraryElement referencingLibrary) { | |
| 3844 Element element = localLookup(name, referencingLibrary); | |
| 3845 if (element != null) { | |
| 3846 return element; | |
| 3847 } | |
| 3848 // May be there is a hidden Element. | |
| 3849 if (_hasHiddenName) { | |
| 3850 Element hiddenElement = _hiddenElements[name]; | |
| 3851 if (hiddenElement != null) { | |
| 3852 errorListener.onError(new AnalysisError( | |
| 3853 getSource(identifier), | |
| 3854 identifier.offset, | |
| 3855 identifier.length, | |
| 3856 CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, [])); | |
| 3857 return hiddenElement; | |
| 3858 } | |
| 3859 } | |
| 3860 // Check enclosing scope. | |
| 3861 return enclosingScope.internalLookup(identifier, name, referencingLibrary); | |
| 3862 } | |
| 3863 } | 3341 } |
| 3864 | 3342 |
| 3865 /** | 3343 /** |
| 3866 * Instances of the class `EnumMemberBuilder` build the members in enum declarat
ions. | 3344 * Instances of the class `EnumMemberBuilder` build the members in enum declarat
ions. |
| 3867 */ | 3345 */ |
| 3868 class EnumMemberBuilder extends RecursiveAstVisitor<Object> { | 3346 class EnumMemberBuilder extends RecursiveAstVisitor<Object> { |
| 3869 /** | 3347 /** |
| 3870 * The type provider used to access the types needed to build an element model
for enum | 3348 * The type provider used to access the types needed to build an element model
for enum |
| 3871 * declarations. | 3349 * declarations. |
| 3872 */ | 3350 */ |
| 3873 final TypeProvider _typeProvider; | 3351 final TypeProvider _typeProvider; |
| 3874 | 3352 |
| 3875 /** | 3353 /** |
| 3876 * Initialize a newly created enum member builder. | 3354 * Initialize a newly created enum member builder. |
| 3877 * | 3355 * |
| 3878 * @param typeProvider the type provider used to access the types needed to bu
ild an element model | 3356 * @param typeProvider the type provider used to access the types needed to bu
ild an element model |
| 3879 * for enum declarations | 3357 * for enum declarations |
| 3880 */ | 3358 */ |
| 3881 EnumMemberBuilder(this._typeProvider); | 3359 EnumMemberBuilder(this._typeProvider); |
| 3882 | 3360 |
| 3883 @override | 3361 @override |
| 3884 Object visitEnumDeclaration(EnumDeclaration node) { | 3362 Object visitEnumDeclaration(EnumDeclaration node) { |
| 3885 // | 3363 // |
| 3886 // Finish building the enum. | 3364 // Finish building the enum. |
| 3887 // | 3365 // |
| 3888 ClassElementImpl enumElement = node.name.staticElement as ClassElementImpl; | 3366 EnumElementImpl enumElement = node.name.staticElement as EnumElementImpl; |
| 3889 InterfaceType enumType = enumElement.type; | 3367 InterfaceType enumType = enumElement.type; |
| 3890 enumElement.supertype = _typeProvider.objectType; | |
| 3891 // | 3368 // |
| 3892 // Populate the fields. | 3369 // Populate the fields. |
| 3893 // | 3370 // |
| 3894 List<FieldElement> fields = new List<FieldElement>(); | 3371 List<FieldElement> fields = new List<FieldElement>(); |
| 3895 List<PropertyAccessorElement> getters = new List<PropertyAccessorElement>(); | 3372 List<PropertyAccessorElement> getters = new List<PropertyAccessorElement>(); |
| 3896 InterfaceType intType = _typeProvider.intType; | 3373 InterfaceType intType = _typeProvider.intType; |
| 3897 String indexFieldName = "index"; | 3374 String indexFieldName = "index"; |
| 3898 FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1); | 3375 FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1); |
| 3899 indexField.final2 = true; | 3376 indexField.final2 = true; |
| 3900 indexField.synthetic = true; | 3377 indexField.synthetic = true; |
| 3901 indexField.type = intType; | 3378 indexField.type = intType; |
| 3902 fields.add(indexField); | 3379 fields.add(indexField); |
| 3903 getters.add(_createGetter(indexField)); | 3380 getters.add(_createGetter(indexField)); |
| 3904 ConstFieldElementImpl valuesField = new ConstFieldElementImpl("values", -1); | 3381 ConstFieldElementImpl valuesField = new ConstFieldElementImpl("values", -1); |
| 3905 valuesField.static = true; | 3382 valuesField.static = true; |
| 3906 valuesField.const3 = true; | 3383 valuesField.const3 = true; |
| 3907 valuesField.synthetic = true; | 3384 valuesField.synthetic = true; |
| 3908 valuesField.type = _typeProvider.listType.substitute4(<DartType>[enumType]); | 3385 valuesField.type = _typeProvider.listType.instantiate(<DartType>[enumType]); |
| 3909 fields.add(valuesField); | 3386 fields.add(valuesField); |
| 3910 getters.add(_createGetter(valuesField)); | 3387 getters.add(_createGetter(valuesField)); |
| 3911 // | 3388 // |
| 3912 // Build the enum constants. | 3389 // Build the enum constants. |
| 3913 // | 3390 // |
| 3914 NodeList<EnumConstantDeclaration> constants = node.constants; | 3391 NodeList<EnumConstantDeclaration> constants = node.constants; |
| 3915 List<DartObjectImpl> constantValues = new List<DartObjectImpl>(); | 3392 List<DartObjectImpl> constantValues = new List<DartObjectImpl>(); |
| 3916 int constantCount = constants.length; | 3393 int constantCount = constants.length; |
| 3917 for (int i = 0; i < constantCount; i++) { | 3394 for (int i = 0; i < constantCount; i++) { |
| 3918 SimpleIdentifier constantName = constants[i].name; | 3395 EnumConstantDeclaration constant = constants[i]; |
| 3919 FieldElementImpl constantField = | 3396 FieldElementImpl constantField = constant.name.staticElement; |
| 3920 new ConstFieldElementImpl.forNode(constantName); | |
| 3921 constantField.static = true; | |
| 3922 constantField.const3 = true; | |
| 3923 constantField.type = enumType; | |
| 3924 // | 3397 // |
| 3925 // Create a value for the constant. | 3398 // Create a value for the constant. |
| 3926 // | 3399 // |
| 3927 HashMap<String, DartObjectImpl> fieldMap = | 3400 HashMap<String, DartObjectImpl> fieldMap = |
| 3928 new HashMap<String, DartObjectImpl>(); | 3401 new HashMap<String, DartObjectImpl>(); |
| 3929 fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i)); | 3402 fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i)); |
| 3930 DartObjectImpl value = | 3403 DartObjectImpl value = |
| 3931 new DartObjectImpl(enumType, new GenericState(fieldMap)); | 3404 new DartObjectImpl(enumType, new GenericState(fieldMap)); |
| 3932 constantValues.add(value); | 3405 constantValues.add(value); |
| 3933 constantField.evaluationResult = new EvaluationResultImpl(value); | 3406 constantField.evaluationResult = new EvaluationResultImpl(value); |
| 3934 fields.add(constantField); | 3407 fields.add(constantField); |
| 3935 getters.add(_createGetter(constantField)); | 3408 getters.add(constantField.getter); |
| 3936 constantName.staticElement = constantField; | |
| 3937 } | 3409 } |
| 3938 // | 3410 // |
| 3939 // Build the value of the 'values' field. | 3411 // Build the value of the 'values' field. |
| 3940 // | 3412 // |
| 3941 valuesField.evaluationResult = new EvaluationResultImpl( | 3413 valuesField.evaluationResult = new EvaluationResultImpl( |
| 3942 new DartObjectImpl(valuesField.type, new ListState(constantValues))); | 3414 new DartObjectImpl(valuesField.type, new ListState(constantValues))); |
| 3943 // | 3415 // |
| 3944 // Finish building the enum. | 3416 // Finish building the enum. |
| 3945 // | 3417 // |
| 3946 enumElement.fields = fields; | 3418 enumElement.fields = fields; |
| 3947 enumElement.accessors = getters; | 3419 enumElement.accessors = getters; |
| 3948 // Client code isn't allowed to invoke the constructor, so we do not model | 3420 // Client code isn't allowed to invoke the constructor, so we do not model |
| 3949 // it. | 3421 // it. |
| 3950 return super.visitEnumDeclaration(node); | 3422 return super.visitEnumDeclaration(node); |
| 3951 } | 3423 } |
| 3952 | 3424 |
| 3953 /** | 3425 /** |
| 3954 * Create a getter that corresponds to the given field. | 3426 * Create a getter that corresponds to the given [field]. |
| 3955 * | |
| 3956 * @param field the field for which a getter is to be created | |
| 3957 * @return the getter that was created | |
| 3958 */ | 3427 */ |
| 3959 PropertyAccessorElement _createGetter(FieldElementImpl field) { | 3428 PropertyAccessorElement _createGetter(FieldElementImpl field) { |
| 3960 PropertyAccessorElementImpl getter = | 3429 return new PropertyAccessorElementImpl_ImplicitGetter(field); |
| 3961 new PropertyAccessorElementImpl.forVariable(field); | |
| 3962 getter.getter = true; | |
| 3963 getter.returnType = field.type; | |
| 3964 getter.type = new FunctionTypeImpl(getter); | |
| 3965 field.getter = getter; | |
| 3966 return getter; | |
| 3967 } | 3430 } |
| 3968 } | 3431 } |
| 3969 | 3432 |
| 3433 /** |
| 3434 * A mixin for classes that use an existing element model to resolve a portion |
| 3435 * of an AST structure. |
| 3436 */ |
| 3437 class ExistingElementResolver { |
| 3438 /** |
| 3439 * The compilation unit containing the AST nodes being visited. |
| 3440 */ |
| 3441 CompilationUnitElementImpl _enclosingUnit; |
| 3442 |
| 3443 /** |
| 3444 * Throw an [ElementMismatchException] to report that the element model and th
e |
| 3445 * AST do not match. The [message] will have the path to the given [node] |
| 3446 * appended to it. |
| 3447 */ |
| 3448 void _mismatch(String message, AstNode node) { |
| 3449 StringBuffer buffer = new StringBuffer(); |
| 3450 buffer.write('Mismatch in '); |
| 3451 buffer.write(runtimeType); |
| 3452 buffer.write(' while resolving '); |
| 3453 buffer.writeln(_enclosingUnit?.source?.fullName); |
| 3454 buffer.writeln(message); |
| 3455 buffer.write('Path to root:'); |
| 3456 String separator = ' '; |
| 3457 AstNode parent = node; |
| 3458 while (parent != null) { |
| 3459 buffer.write(separator); |
| 3460 buffer.write(parent.runtimeType.toString()); |
| 3461 separator = ', '; |
| 3462 parent = parent.parent; |
| 3463 } |
| 3464 throw new ElementMismatchException(buffer.toString()); |
| 3465 } |
| 3466 } |
| 3467 |
| 3970 /** | 3468 /** |
| 3971 * Instances of the class `ExitDetector` determine whether the visited AST node
is guaranteed | 3469 * Instances of the class `ExitDetector` determine whether the visited AST node
is guaranteed |
| 3972 * to terminate by executing a `return` statement, `throw` expression, `rethrow` | 3470 * to terminate by executing a `return` statement, `throw` expression, `rethrow` |
| 3973 * expression, or simple infinite loop such as `while(true)`. | 3471 * expression, or simple infinite loop such as `while(true)`. |
| 3974 */ | 3472 */ |
| 3975 class ExitDetector extends GeneralizingAstVisitor<bool> { | 3473 class ExitDetector extends GeneralizingAstVisitor<bool> { |
| 3976 /** | 3474 /** |
| 3977 * Set to `true` when a `break` is encountered, and reset to `false` when a | 3475 * Set to `true` when a `break` is encountered, and reset to `false` when a |
| 3978 * `do`, `while`, `for` or `switch` block is entered. | 3476 * `do`, `while`, `for` or `switch` block is entered. |
| 3979 */ | 3477 */ |
| 3980 bool _enclosingBlockContainsBreak = false; | 3478 bool _enclosingBlockContainsBreak = false; |
| 3981 | 3479 |
| 3480 /** |
| 3481 * Set to `true` when a `continue` is encountered, and reset to `false` when a |
| 3482 * `do`, `while`, `for` or `switch` block is entered. |
| 3483 */ |
| 3484 bool _enclosingBlockContainsContinue = false; |
| 3485 |
| 3486 /** |
| 3487 * Add node when a labelled `break` is encountered. |
| 3488 */ |
| 3489 Set<AstNode> _enclosingBlockBreaksLabel = new Set<AstNode>(); |
| 3490 |
| 3982 @override | 3491 @override |
| 3983 bool visitArgumentList(ArgumentList node) => | 3492 bool visitArgumentList(ArgumentList node) => |
| 3984 _visitExpressions(node.arguments); | 3493 _visitExpressions(node.arguments); |
| 3985 | 3494 |
| 3986 @override | 3495 @override |
| 3987 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression); | 3496 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression); |
| 3988 | 3497 |
| 3989 @override | 3498 @override |
| 3990 bool visitAssertStatement(AssertStatement node) => false; | 3499 bool visitAssertStatement(AssertStatement node) => false; |
| 3991 | 3500 |
| 3992 @override | 3501 @override |
| 3993 bool visitAssignmentExpression(AssignmentExpression node) { | 3502 bool visitAssignmentExpression(AssignmentExpression node) { |
| 3994 Expression leftHandSide = node.leftHandSide; | 3503 Expression leftHandSide = node.leftHandSide; |
| 3995 if (_nodeExits(leftHandSide)) { | 3504 if (_nodeExits(leftHandSide)) { |
| 3996 return true; | 3505 return true; |
| 3997 } | 3506 } |
| 3998 if (node.operator.type == sc.TokenType.QUESTION_QUESTION_EQ) { | 3507 TokenType operatorType = node.operator.type; |
| 3508 if (operatorType == TokenType.AMPERSAND_AMPERSAND_EQ || |
| 3509 operatorType == TokenType.BAR_BAR_EQ || |
| 3510 operatorType == TokenType.QUESTION_QUESTION_EQ) { |
| 3999 return false; | 3511 return false; |
| 4000 } | 3512 } |
| 4001 if (leftHandSide is PropertyAccess && | 3513 if (leftHandSide is PropertyAccess && |
| 4002 leftHandSide.operator.type == sc.TokenType.QUESTION_PERIOD) { | 3514 leftHandSide.operator.type == TokenType.QUESTION_PERIOD) { |
| 4003 return false; | 3515 return false; |
| 4004 } | 3516 } |
| 4005 return _nodeExits(node.rightHandSide); | 3517 return _nodeExits(node.rightHandSide); |
| 4006 } | 3518 } |
| 4007 | 3519 |
| 4008 @override | 3520 @override |
| 4009 bool visitAwaitExpression(AwaitExpression node) => | 3521 bool visitAwaitExpression(AwaitExpression node) => |
| 4010 _nodeExits(node.expression); | 3522 _nodeExits(node.expression); |
| 4011 | 3523 |
| 4012 @override | 3524 @override |
| 4013 bool visitBinaryExpression(BinaryExpression node) { | 3525 bool visitBinaryExpression(BinaryExpression node) { |
| 4014 Expression lhsExpression = node.leftOperand; | 3526 Expression lhsExpression = node.leftOperand; |
| 4015 Expression rhsExpression = node.rightOperand; | 3527 Expression rhsExpression = node.rightOperand; |
| 4016 sc.TokenType operatorType = node.operator.type; | 3528 TokenType operatorType = node.operator.type; |
| 4017 // If the operator is ||, then only consider the RHS of the binary | 3529 // If the operator is ||, then only consider the RHS of the binary |
| 4018 // expression if the left hand side is the false literal. | 3530 // expression if the left hand side is the false literal. |
| 4019 // TODO(jwren) Do we want to take constant expressions into account, | 3531 // TODO(jwren) Do we want to take constant expressions into account, |
| 4020 // evaluate if(false) {} differently than if(<condition>), when <condition> | 3532 // evaluate if(false) {} differently than if(<condition>), when <condition> |
| 4021 // evaluates to a constant false value? | 3533 // evaluates to a constant false value? |
| 4022 if (operatorType == sc.TokenType.BAR_BAR) { | 3534 if (operatorType == TokenType.BAR_BAR) { |
| 4023 if (lhsExpression is BooleanLiteral) { | 3535 if (lhsExpression is BooleanLiteral) { |
| 4024 BooleanLiteral booleanLiteral = lhsExpression; | 3536 if (!lhsExpression.value) { |
| 4025 if (!booleanLiteral.value) { | |
| 4026 return _nodeExits(rhsExpression); | 3537 return _nodeExits(rhsExpression); |
| 4027 } | 3538 } |
| 4028 } | 3539 } |
| 4029 return _nodeExits(lhsExpression); | 3540 return _nodeExits(lhsExpression); |
| 4030 } | 3541 } |
| 4031 // If the operator is &&, then only consider the RHS of the binary | 3542 // If the operator is &&, then only consider the RHS of the binary |
| 4032 // expression if the left hand side is the true literal. | 3543 // expression if the left hand side is the true literal. |
| 4033 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) { | 3544 if (operatorType == TokenType.AMPERSAND_AMPERSAND) { |
| 4034 if (lhsExpression is BooleanLiteral) { | 3545 if (lhsExpression is BooleanLiteral) { |
| 4035 BooleanLiteral booleanLiteral = lhsExpression; | 3546 if (lhsExpression.value) { |
| 4036 if (booleanLiteral.value) { | |
| 4037 return _nodeExits(rhsExpression); | 3547 return _nodeExits(rhsExpression); |
| 4038 } | 3548 } |
| 4039 } | 3549 } |
| 4040 return _nodeExits(lhsExpression); | 3550 return _nodeExits(lhsExpression); |
| 4041 } | 3551 } |
| 4042 // If the operator is ??, then don't consider the RHS of the binary | 3552 // If the operator is ??, then don't consider the RHS of the binary |
| 4043 // expression. | 3553 // expression. |
| 4044 if (operatorType == sc.TokenType.QUESTION_QUESTION) { | 3554 if (operatorType == TokenType.QUESTION_QUESTION) { |
| 4045 return _nodeExits(lhsExpression); | 3555 return _nodeExits(lhsExpression); |
| 4046 } | 3556 } |
| 4047 return _nodeExits(lhsExpression) || _nodeExits(rhsExpression); | 3557 return _nodeExits(lhsExpression) || _nodeExits(rhsExpression); |
| 4048 } | 3558 } |
| 4049 | 3559 |
| 4050 @override | 3560 @override |
| 4051 bool visitBlock(Block node) => _visitStatements(node.statements); | 3561 bool visitBlock(Block node) => _visitStatements(node.statements); |
| 4052 | 3562 |
| 4053 @override | 3563 @override |
| 4054 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block); | 3564 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block); |
| 4055 | 3565 |
| 4056 @override | 3566 @override |
| 4057 bool visitBreakStatement(BreakStatement node) { | 3567 bool visitBreakStatement(BreakStatement node) { |
| 4058 _enclosingBlockContainsBreak = true; | 3568 _enclosingBlockContainsBreak = true; |
| 3569 if (node.label != null) { |
| 3570 _enclosingBlockBreaksLabel.add(node.target); |
| 3571 } |
| 4059 return false; | 3572 return false; |
| 4060 } | 3573 } |
| 4061 | 3574 |
| 4062 @override | 3575 @override |
| 4063 bool visitCascadeExpression(CascadeExpression node) => | 3576 bool visitCascadeExpression(CascadeExpression node) => |
| 4064 _nodeExits(node.target) || _visitExpressions(node.cascadeSections); | 3577 _nodeExits(node.target) || _visitExpressions(node.cascadeSections); |
| 4065 | 3578 |
| 4066 @override | 3579 @override |
| 4067 bool visitConditionalExpression(ConditionalExpression node) { | 3580 bool visitConditionalExpression(ConditionalExpression node) { |
| 4068 Expression conditionExpression = node.condition; | 3581 Expression conditionExpression = node.condition; |
| 4069 Expression thenStatement = node.thenExpression; | 3582 Expression thenStatement = node.thenExpression; |
| 4070 Expression elseStatement = node.elseExpression; | 3583 Expression elseStatement = node.elseExpression; |
| 4071 // TODO(jwren) Do we want to take constant expressions into account, | 3584 // TODO(jwren) Do we want to take constant expressions into account, |
| 4072 // evaluate if(false) {} differently than if(<condition>), when <condition> | 3585 // evaluate if(false) {} differently than if(<condition>), when <condition> |
| 4073 // evaluates to a constant false value? | 3586 // evaluates to a constant false value? |
| 4074 if (_nodeExits(conditionExpression)) { | 3587 if (_nodeExits(conditionExpression)) { |
| 4075 return true; | 3588 return true; |
| 4076 } | 3589 } |
| 4077 if (thenStatement == null || elseStatement == null) { | 3590 if (thenStatement == null || elseStatement == null) { |
| 4078 return false; | 3591 return false; |
| 4079 } | 3592 } |
| 4080 return thenStatement.accept(this) && elseStatement.accept(this); | 3593 return thenStatement.accept(this) && elseStatement.accept(this); |
| 4081 } | 3594 } |
| 4082 | 3595 |
| 4083 @override | 3596 @override |
| 4084 bool visitContinueStatement(ContinueStatement node) => false; | 3597 bool visitContinueStatement(ContinueStatement node) { |
| 3598 _enclosingBlockContainsContinue = true; |
| 3599 return false; |
| 3600 } |
| 4085 | 3601 |
| 4086 @override | 3602 @override |
| 4087 bool visitDoStatement(DoStatement node) { | 3603 bool visitDoStatement(DoStatement node) { |
| 4088 bool outerBreakValue = _enclosingBlockContainsBreak; | 3604 bool outerBreakValue = _enclosingBlockContainsBreak; |
| 3605 bool outerContinueValue = _enclosingBlockContainsContinue; |
| 4089 _enclosingBlockContainsBreak = false; | 3606 _enclosingBlockContainsBreak = false; |
| 3607 _enclosingBlockContainsContinue = false; |
| 4090 try { | 3608 try { |
| 3609 bool bodyExits = _nodeExits(node.body); |
| 3610 bool containsBreakOrContinue = |
| 3611 _enclosingBlockContainsBreak || _enclosingBlockContainsContinue; |
| 3612 // Even if we determine that the body "exits", there might be break or |
| 3613 // continue statements that actually mean it _doesn't_ always exit. |
| 3614 if (bodyExits && !containsBreakOrContinue) { |
| 3615 return true; |
| 3616 } |
| 4091 Expression conditionExpression = node.condition; | 3617 Expression conditionExpression = node.condition; |
| 4092 if (_nodeExits(conditionExpression)) { | 3618 if (_nodeExits(conditionExpression)) { |
| 4093 return true; | 3619 return true; |
| 4094 } | 3620 } |
| 4095 // TODO(jwren) Do we want to take all constant expressions into account? | 3621 // TODO(jwren) Do we want to take all constant expressions into account? |
| 4096 if (conditionExpression is BooleanLiteral) { | 3622 if (conditionExpression is BooleanLiteral) { |
| 4097 BooleanLiteral booleanLiteral = conditionExpression; | 3623 // If do {} while (true), and the body doesn't break, then return true. |
| 4098 // If do {} while (true), and the body doesn't return or the body | 3624 if (conditionExpression.value && !_enclosingBlockContainsBreak) { |
| 4099 // doesn't have a break, then return true. | |
| 4100 bool blockReturns = _nodeExits(node.body); | |
| 4101 if (booleanLiteral.value && | |
| 4102 (blockReturns || !_enclosingBlockContainsBreak)) { | |
| 4103 return true; | 3625 return true; |
| 4104 } | 3626 } |
| 4105 } | 3627 } |
| 4106 return false; | 3628 return false; |
| 4107 } finally { | 3629 } finally { |
| 4108 _enclosingBlockContainsBreak = outerBreakValue; | 3630 _enclosingBlockContainsBreak = outerBreakValue; |
| 3631 _enclosingBlockContainsContinue = outerContinueValue; |
| 4109 } | 3632 } |
| 4110 } | 3633 } |
| 4111 | 3634 |
| 4112 @override | 3635 @override |
| 4113 bool visitEmptyStatement(EmptyStatement node) => false; | 3636 bool visitEmptyStatement(EmptyStatement node) => false; |
| 4114 | 3637 |
| 4115 @override | 3638 @override |
| 4116 bool visitExpressionStatement(ExpressionStatement node) => | 3639 bool visitExpressionStatement(ExpressionStatement node) => |
| 4117 _nodeExits(node.expression); | 3640 _nodeExits(node.expression); |
| 4118 | 3641 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 4139 if (node.initialization != null && _nodeExits(node.initialization)) { | 3662 if (node.initialization != null && _nodeExits(node.initialization)) { |
| 4140 return true; | 3663 return true; |
| 4141 } | 3664 } |
| 4142 Expression conditionExpression = node.condition; | 3665 Expression conditionExpression = node.condition; |
| 4143 if (conditionExpression != null && _nodeExits(conditionExpression)) { | 3666 if (conditionExpression != null && _nodeExits(conditionExpression)) { |
| 4144 return true; | 3667 return true; |
| 4145 } | 3668 } |
| 4146 if (_visitExpressions(node.updaters)) { | 3669 if (_visitExpressions(node.updaters)) { |
| 4147 return true; | 3670 return true; |
| 4148 } | 3671 } |
| 3672 bool blockReturns = _nodeExits(node.body); |
| 4149 // TODO(jwren) Do we want to take all constant expressions into account? | 3673 // TODO(jwren) Do we want to take all constant expressions into account? |
| 4150 // If for(; true; ) (or for(;;)), and the body doesn't return or the body | 3674 // If for(; true; ) (or for(;;)), and the body doesn't return or the body |
| 4151 // doesn't have a break, then return true. | 3675 // doesn't have a break, then return true. |
| 4152 bool implicitOrExplictTrue = conditionExpression == null || | 3676 bool implicitOrExplictTrue = conditionExpression == null || |
| 4153 (conditionExpression is BooleanLiteral && conditionExpression.value); | 3677 (conditionExpression is BooleanLiteral && conditionExpression.value); |
| 4154 if (implicitOrExplictTrue) { | 3678 if (implicitOrExplictTrue) { |
| 4155 bool blockReturns = _nodeExits(node.body); | |
| 4156 if (blockReturns || !_enclosingBlockContainsBreak) { | 3679 if (blockReturns || !_enclosingBlockContainsBreak) { |
| 4157 return true; | 3680 return true; |
| 4158 } | 3681 } |
| 4159 } | 3682 } |
| 4160 return false; | 3683 return false; |
| 4161 } finally { | 3684 } finally { |
| 4162 _enclosingBlockContainsBreak = outerBreakValue; | 3685 _enclosingBlockContainsBreak = outerBreakValue; |
| 4163 } | 3686 } |
| 4164 } | 3687 } |
| 4165 | 3688 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4184 @override | 3707 @override |
| 4185 bool visitIfStatement(IfStatement node) { | 3708 bool visitIfStatement(IfStatement node) { |
| 4186 Expression conditionExpression = node.condition; | 3709 Expression conditionExpression = node.condition; |
| 4187 Statement thenStatement = node.thenStatement; | 3710 Statement thenStatement = node.thenStatement; |
| 4188 Statement elseStatement = node.elseStatement; | 3711 Statement elseStatement = node.elseStatement; |
| 4189 if (_nodeExits(conditionExpression)) { | 3712 if (_nodeExits(conditionExpression)) { |
| 4190 return true; | 3713 return true; |
| 4191 } | 3714 } |
| 4192 // TODO(jwren) Do we want to take all constant expressions into account? | 3715 // TODO(jwren) Do we want to take all constant expressions into account? |
| 4193 if (conditionExpression is BooleanLiteral) { | 3716 if (conditionExpression is BooleanLiteral) { |
| 4194 BooleanLiteral booleanLiteral = conditionExpression; | 3717 if (conditionExpression.value) { |
| 4195 if (booleanLiteral.value) { | 3718 // if (true) ... |
| 4196 // if(true) ... | |
| 4197 return _nodeExits(thenStatement); | 3719 return _nodeExits(thenStatement); |
| 4198 } else if (elseStatement != null) { | 3720 } else if (elseStatement != null) { |
| 4199 // if (false) ... | 3721 // if (false) ... |
| 4200 return _nodeExits(elseStatement); | 3722 return _nodeExits(elseStatement); |
| 4201 } | 3723 } |
| 4202 } | 3724 } |
| 3725 bool thenExits = _nodeExits(thenStatement); |
| 3726 bool elseExits = _nodeExits(elseStatement); |
| 4203 if (thenStatement == null || elseStatement == null) { | 3727 if (thenStatement == null || elseStatement == null) { |
| 4204 return false; | 3728 return false; |
| 4205 } | 3729 } |
| 4206 return _nodeExits(thenStatement) && _nodeExits(elseStatement); | 3730 return thenExits && elseExits; |
| 4207 } | 3731 } |
| 4208 | 3732 |
| 4209 @override | 3733 @override |
| 4210 bool visitIndexExpression(IndexExpression node) { | 3734 bool visitIndexExpression(IndexExpression node) { |
| 4211 Expression target = node.realTarget; | 3735 Expression target = node.realTarget; |
| 4212 if (_nodeExits(target)) { | 3736 if (_nodeExits(target)) { |
| 4213 return true; | 3737 return true; |
| 4214 } | 3738 } |
| 4215 if (_nodeExits(node.index)) { | 3739 if (_nodeExits(node.index)) { |
| 4216 return true; | 3740 return true; |
| 4217 } | 3741 } |
| 4218 return false; | 3742 return false; |
| 4219 } | 3743 } |
| 4220 | 3744 |
| 4221 @override | 3745 @override |
| 4222 bool visitInstanceCreationExpression(InstanceCreationExpression node) => | 3746 bool visitInstanceCreationExpression(InstanceCreationExpression node) => |
| 4223 _nodeExits(node.argumentList); | 3747 _nodeExits(node.argumentList); |
| 4224 | 3748 |
| 4225 @override | 3749 @override |
| 4226 bool visitIsExpression(IsExpression node) => node.expression.accept(this); | 3750 bool visitIsExpression(IsExpression node) => node.expression.accept(this); |
| 4227 | 3751 |
| 4228 @override | 3752 @override |
| 4229 bool visitLabel(Label node) => false; | 3753 bool visitLabel(Label node) => false; |
| 4230 | 3754 |
| 4231 @override | 3755 @override |
| 4232 bool visitLabeledStatement(LabeledStatement node) => | 3756 bool visitLabeledStatement(LabeledStatement node) { |
| 4233 node.statement.accept(this); | 3757 try { |
| 3758 bool statementExits = _nodeExits(node.statement); |
| 3759 bool neverBrokeFromLabel = |
| 3760 !_enclosingBlockBreaksLabel.contains(node.statement); |
| 3761 return statementExits && neverBrokeFromLabel; |
| 3762 } finally { |
| 3763 _enclosingBlockBreaksLabel.remove(node.statement); |
| 3764 } |
| 3765 } |
| 4234 | 3766 |
| 4235 @override | 3767 @override |
| 4236 bool visitLiteral(Literal node) => false; | 3768 bool visitLiteral(Literal node) => false; |
| 4237 | 3769 |
| 4238 @override | 3770 @override |
| 4239 bool visitMethodInvocation(MethodInvocation node) { | 3771 bool visitMethodInvocation(MethodInvocation node) { |
| 4240 Expression target = node.realTarget; | 3772 Expression target = node.realTarget; |
| 4241 if (target != null) { | 3773 if (target != null) { |
| 4242 if (target.accept(this)) { | 3774 if (target.accept(this)) { |
| 4243 return true; | 3775 return true; |
| 4244 } | 3776 } |
| 4245 if (node.operator.type == sc.TokenType.QUESTION_PERIOD) { | 3777 if (node.operator.type == TokenType.QUESTION_PERIOD) { |
| 4246 return false; | 3778 return false; |
| 4247 } | 3779 } |
| 4248 } | 3780 } |
| 4249 return _nodeExits(node.argumentList); | 3781 return _nodeExits(node.argumentList); |
| 4250 } | 3782 } |
| 4251 | 3783 |
| 4252 @override | 3784 @override |
| 4253 bool visitNamedExpression(NamedExpression node) => | 3785 bool visitNamedExpression(NamedExpression node) => |
| 4254 node.expression.accept(this); | 3786 node.expression.accept(this); |
| 4255 | 3787 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4287 @override | 3819 @override |
| 4288 bool visitSwitchDefault(SwitchDefault node) => | 3820 bool visitSwitchDefault(SwitchDefault node) => |
| 4289 _visitStatements(node.statements); | 3821 _visitStatements(node.statements); |
| 4290 | 3822 |
| 4291 @override | 3823 @override |
| 4292 bool visitSwitchStatement(SwitchStatement node) { | 3824 bool visitSwitchStatement(SwitchStatement node) { |
| 4293 bool outerBreakValue = _enclosingBlockContainsBreak; | 3825 bool outerBreakValue = _enclosingBlockContainsBreak; |
| 4294 _enclosingBlockContainsBreak = false; | 3826 _enclosingBlockContainsBreak = false; |
| 4295 try { | 3827 try { |
| 4296 bool hasDefault = false; | 3828 bool hasDefault = false; |
| 3829 bool hasNonExitingCase = false; |
| 4297 List<SwitchMember> members = node.members; | 3830 List<SwitchMember> members = node.members; |
| 4298 for (int i = 0; i < members.length; i++) { | 3831 for (int i = 0; i < members.length; i++) { |
| 4299 SwitchMember switchMember = members[i]; | 3832 SwitchMember switchMember = members[i]; |
| 4300 if (switchMember is SwitchDefault) { | 3833 if (switchMember is SwitchDefault) { |
| 4301 hasDefault = true; | 3834 hasDefault = true; |
| 4302 // If this is the last member and there are no statements, return | 3835 // If this is the last member and there are no statements, then it |
| 4303 // false | 3836 // does not exit. |
| 4304 if (switchMember.statements.isEmpty && i + 1 == members.length) { | 3837 if (switchMember.statements.isEmpty && i + 1 == members.length) { |
| 4305 return false; | 3838 hasNonExitingCase = true; |
| 3839 continue; |
| 4306 } | 3840 } |
| 4307 } | 3841 } |
| 4308 // For switch members with no statements, don't visit the children, | 3842 // For switch members with no statements, don't visit the children. |
| 4309 // otherwise, return false if no return is found in the children | 3843 // Otherwise, if there children statements don't exit, mark this as a |
| 4310 // statements. | 3844 // non-exiting case. |
| 4311 if (!switchMember.statements.isEmpty && !switchMember.accept(this)) { | 3845 if (!switchMember.statements.isEmpty && !switchMember.accept(this)) { |
| 4312 return false; | 3846 hasNonExitingCase = true; |
| 4313 } | 3847 } |
| 4314 } | 3848 } |
| 4315 // All of the members exit, determine whether there are possible cases | 3849 if (hasNonExitingCase) { |
| 4316 // that are not caught by the members. | 3850 return false; |
| 4317 DartType type = node.expression == null ? null : node.expression.bestType; | |
| 4318 if (type is InterfaceType) { | |
| 4319 ClassElement element = type.element; | |
| 4320 if (element != null && element.isEnum) { | |
| 4321 // If some of the enum values are not covered, then a warning will | |
| 4322 // have already been generated, so there's no point in generating a | |
| 4323 // hint. | |
| 4324 return true; | |
| 4325 } | |
| 4326 } | 3851 } |
| 3852 // As all cases exit, return whether that list includes `default`. |
| 4327 return hasDefault; | 3853 return hasDefault; |
| 4328 } finally { | 3854 } finally { |
| 4329 _enclosingBlockContainsBreak = outerBreakValue; | 3855 _enclosingBlockContainsBreak = outerBreakValue; |
| 4330 } | 3856 } |
| 4331 } | 3857 } |
| 4332 | 3858 |
| 4333 @override | 3859 @override |
| 4334 bool visitThisExpression(ThisExpression node) => false; | 3860 bool visitThisExpression(ThisExpression node) => false; |
| 4335 | 3861 |
| 4336 @override | 3862 @override |
| 4337 bool visitThrowExpression(ThrowExpression node) => true; | 3863 bool visitThrowExpression(ThrowExpression node) => true; |
| 4338 | 3864 |
| 4339 @override | 3865 @override |
| 4340 bool visitTryStatement(TryStatement node) { | 3866 bool visitTryStatement(TryStatement node) { |
| 4341 if (_nodeExits(node.body)) { | 3867 if (_nodeExits(node.finallyBlock)) { |
| 4342 return true; | 3868 return true; |
| 4343 } | 3869 } |
| 4344 Block finallyBlock = node.finallyBlock; | 3870 if (!_nodeExits(node.body)) { |
| 4345 if (_nodeExits(finallyBlock)) { | 3871 return false; |
| 4346 return true; | |
| 4347 } | 3872 } |
| 4348 return false; | 3873 for (CatchClause c in node.catchClauses) { |
| 3874 if (!_nodeExits(c.body)) { |
| 3875 return false; |
| 3876 } |
| 3877 } |
| 3878 return true; |
| 4349 } | 3879 } |
| 4350 | 3880 |
| 4351 @override | 3881 @override |
| 4352 bool visitTypeName(TypeName node) => false; | 3882 bool visitTypeName(TypeName node) => false; |
| 4353 | 3883 |
| 4354 @override | 3884 @override |
| 4355 bool visitVariableDeclaration(VariableDeclaration node) { | 3885 bool visitVariableDeclaration(VariableDeclaration node) { |
| 4356 Expression initializer = node.initializer; | 3886 Expression initializer = node.initializer; |
| 4357 if (initializer != null) { | 3887 if (initializer != null) { |
| 4358 return initializer.accept(this); | 3888 return initializer.accept(this); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4377 | 3907 |
| 4378 @override | 3908 @override |
| 4379 bool visitWhileStatement(WhileStatement node) { | 3909 bool visitWhileStatement(WhileStatement node) { |
| 4380 bool outerBreakValue = _enclosingBlockContainsBreak; | 3910 bool outerBreakValue = _enclosingBlockContainsBreak; |
| 4381 _enclosingBlockContainsBreak = false; | 3911 _enclosingBlockContainsBreak = false; |
| 4382 try { | 3912 try { |
| 4383 Expression conditionExpression = node.condition; | 3913 Expression conditionExpression = node.condition; |
| 4384 if (conditionExpression.accept(this)) { | 3914 if (conditionExpression.accept(this)) { |
| 4385 return true; | 3915 return true; |
| 4386 } | 3916 } |
| 3917 node.body.accept(this); |
| 4387 // TODO(jwren) Do we want to take all constant expressions into account? | 3918 // TODO(jwren) Do we want to take all constant expressions into account? |
| 4388 if (conditionExpression is BooleanLiteral) { | 3919 if (conditionExpression is BooleanLiteral) { |
| 4389 BooleanLiteral booleanLiteral = conditionExpression; | 3920 // If while(true), and the body doesn't have a break, then return true. |
| 4390 // If while(true), and the body doesn't return or the body doesn't have | 3921 // The body might be found to exit, but if there are any break |
| 4391 // a break, then return true. | 3922 // statements, then it is a faulty finding. In other words: |
| 4392 bool blockReturns = node.body.accept(this); | 3923 // |
| 4393 if (booleanLiteral.value && | 3924 // * If the body exits, and does not contain a break statement, then |
| 4394 (blockReturns || !_enclosingBlockContainsBreak)) { | 3925 // it exits. |
| 3926 // * If the body does not exit, and does not contain a break statement, |
| 3927 // then it loops infinitely (also an exit). |
| 3928 // |
| 3929 // As both conditions forbid any break statements to be found, the logic |
| 3930 // just boils down to checking [_enclosingBlockContainsBreak]. |
| 3931 if (conditionExpression.value && !_enclosingBlockContainsBreak) { |
| 4395 return true; | 3932 return true; |
| 4396 } | 3933 } |
| 4397 } | 3934 } |
| 4398 return false; | 3935 return false; |
| 4399 } finally { | 3936 } finally { |
| 4400 _enclosingBlockContainsBreak = outerBreakValue; | 3937 _enclosingBlockContainsBreak = outerBreakValue; |
| 4401 } | 3938 } |
| 4402 } | 3939 } |
| 4403 | 3940 |
| 3941 @override |
| 3942 bool visitYieldStatement(YieldStatement node) => _nodeExits(node.expression); |
| 3943 |
| 4404 /** | 3944 /** |
| 4405 * Return `true` if the given node exits. | 3945 * Return `true` if the given node exits. |
| 4406 * | 3946 * |
| 4407 * @param node the node being tested | 3947 * @param node the node being tested |
| 4408 * @return `true` if the given node exits | 3948 * @return `true` if the given node exits |
| 4409 */ | 3949 */ |
| 4410 bool _nodeExits(AstNode node) { | 3950 bool _nodeExits(AstNode node) { |
| 4411 if (node == null) { | 3951 if (node == null) { |
| 4412 return false; | 3952 return false; |
| 4413 } | 3953 } |
| 4414 return node.accept(this); | 3954 return node.accept(this); |
| 4415 } | 3955 } |
| 4416 | 3956 |
| 4417 bool _visitExpressions(NodeList<Expression> expressions) { | 3957 bool _visitExpressions(NodeList<Expression> expressions) { |
| 4418 for (int i = expressions.length - 1; i >= 0; i--) { | 3958 for (int i = expressions.length - 1; i >= 0; i--) { |
| 4419 if (expressions[i].accept(this)) { | 3959 if (expressions[i].accept(this)) { |
| 4420 return true; | 3960 return true; |
| 4421 } | 3961 } |
| 4422 } | 3962 } |
| 4423 return false; | 3963 return false; |
| 4424 } | 3964 } |
| 4425 | 3965 |
| 4426 bool _visitStatements(NodeList<Statement> statements) { | 3966 bool _visitStatements(NodeList<Statement> statements) { |
| 4427 for (int i = statements.length - 1; i >= 0; i--) { | 3967 for (int i = 0; i < statements.length; i++) { |
| 4428 if (statements[i].accept(this)) { | 3968 if (statements[i].accept(this)) { |
| 4429 return true; | 3969 return true; |
| 4430 } | 3970 } |
| 4431 } | 3971 } |
| 4432 return false; | 3972 return false; |
| 4433 } | 3973 } |
| 4434 | 3974 |
| 4435 bool _visitVariableDeclarations( | 3975 bool _visitVariableDeclarations( |
| 4436 NodeList<VariableDeclaration> variableDeclarations) { | 3976 NodeList<VariableDeclaration> variableDeclarations) { |
| 4437 for (int i = variableDeclarations.length - 1; i >= 0; i--) { | 3977 for (int i = variableDeclarations.length - 1; i >= 0; i--) { |
| 4438 if (variableDeclarations[i].accept(this)) { | 3978 if (variableDeclarations[i].accept(this)) { |
| 4439 return true; | 3979 return true; |
| 4440 } | 3980 } |
| 4441 } | 3981 } |
| 4442 return false; | 3982 return false; |
| 4443 } | 3983 } |
| 4444 | 3984 |
| 4445 /** | 3985 /** |
| 4446 * Return `true` if the given [node] exits. | 3986 * Return `true` if the given [node] exits. |
| 4447 */ | 3987 */ |
| 4448 static bool exits(AstNode node) { | 3988 static bool exits(AstNode node) { |
| 4449 return new ExitDetector()._nodeExits(node); | 3989 return new ExitDetector()._nodeExits(node); |
| 4450 } | 3990 } |
| 4451 } | 3991 } |
| 4452 | 3992 |
| 4453 /** | 3993 /** |
| 4454 * The scope defined by a function. | |
| 4455 */ | |
| 4456 class FunctionScope extends EnclosedScope { | |
| 4457 /** | |
| 4458 * The element representing the function that defines this scope. | |
| 4459 */ | |
| 4460 final ExecutableElement _functionElement; | |
| 4461 | |
| 4462 /** | |
| 4463 * A flag indicating whether the parameters have already been defined, used to | |
| 4464 * prevent the parameters from being defined multiple times. | |
| 4465 */ | |
| 4466 bool _parametersDefined = false; | |
| 4467 | |
| 4468 /** | |
| 4469 * Initialize a newly created scope enclosed within the [enclosingScope] that | |
| 4470 * represents the given [_functionElement]. | |
| 4471 */ | |
| 4472 FunctionScope(Scope enclosingScope, this._functionElement) | |
| 4473 : super(new EnclosedScope(new EnclosedScope(enclosingScope))) { | |
| 4474 if (_functionElement == null) { | |
| 4475 throw new IllegalArgumentException("function element cannot be null"); | |
| 4476 } | |
| 4477 _defineTypeParameters(); | |
| 4478 } | |
| 4479 | |
| 4480 /** | |
| 4481 * Define the parameters for the given function in the scope that encloses | |
| 4482 * this function. | |
| 4483 */ | |
| 4484 void defineParameters() { | |
| 4485 if (_parametersDefined) { | |
| 4486 return; | |
| 4487 } | |
| 4488 _parametersDefined = true; | |
| 4489 Scope parameterScope = enclosingScope; | |
| 4490 for (ParameterElement parameter in _functionElement.parameters) { | |
| 4491 if (!parameter.isInitializingFormal) { | |
| 4492 parameterScope.define(parameter); | |
| 4493 } | |
| 4494 } | |
| 4495 } | |
| 4496 | |
| 4497 /** | |
| 4498 * Define the type parameters for the function. | |
| 4499 */ | |
| 4500 void _defineTypeParameters() { | |
| 4501 Scope typeParameterScope = enclosingScope.enclosingScope; | |
| 4502 for (TypeParameterElement typeParameter | |
| 4503 in _functionElement.typeParameters) { | |
| 4504 typeParameterScope.define(typeParameter); | |
| 4505 } | |
| 4506 } | |
| 4507 } | |
| 4508 | |
| 4509 /** | |
| 4510 * The scope defined by a function type alias. | |
| 4511 */ | |
| 4512 class FunctionTypeScope extends EnclosedScope { | |
| 4513 final FunctionTypeAliasElement _typeElement; | |
| 4514 | |
| 4515 bool _parametersDefined = false; | |
| 4516 | |
| 4517 /** | |
| 4518 * Initialize a newly created scope enclosed within the [enclosingScope] that | |
| 4519 * represents the given [_typeElement]. | |
| 4520 */ | |
| 4521 FunctionTypeScope(Scope enclosingScope, this._typeElement) | |
| 4522 : super(new EnclosedScope(enclosingScope)) { | |
| 4523 _defineTypeParameters(); | |
| 4524 } | |
| 4525 | |
| 4526 /** | |
| 4527 * Define the parameters for the function type alias. | |
| 4528 */ | |
| 4529 void defineParameters() { | |
| 4530 if (_parametersDefined) { | |
| 4531 return; | |
| 4532 } | |
| 4533 _parametersDefined = true; | |
| 4534 for (ParameterElement parameter in _typeElement.parameters) { | |
| 4535 define(parameter); | |
| 4536 } | |
| 4537 } | |
| 4538 | |
| 4539 /** | |
| 4540 * Define the type parameters for the function type alias. | |
| 4541 */ | |
| 4542 void _defineTypeParameters() { | |
| 4543 Scope typeParameterScope = enclosingScope; | |
| 4544 for (TypeParameterElement typeParameter in _typeElement.typeParameters) { | |
| 4545 typeParameterScope.define(typeParameter); | |
| 4546 } | |
| 4547 } | |
| 4548 } | |
| 4549 | |
| 4550 /** | |
| 4551 * A visitor that visits ASTs and fills [UsedImportedElements]. | 3994 * A visitor that visits ASTs and fills [UsedImportedElements]. |
| 4552 */ | 3995 */ |
| 4553 class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor { | 3996 class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor { |
| 4554 final LibraryElement library; | 3997 final LibraryElement library; |
| 4555 final UsedImportedElements usedElements = new UsedImportedElements(); | 3998 final UsedImportedElements usedElements = new UsedImportedElements(); |
| 4556 | 3999 |
| 4557 GatherUsedImportedElementsVisitor(this.library); | 4000 GatherUsedImportedElementsVisitor(this.library); |
| 4558 | 4001 |
| 4559 @override | 4002 @override |
| 4560 void visitExportDirective(ExportDirective node) { | 4003 void visitExportDirective(ExportDirective node) { |
| 4561 _visitMetadata(node.metadata); | 4004 _visitDirective(node); |
| 4562 } | 4005 } |
| 4563 | 4006 |
| 4564 @override | 4007 @override |
| 4565 void visitImportDirective(ImportDirective node) { | 4008 void visitImportDirective(ImportDirective node) { |
| 4566 _visitMetadata(node.metadata); | 4009 _visitDirective(node); |
| 4567 } | 4010 } |
| 4568 | 4011 |
| 4569 @override | 4012 @override |
| 4570 void visitLibraryDirective(LibraryDirective node) { | 4013 void visitLibraryDirective(LibraryDirective node) { |
| 4571 _visitMetadata(node.metadata); | 4014 _visitDirective(node); |
| 4572 } | |
| 4573 | |
| 4574 @override | |
| 4575 void visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 4576 // If the prefixed identifier references some A.B, where A is a library | |
| 4577 // prefix, then we can lookup the associated ImportDirective in | |
| 4578 // prefixElementMap and remove it from the unusedImports list. | |
| 4579 SimpleIdentifier prefixIdentifier = node.prefix; | |
| 4580 Element element = prefixIdentifier.staticElement; | |
| 4581 if (element is PrefixElement) { | |
| 4582 usedElements.prefixes.add(element); | |
| 4583 return; | |
| 4584 } | |
| 4585 // Otherwise, pass the prefixed identifier element and name onto | |
| 4586 // visitIdentifier. | |
| 4587 _visitIdentifier(element, prefixIdentifier.name); | |
| 4588 } | 4015 } |
| 4589 | 4016 |
| 4590 @override | 4017 @override |
| 4591 void visitSimpleIdentifier(SimpleIdentifier node) { | 4018 void visitSimpleIdentifier(SimpleIdentifier node) { |
| 4592 _visitIdentifier(node.staticElement, node.name); | 4019 _visitIdentifier(node, node.staticElement); |
| 4593 } | 4020 } |
| 4594 | 4021 |
| 4595 void _visitIdentifier(Element element, String name) { | 4022 /** |
| 4023 * If the given [identifier] is prefixed with a [PrefixElement], fill the |
| 4024 * corresponding `UsedImportedElements.prefixMap` entry and return `true`. |
| 4025 */ |
| 4026 bool _recordPrefixMap(SimpleIdentifier identifier, Element element) { |
| 4027 bool recordIfTargetIsPrefixElement(Expression target) { |
| 4028 if (target is SimpleIdentifier && target.staticElement is PrefixElement) { |
| 4029 List<Element> prefixedElements = usedElements.prefixMap |
| 4030 .putIfAbsent(target.staticElement, () => <Element>[]); |
| 4031 prefixedElements.add(element); |
| 4032 return true; |
| 4033 } |
| 4034 return false; |
| 4035 } |
| 4036 |
| 4037 AstNode parent = identifier.parent; |
| 4038 if (parent is MethodInvocation && parent.methodName == identifier) { |
| 4039 return recordIfTargetIsPrefixElement(parent.target); |
| 4040 } |
| 4041 if (parent is PrefixedIdentifier && parent.identifier == identifier) { |
| 4042 return recordIfTargetIsPrefixElement(parent.prefix); |
| 4043 } |
| 4044 return false; |
| 4045 } |
| 4046 |
| 4047 /** |
| 4048 * Visit identifiers used by the given [directive]. |
| 4049 */ |
| 4050 void _visitDirective(Directive directive) { |
| 4051 directive.documentationComment?.accept(this); |
| 4052 directive.metadata.accept(this); |
| 4053 } |
| 4054 |
| 4055 void _visitIdentifier(SimpleIdentifier identifier, Element element) { |
| 4596 if (element == null) { | 4056 if (element == null) { |
| 4597 return; | 4057 return; |
| 4598 } | 4058 } |
| 4599 // If the element is multiply defined then call this method recursively for | 4059 // If the element is multiply defined then call this method recursively for |
| 4600 // each of the conflicting elements. | 4060 // each of the conflicting elements. |
| 4601 if (element is MultiplyDefinedElement) { | 4061 if (element is MultiplyDefinedElement) { |
| 4602 MultiplyDefinedElement multiplyDefinedElement = element; | 4062 List<Element> conflictingElements = element.conflictingElements; |
| 4603 for (Element elt in multiplyDefinedElement.conflictingElements) { | 4063 int length = conflictingElements.length; |
| 4604 _visitIdentifier(elt, name); | 4064 for (int i = 0; i < length; i++) { |
| 4065 Element elt = conflictingElements[i]; |
| 4066 _visitIdentifier(identifier, elt); |
| 4605 } | 4067 } |
| 4606 return; | 4068 return; |
| 4607 } else if (element is PrefixElement) { | 4069 } |
| 4608 usedElements.prefixes.add(element); | 4070 |
| 4071 // Record `importPrefix.identifier` into 'prefixMap'. |
| 4072 if (_recordPrefixMap(identifier, element)) { |
| 4073 return; |
| 4074 } |
| 4075 |
| 4076 if (element is PrefixElement) { |
| 4077 usedElements.prefixMap.putIfAbsent(element, () => <Element>[]); |
| 4609 return; | 4078 return; |
| 4610 } else if (element.enclosingElement is! CompilationUnitElement) { | 4079 } else if (element.enclosingElement is! CompilationUnitElement) { |
| 4611 // Identifiers that aren't a prefix element and whose enclosing element | 4080 // Identifiers that aren't a prefix element and whose enclosing element |
| 4612 // isn't a CompilationUnit are ignored- this covers the case the | 4081 // isn't a CompilationUnit are ignored- this covers the case the |
| 4613 // identifier is a relative-reference, a reference to an identifier not | 4082 // identifier is a relative-reference, a reference to an identifier not |
| 4614 // imported by this library. | 4083 // imported by this library. |
| 4615 return; | 4084 return; |
| 4616 } | 4085 } |
| 4617 // Ignore if an unknown library. | 4086 // Ignore if an unknown library. |
| 4618 LibraryElement containingLibrary = element.library; | 4087 LibraryElement containingLibrary = element.library; |
| 4619 if (containingLibrary == null) { | 4088 if (containingLibrary == null) { |
| 4620 return; | 4089 return; |
| 4621 } | 4090 } |
| 4622 // Ignore if a local element. | 4091 // Ignore if a local element. |
| 4623 if (library == containingLibrary) { | 4092 if (library == containingLibrary) { |
| 4624 return; | 4093 return; |
| 4625 } | 4094 } |
| 4626 // Remember the element. | 4095 // Remember the element. |
| 4627 usedElements.elements.add(element); | 4096 usedElements.elements.add(element); |
| 4628 } | 4097 } |
| 4629 | |
| 4630 /** | |
| 4631 * Given some [NodeList] of [Annotation]s, ensure that the identifiers are vis
ited by | |
| 4632 * this visitor. Specifically, this covers the cases where AST nodes don't hav
e their identifiers | |
| 4633 * visited by this visitor, but still need their annotations visited. | |
| 4634 * | |
| 4635 * @param annotations the list of annotations to visit | |
| 4636 */ | |
| 4637 void _visitMetadata(NodeList<Annotation> annotations) { | |
| 4638 int count = annotations.length; | |
| 4639 for (int i = 0; i < count; i++) { | |
| 4640 annotations[i].accept(this); | |
| 4641 } | |
| 4642 } | |
| 4643 } | 4098 } |
| 4644 | 4099 |
| 4645 /** | 4100 /** |
| 4646 * An [AstVisitor] that fills [UsedLocalElements]. | 4101 * An [AstVisitor] that fills [UsedLocalElements]. |
| 4647 */ | 4102 */ |
| 4648 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor { | 4103 class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor { |
| 4649 final UsedLocalElements usedElements = new UsedLocalElements(); | 4104 final UsedLocalElements usedElements = new UsedLocalElements(); |
| 4650 | 4105 |
| 4651 final LibraryElement _enclosingLibrary; | 4106 final LibraryElement _enclosingLibrary; |
| 4652 ClassElement _enclosingClass; | 4107 ClassElement _enclosingClass; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4757 return; | 4212 return; |
| 4758 } | 4213 } |
| 4759 // ignore places where the element is not actually used | 4214 // ignore places where the element is not actually used |
| 4760 if (node.parent is TypeName) { | 4215 if (node.parent is TypeName) { |
| 4761 if (element is ClassElement) { | 4216 if (element is ClassElement) { |
| 4762 AstNode parent2 = node.parent.parent; | 4217 AstNode parent2 = node.parent.parent; |
| 4763 if (parent2 is IsExpression) { | 4218 if (parent2 is IsExpression) { |
| 4764 return; | 4219 return; |
| 4765 } | 4220 } |
| 4766 if (parent2 is VariableDeclarationList) { | 4221 if (parent2 is VariableDeclarationList) { |
| 4767 return; | 4222 // If it's a field's type, it still counts as used. |
| 4223 if (parent2.parent is! FieldDeclaration) { |
| 4224 return; |
| 4225 } |
| 4768 } | 4226 } |
| 4769 } | 4227 } |
| 4770 } | 4228 } |
| 4771 // OK | 4229 // OK |
| 4772 usedElements.addElement(element); | 4230 usedElements.addElement(element); |
| 4773 } | 4231 } |
| 4774 | 4232 |
| 4775 static bool _isReadIdentifier(SimpleIdentifier node) { | 4233 static bool _isReadIdentifier(SimpleIdentifier node) { |
| 4776 // not reading at all | 4234 // not reading at all |
| 4777 if (!node.inGetterContext()) { | 4235 if (!node.inGetterContext()) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4817 */ | 4275 */ |
| 4818 InheritanceManager _manager; | 4276 InheritanceManager _manager; |
| 4819 | 4277 |
| 4820 GatherUsedLocalElementsVisitor _usedLocalElementsVisitor; | 4278 GatherUsedLocalElementsVisitor _usedLocalElementsVisitor; |
| 4821 | 4279 |
| 4822 HintGenerator(this._compilationUnits, this._context, this._errorListener) { | 4280 HintGenerator(this._compilationUnits, this._context, this._errorListener) { |
| 4823 _library = _compilationUnits[0].element.library; | 4281 _library = _compilationUnits[0].element.library; |
| 4824 _usedImportedElementsVisitor = | 4282 _usedImportedElementsVisitor = |
| 4825 new GatherUsedImportedElementsVisitor(_library); | 4283 new GatherUsedImportedElementsVisitor(_library); |
| 4826 _enableDart2JSHints = _context.analysisOptions.dart2jsHint; | 4284 _enableDart2JSHints = _context.analysisOptions.dart2jsHint; |
| 4827 _manager = new InheritanceManager(_compilationUnits[0].element.library); | 4285 _manager = |
| 4286 new InheritanceManager(_library, includeAbstractFromSuperclasses: true); |
| 4828 _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library); | 4287 _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library); |
| 4829 } | 4288 } |
| 4830 | 4289 |
| 4831 void generateForLibrary() { | 4290 void generateForLibrary() { |
| 4832 PerformanceStatistics.hints.makeCurrentWhile(() { | 4291 PerformanceStatistics.hints.makeCurrentWhile(() { |
| 4833 for (CompilationUnit unit in _compilationUnits) { | 4292 int length = _compilationUnits.length; |
| 4293 for (int i = 0; i < length; i++) { |
| 4294 CompilationUnit unit = _compilationUnits[i]; |
| 4834 CompilationUnitElement element = unit.element; | 4295 CompilationUnitElement element = unit.element; |
| 4835 if (element != null) { | 4296 if (element != null) { |
| 4836 _generateForCompilationUnit(unit, element.source); | 4297 _generateForCompilationUnit(unit, element.source); |
| 4837 } | 4298 } |
| 4838 } | 4299 } |
| 4839 CompilationUnit definingUnit = _compilationUnits[0]; | 4300 CompilationUnit definingUnit = _compilationUnits[0]; |
| 4840 ErrorReporter definingUnitErrorReporter = | 4301 ErrorReporter definingUnitErrorReporter = |
| 4841 new ErrorReporter(_errorListener, definingUnit.element.source); | 4302 new ErrorReporter(_errorListener, definingUnit.element.source); |
| 4842 { | 4303 { |
| 4843 ImportsVerifier importsVerifier = new ImportsVerifier(); | 4304 ImportsVerifier importsVerifier = new ImportsVerifier(); |
| 4844 importsVerifier.addImports(definingUnit); | 4305 importsVerifier.addImports(definingUnit); |
| 4845 importsVerifier | 4306 importsVerifier |
| 4846 .removeUsedElements(_usedImportedElementsVisitor.usedElements); | 4307 .removeUsedElements(_usedImportedElementsVisitor.usedElements); |
| 4847 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter); | 4308 importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter); |
| 4848 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter); | 4309 importsVerifier.generateUnusedImportHints(definingUnitErrorReporter); |
| 4310 importsVerifier.generateUnusedShownNameHints(definingUnitErrorReporter); |
| 4849 } | 4311 } |
| 4850 _library.accept(new UnusedLocalElementsVerifier( | 4312 _library.accept(new UnusedLocalElementsVerifier( |
| 4851 _errorListener, _usedLocalElementsVisitor.usedElements)); | 4313 _errorListener, _usedLocalElementsVisitor.usedElements)); |
| 4852 }); | 4314 }); |
| 4853 } | 4315 } |
| 4854 | 4316 |
| 4855 void _generateForCompilationUnit(CompilationUnit unit, Source source) { | 4317 void _generateForCompilationUnit(CompilationUnit unit, Source source) { |
| 4856 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); | 4318 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); |
| 4857 unit.accept(_usedImportedElementsVisitor); | 4319 unit.accept(_usedImportedElementsVisitor); |
| 4858 // dead code analysis | 4320 // dead code analysis |
| 4859 unit.accept( | 4321 unit.accept( |
| 4860 new DeadCodeVerifier(errorReporter, typeSystem: _context.typeSystem)); | 4322 new DeadCodeVerifier(errorReporter, typeSystem: _context.typeSystem)); |
| 4861 unit.accept(_usedLocalElementsVisitor); | 4323 unit.accept(_usedLocalElementsVisitor); |
| 4862 // dart2js analysis | 4324 // dart2js analysis |
| 4863 if (_enableDart2JSHints) { | 4325 if (_enableDart2JSHints) { |
| 4864 unit.accept(new Dart2JSVerifier(errorReporter)); | 4326 unit.accept(new Dart2JSVerifier(errorReporter)); |
| 4865 } | 4327 } |
| 4866 // Dart best practices | 4328 // Dart best practices |
| 4867 unit.accept(new BestPracticesVerifier(errorReporter, _context.typeProvider, | 4329 unit.accept(new BestPracticesVerifier( |
| 4330 errorReporter, _context.typeProvider, _library, _manager, |
| 4868 typeSystem: _context.typeSystem)); | 4331 typeSystem: _context.typeSystem)); |
| 4869 unit.accept(new OverrideVerifier(errorReporter, _manager)); | 4332 unit.accept(new OverrideVerifier(errorReporter, _manager)); |
| 4870 // Find to-do comments | 4333 // Find to-do comments |
| 4871 new ToDoFinder(errorReporter).findIn(unit); | 4334 new ToDoFinder(errorReporter).findIn(unit); |
| 4872 // pub analysis | 4335 // pub analysis |
| 4873 // TODO(danrubel/jwren) Commented out until bugs in the pub verifier are | 4336 // TODO(danrubel/jwren) Commented out until bugs in the pub verifier are |
| 4874 // fixed | 4337 // fixed |
| 4875 // unit.accept(new PubVerifier(context, errorReporter)); | 4338 // unit.accept(new PubVerifier(context, errorReporter)); |
| 4876 } | 4339 } |
| 4877 } | 4340 } |
| 4878 | 4341 |
| 4879 /** | 4342 /** |
| 4880 * Instances of the class {@code HtmlTagInfo} record information about the tags
used in an HTML | 4343 * Instances of the class `ImportsVerifier` visit all of the referenced librarie
s in the source code |
| 4881 * file. | 4344 * verifying that all of the imports are used, otherwise a [HintCode.UNUSED_IMPO
RT] hint is |
| 4882 */ | 4345 * generated with [generateUnusedImportHints]. |
| 4883 class HtmlTagInfo { | 4346 * |
| 4884 /** | 4347 * Additionally, [generateDuplicateImportHints] generates [HintCode.DUPLICATE_IM
PORT] hints and |
| 4885 * An array containing all of the tags used in the HTML file. | 4348 * [HintCode.UNUSED_SHOWN_NAME] hints. |
| 4886 */ | |
| 4887 List<String> allTags; | |
| 4888 | |
| 4889 /** | |
| 4890 * A table mapping the id's defined in the HTML file to an array containing th
e names of tags with | |
| 4891 * that identifier. | |
| 4892 */ | |
| 4893 HashMap<String, String> idToTagMap; | |
| 4894 | |
| 4895 /** | |
| 4896 * A table mapping the classes defined in the HTML file to an array containing
the names of tags | |
| 4897 * with that class. | |
| 4898 */ | |
| 4899 HashMap<String, List<String>> classToTagsMap; | |
| 4900 | |
| 4901 /** | |
| 4902 * Initialize a newly created information holder to hold the given information
about the tags in | |
| 4903 * an HTML file. | |
| 4904 * | |
| 4905 * @param allTags an array containing all of the tags used in the HTML file | |
| 4906 * @param idToTagMap a table mapping the id's defined in the HTML file to an a
rray containing the | |
| 4907 * names of tags with that identifier | |
| 4908 * @param classToTagsMap a table mapping the classes defined in the HTML file
to an array | |
| 4909 * containing the names of tags with that class | |
| 4910 */ | |
| 4911 HtmlTagInfo(this.allTags, this.idToTagMap, this.classToTagsMap); | |
| 4912 | |
| 4913 /** | |
| 4914 * Return an array containing the tags that have the given class, or {@code nu
ll} if there are no | |
| 4915 * such tags. | |
| 4916 * | |
| 4917 * @return an array containing the tags that have the given class | |
| 4918 */ | |
| 4919 List<String> getTagsWithClass(String identifier) { | |
| 4920 return classToTagsMap[identifier]; | |
| 4921 } | |
| 4922 | |
| 4923 /** | |
| 4924 * Return the tag that has the given identifier, or {@code null} if there is n
o such tag (the | |
| 4925 * identifier is not defined). | |
| 4926 * | |
| 4927 * @return the tag that has the given identifier | |
| 4928 */ | |
| 4929 String getTagWithId(String identifier) { | |
| 4930 return idToTagMap[identifier]; | |
| 4931 } | |
| 4932 } | |
| 4933 | |
| 4934 /** | |
| 4935 * Instances of the class {@code HtmlTagInfoBuilder} gather information about th
e tags used in one | |
| 4936 * or more HTML structures. | |
| 4937 */ | |
| 4938 class HtmlTagInfoBuilder implements ht.XmlVisitor { | |
| 4939 /** | |
| 4940 * The name of the 'id' attribute. | |
| 4941 */ | |
| 4942 static final String ID_ATTRIBUTE = "id"; | |
| 4943 | |
| 4944 /** | |
| 4945 * The name of the 'class' attribute. | |
| 4946 */ | |
| 4947 static final String ID_CLASS = "class"; | |
| 4948 | |
| 4949 /** | |
| 4950 * A set containing all of the tag names used in the HTML. | |
| 4951 */ | |
| 4952 HashSet<String> tagSet = new HashSet<String>(); | |
| 4953 | |
| 4954 /** | |
| 4955 * A table mapping the id's that are defined to the tag name with that id. | |
| 4956 */ | |
| 4957 HashMap<String, String> idMap = new HashMap<String, String>(); | |
| 4958 | |
| 4959 /** | |
| 4960 * A table mapping the classes that are defined to a set of the tag names with
that class. | |
| 4961 */ | |
| 4962 HashMap<String, HashSet<String>> classMap = | |
| 4963 new HashMap<String, HashSet<String>>(); | |
| 4964 | |
| 4965 /** | |
| 4966 * Initialize a newly created HTML tag info builder. | |
| 4967 */ | |
| 4968 HtmlTagInfoBuilder(); | |
| 4969 | |
| 4970 /** | |
| 4971 * Create a tag information holder holding all of the information gathered abo
ut the tags in the | |
| 4972 * HTML structures that were visited. | |
| 4973 * | |
| 4974 * @return the information gathered about the tags in the visited HTML structu
res | |
| 4975 */ | |
| 4976 HtmlTagInfo getTagInfo() { | |
| 4977 List<String> allTags = tagSet.toList(); | |
| 4978 HashMap<String, List<String>> classToTagsMap = | |
| 4979 new HashMap<String, List<String>>(); | |
| 4980 classMap.forEach((String key, Set<String> tags) { | |
| 4981 classToTagsMap[key] = tags.toList(); | |
| 4982 }); | |
| 4983 return new HtmlTagInfo(allTags, idMap, classToTagsMap); | |
| 4984 } | |
| 4985 | |
| 4986 @override | |
| 4987 visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) { | |
| 4988 visitXmlTagNode(node); | |
| 4989 } | |
| 4990 | |
| 4991 @override | |
| 4992 visitHtmlUnit(ht.HtmlUnit node) { | |
| 4993 node.visitChildren(this); | |
| 4994 } | |
| 4995 | |
| 4996 @override | |
| 4997 visitXmlAttributeNode(ht.XmlAttributeNode node) {} | |
| 4998 | |
| 4999 @override | |
| 5000 visitXmlTagNode(ht.XmlTagNode node) { | |
| 5001 node.visitChildren(this); | |
| 5002 String tagName = node.tag; | |
| 5003 tagSet.add(tagName); | |
| 5004 for (ht.XmlAttributeNode attribute in node.attributes) { | |
| 5005 String attributeName = attribute.name; | |
| 5006 if (attributeName == ID_ATTRIBUTE) { | |
| 5007 String attributeValue = attribute.text; | |
| 5008 if (attributeValue != null) { | |
| 5009 String tag = idMap[attributeValue]; | |
| 5010 if (tag == null) { | |
| 5011 idMap[attributeValue] = tagName; | |
| 5012 } else { | |
| 5013 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken); | |
| 5014 } | |
| 5015 } | |
| 5016 } else if (attributeName == ID_CLASS) { | |
| 5017 String attributeValue = attribute.text; | |
| 5018 if (attributeValue != null) { | |
| 5019 HashSet<String> tagList = classMap[attributeValue]; | |
| 5020 if (tagList == null) { | |
| 5021 tagList = new HashSet<String>(); | |
| 5022 classMap[attributeValue] = tagList; | |
| 5023 } else { | |
| 5024 // reportError(HtmlWarningCode.MULTIPLY_DEFINED_ID, valueToken); | |
| 5025 } | |
| 5026 tagList.add(tagName); | |
| 5027 } | |
| 5028 } | |
| 5029 } | |
| 5030 } | |
| 5031 | |
| 5032 // /** | |
| 5033 // * Report an error with the given error code at the given location. Use the
given arguments to | |
| 5034 // * compose the error message. | |
| 5035 // * | |
| 5036 // * @param errorCode the error code of the error to be reported | |
| 5037 // * @param offset the offset of the first character to be highlighted | |
| 5038 // * @param length the number of characters to be highlighted | |
| 5039 // * @param arguments the arguments used to compose the error message | |
| 5040 // */ | |
| 5041 // private void reportError(ErrorCode errorCode, Token token, Object... argumen
ts) { | |
| 5042 // errorListener.onError(new AnalysisError( | |
| 5043 // htmlElement.getSource(), | |
| 5044 // token.getOffset(), | |
| 5045 // token.getLength(), | |
| 5046 // errorCode, | |
| 5047 // arguments)); | |
| 5048 // } | |
| 5049 // | |
| 5050 // /** | |
| 5051 // * Report an error with the given error code at the given location. Use the
given arguments to | |
| 5052 // * compose the error message. | |
| 5053 // * | |
| 5054 // * @param errorCode the error code of the error to be reported | |
| 5055 // * @param offset the offset of the first character to be highlighted | |
| 5056 // * @param length the number of characters to be highlighted | |
| 5057 // * @param arguments the arguments used to compose the error message | |
| 5058 // */ | |
| 5059 // private void reportError(ErrorCode errorCode, int offset, int length, Object
... arguments) { | |
| 5060 // errorListener.onError(new AnalysisError( | |
| 5061 // htmlElement.getSource(), | |
| 5062 // offset, | |
| 5063 // length, | |
| 5064 // errorCode, | |
| 5065 // arguments)); | |
| 5066 // } | |
| 5067 } | |
| 5068 | |
| 5069 /** | |
| 5070 * Instances of the class `HtmlUnitBuilder` build an element model for a single
HTML unit. | |
| 5071 */ | |
| 5072 class HtmlUnitBuilder implements ht.XmlVisitor<Object> { | |
| 5073 static String _SRC = "src"; | |
| 5074 | |
| 5075 /** | |
| 5076 * The analysis context in which the element model will be built. | |
| 5077 */ | |
| 5078 final InternalAnalysisContext _context; | |
| 5079 | |
| 5080 /** | |
| 5081 * The error listener to which errors will be reported. | |
| 5082 */ | |
| 5083 RecordingErrorListener _errorListener; | |
| 5084 | |
| 5085 /** | |
| 5086 * The HTML element being built. | |
| 5087 */ | |
| 5088 HtmlElementImpl _htmlElement; | |
| 5089 | |
| 5090 /** | |
| 5091 * The elements in the path from the HTML unit to the current tag node. | |
| 5092 */ | |
| 5093 List<ht.XmlTagNode> _parentNodes; | |
| 5094 | |
| 5095 /** | |
| 5096 * The script elements being built. | |
| 5097 */ | |
| 5098 List<HtmlScriptElement> _scripts; | |
| 5099 | |
| 5100 /** | |
| 5101 * A set of the libraries that were resolved while resolving the HTML unit. | |
| 5102 */ | |
| 5103 Set<Library> _resolvedLibraries = new HashSet<Library>(); | |
| 5104 | |
| 5105 /** | |
| 5106 * Initialize a newly created HTML unit builder. | |
| 5107 * | |
| 5108 * @param context the analysis context in which the element model will be buil
t | |
| 5109 */ | |
| 5110 HtmlUnitBuilder(this._context) { | |
| 5111 this._errorListener = new RecordingErrorListener(); | |
| 5112 } | |
| 5113 | |
| 5114 /** | |
| 5115 * Return the listener to which analysis errors will be reported. | |
| 5116 * | |
| 5117 * @return the listener to which analysis errors will be reported | |
| 5118 */ | |
| 5119 RecordingErrorListener get errorListener => _errorListener; | |
| 5120 | |
| 5121 /** | |
| 5122 * Return an array containing information about all of the libraries that were
resolved. | |
| 5123 * | |
| 5124 * @return an array containing the libraries that were resolved | |
| 5125 */ | |
| 5126 Set<Library> get resolvedLibraries => _resolvedLibraries; | |
| 5127 | |
| 5128 /** | |
| 5129 * Build the HTML element for the given source. | |
| 5130 * | |
| 5131 * @param source the source describing the compilation unit | |
| 5132 * @param unit the AST structure representing the HTML | |
| 5133 * @throws AnalysisException if the analysis could not be performed | |
| 5134 */ | |
| 5135 HtmlElementImpl buildHtmlElement(Source source, ht.HtmlUnit unit) { | |
| 5136 HtmlElementImpl result = new HtmlElementImpl(_context, source.shortName); | |
| 5137 result.source = source; | |
| 5138 _htmlElement = result; | |
| 5139 unit.accept(this); | |
| 5140 _htmlElement = null; | |
| 5141 unit.element = result; | |
| 5142 return result; | |
| 5143 } | |
| 5144 | |
| 5145 @override | |
| 5146 Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) { | |
| 5147 if (_parentNodes.contains(node)) { | |
| 5148 return _reportCircularity(node); | |
| 5149 } | |
| 5150 _parentNodes.add(node); | |
| 5151 try { | |
| 5152 Source htmlSource = _htmlElement.source; | |
| 5153 ht.XmlAttributeNode scriptAttribute = _getScriptSourcePath(node); | |
| 5154 String scriptSourcePath = | |
| 5155 scriptAttribute == null ? null : scriptAttribute.text; | |
| 5156 if (node.attributeEnd.type == ht.TokenType.GT && | |
| 5157 scriptSourcePath == null) { | |
| 5158 EmbeddedHtmlScriptElementImpl script = | |
| 5159 new EmbeddedHtmlScriptElementImpl(node); | |
| 5160 try { | |
| 5161 LibraryResolver resolver = new LibraryResolver(_context); | |
| 5162 LibraryElementImpl library = | |
| 5163 resolver.resolveEmbeddedLibrary(htmlSource, node.script, true); | |
| 5164 script.scriptLibrary = library; | |
| 5165 _resolvedLibraries.addAll(resolver.resolvedLibraries); | |
| 5166 _errorListener.addAll(resolver.errorListener); | |
| 5167 } on AnalysisException catch (exception, stackTrace) { | |
| 5168 //TODO (danrubel): Handle or forward the exception | |
| 5169 AnalysisEngine.instance.logger.logError( | |
| 5170 "Could not resolve script tag", | |
| 5171 new CaughtException(exception, stackTrace)); | |
| 5172 } | |
| 5173 node.scriptElement = script; | |
| 5174 _scripts.add(script); | |
| 5175 } else { | |
| 5176 ExternalHtmlScriptElementImpl script = | |
| 5177 new ExternalHtmlScriptElementImpl(node); | |
| 5178 if (scriptSourcePath != null) { | |
| 5179 try { | |
| 5180 scriptSourcePath = Uri.encodeFull(scriptSourcePath); | |
| 5181 // Force an exception to be thrown if the URI is invalid so that we | |
| 5182 // can report the problem. | |
| 5183 parseUriWithException(scriptSourcePath); | |
| 5184 Source scriptSource = | |
| 5185 _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath); | |
| 5186 script.scriptSource = scriptSource; | |
| 5187 if (!_context.exists(scriptSource)) { | |
| 5188 _reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST, | |
| 5189 scriptAttribute, [scriptSourcePath]); | |
| 5190 } | |
| 5191 } on URISyntaxException { | |
| 5192 _reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, | |
| 5193 [scriptSourcePath]); | |
| 5194 } | |
| 5195 } | |
| 5196 node.scriptElement = script; | |
| 5197 _scripts.add(script); | |
| 5198 } | |
| 5199 } finally { | |
| 5200 _parentNodes.remove(node); | |
| 5201 } | |
| 5202 return null; | |
| 5203 } | |
| 5204 | |
| 5205 @override | |
| 5206 Object visitHtmlUnit(ht.HtmlUnit node) { | |
| 5207 _parentNodes = new List<ht.XmlTagNode>(); | |
| 5208 _scripts = new List<HtmlScriptElement>(); | |
| 5209 try { | |
| 5210 node.visitChildren(this); | |
| 5211 _htmlElement.scripts = new List.from(_scripts); | |
| 5212 } finally { | |
| 5213 _scripts = null; | |
| 5214 _parentNodes = null; | |
| 5215 } | |
| 5216 return null; | |
| 5217 } | |
| 5218 | |
| 5219 @override | |
| 5220 Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null; | |
| 5221 | |
| 5222 @override | |
| 5223 Object visitXmlTagNode(ht.XmlTagNode node) { | |
| 5224 if (_parentNodes.contains(node)) { | |
| 5225 return _reportCircularity(node); | |
| 5226 } | |
| 5227 _parentNodes.add(node); | |
| 5228 try { | |
| 5229 node.visitChildren(this); | |
| 5230 } finally { | |
| 5231 _parentNodes.remove(node); | |
| 5232 } | |
| 5233 return null; | |
| 5234 } | |
| 5235 | |
| 5236 /** | |
| 5237 * Return the first source attribute for the given tag node, or `null` if it d
oes not exist. | |
| 5238 * | |
| 5239 * @param node the node containing attributes | |
| 5240 * @return the source attribute contained in the given tag | |
| 5241 */ | |
| 5242 ht.XmlAttributeNode _getScriptSourcePath(ht.XmlTagNode node) { | |
| 5243 for (ht.XmlAttributeNode attribute in node.attributes) { | |
| 5244 if (attribute.name == _SRC) { | |
| 5245 return attribute; | |
| 5246 } | |
| 5247 } | |
| 5248 return null; | |
| 5249 } | |
| 5250 | |
| 5251 Object _reportCircularity(ht.XmlTagNode node) { | |
| 5252 // | |
| 5253 // This should not be possible, but we have an error report that suggests | |
| 5254 // that it happened at least once. This code will guard against infinite | |
| 5255 // recursion and might help us identify the cause of the issue. | |
| 5256 // | |
| 5257 StringBuffer buffer = new StringBuffer(); | |
| 5258 buffer.write("Found circularity in XML nodes: "); | |
| 5259 bool first = true; | |
| 5260 for (ht.XmlTagNode pathNode in _parentNodes) { | |
| 5261 if (first) { | |
| 5262 first = false; | |
| 5263 } else { | |
| 5264 buffer.write(", "); | |
| 5265 } | |
| 5266 String tagName = pathNode.tag; | |
| 5267 if (identical(pathNode, node)) { | |
| 5268 buffer.write("*"); | |
| 5269 buffer.write(tagName); | |
| 5270 buffer.write("*"); | |
| 5271 } else { | |
| 5272 buffer.write(tagName); | |
| 5273 } | |
| 5274 } | |
| 5275 AnalysisEngine.instance.logger.logError(buffer.toString()); | |
| 5276 return null; | |
| 5277 } | |
| 5278 | |
| 5279 /** | |
| 5280 * Report an error with the given error code at the given location. Use the gi
ven arguments to | |
| 5281 * compose the error message. | |
| 5282 * | |
| 5283 * @param errorCode the error code of the error to be reported | |
| 5284 * @param offset the offset of the first character to be highlighted | |
| 5285 * @param length the number of characters to be highlighted | |
| 5286 * @param arguments the arguments used to compose the error message | |
| 5287 */ | |
| 5288 void _reportErrorForOffset( | |
| 5289 ErrorCode errorCode, int offset, int length, List<Object> arguments) { | |
| 5290 _errorListener.onError(new AnalysisError( | |
| 5291 _htmlElement.source, offset, length, errorCode, arguments)); | |
| 5292 } | |
| 5293 | |
| 5294 /** | |
| 5295 * Report an error with the given error code at the location of the value of t
he given attribute. | |
| 5296 * Use the given arguments to compose the error message. | |
| 5297 * | |
| 5298 * @param errorCode the error code of the error to be reported | |
| 5299 * @param offset the offset of the first character to be highlighted | |
| 5300 * @param length the number of characters to be highlighted | |
| 5301 * @param arguments the arguments used to compose the error message | |
| 5302 */ | |
| 5303 void _reportValueError(ErrorCode errorCode, ht.XmlAttributeNode attribute, | |
| 5304 List<Object> arguments) { | |
| 5305 int offset = attribute.valueToken.offset + 1; | |
| 5306 int length = attribute.valueToken.length - 2; | |
| 5307 _reportErrorForOffset(errorCode, offset, length, arguments); | |
| 5308 } | |
| 5309 } | |
| 5310 | |
| 5311 /** | |
| 5312 * Instances of the class `ImplicitLabelScope` represent the scope statements | |
| 5313 * that can be the target of unlabeled break and continue statements. | |
| 5314 */ | |
| 5315 class ImplicitLabelScope { | |
| 5316 /** | |
| 5317 * The implicit label scope associated with the top level of a function. | |
| 5318 */ | |
| 5319 static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null); | |
| 5320 | |
| 5321 /** | |
| 5322 * The implicit label scope enclosing this implicit label scope. | |
| 5323 */ | |
| 5324 final ImplicitLabelScope outerScope; | |
| 5325 | |
| 5326 /** | |
| 5327 * The statement that acts as a target for break and/or continue statements | |
| 5328 * at this scoping level. | |
| 5329 */ | |
| 5330 final Statement statement; | |
| 5331 | |
| 5332 /** | |
| 5333 * Private constructor. | |
| 5334 */ | |
| 5335 const ImplicitLabelScope._(this.outerScope, this.statement); | |
| 5336 | |
| 5337 /** | |
| 5338 * Get the statement which should be the target of an unlabeled `break` or | |
| 5339 * `continue` statement, or `null` if there is no appropriate target. | |
| 5340 */ | |
| 5341 Statement getTarget(bool isContinue) { | |
| 5342 if (outerScope == null) { | |
| 5343 // This scope represents the toplevel of a function body, so it doesn't | |
| 5344 // match either break or continue. | |
| 5345 return null; | |
| 5346 } | |
| 5347 if (isContinue && statement is SwitchStatement) { | |
| 5348 return outerScope.getTarget(isContinue); | |
| 5349 } | |
| 5350 return statement; | |
| 5351 } | |
| 5352 | |
| 5353 /** | |
| 5354 * Initialize a newly created scope to represent a switch statement or loop | |
| 5355 * nested within the current scope. [statement] is the statement associated | |
| 5356 * with the newly created scope. | |
| 5357 */ | |
| 5358 ImplicitLabelScope nest(Statement statement) => | |
| 5359 new ImplicitLabelScope._(this, statement); | |
| 5360 } | |
| 5361 | |
| 5362 /** | |
| 5363 * Instances of the class `ImportsVerifier` visit all of the referenced librarie
s in the | |
| 5364 * source code verifying that all of the imports are used, otherwise a | |
| 5365 * [HintCode.UNUSED_IMPORT] is generated with | |
| 5366 * [generateUnusedImportHints]. | |
| 5367 * | 4349 * |
| 5368 * While this class does not yet have support for an "Organize Imports" action,
this logic built up | 4350 * While this class does not yet have support for an "Organize Imports" action,
this logic built up |
| 5369 * in this class could be used for such an action in the future. | 4351 * in this class could be used for such an action in the future. |
| 5370 */ | 4352 */ |
| 5371 class ImportsVerifier /*extends RecursiveAstVisitor<Object>*/ { | 4353 class ImportsVerifier { |
| 5372 /** | 4354 /** |
| 5373 * A list of [ImportDirective]s that the current library imports, as identifie
rs are visited | 4355 * A list of [ImportDirective]s that the current library imports, but does not
use. |
| 5374 * by this visitor and an import has been identified as being used by the libr
ary, the | 4356 * |
| 5375 * [ImportDirective] is removed from this list. After all the sources in the l
ibrary have | 4357 * As identifiers are visited by this visitor and an import has been identifie
d as being used |
| 5376 * been evaluated, this list represents the set of unused imports. | 4358 * by the library, the [ImportDirective] is removed from this list. After all
the sources in the |
| 4359 * library have been evaluated, this list represents the set of unused imports
. |
| 5377 * | 4360 * |
| 5378 * See [ImportsVerifier.generateUnusedImportErrors]. | 4361 * See [ImportsVerifier.generateUnusedImportErrors]. |
| 5379 */ | 4362 */ |
| 5380 final List<ImportDirective> _unusedImports = <ImportDirective>[]; | 4363 final List<ImportDirective> _unusedImports = <ImportDirective>[]; |
| 5381 | 4364 |
| 5382 /** | 4365 /** |
| 5383 * After the list of [unusedImports] has been computed, this list is a proper
subset of the | 4366 * After the list of [unusedImports] has been computed, this list is a proper
subset of the |
| 5384 * unused imports that are listed more than once. | 4367 * unused imports that are listed more than once. |
| 5385 */ | 4368 */ |
| 5386 final List<ImportDirective> _duplicateImports = <ImportDirective>[]; | 4369 final List<ImportDirective> _duplicateImports = <ImportDirective>[]; |
| 5387 | 4370 |
| 5388 /** | 4371 /** |
| 5389 * This is a map between the set of [LibraryElement]s that the current library
imports, and | 4372 * This is a map between the set of [LibraryElement]s that the current library
imports, and the |
| 5390 * a list of [ImportDirective]s that imports the library. In cases where the c
urrent library | 4373 * list of [ImportDirective]s that import each [LibraryElement]. In cases wher
e the current |
| 5391 * imports a library with a single directive (such as `import lib1.dart;`), th
e library | 4374 * library imports a library with a single directive (such as `import lib1.dar
t;`), the library |
| 5392 * element will map to a list of one [ImportDirective], which will then be rem
oved from the | 4375 * element will map to a list of one [ImportDirective], which will then be rem
oved from the |
| 5393 * [unusedImports] list. In cases where the current library imports a library
with multiple | 4376 * [unusedImports] list. In cases where the current library imports a library
with multiple |
| 5394 * directives (such as `import lib1.dart; import lib1.dart show C;`), the | 4377 * directives (such as `import lib1.dart; import lib1.dart show C;`), the [Lib
raryElement] will |
| 5395 * [LibraryElement] will be mapped to a list of the import directives, and the
namespace | 4378 * be mapped to a list of the import directives, and the namespace will need t
o be used to |
| 5396 * will need to be used to compute the correct [ImportDirective] being used, s
ee | 4379 * compute the correct [ImportDirective] being used; see [_namespaceMap]. |
| 5397 * [namespaceMap]. | |
| 5398 */ | 4380 */ |
| 5399 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap = | 4381 final HashMap<LibraryElement, List<ImportDirective>> _libraryMap = |
| 5400 new HashMap<LibraryElement, List<ImportDirective>>(); | 4382 new HashMap<LibraryElement, List<ImportDirective>>(); |
| 5401 | 4383 |
| 5402 /** | 4384 /** |
| 5403 * In cases where there is more than one import directive per library element,
this mapping is | 4385 * In cases where there is more than one import directive per library element,
this mapping is |
| 5404 * used to determine which of the multiple import directives are used by gener
ating a | 4386 * used to determine which of the multiple import directives are used by gener
ating a |
| 5405 * [Namespace] for each of the imports to do lookups in the same way that they
are done from | 4387 * [Namespace] for each of the imports to do lookups in the same way that they
are done from |
| 5406 * the [ElementResolver]. | 4388 * the [ElementResolver]. |
| 5407 */ | 4389 */ |
| 5408 final HashMap<ImportDirective, Namespace> _namespaceMap = | 4390 final HashMap<ImportDirective, Namespace> _namespaceMap = |
| 5409 new HashMap<ImportDirective, Namespace>(); | 4391 new HashMap<ImportDirective, Namespace>(); |
| 5410 | 4392 |
| 5411 /** | 4393 /** |
| 5412 * This is a map between prefix elements and the import directives from which
they are derived. In | 4394 * This is a map between prefix elements and the import directives from which
they are derived. In |
| 5413 * cases where a type is referenced via a prefix element, the import directive
can be marked as | 4395 * cases where a type is referenced via a prefix element, the import directive
can be marked as |
| 5414 * used (removed from the unusedImports) by looking at the resolved `lib` in `
lib.X`, | 4396 * used (removed from the unusedImports) by looking at the resolved `lib` in `
lib.X`, |
| 5415 * instead of looking at which library the `lib.X` resolves. | 4397 * instead of looking at which library the `lib.X` resolves. |
| 5416 * | 4398 * |
| 5417 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl
ement], | 4399 * TODO (jwren) Since multiple [ImportDirective]s can share the same [PrefixEl
ement], |
| 5418 * it is possible to have an unreported unused import in situations where two
imports use the same | 4400 * it is possible to have an unreported unused import in situations where two
imports use the same |
| 5419 * prefix and at least one import directive is used. | 4401 * prefix and at least one import directive is used. |
| 5420 */ | 4402 */ |
| 5421 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap = | 4403 final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap = |
| 5422 new HashMap<PrefixElement, List<ImportDirective>>(); | 4404 new HashMap<PrefixElement, List<ImportDirective>>(); |
| 5423 | 4405 |
| 4406 /** |
| 4407 * A map of identifiers that the current library's imports show, but that the
library does not |
| 4408 * use. |
| 4409 * |
| 4410 * Each import directive maps to a list of the identifiers that are imported v
ia the "show" |
| 4411 * keyword. |
| 4412 * |
| 4413 * As each identifier is visited by this visitor, it is identified as being us
ed by the library, |
| 4414 * and the identifier is removed from this map (under the import that imported
it). After all the |
| 4415 * sources in the library have been evaluated, each list in this map's values
present the set of |
| 4416 * unused shown elements. |
| 4417 * |
| 4418 * See [ImportsVerifier.generateUnusedShownNameHints]. |
| 4419 */ |
| 4420 final HashMap<ImportDirective, List<SimpleIdentifier>> _unusedShownNamesMap = |
| 4421 new HashMap<ImportDirective, List<SimpleIdentifier>>(); |
| 4422 |
| 5424 void addImports(CompilationUnit node) { | 4423 void addImports(CompilationUnit node) { |
| 5425 for (Directive directive in node.directives) { | 4424 for (Directive directive in node.directives) { |
| 5426 if (directive is ImportDirective) { | 4425 if (directive is ImportDirective) { |
| 5427 ImportDirective importDirective = directive; | 4426 LibraryElement libraryElement = directive.uriElement; |
| 5428 LibraryElement libraryElement = importDirective.uriElement; | 4427 if (libraryElement == null) { |
| 5429 if (libraryElement != null) { | 4428 continue; |
| 5430 _unusedImports.add(importDirective); | 4429 } |
| 5431 // | 4430 _unusedImports.add(directive); |
| 5432 // Initialize prefixElementMap | 4431 // |
| 5433 // | 4432 // Initialize prefixElementMap |
| 5434 if (importDirective.asKeyword != null) { | 4433 // |
| 5435 SimpleIdentifier prefixIdentifier = importDirective.prefix; | 4434 if (directive.asKeyword != null) { |
| 5436 if (prefixIdentifier != null) { | 4435 SimpleIdentifier prefixIdentifier = directive.prefix; |
| 5437 Element element = prefixIdentifier.staticElement; | 4436 if (prefixIdentifier != null) { |
| 5438 if (element is PrefixElement) { | 4437 Element element = prefixIdentifier.staticElement; |
| 5439 PrefixElement prefixElementKey = element; | 4438 if (element is PrefixElement) { |
| 5440 List<ImportDirective> list = | 4439 List<ImportDirective> list = _prefixElementMap[element]; |
| 5441 _prefixElementMap[prefixElementKey]; | 4440 if (list == null) { |
| 5442 if (list == null) { | 4441 list = new List<ImportDirective>(); |
| 5443 list = new List<ImportDirective>(); | 4442 _prefixElementMap[element] = list; |
| 5444 _prefixElementMap[prefixElementKey] = list; | |
| 5445 } | |
| 5446 list.add(importDirective); | |
| 5447 } | 4443 } |
| 5448 // TODO (jwren) Can the element ever not be a PrefixElement? | 4444 list.add(directive); |
| 5449 } | 4445 } |
| 4446 // TODO (jwren) Can the element ever not be a PrefixElement? |
| 5450 } | 4447 } |
| 5451 // | 4448 } |
| 5452 // Initialize libraryMap: libraryElement -> importDirective | 4449 // |
| 5453 // | 4450 // Initialize libraryMap: libraryElement -> importDirective |
| 5454 _putIntoLibraryMap(libraryElement, importDirective); | 4451 // |
| 5455 // | 4452 _putIntoLibraryMap(libraryElement, directive); |
| 5456 // For this new addition to the libraryMap, also recursively add any | 4453 // |
| 5457 // exports from the libraryElement. | 4454 // For this new addition to the libraryMap, also recursively add any |
| 5458 // | 4455 // exports from the libraryElement. |
| 5459 _addAdditionalLibrariesForExports( | 4456 // |
| 5460 libraryElement, importDirective, new List<LibraryElement>()); | 4457 _addAdditionalLibrariesForExports( |
| 5461 } | 4458 libraryElement, directive, new HashSet<LibraryElement>()); |
| 4459 _addShownNames(directive); |
| 5462 } | 4460 } |
| 5463 } | 4461 } |
| 5464 if (_unusedImports.length > 1) { | 4462 if (_unusedImports.length > 1) { |
| 5465 // order the list of unusedImports to find duplicates in faster than | 4463 // order the list of unusedImports to find duplicates in faster than |
| 5466 // O(n^2) time | 4464 // O(n^2) time |
| 5467 List<ImportDirective> importDirectiveArray = | 4465 List<ImportDirective> importDirectiveArray = |
| 5468 new List<ImportDirective>.from(_unusedImports); | 4466 new List<ImportDirective>.from(_unusedImports); |
| 5469 importDirectiveArray.sort(ImportDirective.COMPARATOR); | 4467 importDirectiveArray.sort(ImportDirective.COMPARATOR); |
| 5470 ImportDirective currentDirective = importDirectiveArray[0]; | 4468 ImportDirective currentDirective = importDirectiveArray[0]; |
| 5471 for (int i = 1; i < importDirectiveArray.length; i++) { | 4469 for (int i = 1; i < importDirectiveArray.length; i++) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 5487 | 4485 |
| 5488 /** | 4486 /** |
| 5489 * Any time after the defining compilation unit has been visited by this visit
or, this method can | 4487 * Any time after the defining compilation unit has been visited by this visit
or, this method can |
| 5490 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp
ort directives | 4488 * be called to report an [HintCode.DUPLICATE_IMPORT] hint for each of the imp
ort directives |
| 5491 * in the [duplicateImports] list. | 4489 * in the [duplicateImports] list. |
| 5492 * | 4490 * |
| 5493 * @param errorReporter the error reporter to report the set of [HintCode.DUPL
ICATE_IMPORT] | 4491 * @param errorReporter the error reporter to report the set of [HintCode.DUPL
ICATE_IMPORT] |
| 5494 * hints to | 4492 * hints to |
| 5495 */ | 4493 */ |
| 5496 void generateDuplicateImportHints(ErrorReporter errorReporter) { | 4494 void generateDuplicateImportHints(ErrorReporter errorReporter) { |
| 5497 for (ImportDirective duplicateImport in _duplicateImports) { | 4495 int length = _duplicateImports.length; |
| 4496 for (int i = 0; i < length; i++) { |
| 5498 errorReporter.reportErrorForNode( | 4497 errorReporter.reportErrorForNode( |
| 5499 HintCode.DUPLICATE_IMPORT, duplicateImport.uri); | 4498 HintCode.DUPLICATE_IMPORT, _duplicateImports[i].uri); |
| 5500 } | 4499 } |
| 5501 } | 4500 } |
| 5502 | 4501 |
| 5503 /** | 4502 /** |
| 5504 * After all of the compilation units have been visited by this visitor, this
method can be called | 4503 * Report an [HintCode.UNUSED_IMPORT] hint for each unused import. |
| 5505 * to report an [HintCode.UNUSED_IMPORT] hint for each of the import directive
s in the | 4504 * |
| 5506 * [unusedImports] list. | 4505 * Only call this method after all of the compilation units have been visited
by this visitor. |
| 5507 * | 4506 * |
| 5508 * @param errorReporter the error reporter to report the set of [HintCode.UNUS
ED_IMPORT] | 4507 * @param errorReporter the error reporter used to report the set of [HintCode
.UNUSED_IMPORT] |
| 5509 * hints to | 4508 * hints |
| 5510 */ | 4509 */ |
| 5511 void generateUnusedImportHints(ErrorReporter errorReporter) { | 4510 void generateUnusedImportHints(ErrorReporter errorReporter) { |
| 5512 for (ImportDirective unusedImport in _unusedImports) { | 4511 int length = _unusedImports.length; |
| 5513 // Check that the import isn't dart:core | 4512 for (int i = 0; i < length; i++) { |
| 4513 ImportDirective unusedImport = _unusedImports[i]; |
| 4514 // Check that the imported URI exists and isn't dart:core |
| 5514 ImportElement importElement = unusedImport.element; | 4515 ImportElement importElement = unusedImport.element; |
| 5515 if (importElement != null) { | 4516 if (importElement != null) { |
| 5516 LibraryElement libraryElement = importElement.importedLibrary; | 4517 LibraryElement libraryElement = importElement.importedLibrary; |
| 5517 if (libraryElement != null && libraryElement.isDartCore) { | 4518 if (libraryElement == null || |
| 4519 libraryElement.isDartCore || |
| 4520 libraryElement.isSynthetic) { |
| 5518 continue; | 4521 continue; |
| 5519 } | 4522 } |
| 5520 } | 4523 } |
| 5521 errorReporter.reportErrorForNode( | 4524 errorReporter.reportErrorForNode( |
| 5522 HintCode.UNUSED_IMPORT, unusedImport.uri); | 4525 HintCode.UNUSED_IMPORT, unusedImport.uri); |
| 5523 } | 4526 } |
| 5524 } | 4527 } |
| 5525 | 4528 |
| 5526 /** | 4529 /** |
| 4530 * Report an [HintCode.UNUSED_SHOWN_NAME] hint for each unused shown name. |
| 4531 * |
| 4532 * Only call this method after all of the compilation units have been visited
by this visitor. |
| 4533 * |
| 4534 * @param errorReporter the error reporter used to report the set of [HintCode
.UNUSED_SHOWN_NAME] |
| 4535 * hints |
| 4536 */ |
| 4537 void generateUnusedShownNameHints(ErrorReporter reporter) { |
| 4538 _unusedShownNamesMap.forEach( |
| 4539 (ImportDirective importDirective, List<SimpleIdentifier> identifiers) { |
| 4540 if (_unusedImports.contains(importDirective)) { |
| 4541 // This import is actually wholly unused, not just one or more shown nam
es from it. |
| 4542 // This is then an "unused import", rather than unused shown names. |
| 4543 return; |
| 4544 } |
| 4545 int length = identifiers.length; |
| 4546 for (int i = 0; i < length; i++) { |
| 4547 Identifier identifier = identifiers[i]; |
| 4548 reporter.reportErrorForNode( |
| 4549 HintCode.UNUSED_SHOWN_NAME, identifier, [identifier.name]); |
| 4550 } |
| 4551 }); |
| 4552 } |
| 4553 |
| 4554 /** |
| 5527 * Remove elements from [_unusedImports] using the given [usedElements]. | 4555 * Remove elements from [_unusedImports] using the given [usedElements]. |
| 5528 */ | 4556 */ |
| 5529 void removeUsedElements(UsedImportedElements usedElements) { | 4557 void removeUsedElements(UsedImportedElements usedElements) { |
| 5530 // Stop if all the imports are known to be used. | 4558 // Stop if all the imports and shown names are known to be used. |
| 5531 if (_unusedImports.isEmpty) { | 4559 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) { |
| 5532 return; | 4560 return; |
| 5533 } | 4561 } |
| 5534 // Process import prefixes. | 4562 // Process import prefixes. |
| 5535 for (PrefixElement prefix in usedElements.prefixes) { | 4563 usedElements.prefixMap |
| 4564 .forEach((PrefixElement prefix, List<Element> elements) { |
| 5536 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; | 4565 List<ImportDirective> importDirectives = _prefixElementMap[prefix]; |
| 5537 if (importDirectives != null) { | 4566 if (importDirectives != null) { |
| 5538 for (ImportDirective importDirective in importDirectives) { | 4567 int importLength = importDirectives.length; |
| 4568 for (int i = 0; i < importLength; i++) { |
| 4569 ImportDirective importDirective = importDirectives[i]; |
| 5539 _unusedImports.remove(importDirective); | 4570 _unusedImports.remove(importDirective); |
| 5540 } | 4571 int elementLength = elements.length; |
| 5541 } | 4572 for (int j = 0; j < elementLength; j++) { |
| 5542 } | 4573 Element element = elements[j]; |
| 4574 _removeFromUnusedShownNamesMap(element, importDirective); |
| 4575 } |
| 4576 } |
| 4577 } |
| 4578 }); |
| 5543 // Process top-level elements. | 4579 // Process top-level elements. |
| 5544 for (Element element in usedElements.elements) { | 4580 for (Element element in usedElements.elements) { |
| 5545 // Stop if all the imports are known to be used. | 4581 // Stop if all the imports and shown names are known to be used. |
| 5546 if (_unusedImports.isEmpty) { | 4582 if (_unusedImports.isEmpty && _unusedShownNamesMap.isEmpty) { |
| 5547 return; | 4583 return; |
| 5548 } | 4584 } |
| 5549 // Prepare import directives for this library. | 4585 // Prepare import directives for this element's library. |
| 5550 LibraryElement library = element.library; | 4586 LibraryElement library = element.library; |
| 5551 List<ImportDirective> importsLibrary = _libraryMap[library]; | 4587 List<ImportDirective> importsLibrary = _libraryMap[library]; |
| 5552 if (importsLibrary == null) { | 4588 if (importsLibrary == null) { |
| 4589 // element's library is not imported. Must be the current library. |
| 5553 continue; | 4590 continue; |
| 5554 } | 4591 } |
| 5555 // If there is only one import directive for this library, then it must be | 4592 // If there is only one import directive for this library, then it must be |
| 5556 // the directive that this element is imported with, remove it from the | 4593 // the directive that this element is imported with, remove it from the |
| 5557 // unusedImports list. | 4594 // unusedImports list. |
| 5558 if (importsLibrary.length == 1) { | 4595 if (importsLibrary.length == 1) { |
| 5559 ImportDirective usedImportDirective = importsLibrary[0]; | 4596 ImportDirective usedImportDirective = importsLibrary[0]; |
| 5560 _unusedImports.remove(usedImportDirective); | 4597 _unusedImports.remove(usedImportDirective); |
| 4598 _removeFromUnusedShownNamesMap(element, usedImportDirective); |
| 5561 continue; | 4599 continue; |
| 5562 } | 4600 } |
| 5563 // Otherwise, find import directives using namespaces. | 4601 // Otherwise, find import directives using namespaces. |
| 5564 String name = element.displayName; | 4602 String name = element.displayName; |
| 5565 for (ImportDirective importDirective in importsLibrary) { | 4603 for (ImportDirective importDirective in importsLibrary) { |
| 5566 Namespace namespace = _computeNamespace(importDirective); | 4604 Namespace namespace = _computeNamespace(importDirective); |
| 5567 if (namespace != null && namespace.get(name) != null) { | 4605 if (namespace?.get(name) != null) { |
| 5568 _unusedImports.remove(importDirective); | 4606 _unusedImports.remove(importDirective); |
| 4607 _removeFromUnusedShownNamesMap(element, importDirective); |
| 5569 } | 4608 } |
| 5570 } | 4609 } |
| 5571 } | 4610 } |
| 5572 } | 4611 } |
| 5573 | 4612 |
| 5574 /** | 4613 /** |
| 5575 * Recursively add any exported library elements into the [libraryMap]. | 4614 * Recursively add any exported library elements into the [libraryMap]. |
| 5576 */ | 4615 */ |
| 5577 void _addAdditionalLibrariesForExports(LibraryElement library, | 4616 void _addAdditionalLibrariesForExports(LibraryElement library, |
| 5578 ImportDirective importDirective, List<LibraryElement> exportPath) { | 4617 ImportDirective importDirective, Set<LibraryElement> visitedLibraries) { |
| 5579 if (exportPath.contains(library)) { | 4618 if (!visitedLibraries.add(library)) { |
| 5580 return; | 4619 return; |
| 5581 } | 4620 } |
| 5582 exportPath.add(library); | 4621 List<ExportElement> exports = library.exports; |
| 5583 for (LibraryElement exportedLibraryElt in library.exportedLibraries) { | 4622 int length = exports.length; |
| 5584 _putIntoLibraryMap(exportedLibraryElt, importDirective); | 4623 for (int i = 0; i < length; i++) { |
| 4624 ExportElement exportElt = exports[i]; |
| 4625 LibraryElement exportedLibrary = exportElt.exportedLibrary; |
| 4626 _putIntoLibraryMap(exportedLibrary, importDirective); |
| 5585 _addAdditionalLibrariesForExports( | 4627 _addAdditionalLibrariesForExports( |
| 5586 exportedLibraryElt, importDirective, exportPath); | 4628 exportedLibrary, importDirective, visitedLibraries); |
| 5587 } | 4629 } |
| 5588 } | 4630 } |
| 5589 | 4631 |
| 5590 /** | 4632 /** |
| 5591 * Lookup and return the [Namespace] from the [namespaceMap], if the map does
not | 4633 * Add every shown name from [importDirective] into [_unusedShownNamesMap]. |
| 5592 * have the computed namespace, compute it and cache it in the map. If the imp
ort directive is not | 4634 */ |
| 5593 * resolved or is not resolvable, `null` is returned. | 4635 void _addShownNames(ImportDirective importDirective) { |
| 4636 if (importDirective.combinators == null) { |
| 4637 return; |
| 4638 } |
| 4639 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); |
| 4640 _unusedShownNamesMap[importDirective] = identifiers; |
| 4641 for (Combinator combinator in importDirective.combinators) { |
| 4642 if (combinator is ShowCombinator) { |
| 4643 for (SimpleIdentifier name in combinator.shownNames) { |
| 4644 if (name.staticElement != null) { |
| 4645 identifiers.add(name); |
| 4646 } |
| 4647 } |
| 4648 } |
| 4649 } |
| 4650 } |
| 4651 |
| 4652 /** |
| 4653 * Lookup and return the [Namespace] from the [_namespaceMap]. |
| 4654 * |
| 4655 * If the map does not have the computed namespace, compute it and cache it in
the map. If |
| 4656 * [importDirective] is not resolved or is not resolvable, `null` is returned. |
| 5594 * | 4657 * |
| 5595 * @param importDirective the import directive used to compute the returned na
mespace | 4658 * @param importDirective the import directive used to compute the returned na
mespace |
| 5596 * @return the computed or looked up [Namespace] | 4659 * @return the computed or looked up [Namespace] |
| 5597 */ | 4660 */ |
| 5598 Namespace _computeNamespace(ImportDirective importDirective) { | 4661 Namespace _computeNamespace(ImportDirective importDirective) { |
| 5599 Namespace namespace = _namespaceMap[importDirective]; | 4662 Namespace namespace = _namespaceMap[importDirective]; |
| 5600 if (namespace == null) { | 4663 if (namespace == null) { |
| 5601 // If the namespace isn't in the namespaceMap, then compute and put it in | 4664 // If the namespace isn't in the namespaceMap, then compute and put it in |
| 5602 // the map. | 4665 // the map. |
| 5603 ImportElement importElement = importDirective.element; | 4666 ImportElement importElement = importDirective.element; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 5618 */ | 4681 */ |
| 5619 void _putIntoLibraryMap( | 4682 void _putIntoLibraryMap( |
| 5620 LibraryElement libraryElement, ImportDirective importDirective) { | 4683 LibraryElement libraryElement, ImportDirective importDirective) { |
| 5621 List<ImportDirective> importList = _libraryMap[libraryElement]; | 4684 List<ImportDirective> importList = _libraryMap[libraryElement]; |
| 5622 if (importList == null) { | 4685 if (importList == null) { |
| 5623 importList = new List<ImportDirective>(); | 4686 importList = new List<ImportDirective>(); |
| 5624 _libraryMap[libraryElement] = importList; | 4687 _libraryMap[libraryElement] = importList; |
| 5625 } | 4688 } |
| 5626 importList.add(importDirective); | 4689 importList.add(importDirective); |
| 5627 } | 4690 } |
| 4691 |
| 4692 /** |
| 4693 * Remove [element] from the list of names shown by [importDirective]. |
| 4694 */ |
| 4695 void _removeFromUnusedShownNamesMap( |
| 4696 Element element, ImportDirective importDirective) { |
| 4697 List<SimpleIdentifier> identifiers = _unusedShownNamesMap[importDirective]; |
| 4698 if (identifiers == null) { |
| 4699 return; |
| 4700 } |
| 4701 int length = identifiers.length; |
| 4702 for (int i = 0; i < length; i++) { |
| 4703 Identifier identifier = identifiers[i]; |
| 4704 if (element is PropertyAccessorElement) { |
| 4705 // If the getter or setter of a variable is used, then the variable (the |
| 4706 // shown name) is used. |
| 4707 if (identifier.staticElement == element.variable) { |
| 4708 identifiers.remove(identifier); |
| 4709 break; |
| 4710 } |
| 4711 } else { |
| 4712 if (identifier.staticElement == element) { |
| 4713 identifiers.remove(identifier); |
| 4714 break; |
| 4715 } |
| 4716 } |
| 4717 } |
| 4718 if (identifiers.isEmpty) { |
| 4719 _unusedShownNamesMap.remove(importDirective); |
| 4720 } |
| 4721 } |
| 5628 } | 4722 } |
| 5629 | 4723 |
| 5630 /** | 4724 /** |
| 5631 * Instances of the class `InheritanceManager` manage the knowledge of where cla
ss members | 4725 * Maintains and manages contextual type information used for |
| 5632 * (methods, getters & setters) are inherited from. | 4726 * inferring types. |
| 5633 */ | 4727 */ |
| 5634 class InheritanceManager { | 4728 class InferenceContext { |
| 5635 /** | 4729 // TODO(leafp): Consider replacing these node properties with a |
| 5636 * The [LibraryElement] that is managed by this manager. | 4730 // hash table help in an instance of this class. |
| 5637 */ | 4731 static const String _typeProperty = |
| 5638 LibraryElement _library; | 4732 'analyzer.src.generated.InferenceContext.contextType'; |
| 5639 | 4733 |
| 5640 /** | 4734 /** |
| 5641 * This is a mapping between each [ClassElement] and a map between the [String
] member | 4735 * The error listener on which to record inference information. |
| 5642 * names and the associated [ExecutableElement] in the mixin and superclass ch
ain. | 4736 */ |
| 5643 */ | 4737 final ErrorReporter _errorReporter; |
| 5644 HashMap<ClassElement, MemberMap> _classLookup; | 4738 |
| 5645 | 4739 /** |
| 5646 /** | 4740 * If true, emit hints when types are inferred |
| 5647 * This is a mapping between each [ClassElement] and a map between the [String
] member | 4741 */ |
| 5648 * names and the associated [ExecutableElement] in the interface set. | 4742 final bool _inferenceHints; |
| 5649 */ | 4743 |
| 5650 HashMap<ClassElement, MemberMap> _interfaceLookup; | 4744 /** |
| 5651 | 4745 * Type provider, needed for type matching. |
| 5652 /** | 4746 */ |
| 5653 * A map between each visited [ClassElement] and the set of [AnalysisError]s f
ound on | 4747 final TypeProvider _typeProvider; |
| 5654 * the class element. | 4748 |
| 5655 */ | 4749 /** |
| 5656 HashMap<ClassElement, HashSet<AnalysisError>> _errorsInClassElement = | 4750 * The type system in use. |
| 5657 new HashMap<ClassElement, HashSet<AnalysisError>>(); | 4751 */ |
| 5658 | 4752 final TypeSystem _typeSystem; |
| 5659 /** | 4753 |
| 5660 * Initialize a newly created inheritance manager. | 4754 /** |
| 5661 * | 4755 * When no context type is available, this will track the least upper bound |
| 5662 * @param library the library element context that the inheritance mappings ar
e being generated | 4756 * of all return statements in a lambda. |
| 5663 */ | 4757 * |
| 5664 InheritanceManager(LibraryElement library) { | 4758 * This will always be kept in sync with [_returnStack]. |
| 5665 this._library = library; | 4759 */ |
| 5666 _classLookup = new HashMap<ClassElement, MemberMap>(); | 4760 final List<DartType> _inferredReturn = <DartType>[]; |
| 5667 _interfaceLookup = new HashMap<ClassElement, MemberMap>(); | 4761 |
| 5668 } | 4762 /** |
| 5669 | 4763 * A stack of return types for all of the enclosing |
| 5670 /** | 4764 * functions and methods. |
| 5671 * Set the new library element context. | 4765 */ |
| 5672 * | 4766 final List<DartType> _returnStack = <DartType>[]; |
| 5673 * @param library the new library element | 4767 |
| 5674 */ | 4768 InferenceContext._(this._errorReporter, TypeProvider typeProvider, |
| 5675 void set libraryElement(LibraryElement library) { | 4769 this._typeSystem, this._inferenceHints) |
| 5676 this._library = library; | 4770 : _typeProvider = typeProvider; |
| 5677 } | 4771 |
| 5678 | 4772 /** |
| 5679 /** | 4773 * Get the return type of the current enclosing function, if any. |
| 5680 * Return the set of [AnalysisError]s found on the passed [ClassElement], or | 4774 * |
| 5681 * `null` if there are none. | 4775 * The type returned for a function is the type that is expected |
| 5682 * | 4776 * to be used in a return or yield context. For ordinary functions |
| 5683 * @param classElt the class element to query | 4777 * this is the same as the return type of the function. For async |
| 5684 * @return the set of [AnalysisError]s found on the passed [ClassElement], or | 4778 * functions returning Future<T> and for generator functions |
| 5685 * `null` if there are none | 4779 * returning Stream<T> or Iterable<T>, this is T. |
| 5686 */ | 4780 */ |
| 5687 HashSet<AnalysisError> getErrors(ClassElement classElt) => | 4781 DartType get returnContext => |
| 5688 _errorsInClassElement[classElt]; | 4782 _returnStack.isNotEmpty ? _returnStack.last : null; |
| 5689 | 4783 |
| 5690 /** | 4784 /** |
| 5691 * Get and return a mapping between the set of all string names of the members
inherited from the | 4785 * Records the type of the expression of a return statement. |
| 5692 * passed [ClassElement] superclass hierarchy, and the associated [ExecutableE
lement]. | 4786 * |
| 5693 * | 4787 * This will be used for inferring a block bodied lambda, if no context |
| 5694 * @param classElt the class element to query | 4788 * type was available. |
| 5695 * @return a mapping between the set of all members inherited from the passed
[ClassElement] | 4789 */ |
| 5696 * superclass hierarchy, and the associated [ExecutableElement] | 4790 void addReturnOrYieldType(DartType type) { |
| 5697 */ | 4791 if (_returnStack.isEmpty) { |
| 5698 MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) => | 4792 return; |
| 5699 _computeClassChainLookupMap(classElt, new HashSet<ClassElement>()); | 4793 } |
| 5700 | 4794 |
| 5701 /** | 4795 DartType inferred = _inferredReturn.last; |
| 5702 * Get and return a mapping between the set of all string names of the members
inherited from the | 4796 inferred = _typeSystem.getLeastUpperBound(_typeProvider, type, inferred); |
| 5703 * passed [ClassElement] interface hierarchy, and the associated [ExecutableEl
ement]. | 4797 _inferredReturn[_inferredReturn.length - 1] = inferred; |
| 5704 * | 4798 } |
| 5705 * @param classElt the class element to query | 4799 |
| 5706 * @return a mapping between the set of all string names of the members inheri
ted from the passed | 4800 /** |
| 5707 * [ClassElement] interface hierarchy, and the associated [ExecutableE
lement]. | 4801 * Match type [t1] against type [t2] as follows. |
| 5708 */ | 4802 * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype |
| 5709 MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) => | 4803 * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>` |
| 5710 _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>()); | 4804 * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'` |
| 5711 | 4805 * to derive a concrete instantation for I of the form `<T0, ..., Tn>`, |
| 5712 /** | 4806 * such that `I<T0, .., Tn> <: t2` |
| 5713 * Given some [ClassElement] and some member name, this returns the | 4807 */ |
| 5714 * [ExecutableElement] that the class inherits from the mixins, | 4808 List<DartType> matchTypes(DartType t1, DartType t2) => |
| 5715 * superclasses or interfaces, that has the member name, if no member is inher
ited `null` is | 4809 (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null; |
| 5716 * returned. | 4810 |
| 5717 * | 4811 /** |
| 5718 * @param classElt the class element to query | 4812 * Pop a return type off of the return stack. |
| 5719 * @param memberName the name of the executable element to find and return | 4813 * |
| 5720 * @return the inherited executable element with the member name, or `null` if
no such | 4814 * Also record any inferred return type using [setType], unless this node |
| 5721 * member exists | 4815 * already has a context type. This recorded type will be the least upper |
| 5722 */ | 4816 * bound of all types added with [addReturnOrYieldType]. |
| 5723 ExecutableElement lookupInheritance( | 4817 */ |
| 5724 ClassElement classElt, String memberName) { | 4818 void popReturnContext(BlockFunctionBody node) { |
| 5725 if (memberName == null || memberName.isEmpty) { | 4819 if (_returnStack.isNotEmpty && _inferredReturn.isNotEmpty) { |
| 4820 DartType context = _returnStack.removeLast() ?? DynamicTypeImpl.instance; |
| 4821 DartType inferred = _inferredReturn.removeLast(); |
| 4822 if (inferred.isBottom) { |
| 4823 return; |
| 4824 } |
| 4825 |
| 4826 if (context is FutureUnionType) { |
| 4827 // Try and match the Future type first. |
| 4828 if (_typeSystem.isSubtypeOf(inferred, context.futureOfType) || |
| 4829 _typeSystem.isSubtypeOf(inferred, context.type)) { |
| 4830 setType(node, inferred); |
| 4831 } |
| 4832 } else if (_typeSystem.isSubtypeOf(inferred, context)) { |
| 4833 setType(node, inferred); |
| 4834 } |
| 4835 } else { |
| 4836 assert(false); |
| 4837 } |
| 4838 } |
| 4839 |
| 4840 /** |
| 4841 * Push a block function body's return type onto the return stack. |
| 4842 */ |
| 4843 void pushReturnContext(BlockFunctionBody node) { |
| 4844 _returnStack.add(getContext(node)); |
| 4845 _inferredReturn.add(BottomTypeImpl.instance); |
| 4846 } |
| 4847 |
| 4848 /** |
| 4849 * Place an info node into the error stream indicating that a |
| 4850 * [type] has been inferred as the type of [node]. |
| 4851 */ |
| 4852 void recordInference(Expression node, DartType type) { |
| 4853 if (!_inferenceHints) { |
| 4854 return; |
| 4855 } |
| 4856 |
| 4857 ErrorCode error; |
| 4858 if (node is Literal) { |
| 4859 error = StrongModeCode.INFERRED_TYPE_LITERAL; |
| 4860 } else if (node is InstanceCreationExpression) { |
| 4861 error = StrongModeCode.INFERRED_TYPE_ALLOCATION; |
| 4862 } else if (node is FunctionExpression) { |
| 4863 error = StrongModeCode.INFERRED_TYPE_CLOSURE; |
| 4864 } else { |
| 4865 error = StrongModeCode.INFERRED_TYPE; |
| 4866 } |
| 4867 |
| 4868 _errorReporter.reportErrorForNode(error, node, [node, type]); |
| 4869 } |
| 4870 |
| 4871 List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) { |
| 4872 if (t1 == t2) { |
| 4873 return t2.typeArguments; |
| 4874 } |
| 4875 List<DartType> tArgs1 = t1.typeArguments; |
| 4876 List<DartType> tArgs2 = t2.typeArguments; |
| 4877 // If t1 isn't a raw type, bail out |
| 4878 if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) { |
| 5726 return null; | 4879 return null; |
| 5727 } | 4880 } |
| 5728 ExecutableElement executable = _computeClassChainLookupMap( | 4881 |
| 5729 classElt, new HashSet<ClassElement>()).get(memberName); | 4882 // This is our inferred type argument list. We start at all dynamic, |
| 5730 if (executable == null) { | 4883 // and fill in with inferred types when we reach a match. |
| 5731 return _computeInterfaceLookupMap(classElt, new HashSet<ClassElement>()) | 4884 List<DartType> actuals = |
| 5732 .get(memberName); | 4885 new List<DartType>.filled(tArgs1.length, _typeProvider.dynamicType); |
| 5733 } | 4886 |
| 5734 return executable; | 4887 // When we find the supertype of t1 with the same |
| 5735 } | 4888 // classname as t2 (see below), we have the following: |
| 5736 | 4889 // If t1 is an instantiation of a class T1<X0, ..., Xn> |
| 5737 /** | 4890 // and t2 is an instantiation of a class T2<Y0, ...., Ym> |
| 5738 * Given some [ClassElement] and some member name, this returns the | 4891 // of the form t2 = T2<S0, ..., Sm> |
| 5739 * [ExecutableElement] that the class either declares itself, or | 4892 // then we want to choose instantiations for the Xi |
| 5740 * inherits, that has the member name, if no member is inherited `null` is ret
urned. | 4893 // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 . |
| 5741 * | 4894 // To find this, we simply instantate T1 with |
| 5742 * @param classElt the class element to query | 4895 // X0, ..., Xn, and then find its superclass |
| 5743 * @param memberName the name of the executable element to find and return | 4896 // T2<T0', ..., Tn'>. We then solve the constraint |
| 5744 * @return the inherited executable element with the member name, or `null` if
no such | 4897 // set T0' <: S0, ..., Tn' <: Sn for the Xi. |
| 5745 * member exists | 4898 // Currently, we only handle constraints where |
| 5746 */ | 4899 // the Ti' is one of the Xi'. If there are multiple |
| 5747 ExecutableElement lookupMember(ClassElement classElt, String memberName) { | 4900 // constraints on some Xi, we choose the lower of the |
| 5748 ExecutableElement element = _lookupMemberInClass(classElt, memberName); | 4901 // two (if it exists). |
| 5749 if (element != null) { | 4902 bool permute(List<DartType> permutedArgs) { |
| 5750 return element; | 4903 if (permutedArgs == null) { |
| 5751 } | 4904 return false; |
| 5752 return lookupInheritance(classElt, memberName); | 4905 } |
| 5753 } | 4906 List<TypeParameterElement> ps = t1.typeParameters; |
| 5754 | 4907 List<DartType> ts = ps.map((p) => p.type).toList(); |
| 5755 /** | 4908 for (int i = 0; i < permutedArgs.length; i++) { |
| 5756 * Given some [InterfaceType] and some member name, this returns the | 4909 DartType tVar = permutedArgs[i]; |
| 5757 * [FunctionType] of the [ExecutableElement] that the | 4910 DartType tActual = tArgs2[i]; |
| 5758 * class either declares itself, or inherits, that has the member name, if no
member is inherited | 4911 int index = ts.indexOf(tVar); |
| 5759 * `null` is returned. The returned [FunctionType] has all type | 4912 if (index >= 0 && _typeSystem.isSubtypeOf(tActual, actuals[index])) { |
| 5760 * parameters substituted with corresponding type arguments from the given [In
terfaceType]. | 4913 actuals[index] = tActual; |
| 5761 * | 4914 } |
| 5762 * @param interfaceType the interface type to query | 4915 } |
| 5763 * @param memberName the name of the executable element to find and return | 4916 return actuals.any((x) => !x.isDynamic); |
| 5764 * @return the member's function type, or `null` if no such member exists | 4917 } |
| 5765 */ | 4918 |
| 5766 FunctionType lookupMemberType( | 4919 // Look for the first supertype of t1 with the same class name as t2. |
| 5767 InterfaceType interfaceType, String memberName) { | 4920 bool match(InterfaceType t1, Set<Element> visited) { |
| 5768 ExecutableElement iteratorMember = | 4921 if (t1.element == t2.element) { |
| 5769 lookupMember(interfaceType.element, memberName); | 4922 return permute(t1.typeArguments); |
| 5770 if (iteratorMember == null) { | 4923 } |
| 4924 |
| 4925 if (t1 == _typeProvider.objectType) { |
| 4926 return false; |
| 4927 } |
| 4928 |
| 4929 Element element = t1.element; |
| 4930 if (visited == null) { |
| 4931 visited = new HashSet<Element>(); |
| 4932 } |
| 4933 if (element == null || !visited.add(element)) { |
| 4934 return false; |
| 4935 } |
| 4936 try { |
| 4937 if (match(t1.superclass, visited)) { |
| 4938 return true; |
| 4939 } |
| 4940 |
| 4941 List<InterfaceType> mixins = t1.mixins; |
| 4942 int mixinLength = mixins.length; |
| 4943 for (int i = 0; i < mixinLength; i++) { |
| 4944 if (match(mixins[i], visited)) { |
| 4945 return true; |
| 4946 } |
| 4947 } |
| 4948 |
| 4949 List<InterfaceType> interfaces = t1.interfaces; |
| 4950 int interfaceLength = interfaces.length; |
| 4951 for (int j = 0; j < interfaceLength; j++) { |
| 4952 if (match(interfaces[j], visited)) { |
| 4953 return true; |
| 4954 } |
| 4955 } |
| 4956 } finally { |
| 4957 visited.remove(element); |
| 4958 } |
| 4959 return false; |
| 4960 } |
| 4961 |
| 4962 // We have that t1 = T1<dynamic, ..., dynamic>. |
| 4963 // To match t1 against t2, we use the uninstantiated version |
| 4964 // of t1, essentially treating it as an instantiation with |
| 4965 // fresh variables, and solve for the variables. |
| 4966 // t1.element.type will be of the form T1<X0, ..., Xn> |
| 4967 if (!match(t1.element.type, null)) { |
| 5771 return null; | 4968 return null; |
| 5772 } | 4969 } |
| 5773 return substituteTypeArgumentsInMemberFromInheritance( | 4970 DartType newT1 = t1.element.type.instantiate(actuals); |
| 5774 iteratorMember.type, memberName, interfaceType); | 4971 // If we found a solution, return it. |
| 5775 } | 4972 if (_typeSystem.isSubtypeOf(newT1, t2)) { |
| 5776 | 4973 return actuals; |
| 5777 /** | 4974 } |
| 5778 * Determine the set of methods which is overridden by the given class member.
If no member is | 4975 return null; |
| 5779 * inherited, an empty list is returned. If one of the inherited members is a | 4976 } |
| 5780 * [MultiplyInheritedExecutableElement], then it is expanded into its constitu
ent inherited | 4977 |
| 5781 * elements. | 4978 /** |
| 5782 * | 4979 * Clear the type information assocated with [node]. |
| 5783 * @param classElt the class to query | 4980 */ |
| 5784 * @param memberName the name of the class member to query | 4981 static void clearType(AstNode node) { |
| 5785 * @return a list of overridden methods | 4982 node?.setProperty(_typeProperty, null); |
| 5786 */ | 4983 } |
| 5787 List<ExecutableElement> lookupOverrides( | 4984 |
| 5788 ClassElement classElt, String memberName) { | 4985 /** |
| 5789 List<ExecutableElement> result = new List<ExecutableElement>(); | 4986 * Look for contextual type information attached to [node]. Returns |
| 5790 if (memberName == null || memberName.isEmpty) { | 4987 * the type if found, otherwise null. |
| 5791 return result; | 4988 * |
| 5792 } | 4989 * If [node] has a contextual union type like `T | Future<T>` this will be |
| 5793 List<MemberMap> interfaceMaps = | 4990 * returned. You can use [getType] if you prefer to only get the `T`. |
| 5794 _gatherInterfaceLookupMaps(classElt, new HashSet<ClassElement>()); | 4991 */ |
| 5795 if (interfaceMaps != null) { | 4992 static DartType getContext(AstNode node) => node?.getProperty(_typeProperty); |
| 5796 for (MemberMap interfaceMap in interfaceMaps) { | 4993 |
| 5797 ExecutableElement overriddenElement = interfaceMap.get(memberName); | 4994 /** |
| 5798 if (overriddenElement != null) { | 4995 * Look for a single contextual type attached to [node], and returns the type |
| 5799 if (overriddenElement is MultiplyInheritedExecutableElement) { | 4996 * if found, otherwise null. |
| 5800 MultiplyInheritedExecutableElement multiplyInheritedElement = | 4997 * |
| 5801 overriddenElement; | 4998 * If [node] has a contextual union type like `T | Future<T>` this will |
| 5802 for (ExecutableElement element | 4999 * simplify it to only return `T`. If the caller can handle a union type, |
| 5803 in multiplyInheritedElement.inheritedElements) { | 5000 * [getContext] should be used instead. |
| 5804 result.add(element); | 5001 */ |
| 5805 } | 5002 static DartType getType(AstNode node) { |
| 5806 } else { | 5003 DartType t = getContext(node); |
| 5807 result.add(overriddenElement); | 5004 if (t is FutureUnionType) { |
| 5808 } | 5005 return t.type; |
| 5809 } | 5006 } |
| 5810 } | 5007 return t; |
| 5811 } | 5008 } |
| 5812 return result; | 5009 |
| 5813 } | 5010 /** |
| 5814 | 5011 * Like [getContext] but expands a union type into a list of types. |
| 5815 /** | 5012 */ |
| 5816 * This method takes some inherited [FunctionType], and resolves all the param
eterized types | 5013 static Iterable<DartType> getTypes(AstNode node) { |
| 5817 * in the function type, dependent on the class in which it is being overridde
n. | 5014 DartType t = getContext(node); |
| 5818 * | 5015 if (t == null) { |
| 5819 * @param baseFunctionType the function type that is being overridden | 5016 return DartType.EMPTY_LIST; |
| 5820 * @param memberName the name of the member, this is used to lookup the inheri
tance path of the | 5017 } |
| 5821 * override | 5018 if (t is FutureUnionType) { |
| 5822 * @param definingType the type that is overriding the member | 5019 return t.types; |
| 5823 * @return the passed function type with any parameterized types substituted | 5020 } |
| 5824 */ | 5021 return <DartType>[t]; |
| 5825 FunctionType substituteTypeArgumentsInMemberFromInheritance( | 5022 } |
| 5826 FunctionType baseFunctionType, | 5023 |
| 5827 String memberName, | 5024 /** |
| 5828 InterfaceType definingType) { | 5025 * Attach contextual type information [type] to [node] for use during |
| 5829 // if the baseFunctionType is null, or does not have any parameters, | 5026 * inference. |
| 5830 // return it. | 5027 */ |
| 5831 if (baseFunctionType == null || | 5028 static void setType(AstNode node, DartType type) { |
| 5832 baseFunctionType.typeArguments.length == 0) { | 5029 if (type == null || type.isDynamic) { |
| 5833 return baseFunctionType; | 5030 clearType(node); |
| 5834 } | |
| 5835 // First, generate the path from the defining type to the overridden member | |
| 5836 Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>(); | |
| 5837 _computeInheritancePath(inheritancePath, definingType, memberName); | |
| 5838 if (inheritancePath == null || inheritancePath.isEmpty) { | |
| 5839 // TODO(jwren) log analysis engine error | |
| 5840 return baseFunctionType; | |
| 5841 } | |
| 5842 FunctionType functionTypeToReturn = baseFunctionType; | |
| 5843 // loop backward through the list substituting as we go: | |
| 5844 while (!inheritancePath.isEmpty) { | |
| 5845 InterfaceType lastType = inheritancePath.removeLast(); | |
| 5846 List<DartType> parameterTypes = lastType.element.type.typeArguments; | |
| 5847 List<DartType> argumentTypes = lastType.typeArguments; | |
| 5848 functionTypeToReturn = | |
| 5849 functionTypeToReturn.substitute2(argumentTypes, parameterTypes); | |
| 5850 } | |
| 5851 return functionTypeToReturn; | |
| 5852 } | |
| 5853 | |
| 5854 /** | |
| 5855 * Compute and return a mapping between the set of all string names of the mem
bers inherited from | |
| 5856 * the passed [ClassElement] superclass hierarchy, and the associated | |
| 5857 * [ExecutableElement]. | |
| 5858 * | |
| 5859 * @param classElt the class element to query | |
| 5860 * @param visitedClasses a set of visited classes passed back into this method
when it calls | |
| 5861 * itself recursively | |
| 5862 * @return a mapping between the set of all string names of the members inheri
ted from the passed | |
| 5863 * [ClassElement] superclass hierarchy, and the associated [Executable
Element] | |
| 5864 */ | |
| 5865 MemberMap _computeClassChainLookupMap( | |
| 5866 ClassElement classElt, HashSet<ClassElement> visitedClasses) { | |
| 5867 MemberMap resultMap = _classLookup[classElt]; | |
| 5868 if (resultMap != null) { | |
| 5869 return resultMap; | |
| 5870 } else { | 5031 } else { |
| 5871 resultMap = new MemberMap(); | 5032 node?.setProperty(_typeProperty, type); |
| 5872 } | 5033 } |
| 5873 ClassElement superclassElt = null; | 5034 } |
| 5874 InterfaceType supertype = classElt.supertype; | 5035 |
| 5875 if (supertype != null) { | 5036 /** |
| 5876 superclassElt = supertype.element; | 5037 * Attach contextual type information [type] to [node] for use during |
| 5877 } else { | 5038 * inference. |
| 5878 // classElt is Object | 5039 */ |
| 5879 _classLookup[classElt] = resultMap; | 5040 static void setTypeFromNode(AstNode innerNode, AstNode outerNode) { |
| 5880 return resultMap; | 5041 setType(innerNode, getContext(outerNode)); |
| 5881 } | |
| 5882 if (superclassElt != null) { | |
| 5883 if (!visitedClasses.contains(superclassElt)) { | |
| 5884 visitedClasses.add(superclassElt); | |
| 5885 try { | |
| 5886 resultMap = new MemberMap.from( | |
| 5887 _computeClassChainLookupMap(superclassElt, visitedClasses)); | |
| 5888 // | |
| 5889 // Substitute the super types down the hierarchy. | |
| 5890 // | |
| 5891 _substituteTypeParametersDownHierarchy(supertype, resultMap); | |
| 5892 // | |
| 5893 // Include the members from the superclass in the resultMap. | |
| 5894 // | |
| 5895 _recordMapWithClassMembers(resultMap, supertype, false); | |
| 5896 } finally { | |
| 5897 visitedClasses.remove(superclassElt); | |
| 5898 } | |
| 5899 } else { | |
| 5900 // This case happens only when the superclass was previously visited and | |
| 5901 // not in the lookup, meaning this is meant to shorten the compute for | |
| 5902 // recursive cases. | |
| 5903 _classLookup[superclassElt] = resultMap; | |
| 5904 return resultMap; | |
| 5905 } | |
| 5906 } | |
| 5907 // | |
| 5908 // Include the members from the mixins in the resultMap. If there are | |
| 5909 // multiple mixins, visit them in the order listed so that methods in later | |
| 5910 // mixins will overwrite identically-named methods in earlier mixins. | |
| 5911 // | |
| 5912 List<InterfaceType> mixins = classElt.mixins; | |
| 5913 for (InterfaceType mixin in mixins) { | |
| 5914 ClassElement mixinElement = mixin.element; | |
| 5915 if (mixinElement != null) { | |
| 5916 if (!visitedClasses.contains(mixinElement)) { | |
| 5917 visitedClasses.add(mixinElement); | |
| 5918 try { | |
| 5919 MemberMap map = new MemberMap.from( | |
| 5920 _computeClassChainLookupMap(mixinElement, visitedClasses)); | |
| 5921 // | |
| 5922 // Substitute the super types down the hierarchy. | |
| 5923 // | |
| 5924 _substituteTypeParametersDownHierarchy(mixin, map); | |
| 5925 // | |
| 5926 // Include the members from the superclass in the resultMap. | |
| 5927 // | |
| 5928 _recordMapWithClassMembers(map, mixin, false); | |
| 5929 // | |
| 5930 // Add the members from map into result map. | |
| 5931 // | |
| 5932 for (int j = 0; j < map.size; j++) { | |
| 5933 String key = map.getKey(j); | |
| 5934 ExecutableElement value = map.getValue(j); | |
| 5935 if (key != null) { | |
| 5936 ClassElement definingClass = value | |
| 5937 .getAncestor((Element element) => element is ClassElement); | |
| 5938 if (!definingClass.type.isObject) { | |
| 5939 ExecutableElement existingValue = resultMap.get(key); | |
| 5940 if (existingValue == null || | |
| 5941 (existingValue != null && !_isAbstract(value))) { | |
| 5942 resultMap.put(key, value); | |
| 5943 } | |
| 5944 } | |
| 5945 } | |
| 5946 } | |
| 5947 } finally { | |
| 5948 visitedClasses.remove(mixinElement); | |
| 5949 } | |
| 5950 } else { | |
| 5951 // This case happens only when the superclass was previously visited | |
| 5952 // and not in the lookup, meaning this is meant to shorten the compute | |
| 5953 // for recursive cases. | |
| 5954 _classLookup[mixinElement] = resultMap; | |
| 5955 return resultMap; | |
| 5956 } | |
| 5957 } | |
| 5958 } | |
| 5959 _classLookup[classElt] = resultMap; | |
| 5960 return resultMap; | |
| 5961 } | |
| 5962 | |
| 5963 /** | |
| 5964 * Compute and return the inheritance path given the context of a type and a m
ember that is | |
| 5965 * overridden in the inheritance path (for which the type is in the path). | |
| 5966 * | |
| 5967 * @param chain the inheritance path that is built up as this method calls its
elf recursively, | |
| 5968 * when this method is called an empty [LinkedList] should be provide
d | |
| 5969 * @param currentType the current type in the inheritance path | |
| 5970 * @param memberName the name of the member that is being looked up the inheri
tance path | |
| 5971 */ | |
| 5972 void _computeInheritancePath(Queue<InterfaceType> chain, | |
| 5973 InterfaceType currentType, String memberName) { | |
| 5974 // TODO (jwren) create a public version of this method which doesn't require | |
| 5975 // the initial chain to be provided, then provided tests for this | |
| 5976 // functionality in InheritanceManagerTest | |
| 5977 chain.add(currentType); | |
| 5978 ClassElement classElt = currentType.element; | |
| 5979 InterfaceType supertype = classElt.supertype; | |
| 5980 // Base case- reached Object | |
| 5981 if (supertype == null) { | |
| 5982 // Looked up the chain all the way to Object, return null. | |
| 5983 // This should never happen. | |
| 5984 return; | |
| 5985 } | |
| 5986 // If we are done, return the chain | |
| 5987 // We are not done if this is the first recursive call on this method. | |
| 5988 if (chain.length != 1) { | |
| 5989 // We are done however if the member is in this classElt | |
| 5990 if (_lookupMemberInClass(classElt, memberName) != null) { | |
| 5991 return; | |
| 5992 } | |
| 5993 } | |
| 5994 // Mixins- note that mixins call lookupMemberInClass, not lookupMember | |
| 5995 List<InterfaceType> mixins = classElt.mixins; | |
| 5996 for (int i = mixins.length - 1; i >= 0; i--) { | |
| 5997 ClassElement mixinElement = mixins[i].element; | |
| 5998 if (mixinElement != null) { | |
| 5999 ExecutableElement elt = _lookupMemberInClass(mixinElement, memberName); | |
| 6000 if (elt != null) { | |
| 6001 // this is equivalent (but faster than) calling this method | |
| 6002 // recursively | |
| 6003 // (return computeInheritancePath(chain, mixins[i], memberName);) | |
| 6004 chain.add(mixins[i]); | |
| 6005 return; | |
| 6006 } | |
| 6007 } | |
| 6008 } | |
| 6009 // Superclass | |
| 6010 ClassElement superclassElt = supertype.element; | |
| 6011 if (lookupMember(superclassElt, memberName) != null) { | |
| 6012 _computeInheritancePath(chain, supertype, memberName); | |
| 6013 return; | |
| 6014 } | |
| 6015 // Interfaces | |
| 6016 List<InterfaceType> interfaces = classElt.interfaces; | |
| 6017 for (InterfaceType interfaceType in interfaces) { | |
| 6018 ClassElement interfaceElement = interfaceType.element; | |
| 6019 if (interfaceElement != null && | |
| 6020 lookupMember(interfaceElement, memberName) != null) { | |
| 6021 _computeInheritancePath(chain, interfaceType, memberName); | |
| 6022 return; | |
| 6023 } | |
| 6024 } | |
| 6025 } | |
| 6026 | |
| 6027 /** | |
| 6028 * Compute and return a mapping between the set of all string names of the mem
bers inherited from | |
| 6029 * the passed [ClassElement] interface hierarchy, and the associated | |
| 6030 * [ExecutableElement]. | |
| 6031 * | |
| 6032 * @param classElt the class element to query | |
| 6033 * @param visitedInterfaces a set of visited classes passed back into this met
hod when it calls | |
| 6034 * itself recursively | |
| 6035 * @return a mapping between the set of all string names of the members inheri
ted from the passed | |
| 6036 * [ClassElement] interface hierarchy, and the associated [ExecutableE
lement] | |
| 6037 */ | |
| 6038 MemberMap _computeInterfaceLookupMap( | |
| 6039 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) { | |
| 6040 MemberMap resultMap = _interfaceLookup[classElt]; | |
| 6041 if (resultMap != null) { | |
| 6042 return resultMap; | |
| 6043 } | |
| 6044 List<MemberMap> lookupMaps = | |
| 6045 _gatherInterfaceLookupMaps(classElt, visitedInterfaces); | |
| 6046 if (lookupMaps == null) { | |
| 6047 resultMap = new MemberMap(); | |
| 6048 } else { | |
| 6049 HashMap<String, List<ExecutableElement>> unionMap = | |
| 6050 _unionInterfaceLookupMaps(lookupMaps); | |
| 6051 resultMap = _resolveInheritanceLookup(classElt, unionMap); | |
| 6052 } | |
| 6053 _interfaceLookup[classElt] = resultMap; | |
| 6054 return resultMap; | |
| 6055 } | |
| 6056 | |
| 6057 /** | |
| 6058 * Collect a list of interface lookup maps whose elements correspond to all of
the classes | |
| 6059 * directly above [classElt] in the class hierarchy (the direct superclass if
any, all | |
| 6060 * mixins, and all direct superinterfaces). Each item in the list is the inter
face lookup map | |
| 6061 * returned by [computeInterfaceLookupMap] for the corresponding super, except
with type | |
| 6062 * parameters appropriately substituted. | |
| 6063 * | |
| 6064 * @param classElt the class element to query | |
| 6065 * @param visitedInterfaces a set of visited classes passed back into this met
hod when it calls | |
| 6066 * itself recursively | |
| 6067 * @return `null` if there was a problem (such as a loop in the class hierarch
y) or if there | |
| 6068 * are no classes above this one in the class hierarchy. Otherwise, a
list of interface | |
| 6069 * lookup maps. | |
| 6070 */ | |
| 6071 List<MemberMap> _gatherInterfaceLookupMaps( | |
| 6072 ClassElement classElt, HashSet<ClassElement> visitedInterfaces) { | |
| 6073 InterfaceType supertype = classElt.supertype; | |
| 6074 ClassElement superclassElement = | |
| 6075 supertype != null ? supertype.element : null; | |
| 6076 List<InterfaceType> mixins = classElt.mixins; | |
| 6077 List<InterfaceType> interfaces = classElt.interfaces; | |
| 6078 // Recursively collect the list of mappings from all of the interface types | |
| 6079 List<MemberMap> lookupMaps = new List<MemberMap>(); | |
| 6080 // | |
| 6081 // Superclass element | |
| 6082 // | |
| 6083 if (superclassElement != null) { | |
| 6084 if (!visitedInterfaces.contains(superclassElement)) { | |
| 6085 try { | |
| 6086 visitedInterfaces.add(superclassElement); | |
| 6087 // | |
| 6088 // Recursively compute the map for the super type. | |
| 6089 // | |
| 6090 MemberMap map = | |
| 6091 _computeInterfaceLookupMap(superclassElement, visitedInterfaces); | |
| 6092 map = new MemberMap.from(map); | |
| 6093 // | |
| 6094 // Substitute the super type down the hierarchy. | |
| 6095 // | |
| 6096 _substituteTypeParametersDownHierarchy(supertype, map); | |
| 6097 // | |
| 6098 // Add any members from the super type into the map as well. | |
| 6099 // | |
| 6100 _recordMapWithClassMembers(map, supertype, true); | |
| 6101 lookupMaps.add(map); | |
| 6102 } finally { | |
| 6103 visitedInterfaces.remove(superclassElement); | |
| 6104 } | |
| 6105 } else { | |
| 6106 return null; | |
| 6107 } | |
| 6108 } | |
| 6109 // | |
| 6110 // Mixin elements | |
| 6111 // | |
| 6112 for (int i = mixins.length - 1; i >= 0; i--) { | |
| 6113 InterfaceType mixinType = mixins[i]; | |
| 6114 ClassElement mixinElement = mixinType.element; | |
| 6115 if (mixinElement != null) { | |
| 6116 if (!visitedInterfaces.contains(mixinElement)) { | |
| 6117 try { | |
| 6118 visitedInterfaces.add(mixinElement); | |
| 6119 // | |
| 6120 // Recursively compute the map for the mixin. | |
| 6121 // | |
| 6122 MemberMap map = | |
| 6123 _computeInterfaceLookupMap(mixinElement, visitedInterfaces); | |
| 6124 map = new MemberMap.from(map); | |
| 6125 // | |
| 6126 // Substitute the mixin type down the hierarchy. | |
| 6127 // | |
| 6128 _substituteTypeParametersDownHierarchy(mixinType, map); | |
| 6129 // | |
| 6130 // Add any members from the mixin type into the map as well. | |
| 6131 // | |
| 6132 _recordMapWithClassMembers(map, mixinType, true); | |
| 6133 lookupMaps.add(map); | |
| 6134 } finally { | |
| 6135 visitedInterfaces.remove(mixinElement); | |
| 6136 } | |
| 6137 } else { | |
| 6138 return null; | |
| 6139 } | |
| 6140 } | |
| 6141 } | |
| 6142 // | |
| 6143 // Interface elements | |
| 6144 // | |
| 6145 for (InterfaceType interfaceType in interfaces) { | |
| 6146 ClassElement interfaceElement = interfaceType.element; | |
| 6147 if (interfaceElement != null) { | |
| 6148 if (!visitedInterfaces.contains(interfaceElement)) { | |
| 6149 try { | |
| 6150 visitedInterfaces.add(interfaceElement); | |
| 6151 // | |
| 6152 // Recursively compute the map for the interfaces. | |
| 6153 // | |
| 6154 MemberMap map = | |
| 6155 _computeInterfaceLookupMap(interfaceElement, visitedInterfaces); | |
| 6156 map = new MemberMap.from(map); | |
| 6157 // | |
| 6158 // Substitute the supertypes down the hierarchy | |
| 6159 // | |
| 6160 _substituteTypeParametersDownHierarchy(interfaceType, map); | |
| 6161 // | |
| 6162 // And add any members from the interface into the map as well. | |
| 6163 // | |
| 6164 _recordMapWithClassMembers(map, interfaceType, true); | |
| 6165 lookupMaps.add(map); | |
| 6166 } finally { | |
| 6167 visitedInterfaces.remove(interfaceElement); | |
| 6168 } | |
| 6169 } else { | |
| 6170 return null; | |
| 6171 } | |
| 6172 } | |
| 6173 } | |
| 6174 if (lookupMaps.length == 0) { | |
| 6175 return null; | |
| 6176 } | |
| 6177 return lookupMaps; | |
| 6178 } | |
| 6179 | |
| 6180 /** | |
| 6181 * Given some [ClassElement], this method finds and returns the [ExecutableEle
ment] of | |
| 6182 * the passed name in the class element. Static members, members in super type
s and members not | |
| 6183 * accessible from the current library are not considered. | |
| 6184 * | |
| 6185 * @param classElt the class element to query | |
| 6186 * @param memberName the name of the member to lookup in the class | |
| 6187 * @return the found [ExecutableElement], or `null` if no such member was foun
d | |
| 6188 */ | |
| 6189 ExecutableElement _lookupMemberInClass( | |
| 6190 ClassElement classElt, String memberName) { | |
| 6191 List<MethodElement> methods = classElt.methods; | |
| 6192 for (MethodElement method in methods) { | |
| 6193 if (memberName == method.name && | |
| 6194 method.isAccessibleIn(_library) && | |
| 6195 !method.isStatic) { | |
| 6196 return method; | |
| 6197 } | |
| 6198 } | |
| 6199 List<PropertyAccessorElement> accessors = classElt.accessors; | |
| 6200 for (PropertyAccessorElement accessor in accessors) { | |
| 6201 if (memberName == accessor.name && | |
| 6202 accessor.isAccessibleIn(_library) && | |
| 6203 !accessor.isStatic) { | |
| 6204 return accessor; | |
| 6205 } | |
| 6206 } | |
| 6207 return null; | |
| 6208 } | |
| 6209 | |
| 6210 /** | |
| 6211 * Record the passed map with the set of all members (methods, getters and set
ters) in the type | |
| 6212 * into the passed map. | |
| 6213 * | |
| 6214 * @param map some non-`null` map to put the methods and accessors from the pa
ssed | |
| 6215 * [ClassElement] into | |
| 6216 * @param type the type that will be recorded into the passed map | |
| 6217 * @param doIncludeAbstract `true` if abstract members will be put into the ma
p | |
| 6218 */ | |
| 6219 void _recordMapWithClassMembers( | |
| 6220 MemberMap map, InterfaceType type, bool doIncludeAbstract) { | |
| 6221 List<MethodElement> methods = type.methods; | |
| 6222 for (MethodElement method in methods) { | |
| 6223 if (method.isAccessibleIn(_library) && | |
| 6224 !method.isStatic && | |
| 6225 (doIncludeAbstract || !method.isAbstract)) { | |
| 6226 map.put(method.name, method); | |
| 6227 } | |
| 6228 } | |
| 6229 List<PropertyAccessorElement> accessors = type.accessors; | |
| 6230 for (PropertyAccessorElement accessor in accessors) { | |
| 6231 if (accessor.isAccessibleIn(_library) && | |
| 6232 !accessor.isStatic && | |
| 6233 (doIncludeAbstract || !accessor.isAbstract)) { | |
| 6234 map.put(accessor.name, accessor); | |
| 6235 } | |
| 6236 } | |
| 6237 } | |
| 6238 | |
| 6239 /** | |
| 6240 * This method is used to report errors on when they are found computing inher
itance information. | |
| 6241 * See [ErrorVerifier.checkForInconsistentMethodInheritance] to see where thes
e generated | |
| 6242 * error codes are reported back into the analysis engine. | |
| 6243 * | |
| 6244 * @param classElt the location of the source for which the exception occurred | |
| 6245 * @param offset the offset of the location of the error | |
| 6246 * @param length the length of the location of the error | |
| 6247 * @param errorCode the error code to be associated with this error | |
| 6248 * @param arguments the arguments used to build the error message | |
| 6249 */ | |
| 6250 void _reportError(ClassElement classElt, int offset, int length, | |
| 6251 ErrorCode errorCode, List<Object> arguments) { | |
| 6252 HashSet<AnalysisError> errorSet = _errorsInClassElement[classElt]; | |
| 6253 if (errorSet == null) { | |
| 6254 errorSet = new HashSet<AnalysisError>(); | |
| 6255 _errorsInClassElement[classElt] = errorSet; | |
| 6256 } | |
| 6257 errorSet.add(new AnalysisError( | |
| 6258 classElt.source, offset, length, errorCode, arguments)); | |
| 6259 } | |
| 6260 | |
| 6261 /** | |
| 6262 * Given the set of methods defined by classes above [classElt] in the class h
ierarchy, | |
| 6263 * apply the appropriate inheritance rules to determine those methods inherite
d by or overridden | |
| 6264 * by [classElt]. Also report static warnings | |
| 6265 * [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE] and | |
| 6266 * [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD] if ap
propriate. | |
| 6267 * | |
| 6268 * @param classElt the class element to query. | |
| 6269 * @param unionMap a mapping from method name to the set of unique (in terms o
f signature) methods | |
| 6270 * defined in superclasses of [classElt]. | |
| 6271 * @return the inheritance lookup map for [classElt]. | |
| 6272 */ | |
| 6273 MemberMap _resolveInheritanceLookup(ClassElement classElt, | |
| 6274 HashMap<String, List<ExecutableElement>> unionMap) { | |
| 6275 MemberMap resultMap = new MemberMap(); | |
| 6276 unionMap.forEach((String key, List<ExecutableElement> list) { | |
| 6277 int numOfEltsWithMatchingNames = list.length; | |
| 6278 if (numOfEltsWithMatchingNames == 1) { | |
| 6279 // | |
| 6280 // Example: class A inherits only 1 method named 'm'. | |
| 6281 // Since it is the only such method, it is inherited. | |
| 6282 // Another example: class A inherits 2 methods named 'm' from 2 | |
| 6283 // different interfaces, but they both have the same signature, so it is | |
| 6284 // the method inherited. | |
| 6285 // | |
| 6286 resultMap.put(key, list[0]); | |
| 6287 } else { | |
| 6288 // | |
| 6289 // Then numOfEltsWithMatchingNames > 1, check for the warning cases. | |
| 6290 // | |
| 6291 bool allMethods = true; | |
| 6292 bool allSetters = true; | |
| 6293 bool allGetters = true; | |
| 6294 for (ExecutableElement executableElement in list) { | |
| 6295 if (executableElement is PropertyAccessorElement) { | |
| 6296 allMethods = false; | |
| 6297 if (executableElement.isSetter) { | |
| 6298 allGetters = false; | |
| 6299 } else { | |
| 6300 allSetters = false; | |
| 6301 } | |
| 6302 } else { | |
| 6303 allGetters = false; | |
| 6304 allSetters = false; | |
| 6305 } | |
| 6306 } | |
| 6307 // | |
| 6308 // If there isn't a mixture of methods with getters, then continue, | |
| 6309 // otherwise create a warning. | |
| 6310 // | |
| 6311 if (allMethods || allGetters || allSetters) { | |
| 6312 // | |
| 6313 // Compute the element whose type is the subtype of all of the other | |
| 6314 // types. | |
| 6315 // | |
| 6316 List<ExecutableElement> elements = new List.from(list); | |
| 6317 List<FunctionType> executableElementTypes = | |
| 6318 new List<FunctionType>(numOfEltsWithMatchingNames); | |
| 6319 for (int i = 0; i < numOfEltsWithMatchingNames; i++) { | |
| 6320 executableElementTypes[i] = elements[i].type; | |
| 6321 } | |
| 6322 List<int> subtypesOfAllOtherTypesIndexes = new List<int>(); | |
| 6323 for (int i = 0; i < numOfEltsWithMatchingNames; i++) { | |
| 6324 FunctionType subtype = executableElementTypes[i]; | |
| 6325 if (subtype == null) { | |
| 6326 continue; | |
| 6327 } | |
| 6328 bool subtypeOfAllTypes = true; | |
| 6329 TypeSystem typeSystem = _library.context.typeSystem; | |
| 6330 for (int j = 0; | |
| 6331 j < numOfEltsWithMatchingNames && subtypeOfAllTypes; | |
| 6332 j++) { | |
| 6333 if (i != j) { | |
| 6334 if (!typeSystem.isSubtypeOf( | |
| 6335 subtype, executableElementTypes[j])) { | |
| 6336 subtypeOfAllTypes = false; | |
| 6337 break; | |
| 6338 } | |
| 6339 } | |
| 6340 } | |
| 6341 if (subtypeOfAllTypes) { | |
| 6342 subtypesOfAllOtherTypesIndexes.add(i); | |
| 6343 } | |
| 6344 } | |
| 6345 // | |
| 6346 // The following is split into three cases determined by the number of | |
| 6347 // elements in subtypesOfAllOtherTypes | |
| 6348 // | |
| 6349 if (subtypesOfAllOtherTypesIndexes.length == 1) { | |
| 6350 // | |
| 6351 // Example: class A inherited only 2 method named 'm'. | |
| 6352 // One has the function type '() -> dynamic' and one has the | |
| 6353 // function type '([int]) -> dynamic'. Since the second method is a | |
| 6354 // subtype of all the others, it is the inherited method. | |
| 6355 // Tests: InheritanceManagerTest. | |
| 6356 // test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_* | |
| 6357 // | |
| 6358 resultMap.put(key, elements[subtypesOfAllOtherTypesIndexes[0]]); | |
| 6359 } else { | |
| 6360 if (subtypesOfAllOtherTypesIndexes.isEmpty) { | |
| 6361 // | |
| 6362 // Determine if the current class has a method or accessor with | |
| 6363 // the member name, if it does then then this class does not | |
| 6364 // "inherit" from any of the supertypes. See issue 16134. | |
| 6365 // | |
| 6366 bool classHasMember = false; | |
| 6367 if (allMethods) { | |
| 6368 classHasMember = classElt.getMethod(key) != null; | |
| 6369 } else { | |
| 6370 List<PropertyAccessorElement> accessors = classElt.accessors; | |
| 6371 for (int i = 0; i < accessors.length; i++) { | |
| 6372 if (accessors[i].name == key) { | |
| 6373 classHasMember = true; | |
| 6374 } | |
| 6375 } | |
| 6376 } | |
| 6377 // | |
| 6378 // Example: class A inherited only 2 method named 'm'. | |
| 6379 // One has the function type '() -> int' and one has the function | |
| 6380 // type '() -> String'. Since neither is a subtype of the other, | |
| 6381 // we create a warning, and have this class inherit nothing. | |
| 6382 // | |
| 6383 if (!classHasMember) { | |
| 6384 String firstTwoFuntionTypesStr = | |
| 6385 "${executableElementTypes[0]}, ${executableElementTypes[1]}"
; | |
| 6386 _reportError( | |
| 6387 classElt, | |
| 6388 classElt.nameOffset, | |
| 6389 classElt.nameLength, | |
| 6390 StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, | |
| 6391 [key, firstTwoFuntionTypesStr]); | |
| 6392 } | |
| 6393 } else { | |
| 6394 // | |
| 6395 // Example: class A inherits 2 methods named 'm'. | |
| 6396 // One has the function type '(int) -> dynamic' and one has the | |
| 6397 // function type '(num) -> dynamic'. Since they are both a subtype | |
| 6398 // of the other, a synthetic function '(dynamic) -> dynamic' is | |
| 6399 // inherited. | |
| 6400 // Tests: test_getMapOfMembersInheritedFromInterfaces_ | |
| 6401 // union_multipleSubtypes_* | |
| 6402 // | |
| 6403 List<ExecutableElement> elementArrayToMerge = new List< | |
| 6404 ExecutableElement>(subtypesOfAllOtherTypesIndexes.length); | |
| 6405 for (int i = 0; i < elementArrayToMerge.length; i++) { | |
| 6406 elementArrayToMerge[i] = | |
| 6407 elements[subtypesOfAllOtherTypesIndexes[i]]; | |
| 6408 } | |
| 6409 ExecutableElement mergedExecutableElement = | |
| 6410 _computeMergedExecutableElement(elementArrayToMerge); | |
| 6411 resultMap.put(key, mergedExecutableElement); | |
| 6412 } | |
| 6413 } | |
| 6414 } else { | |
| 6415 _reportError( | |
| 6416 classElt, | |
| 6417 classElt.nameOffset, | |
| 6418 classElt.nameLength, | |
| 6419 StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHO
D, | |
| 6420 [key]); | |
| 6421 } | |
| 6422 } | |
| 6423 }); | |
| 6424 return resultMap; | |
| 6425 } | |
| 6426 | |
| 6427 /** | |
| 6428 * Loop through all of the members in some [MemberMap], performing type parame
ter | |
| 6429 * substitutions using a passed supertype. | |
| 6430 * | |
| 6431 * @param superType the supertype to substitute into the members of the [Membe
rMap] | |
| 6432 * @param map the MemberMap to perform the substitutions on | |
| 6433 */ | |
| 6434 void _substituteTypeParametersDownHierarchy( | |
| 6435 InterfaceType superType, MemberMap map) { | |
| 6436 for (int i = 0; i < map.size; i++) { | |
| 6437 ExecutableElement executableElement = map.getValue(i); | |
| 6438 if (executableElement is MethodMember) { | |
| 6439 executableElement = | |
| 6440 MethodMember.from(executableElement as MethodMember, superType); | |
| 6441 map.setValue(i, executableElement); | |
| 6442 } else if (executableElement is PropertyAccessorMember) { | |
| 6443 executableElement = PropertyAccessorMember.from( | |
| 6444 executableElement as PropertyAccessorMember, superType); | |
| 6445 map.setValue(i, executableElement); | |
| 6446 } | |
| 6447 } | |
| 6448 } | |
| 6449 | |
| 6450 /** | |
| 6451 * Union all of the [lookupMaps] together into a single map, grouping the Exec
utableElements | |
| 6452 * into a list where none of the elements are equal where equality is determin
ed by having equal | |
| 6453 * function types. (We also take note too of the kind of the element: ()->int
and () -> int may | |
| 6454 * not be equal if one is a getter and the other is a method.) | |
| 6455 * | |
| 6456 * @param lookupMaps the maps to be unioned together. | |
| 6457 * @return the resulting union map. | |
| 6458 */ | |
| 6459 HashMap<String, List<ExecutableElement>> _unionInterfaceLookupMaps( | |
| 6460 List<MemberMap> lookupMaps) { | |
| 6461 HashMap<String, List<ExecutableElement>> unionMap = | |
| 6462 new HashMap<String, List<ExecutableElement>>(); | |
| 6463 for (MemberMap lookupMap in lookupMaps) { | |
| 6464 int lookupMapSize = lookupMap.size; | |
| 6465 for (int i = 0; i < lookupMapSize; i++) { | |
| 6466 // Get the string key, if null, break. | |
| 6467 String key = lookupMap.getKey(i); | |
| 6468 if (key == null) { | |
| 6469 break; | |
| 6470 } | |
| 6471 // Get the list value out of the unionMap | |
| 6472 List<ExecutableElement> list = unionMap[key]; | |
| 6473 // If we haven't created such a map for this key yet, do create it and | |
| 6474 // put the list entry into the unionMap. | |
| 6475 if (list == null) { | |
| 6476 list = new List<ExecutableElement>(); | |
| 6477 unionMap[key] = list; | |
| 6478 } | |
| 6479 // Fetch the entry out of this lookupMap | |
| 6480 ExecutableElement newExecutableElementEntry = lookupMap.getValue(i); | |
| 6481 if (list.isEmpty) { | |
| 6482 // If the list is empty, just the new value | |
| 6483 list.add(newExecutableElementEntry); | |
| 6484 } else { | |
| 6485 // Otherwise, only add the newExecutableElementEntry if it isn't | |
| 6486 // already in the list, this covers situation where a class inherits | |
| 6487 // two methods (or two getters) that are identical. | |
| 6488 bool alreadyInList = false; | |
| 6489 bool isMethod1 = newExecutableElementEntry is MethodElement; | |
| 6490 for (ExecutableElement executableElementInList in list) { | |
| 6491 bool isMethod2 = executableElementInList is MethodElement; | |
| 6492 if (isMethod1 == isMethod2 && | |
| 6493 executableElementInList.type == | |
| 6494 newExecutableElementEntry.type) { | |
| 6495 alreadyInList = true; | |
| 6496 break; | |
| 6497 } | |
| 6498 } | |
| 6499 if (!alreadyInList) { | |
| 6500 list.add(newExecutableElementEntry); | |
| 6501 } | |
| 6502 } | |
| 6503 } | |
| 6504 } | |
| 6505 return unionMap; | |
| 6506 } | |
| 6507 | |
| 6508 /** | |
| 6509 * Given some array of [ExecutableElement]s, this method creates a synthetic e
lement as | |
| 6510 * described in 8.1.1: | |
| 6511 * | |
| 6512 * Let <i>numberOfPositionals</i>(<i>f</i>) denote the number of positional pa
rameters of a | |
| 6513 * function <i>f</i>, and let <i>numberOfRequiredParams</i>(<i>f</i>) denote t
he number of | |
| 6514 * required parameters of a function <i>f</i>. Furthermore, let <i>s</i> denot
e the set of all | |
| 6515 * named parameters of the <i>m<sub>1</sub>, …, m<sub>k</sub></i>. Then
let | |
| 6516 * * <i>h = max(numberOfPositionals(m<sub>i</sub>)),</i> | |
| 6517 * * <i>r = min(numberOfRequiredParams(m<sub>i</sub>)), for all <i>i</i>, 1 <=
i <= k.</i> | |
| 6518 * Then <i>I</i> has a method named <i>n</i>, with <i>r</i> required parameter
s of type | |
| 6519 * <b>dynamic</b>, <i>h</i> positional parameters of type <b>dynamic</b>, name
d parameters | |
| 6520 * <i>s</i> of type <b>dynamic</b> and return type <b>dynamic</b>. | |
| 6521 * | |
| 6522 */ | |
| 6523 static ExecutableElement _computeMergedExecutableElement( | |
| 6524 List<ExecutableElement> elementArrayToMerge) { | |
| 6525 int h = _getNumOfPositionalParameters(elementArrayToMerge[0]); | |
| 6526 int r = _getNumOfRequiredParameters(elementArrayToMerge[0]); | |
| 6527 Set<String> namedParametersList = new HashSet<String>(); | |
| 6528 for (int i = 1; i < elementArrayToMerge.length; i++) { | |
| 6529 ExecutableElement element = elementArrayToMerge[i]; | |
| 6530 int numOfPositionalParams = _getNumOfPositionalParameters(element); | |
| 6531 if (h < numOfPositionalParams) { | |
| 6532 h = numOfPositionalParams; | |
| 6533 } | |
| 6534 int numOfRequiredParams = _getNumOfRequiredParameters(element); | |
| 6535 if (r > numOfRequiredParams) { | |
| 6536 r = numOfRequiredParams; | |
| 6537 } | |
| 6538 namedParametersList.addAll(_getNamedParameterNames(element)); | |
| 6539 } | |
| 6540 return _createSyntheticExecutableElement( | |
| 6541 elementArrayToMerge, | |
| 6542 elementArrayToMerge[0].displayName, | |
| 6543 r, | |
| 6544 h - r, | |
| 6545 new List.from(namedParametersList)); | |
| 6546 } | |
| 6547 | |
| 6548 /** | |
| 6549 * Used by [computeMergedExecutableElement] to actually create the | |
| 6550 * synthetic element. | |
| 6551 * | |
| 6552 * @param elementArrayToMerge the array used to create the synthetic element | |
| 6553 * @param name the name of the method, getter or setter | |
| 6554 * @param numOfRequiredParameters the number of required parameters | |
| 6555 * @param numOfPositionalParameters the number of positional parameters | |
| 6556 * @param namedParameters the list of [String]s that are the named parameters | |
| 6557 * @return the created synthetic element | |
| 6558 */ | |
| 6559 static ExecutableElement _createSyntheticExecutableElement( | |
| 6560 List<ExecutableElement> elementArrayToMerge, | |
| 6561 String name, | |
| 6562 int numOfRequiredParameters, | |
| 6563 int numOfPositionalParameters, | |
| 6564 List<String> namedParameters) { | |
| 6565 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance; | |
| 6566 SimpleIdentifier nameIdentifier = new SimpleIdentifier( | |
| 6567 new sc.StringToken(sc.TokenType.IDENTIFIER, name, 0)); | |
| 6568 ExecutableElementImpl executable; | |
| 6569 if (elementArrayToMerge[0] is MethodElement) { | |
| 6570 MultiplyInheritedMethodElementImpl unionedMethod = | |
| 6571 new MultiplyInheritedMethodElementImpl(nameIdentifier); | |
| 6572 unionedMethod.inheritedElements = elementArrayToMerge; | |
| 6573 executable = unionedMethod; | |
| 6574 } else { | |
| 6575 MultiplyInheritedPropertyAccessorElementImpl unionedPropertyAccessor = | |
| 6576 new MultiplyInheritedPropertyAccessorElementImpl(nameIdentifier); | |
| 6577 unionedPropertyAccessor.getter = | |
| 6578 (elementArrayToMerge[0] as PropertyAccessorElement).isGetter; | |
| 6579 unionedPropertyAccessor.setter = | |
| 6580 (elementArrayToMerge[0] as PropertyAccessorElement).isSetter; | |
| 6581 unionedPropertyAccessor.inheritedElements = elementArrayToMerge; | |
| 6582 executable = unionedPropertyAccessor; | |
| 6583 } | |
| 6584 int numOfParameters = numOfRequiredParameters + | |
| 6585 numOfPositionalParameters + | |
| 6586 namedParameters.length; | |
| 6587 List<ParameterElement> parameters = | |
| 6588 new List<ParameterElement>(numOfParameters); | |
| 6589 int i = 0; | |
| 6590 for (int j = 0; j < numOfRequiredParameters; j++, i++) { | |
| 6591 ParameterElementImpl parameter = new ParameterElementImpl("", 0); | |
| 6592 parameter.type = dynamicType; | |
| 6593 parameter.parameterKind = ParameterKind.REQUIRED; | |
| 6594 parameters[i] = parameter; | |
| 6595 } | |
| 6596 for (int k = 0; k < numOfPositionalParameters; k++, i++) { | |
| 6597 ParameterElementImpl parameter = new ParameterElementImpl("", 0); | |
| 6598 parameter.type = dynamicType; | |
| 6599 parameter.parameterKind = ParameterKind.POSITIONAL; | |
| 6600 parameters[i] = parameter; | |
| 6601 } | |
| 6602 for (int m = 0; m < namedParameters.length; m++, i++) { | |
| 6603 ParameterElementImpl parameter = | |
| 6604 new ParameterElementImpl(namedParameters[m], 0); | |
| 6605 parameter.type = dynamicType; | |
| 6606 parameter.parameterKind = ParameterKind.NAMED; | |
| 6607 parameters[i] = parameter; | |
| 6608 } | |
| 6609 executable.returnType = dynamicType; | |
| 6610 executable.parameters = parameters; | |
| 6611 FunctionTypeImpl methodType = new FunctionTypeImpl(executable); | |
| 6612 executable.type = methodType; | |
| 6613 return executable; | |
| 6614 } | |
| 6615 | |
| 6616 /** | |
| 6617 * Given some [ExecutableElement], return the list of named parameters. | |
| 6618 */ | |
| 6619 static List<String> _getNamedParameterNames( | |
| 6620 ExecutableElement executableElement) { | |
| 6621 List<String> namedParameterNames = new List<String>(); | |
| 6622 List<ParameterElement> parameters = executableElement.parameters; | |
| 6623 for (int i = 0; i < parameters.length; i++) { | |
| 6624 ParameterElement parameterElement = parameters[i]; | |
| 6625 if (parameterElement.parameterKind == ParameterKind.NAMED) { | |
| 6626 namedParameterNames.add(parameterElement.name); | |
| 6627 } | |
| 6628 } | |
| 6629 return namedParameterNames; | |
| 6630 } | |
| 6631 | |
| 6632 /** | |
| 6633 * Given some [ExecutableElement] return the number of parameters of the speci
fied kind. | |
| 6634 */ | |
| 6635 static int _getNumOfParameters( | |
| 6636 ExecutableElement executableElement, ParameterKind parameterKind) { | |
| 6637 int parameterCount = 0; | |
| 6638 List<ParameterElement> parameters = executableElement.parameters; | |
| 6639 for (int i = 0; i < parameters.length; i++) { | |
| 6640 ParameterElement parameterElement = parameters[i]; | |
| 6641 if (parameterElement.parameterKind == parameterKind) { | |
| 6642 parameterCount++; | |
| 6643 } | |
| 6644 } | |
| 6645 return parameterCount; | |
| 6646 } | |
| 6647 | |
| 6648 /** | |
| 6649 * Given some [ExecutableElement] return the number of positional parameters. | |
| 6650 * | |
| 6651 * Note: by positional we mean [ParameterKind.REQUIRED] or [ParameterKind.POSI
TIONAL]. | |
| 6652 */ | |
| 6653 static int _getNumOfPositionalParameters( | |
| 6654 ExecutableElement executableElement) => | |
| 6655 _getNumOfParameters(executableElement, ParameterKind.REQUIRED) + | |
| 6656 _getNumOfParameters(executableElement, ParameterKind.POSITIONAL); | |
| 6657 | |
| 6658 /** | |
| 6659 * Given some [ExecutableElement] return the number of required parameters. | |
| 6660 */ | |
| 6661 static int _getNumOfRequiredParameters(ExecutableElement executableElement) => | |
| 6662 _getNumOfParameters(executableElement, ParameterKind.REQUIRED); | |
| 6663 | |
| 6664 /** | |
| 6665 * Given some [ExecutableElement] returns `true` if it is an abstract member o
f a | |
| 6666 * class. | |
| 6667 * | |
| 6668 * @param executableElement some [ExecutableElement] to evaluate | |
| 6669 * @return `true` if the given element is an abstract member of a class | |
| 6670 */ | |
| 6671 static bool _isAbstract(ExecutableElement executableElement) { | |
| 6672 if (executableElement is MethodElement) { | |
| 6673 return executableElement.isAbstract; | |
| 6674 } else if (executableElement is PropertyAccessorElement) { | |
| 6675 return executableElement.isAbstract; | |
| 6676 } | |
| 6677 return false; | |
| 6678 } | 5042 } |
| 6679 } | 5043 } |
| 6680 | 5044 |
| 6681 /** | 5045 /** |
| 6682 * This enum holds one of four states of a field initialization state through a
constructor | 5046 * The four states of a field initialization state through a constructor |
| 6683 * signature, not initialized, initialized in the field declaration, initialized
in the field | 5047 * signature, not initialized, initialized in the field declaration, initialized |
| 6684 * formal, and finally, initialized in the initializers list. | 5048 * in the field formal, and finally, initialized in the initializers list. |
| 6685 */ | 5049 */ |
| 6686 class INIT_STATE extends Enum<INIT_STATE> { | 5050 class INIT_STATE implements Comparable<INIT_STATE> { |
| 6687 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0); | 5051 static const INIT_STATE NOT_INIT = const INIT_STATE('NOT_INIT', 0); |
| 6688 | 5052 |
| 6689 static const INIT_STATE INIT_IN_DECLARATION = | 5053 static const INIT_STATE INIT_IN_DECLARATION = |
| 6690 const INIT_STATE('INIT_IN_DECLARATION', 1); | 5054 const INIT_STATE('INIT_IN_DECLARATION', 1); |
| 6691 | 5055 |
| 6692 static const INIT_STATE INIT_IN_FIELD_FORMAL = | 5056 static const INIT_STATE INIT_IN_FIELD_FORMAL = |
| 6693 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2); | 5057 const INIT_STATE('INIT_IN_FIELD_FORMAL', 2); |
| 6694 | 5058 |
| 6695 static const INIT_STATE INIT_IN_INITIALIZERS = | 5059 static const INIT_STATE INIT_IN_INITIALIZERS = |
| 6696 const INIT_STATE('INIT_IN_INITIALIZERS', 3); | 5060 const INIT_STATE('INIT_IN_INITIALIZERS', 3); |
| 6697 | 5061 |
| 6698 static const List<INIT_STATE> values = const [ | 5062 static const List<INIT_STATE> values = const [ |
| 6699 NOT_INIT, | 5063 NOT_INIT, |
| 6700 INIT_IN_DECLARATION, | 5064 INIT_IN_DECLARATION, |
| 6701 INIT_IN_FIELD_FORMAL, | 5065 INIT_IN_FIELD_FORMAL, |
| 6702 INIT_IN_INITIALIZERS | 5066 INIT_IN_INITIALIZERS |
| 6703 ]; | 5067 ]; |
| 6704 | 5068 |
| 6705 const INIT_STATE(String name, int ordinal) : super(name, ordinal); | 5069 /** |
| 5070 * The name of this init state. |
| 5071 */ |
| 5072 final String name; |
| 5073 |
| 5074 /** |
| 5075 * The ordinal value of the init state. |
| 5076 */ |
| 5077 final int ordinal; |
| 5078 |
| 5079 const INIT_STATE(this.name, this.ordinal); |
| 5080 |
| 5081 @override |
| 5082 int get hashCode => ordinal; |
| 5083 |
| 5084 @override |
| 5085 int compareTo(INIT_STATE other) => ordinal - other.ordinal; |
| 5086 |
| 5087 @override |
| 5088 String toString() => name; |
| 6706 } | 5089 } |
| 6707 | 5090 |
| 6708 /** | 5091 /** |
| 6709 * Instances of the class `LabelScope` represent a scope in which a single label
is defined. | 5092 * An AST visitor that is used to re-resolve the initializers of instance |
| 5093 * fields. Although this class is an AST visitor, clients are expected to use |
| 5094 * the method [resolveCompilationUnit] to run it over a compilation unit. |
| 6710 */ | 5095 */ |
| 6711 class LabelScope { | 5096 class InstanceFieldResolverVisitor extends ResolverVisitor { |
| 6712 /** | 5097 /** |
| 6713 * The label scope enclosing this label scope. | 5098 * Initialize a newly created visitor to resolve the nodes in an AST node. |
| 6714 */ | 5099 * |
| 6715 final LabelScope _outerScope; | 5100 * The [definingLibrary] is the element for the library containing the node |
| 6716 | 5101 * being visited. The [source] is the source representing the compilation unit |
| 6717 /** | 5102 * containing the node being visited. The [typeProvider] is the object used to |
| 6718 * The label defined in this scope. | 5103 * access the types from the core library. The [errorListener] is the error |
| 6719 */ | 5104 * listener that will be informed of any errors that are found during |
| 6720 final String _label; | 5105 * resolution. The [nameScope] is the scope used to resolve identifiers in the |
| 6721 | 5106 * node that will first be visited. If `null` or unspecified, a new |
| 6722 /** | 5107 * [LibraryScope] will be created based on the [definingLibrary]. |
| 6723 * The element to which the label resolves. | 5108 */ |
| 6724 */ | 5109 InstanceFieldResolverVisitor(LibraryElement definingLibrary, Source source, |
| 6725 final LabelElement element; | 5110 TypeProvider typeProvider, AnalysisErrorListener errorListener, |
| 6726 | 5111 {Scope nameScope}) |
| 6727 /** | 5112 : super(definingLibrary, source, typeProvider, errorListener, |
| 6728 * The AST node to which the label resolves. | 5113 nameScope: nameScope); |
| 6729 */ | 5114 |
| 6730 final AstNode node; | 5115 /** |
| 6731 | 5116 * Resolve the instance fields in the given compilation unit [node]. |
| 6732 /** | 5117 */ |
| 6733 * Initialize a newly created scope to represent the label [_label]. | 5118 void resolveCompilationUnit(CompilationUnit node) { |
| 6734 * [_outerScope] is the scope enclosing the new label scope. [node] is the | 5119 _overrideManager.enterScope(); |
| 6735 * AST node the label resolves to. [element] is the element the label | |
| 6736 * resolves to. | |
| 6737 */ | |
| 6738 LabelScope(this._outerScope, this._label, this.node, this.element); | |
| 6739 | |
| 6740 /** | |
| 6741 * Return the LabelScope which defines [targetLabel], or `null` if it is not | |
| 6742 * defined in this scope. | |
| 6743 */ | |
| 6744 LabelScope lookup(String targetLabel) { | |
| 6745 if (_label == targetLabel) { | |
| 6746 return this; | |
| 6747 } else if (_outerScope != null) { | |
| 6748 return _outerScope.lookup(targetLabel); | |
| 6749 } else { | |
| 6750 return null; | |
| 6751 } | |
| 6752 } | |
| 6753 } | |
| 6754 | |
| 6755 /** | |
| 6756 * Instances of the class `Library` represent the data about a single library du
ring the | |
| 6757 * resolution of some (possibly different) library. They are not intended to be
used except during | |
| 6758 * the resolution process. | |
| 6759 */ | |
| 6760 class Library { | |
| 6761 /** | |
| 6762 * An empty list that can be used to initialize lists of libraries. | |
| 6763 */ | |
| 6764 static const List<Library> _EMPTY_ARRAY = const <Library>[]; | |
| 6765 | |
| 6766 /** | |
| 6767 * The prefix of a URI using the dart-ext scheme to reference a native code li
brary. | |
| 6768 */ | |
| 6769 static String _DART_EXT_SCHEME = "dart-ext:"; | |
| 6770 | |
| 6771 /** | |
| 6772 * The analysis context in which this library is being analyzed. | |
| 6773 */ | |
| 6774 final InternalAnalysisContext _analysisContext; | |
| 6775 | |
| 6776 /** | |
| 6777 * The inheritance manager which is used for this member lookups in this libra
ry. | |
| 6778 */ | |
| 6779 InheritanceManager _inheritanceManager; | |
| 6780 | |
| 6781 /** | |
| 6782 * The listener to which analysis errors will be reported. | |
| 6783 */ | |
| 6784 final AnalysisErrorListener errorListener; | |
| 6785 | |
| 6786 /** | |
| 6787 * The source specifying the defining compilation unit of this library. | |
| 6788 */ | |
| 6789 final Source librarySource; | |
| 6790 | |
| 6791 /** | |
| 6792 * The library element representing this library. | |
| 6793 */ | |
| 6794 LibraryElementImpl _libraryElement; | |
| 6795 | |
| 6796 /** | |
| 6797 * A list containing all of the libraries that are imported into this library. | |
| 6798 */ | |
| 6799 List<Library> _importedLibraries = _EMPTY_ARRAY; | |
| 6800 | |
| 6801 /** | |
| 6802 * A table mapping URI-based directive to the actual URI value. | |
| 6803 */ | |
| 6804 HashMap<UriBasedDirective, String> _directiveUris = | |
| 6805 new HashMap<UriBasedDirective, String>(); | |
| 6806 | |
| 6807 /** | |
| 6808 * A flag indicating whether this library explicitly imports core. | |
| 6809 */ | |
| 6810 bool explicitlyImportsCore = false; | |
| 6811 | |
| 6812 /** | |
| 6813 * A list containing all of the libraries that are exported from this library. | |
| 6814 */ | |
| 6815 List<Library> _exportedLibraries = _EMPTY_ARRAY; | |
| 6816 | |
| 6817 /** | |
| 6818 * A table mapping the sources for the compilation units in this library to th
eir corresponding | |
| 6819 * AST structures. | |
| 6820 */ | |
| 6821 HashMap<Source, CompilationUnit> _astMap = | |
| 6822 new HashMap<Source, CompilationUnit>(); | |
| 6823 | |
| 6824 /** | |
| 6825 * The library scope used when resolving elements within this library's compil
ation units. | |
| 6826 */ | |
| 6827 LibraryScope _libraryScope; | |
| 6828 | |
| 6829 /** | |
| 6830 * Initialize a newly created data holder that can maintain the data associate
d with a library. | |
| 6831 * | |
| 6832 * @param analysisContext the analysis context in which this library is being
analyzed | |
| 6833 * @param errorListener the listener to which analysis errors will be reported | |
| 6834 * @param librarySource the source specifying the defining compilation unit of
this library | |
| 6835 */ | |
| 6836 Library(this._analysisContext, this.errorListener, this.librarySource) { | |
| 6837 this._libraryElement = | |
| 6838 _analysisContext.getLibraryElement(librarySource) as LibraryElementImpl; | |
| 6839 } | |
| 6840 | |
| 6841 /** | |
| 6842 * Return an array of the [CompilationUnit]s that make up the library. The fir
st unit is | |
| 6843 * always the defining unit. | |
| 6844 * | |
| 6845 * @return an array of the [CompilationUnit]s that make up the library. The fi
rst unit is | |
| 6846 * always the defining unit | |
| 6847 */ | |
| 6848 List<CompilationUnit> get compilationUnits { | |
| 6849 List<CompilationUnit> unitArrayList = new List<CompilationUnit>(); | |
| 6850 unitArrayList.add(definingCompilationUnit); | |
| 6851 for (Source source in _astMap.keys.toSet()) { | |
| 6852 if (librarySource != source) { | |
| 6853 unitArrayList.add(getAST(source)); | |
| 6854 } | |
| 6855 } | |
| 6856 return unitArrayList; | |
| 6857 } | |
| 6858 | |
| 6859 /** | |
| 6860 * Return a collection containing the sources for the compilation units in thi
s library, including | |
| 6861 * the defining compilation unit. | |
| 6862 * | |
| 6863 * @return the sources for the compilation units in this library | |
| 6864 */ | |
| 6865 Set<Source> get compilationUnitSources => _astMap.keys.toSet(); | |
| 6866 | |
| 6867 /** | |
| 6868 * Return the AST structure associated with the defining compilation unit for
this library. | |
| 6869 * | |
| 6870 * @return the AST structure associated with the defining compilation unit for
this library | |
| 6871 * @throws AnalysisException if an AST structure could not be created for the
defining compilation | |
| 6872 * unit | |
| 6873 */ | |
| 6874 CompilationUnit get definingCompilationUnit => getAST(librarySource); | |
| 6875 | |
| 6876 /** | |
| 6877 * Set the libraries that are exported by this library to be those in the give
n array. | |
| 6878 * | |
| 6879 * @param exportedLibraries the libraries that are exported by this library | |
| 6880 */ | |
| 6881 void set exportedLibraries(List<Library> exportedLibraries) { | |
| 6882 this._exportedLibraries = exportedLibraries; | |
| 6883 } | |
| 6884 | |
| 6885 /** | |
| 6886 * Return an array containing the libraries that are exported from this librar
y. | |
| 6887 * | |
| 6888 * @return an array containing the libraries that are exported from this libra
ry | |
| 6889 */ | |
| 6890 List<Library> get exports => _exportedLibraries; | |
| 6891 | |
| 6892 /** | |
| 6893 * Set the libraries that are imported into this library to be those in the gi
ven array. | |
| 6894 * | |
| 6895 * @param importedLibraries the libraries that are imported into this library | |
| 6896 */ | |
| 6897 void set importedLibraries(List<Library> importedLibraries) { | |
| 6898 this._importedLibraries = importedLibraries; | |
| 6899 } | |
| 6900 | |
| 6901 /** | |
| 6902 * Return an array containing the libraries that are imported into this librar
y. | |
| 6903 * | |
| 6904 * @return an array containing the libraries that are imported into this libra
ry | |
| 6905 */ | |
| 6906 List<Library> get imports => _importedLibraries; | |
| 6907 | |
| 6908 /** | |
| 6909 * Return an array containing the libraries that are either imported or export
ed from this | |
| 6910 * library. | |
| 6911 * | |
| 6912 * @return the libraries that are either imported or exported from this librar
y | |
| 6913 */ | |
| 6914 List<Library> get importsAndExports { | |
| 6915 HashSet<Library> libraries = new HashSet<Library>(); | |
| 6916 for (Library library in _importedLibraries) { | |
| 6917 libraries.add(library); | |
| 6918 } | |
| 6919 for (Library library in _exportedLibraries) { | |
| 6920 libraries.add(library); | |
| 6921 } | |
| 6922 return new List.from(libraries); | |
| 6923 } | |
| 6924 | |
| 6925 /** | |
| 6926 * Return the inheritance manager for this library. | |
| 6927 * | |
| 6928 * @return the inheritance manager for this library | |
| 6929 */ | |
| 6930 InheritanceManager get inheritanceManager { | |
| 6931 if (_inheritanceManager == null) { | |
| 6932 return _inheritanceManager = new InheritanceManager(_libraryElement); | |
| 6933 } | |
| 6934 return _inheritanceManager; | |
| 6935 } | |
| 6936 | |
| 6937 /** | |
| 6938 * Return the library element representing this library, creating it if necess
ary. | |
| 6939 * | |
| 6940 * @return the library element representing this library | |
| 6941 */ | |
| 6942 LibraryElementImpl get libraryElement { | |
| 6943 if (_libraryElement == null) { | |
| 6944 try { | |
| 6945 _libraryElement = _analysisContext.computeLibraryElement(librarySource) | |
| 6946 as LibraryElementImpl; | |
| 6947 } on AnalysisException catch (exception, stackTrace) { | |
| 6948 AnalysisEngine.instance.logger.logError( | |
| 6949 "Could not compute library element for ${librarySource.fullName}", | |
| 6950 new CaughtException(exception, stackTrace)); | |
| 6951 } | |
| 6952 } | |
| 6953 return _libraryElement; | |
| 6954 } | |
| 6955 | |
| 6956 /** | |
| 6957 * Set the library element representing this library to the given library elem
ent. | |
| 6958 * | |
| 6959 * @param libraryElement the library element representing this library | |
| 6960 */ | |
| 6961 void set libraryElement(LibraryElementImpl libraryElement) { | |
| 6962 this._libraryElement = libraryElement; | |
| 6963 if (_inheritanceManager != null) { | |
| 6964 _inheritanceManager.libraryElement = libraryElement; | |
| 6965 } | |
| 6966 } | |
| 6967 | |
| 6968 /** | |
| 6969 * Return the library scope used when resolving elements within this library's
compilation units. | |
| 6970 * | |
| 6971 * @return the library scope used when resolving elements within this library'
s compilation units | |
| 6972 */ | |
| 6973 LibraryScope get libraryScope { | |
| 6974 if (_libraryScope == null) { | |
| 6975 _libraryScope = new LibraryScope(_libraryElement, errorListener); | |
| 6976 } | |
| 6977 return _libraryScope; | |
| 6978 } | |
| 6979 | |
| 6980 /** | |
| 6981 * Return the AST structure associated with the given source. | |
| 6982 * | |
| 6983 * @param source the source representing the compilation unit whose AST is to
be returned | |
| 6984 * @return the AST structure associated with the given source | |
| 6985 * @throws AnalysisException if an AST structure could not be created for the
compilation unit | |
| 6986 */ | |
| 6987 CompilationUnit getAST(Source source) { | |
| 6988 CompilationUnit unit = _astMap[source]; | |
| 6989 if (unit == null) { | |
| 6990 unit = _analysisContext.computeResolvableCompilationUnit(source); | |
| 6991 _astMap[source] = unit; | |
| 6992 } | |
| 6993 return unit; | |
| 6994 } | |
| 6995 | |
| 6996 /** | |
| 6997 * Return the result of resolving the URI of the given URI-based directive aga
inst the URI of the | |
| 6998 * library, or `null` if the URI is not valid. If the URI is not valid, report
the error. | |
| 6999 * | |
| 7000 * @param directive the directive which URI should be resolved | |
| 7001 * @return the result of resolving the URI against the URI of the library | |
| 7002 */ | |
| 7003 Source getSource(UriBasedDirective directive) { | |
| 7004 StringLiteral uriLiteral = directive.uri; | |
| 7005 if (uriLiteral is StringInterpolation) { | |
| 7006 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, | |
| 7007 uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION)); | |
| 7008 return null; | |
| 7009 } | |
| 7010 String uriContent = uriLiteral.stringValue.trim(); | |
| 7011 _directiveUris[directive] = uriContent; | |
| 7012 uriContent = Uri.encodeFull(uriContent); | |
| 7013 if (directive is ImportDirective && | |
| 7014 uriContent.startsWith(_DART_EXT_SCHEME)) { | |
| 7015 _libraryElement.hasExtUri = true; | |
| 7016 return null; | |
| 7017 } | |
| 7018 try { | 5120 try { |
| 7019 parseUriWithException(uriContent); | 5121 NodeList<CompilationUnitMember> declarations = node.declarations; |
| 7020 Source source = | 5122 int declarationCount = declarations.length; |
| 7021 _analysisContext.sourceFactory.resolveUri(librarySource, uriContent); | 5123 for (int i = 0; i < declarationCount; i++) { |
| 7022 if (!_analysisContext.exists(source)) { | 5124 CompilationUnitMember declaration = declarations[i]; |
| 7023 errorListener.onError(new AnalysisError( | 5125 if (declaration is ClassDeclaration) { |
| 7024 librarySource, | 5126 _resolveClassDeclaration(declaration); |
| 7025 uriLiteral.offset, | 5127 } |
| 7026 uriLiteral.length, | 5128 } |
| 7027 CompileTimeErrorCode.URI_DOES_NOT_EXIST, | 5129 } finally { |
| 7028 [uriContent])); | 5130 _overrideManager.exitScope(); |
| 7029 } | 5131 } |
| 7030 return source; | 5132 } |
| 7031 } on URISyntaxException { | 5133 |
| 7032 errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset, | 5134 /** |
| 7033 uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent])); | 5135 * Resolve the instance fields in the given class declaration [node]. |
| 7034 } | 5136 */ |
| 7035 return null; | 5137 void _resolveClassDeclaration(ClassDeclaration node) { |
| 7036 } | 5138 _enclosingClassDeclaration = node; |
| 7037 | 5139 ClassElement outerType = enclosingClass; |
| 7038 /** | 5140 Scope outerScope = nameScope; |
| 7039 * Returns the URI value of the given directive. | 5141 try { |
| 7040 */ | 5142 enclosingClass = node.element; |
| 7041 String getUri(UriBasedDirective directive) => _directiveUris[directive]; | 5143 typeAnalyzer.thisType = enclosingClass?.type; |
| 7042 | 5144 if (enclosingClass == null) { |
| 7043 /** | 5145 AnalysisEngine.instance.logger.logInformation( |
| 7044 * Set the AST structure associated with the defining compilation unit for thi
s library to the | 5146 "Missing element for class declaration ${node.name.name} in ${defini
ngLibrary.source.fullName}", |
| 7045 * given AST structure. | 5147 new CaughtException(new AnalysisException(), null)); |
| 7046 * | 5148 // Don't try to re-resolve the initializers if we cannot set up the |
| 7047 * @param unit the AST structure associated with the defining compilation unit
for this library | 5149 // right name scope for resolution. |
| 7048 */ | 5150 } else { |
| 7049 void setDefiningCompilationUnit(CompilationUnit unit) { | 5151 nameScope = new ClassScope(nameScope, enclosingClass); |
| 7050 _astMap[librarySource] = unit; | 5152 NodeList<ClassMember> members = node.members; |
| 7051 } | 5153 int length = members.length; |
| 7052 | 5154 for (int i = 0; i < length; i++) { |
| 7053 @override | 5155 ClassMember member = members[i]; |
| 7054 String toString() => librarySource.shortName; | 5156 if (member is FieldDeclaration) { |
| 7055 } | 5157 _resolveFieldDeclaration(member); |
| 7056 | |
| 7057 /** | |
| 7058 * Instances of the class `LibraryElementBuilder` build an element model for a s
ingle library. | |
| 7059 */ | |
| 7060 class LibraryElementBuilder { | |
| 7061 /** | |
| 7062 * The analysis context in which the element model will be built. | |
| 7063 */ | |
| 7064 final InternalAnalysisContext _analysisContext; | |
| 7065 | |
| 7066 /** | |
| 7067 * The listener to which errors will be reported. | |
| 7068 */ | |
| 7069 final AnalysisErrorListener _errorListener; | |
| 7070 | |
| 7071 /** | |
| 7072 * Initialize a newly created library element builder. | |
| 7073 * | |
| 7074 * @param analysisContext the analysis context in which the element model will
be built | |
| 7075 * @param errorListener the listener to which errors will be reported | |
| 7076 */ | |
| 7077 LibraryElementBuilder(this._analysisContext, this._errorListener); | |
| 7078 | |
| 7079 /** | |
| 7080 * Build the library element for the given library. | |
| 7081 * | |
| 7082 * @param library the library for which an element model is to be built | |
| 7083 * @return the library element that was built | |
| 7084 * @throws AnalysisException if the analysis could not be performed | |
| 7085 */ | |
| 7086 LibraryElementImpl buildLibrary(Library library) { | |
| 7087 CompilationUnitBuilder builder = new CompilationUnitBuilder(); | |
| 7088 Source librarySource = library.librarySource; | |
| 7089 CompilationUnit definingCompilationUnit = library.definingCompilationUnit; | |
| 7090 CompilationUnitElementImpl definingCompilationUnitElement = builder | |
| 7091 .buildCompilationUnit( | |
| 7092 librarySource, definingCompilationUnit, librarySource); | |
| 7093 NodeList<Directive> directives = definingCompilationUnit.directives; | |
| 7094 LibraryDirective libraryDirective = null; | |
| 7095 LibraryIdentifier libraryNameNode = null; | |
| 7096 bool hasPartDirective = false; | |
| 7097 FunctionElement entryPoint = | |
| 7098 _findEntryPoint(definingCompilationUnitElement); | |
| 7099 List<Directive> directivesToResolve = new List<Directive>(); | |
| 7100 List<CompilationUnitElementImpl> sourcedCompilationUnits = | |
| 7101 new List<CompilationUnitElementImpl>(); | |
| 7102 for (Directive directive in directives) { | |
| 7103 // | |
| 7104 // We do not build the elements representing the import and export | |
| 7105 // directives at this point. That is not done until we get to | |
| 7106 // LibraryResolver.buildDirectiveModels() because we need the | |
| 7107 // LibraryElements for the referenced libraries, which might not exist at | |
| 7108 // this point (due to the possibility of circular references). | |
| 7109 // | |
| 7110 if (directive is LibraryDirective) { | |
| 7111 if (libraryNameNode == null) { | |
| 7112 libraryDirective = directive; | |
| 7113 libraryNameNode = directive.name; | |
| 7114 directivesToResolve.add(directive); | |
| 7115 } | |
| 7116 } else if (directive is PartDirective) { | |
| 7117 PartDirective partDirective = directive; | |
| 7118 StringLiteral partUri = partDirective.uri; | |
| 7119 Source partSource = partDirective.source; | |
| 7120 if (_analysisContext.exists(partSource)) { | |
| 7121 hasPartDirective = true; | |
| 7122 CompilationUnit partUnit = library.getAST(partSource); | |
| 7123 CompilationUnitElementImpl part = | |
| 7124 builder.buildCompilationUnit(partSource, partUnit, librarySource); | |
| 7125 part.uriOffset = partUri.offset; | |
| 7126 part.uriEnd = partUri.end; | |
| 7127 part.uri = partDirective.uriContent; | |
| 7128 // | |
| 7129 // Validate that the part contains a part-of directive with the same | |
| 7130 // name as the library. | |
| 7131 // | |
| 7132 String partLibraryName = | |
| 7133 _getPartLibraryName(partSource, partUnit, directivesToResolve); | |
| 7134 if (partLibraryName == null) { | |
| 7135 _errorListener.onError(new AnalysisError( | |
| 7136 librarySource, | |
| 7137 partUri.offset, | |
| 7138 partUri.length, | |
| 7139 CompileTimeErrorCode.PART_OF_NON_PART, | |
| 7140 [partUri.toSource()])); | |
| 7141 } else if (libraryNameNode == null) { | |
| 7142 // TODO(brianwilkerson) Collect the names declared by the part. | |
| 7143 // If they are all the same then we can use that name as the | |
| 7144 // inferred name of the library and present it in a quick-fix. | |
| 7145 // partLibraryNames.add(partLibraryName); | |
| 7146 } else if (libraryNameNode.name != partLibraryName) { | |
| 7147 _errorListener.onError(new AnalysisError( | |
| 7148 librarySource, | |
| 7149 partUri.offset, | |
| 7150 partUri.length, | |
| 7151 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, | |
| 7152 [libraryNameNode.name, partLibraryName])); | |
| 7153 } | 5158 } |
| 7154 if (entryPoint == null) { | 5159 } |
| 7155 entryPoint = _findEntryPoint(part); | 5160 } |
| 5161 } finally { |
| 5162 nameScope = outerScope; |
| 5163 typeAnalyzer.thisType = outerType?.type; |
| 5164 enclosingClass = outerType; |
| 5165 _enclosingClassDeclaration = null; |
| 5166 } |
| 5167 } |
| 5168 |
| 5169 /** |
| 5170 * Resolve the instance fields in the given field declaration [node]. |
| 5171 */ |
| 5172 void _resolveFieldDeclaration(FieldDeclaration node) { |
| 5173 if (!node.isStatic) { |
| 5174 for (VariableDeclaration field in node.fields.variables) { |
| 5175 if (field.initializer != null) { |
| 5176 field.initializer.accept(this); |
| 5177 FieldElement fieldElement = field.name.staticElement; |
| 5178 if (fieldElement.initializer != null) { |
| 5179 (fieldElement.initializer as ExecutableElementImpl).returnType = |
| 5180 field.initializer.staticType; |
| 7156 } | 5181 } |
| 7157 directive.element = part; | 5182 } |
| 7158 sourcedCompilationUnits.add(part); | 5183 } |
| 7159 } | 5184 } |
| 7160 } | |
| 7161 } | |
| 7162 if (hasPartDirective && libraryNameNode == null) { | |
| 7163 _errorListener.onError(new AnalysisError(librarySource, 0, 0, | |
| 7164 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART)); | |
| 7165 } | |
| 7166 // | |
| 7167 // Create and populate the library element. | |
| 7168 // | |
| 7169 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode( | |
| 7170 _analysisContext.getContextFor(librarySource), libraryNameNode); | |
| 7171 _setDocRange(libraryElement, libraryDirective); | |
| 7172 libraryElement.definingCompilationUnit = definingCompilationUnitElement; | |
| 7173 if (entryPoint != null) { | |
| 7174 libraryElement.entryPoint = entryPoint; | |
| 7175 } | |
| 7176 int sourcedUnitCount = sourcedCompilationUnits.length; | |
| 7177 libraryElement.parts = sourcedCompilationUnits; | |
| 7178 for (Directive directive in directivesToResolve) { | |
| 7179 directive.element = libraryElement; | |
| 7180 } | |
| 7181 library.libraryElement = libraryElement; | |
| 7182 if (sourcedUnitCount > 0) { | |
| 7183 _patchTopLevelAccessors(libraryElement); | |
| 7184 } | |
| 7185 return libraryElement; | |
| 7186 } | |
| 7187 | |
| 7188 /** | |
| 7189 * Build the library element for the given library. The resulting element is | |
| 7190 * stored in the [ResolvableLibrary] structure. | |
| 7191 * | |
| 7192 * @param library the library for which an element model is to be built | |
| 7193 * @throws AnalysisException if the analysis could not be performed | |
| 7194 */ | |
| 7195 void buildLibrary2(ResolvableLibrary library) { | |
| 7196 CompilationUnitBuilder builder = new CompilationUnitBuilder(); | |
| 7197 Source librarySource = library.librarySource; | |
| 7198 CompilationUnit definingCompilationUnit = library.definingCompilationUnit; | |
| 7199 CompilationUnitElementImpl definingCompilationUnitElement = builder | |
| 7200 .buildCompilationUnit( | |
| 7201 librarySource, definingCompilationUnit, librarySource); | |
| 7202 NodeList<Directive> directives = definingCompilationUnit.directives; | |
| 7203 LibraryDirective libraryDirective = null; | |
| 7204 LibraryIdentifier libraryNameNode = null; | |
| 7205 bool hasPartDirective = false; | |
| 7206 FunctionElement entryPoint = | |
| 7207 _findEntryPoint(definingCompilationUnitElement); | |
| 7208 List<Directive> directivesToResolve = new List<Directive>(); | |
| 7209 List<CompilationUnitElementImpl> sourcedCompilationUnits = | |
| 7210 new List<CompilationUnitElementImpl>(); | |
| 7211 for (Directive directive in directives) { | |
| 7212 // | |
| 7213 // We do not build the elements representing the import and export | |
| 7214 // directives at this point. That is not done until we get to | |
| 7215 // LibraryResolver.buildDirectiveModels() because we need the | |
| 7216 // LibraryElements for the referenced libraries, which might not exist at | |
| 7217 // this point (due to the possibility of circular references). | |
| 7218 // | |
| 7219 if (directive is LibraryDirective) { | |
| 7220 if (libraryNameNode == null) { | |
| 7221 libraryDirective = directive; | |
| 7222 libraryNameNode = directive.name; | |
| 7223 directivesToResolve.add(directive); | |
| 7224 } | |
| 7225 } else if (directive is PartDirective) { | |
| 7226 PartDirective partDirective = directive; | |
| 7227 StringLiteral partUri = partDirective.uri; | |
| 7228 Source partSource = partDirective.source; | |
| 7229 if (_analysisContext.exists(partSource)) { | |
| 7230 hasPartDirective = true; | |
| 7231 CompilationUnit partUnit = library.getAST(partSource); | |
| 7232 if (partUnit != null) { | |
| 7233 CompilationUnitElementImpl part = builder.buildCompilationUnit( | |
| 7234 partSource, partUnit, librarySource); | |
| 7235 part.uriOffset = partUri.offset; | |
| 7236 part.uriEnd = partUri.end; | |
| 7237 part.uri = partDirective.uriContent; | |
| 7238 // | |
| 7239 // Validate that the part contains a part-of directive with the same | |
| 7240 // name as the library. | |
| 7241 // | |
| 7242 String partLibraryName = | |
| 7243 _getPartLibraryName(partSource, partUnit, directivesToResolve); | |
| 7244 if (partLibraryName == null) { | |
| 7245 _errorListener.onError(new AnalysisError( | |
| 7246 librarySource, | |
| 7247 partUri.offset, | |
| 7248 partUri.length, | |
| 7249 CompileTimeErrorCode.PART_OF_NON_PART, | |
| 7250 [partUri.toSource()])); | |
| 7251 } else if (libraryNameNode == null) { | |
| 7252 // TODO(brianwilkerson) Collect the names declared by the part. | |
| 7253 // If they are all the same then we can use that name as the | |
| 7254 // inferred name of the library and present it in a quick-fix. | |
| 7255 // partLibraryNames.add(partLibraryName); | |
| 7256 } else if (libraryNameNode.name != partLibraryName) { | |
| 7257 _errorListener.onError(new AnalysisError( | |
| 7258 librarySource, | |
| 7259 partUri.offset, | |
| 7260 partUri.length, | |
| 7261 StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, | |
| 7262 [libraryNameNode.name, partLibraryName])); | |
| 7263 } | |
| 7264 if (entryPoint == null) { | |
| 7265 entryPoint = _findEntryPoint(part); | |
| 7266 } | |
| 7267 directive.element = part; | |
| 7268 sourcedCompilationUnits.add(part); | |
| 7269 } | |
| 7270 } | |
| 7271 } | |
| 7272 } | |
| 7273 if (hasPartDirective && libraryNameNode == null) { | |
| 7274 _errorListener.onError(new AnalysisError(librarySource, 0, 0, | |
| 7275 ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART)); | |
| 7276 } | |
| 7277 // | |
| 7278 // Create and populate the library element. | |
| 7279 // | |
| 7280 LibraryElementImpl libraryElement = new LibraryElementImpl.forNode( | |
| 7281 _analysisContext.getContextFor(librarySource), libraryNameNode); | |
| 7282 _setDocRange(libraryElement, libraryDirective); | |
| 7283 libraryElement.definingCompilationUnit = definingCompilationUnitElement; | |
| 7284 if (entryPoint != null) { | |
| 7285 libraryElement.entryPoint = entryPoint; | |
| 7286 } | |
| 7287 int sourcedUnitCount = sourcedCompilationUnits.length; | |
| 7288 libraryElement.parts = sourcedCompilationUnits; | |
| 7289 for (Directive directive in directivesToResolve) { | |
| 7290 directive.element = libraryElement; | |
| 7291 } | |
| 7292 library.libraryElement = libraryElement; | |
| 7293 if (sourcedUnitCount > 0) { | |
| 7294 _patchTopLevelAccessors(libraryElement); | |
| 7295 } | |
| 7296 } | |
| 7297 | |
| 7298 /** | |
| 7299 * Add all of the non-synthetic getters and setters defined in the given compi
lation unit that | |
| 7300 * have no corresponding accessor to one of the given collections. | |
| 7301 * | |
| 7302 * @param getters the map to which getters are to be added | |
| 7303 * @param setters the list to which setters are to be added | |
| 7304 * @param unit the compilation unit defining the accessors that are potentiall
y being added | |
| 7305 */ | |
| 7306 void _collectAccessors(HashMap<String, PropertyAccessorElement> getters, | |
| 7307 List<PropertyAccessorElement> setters, CompilationUnitElement unit) { | |
| 7308 for (PropertyAccessorElement accessor in unit.accessors) { | |
| 7309 if (accessor.isGetter) { | |
| 7310 if (!accessor.isSynthetic && accessor.correspondingSetter == null) { | |
| 7311 getters[accessor.displayName] = accessor; | |
| 7312 } | |
| 7313 } else { | |
| 7314 if (!accessor.isSynthetic && accessor.correspondingGetter == null) { | |
| 7315 setters.add(accessor); | |
| 7316 } | |
| 7317 } | |
| 7318 } | |
| 7319 } | |
| 7320 | |
| 7321 /** | |
| 7322 * Search the top-level functions defined in the given compilation unit for th
e entry point. | |
| 7323 * | |
| 7324 * @param element the compilation unit to be searched | |
| 7325 * @return the entry point that was found, or `null` if the compilation unit d
oes not define | |
| 7326 * an entry point | |
| 7327 */ | |
| 7328 FunctionElement _findEntryPoint(CompilationUnitElementImpl element) { | |
| 7329 for (FunctionElement function in element.functions) { | |
| 7330 if (function.isEntryPoint) { | |
| 7331 return function; | |
| 7332 } | |
| 7333 } | |
| 7334 return null; | |
| 7335 } | |
| 7336 | |
| 7337 /** | |
| 7338 * Return the name of the library that the given part is declared to be a part
of, or `null` | |
| 7339 * if the part does not contain a part-of directive. | |
| 7340 * | |
| 7341 * @param partSource the source representing the part | |
| 7342 * @param partUnit the AST structure of the part | |
| 7343 * @param directivesToResolve a list of directives that should be resolved to
the library being | |
| 7344 * built | |
| 7345 * @return the name of the library that the given part is declared to be a par
t of | |
| 7346 */ | |
| 7347 String _getPartLibraryName(Source partSource, CompilationUnit partUnit, | |
| 7348 List<Directive> directivesToResolve) { | |
| 7349 for (Directive directive in partUnit.directives) { | |
| 7350 if (directive is PartOfDirective) { | |
| 7351 directivesToResolve.add(directive); | |
| 7352 LibraryIdentifier libraryName = directive.libraryName; | |
| 7353 if (libraryName != null) { | |
| 7354 return libraryName.name; | |
| 7355 } | |
| 7356 } | |
| 7357 } | |
| 7358 return null; | |
| 7359 } | |
| 7360 | |
| 7361 /** | |
| 7362 * Look through all of the compilation units defined for the given library, lo
oking for getters | |
| 7363 * and setters that are defined in different compilation units but that have t
he same names. If | |
| 7364 * any are found, make sure that they have the same variable element. | |
| 7365 * | |
| 7366 * @param libraryElement the library defining the compilation units to be proc
essed | |
| 7367 */ | |
| 7368 void _patchTopLevelAccessors(LibraryElementImpl libraryElement) { | |
| 7369 HashMap<String, PropertyAccessorElement> getters = | |
| 7370 new HashMap<String, PropertyAccessorElement>(); | |
| 7371 List<PropertyAccessorElement> setters = new List<PropertyAccessorElement>(); | |
| 7372 _collectAccessors(getters, setters, libraryElement.definingCompilationUnit); | |
| 7373 for (CompilationUnitElement unit in libraryElement.parts) { | |
| 7374 _collectAccessors(getters, setters, unit); | |
| 7375 } | |
| 7376 for (PropertyAccessorElement setter in setters) { | |
| 7377 PropertyAccessorElement getter = getters[setter.displayName]; | |
| 7378 if (getter != null) { | |
| 7379 PropertyInducingElementImpl variable = | |
| 7380 getter.variable as PropertyInducingElementImpl; | |
| 7381 variable.setter = setter; | |
| 7382 (setter as PropertyAccessorElementImpl).variable = variable; | |
| 7383 } | |
| 7384 } | |
| 7385 } | |
| 7386 | |
| 7387 /** | |
| 7388 * If the given [node] has a documentation comment, remember its range | |
| 7389 * into the given [element]. | |
| 7390 */ | |
| 7391 void _setDocRange(ElementImpl element, LibraryDirective node) { | |
| 7392 if (node != null) { | |
| 7393 Comment comment = node.documentationComment; | |
| 7394 if (comment != null && comment.isDocumentation) { | |
| 7395 element.setDocRange(comment.offset, comment.length); | |
| 7396 } | |
| 7397 } | |
| 7398 } | |
| 7399 } | |
| 7400 | |
| 7401 /** | |
| 7402 * Instances of the class `LibraryImportScope` represent the scope containing al
l of the names | |
| 7403 * available from imported libraries. | |
| 7404 */ | |
| 7405 class LibraryImportScope extends Scope { | |
| 7406 /** | |
| 7407 * The element representing the library in which this scope is enclosed. | |
| 7408 */ | |
| 7409 final LibraryElement _definingLibrary; | |
| 7410 | |
| 7411 /** | |
| 7412 * The listener that is to be informed when an error is encountered. | |
| 7413 */ | |
| 7414 final AnalysisErrorListener errorListener; | |
| 7415 | |
| 7416 /** | |
| 7417 * A list of the namespaces representing the names that are available in this
scope from imported | |
| 7418 * libraries. | |
| 7419 */ | |
| 7420 List<Namespace> _importedNamespaces; | |
| 7421 | |
| 7422 /** | |
| 7423 * Initialize a newly created scope representing the names imported into the g
iven library. | |
| 7424 * | |
| 7425 * @param definingLibrary the element representing the library that imports th
e names defined in | |
| 7426 * this scope | |
| 7427 * @param errorListener the listener that is to be informed when an error is e
ncountered | |
| 7428 */ | |
| 7429 LibraryImportScope(this._definingLibrary, this.errorListener) { | |
| 7430 _createImportedNamespaces(); | |
| 7431 } | |
| 7432 | |
| 7433 @override | |
| 7434 void define(Element element) { | |
| 7435 if (!Scope.isPrivateName(element.displayName)) { | |
| 7436 super.define(element); | |
| 7437 } | |
| 7438 } | |
| 7439 | |
| 7440 @override | |
| 7441 Source getSource(AstNode node) { | |
| 7442 Source source = super.getSource(node); | |
| 7443 if (source == null) { | |
| 7444 source = _definingLibrary.definingCompilationUnit.source; | |
| 7445 } | |
| 7446 return source; | |
| 7447 } | |
| 7448 | |
| 7449 @override | |
| 7450 Element internalLookup( | |
| 7451 Identifier identifier, String name, LibraryElement referencingLibrary) { | |
| 7452 Element foundElement = localLookup(name, referencingLibrary); | |
| 7453 if (foundElement != null) { | |
| 7454 return foundElement; | |
| 7455 } | |
| 7456 for (int i = 0; i < _importedNamespaces.length; i++) { | |
| 7457 Namespace nameSpace = _importedNamespaces[i]; | |
| 7458 Element element = nameSpace.get(name); | |
| 7459 if (element != null) { | |
| 7460 if (foundElement == null) { | |
| 7461 foundElement = element; | |
| 7462 } else if (!identical(foundElement, element)) { | |
| 7463 foundElement = MultiplyDefinedElementImpl.fromElements( | |
| 7464 _definingLibrary.context, foundElement, element); | |
| 7465 } | |
| 7466 } | |
| 7467 } | |
| 7468 if (foundElement is MultiplyDefinedElementImpl) { | |
| 7469 foundElement = _removeSdkElements( | |
| 7470 identifier, name, foundElement as MultiplyDefinedElementImpl); | |
| 7471 } | |
| 7472 if (foundElement is MultiplyDefinedElementImpl) { | |
| 7473 String foundEltName = foundElement.displayName; | |
| 7474 List<Element> conflictingMembers = foundElement.conflictingElements; | |
| 7475 int count = conflictingMembers.length; | |
| 7476 List<String> libraryNames = new List<String>(count); | |
| 7477 for (int i = 0; i < count; i++) { | |
| 7478 libraryNames[i] = _getLibraryName(conflictingMembers[i]); | |
| 7479 } | |
| 7480 libraryNames.sort(); | |
| 7481 errorListener.onError(new AnalysisError( | |
| 7482 getSource(identifier), | |
| 7483 identifier.offset, | |
| 7484 identifier.length, | |
| 7485 StaticWarningCode.AMBIGUOUS_IMPORT, [ | |
| 7486 foundEltName, | |
| 7487 StringUtilities.printListOfQuotedNames(libraryNames) | |
| 7488 ])); | |
| 7489 return foundElement; | |
| 7490 } | |
| 7491 if (foundElement != null) { | |
| 7492 defineNameWithoutChecking(name, foundElement); | |
| 7493 } | |
| 7494 return foundElement; | |
| 7495 } | |
| 7496 | |
| 7497 /** | |
| 7498 * Create all of the namespaces associated with the libraries imported into th
is library. The | |
| 7499 * names are not added to this scope, but are stored for later reference. | |
| 7500 * | |
| 7501 * @param definingLibrary the element representing the library that imports th
e libraries for | |
| 7502 * which namespaces will be created | |
| 7503 */ | |
| 7504 void _createImportedNamespaces() { | |
| 7505 NamespaceBuilder builder = new NamespaceBuilder(); | |
| 7506 List<ImportElement> imports = _definingLibrary.imports; | |
| 7507 int count = imports.length; | |
| 7508 _importedNamespaces = new List<Namespace>(count); | |
| 7509 for (int i = 0; i < count; i++) { | |
| 7510 _importedNamespaces[i] = | |
| 7511 builder.createImportNamespaceForDirective(imports[i]); | |
| 7512 } | |
| 7513 } | |
| 7514 | |
| 7515 /** | |
| 7516 * Returns the name of the library that defines given element. | |
| 7517 * | |
| 7518 * @param element the element to get library name | |
| 7519 * @return the name of the library that defines given element | |
| 7520 */ | |
| 7521 String _getLibraryName(Element element) { | |
| 7522 if (element == null) { | |
| 7523 return StringUtilities.EMPTY; | |
| 7524 } | |
| 7525 LibraryElement library = element.library; | |
| 7526 if (library == null) { | |
| 7527 return StringUtilities.EMPTY; | |
| 7528 } | |
| 7529 List<ImportElement> imports = _definingLibrary.imports; | |
| 7530 int count = imports.length; | |
| 7531 for (int i = 0; i < count; i++) { | |
| 7532 if (identical(imports[i].importedLibrary, library)) { | |
| 7533 return library.definingCompilationUnit.displayName; | |
| 7534 } | |
| 7535 } | |
| 7536 List<String> indirectSources = new List<String>(); | |
| 7537 for (int i = 0; i < count; i++) { | |
| 7538 LibraryElement importedLibrary = imports[i].importedLibrary; | |
| 7539 if (importedLibrary != null) { | |
| 7540 for (LibraryElement exportedLibrary | |
| 7541 in importedLibrary.exportedLibraries) { | |
| 7542 if (identical(exportedLibrary, library)) { | |
| 7543 indirectSources | |
| 7544 .add(importedLibrary.definingCompilationUnit.displayName); | |
| 7545 } | |
| 7546 } | |
| 7547 } | |
| 7548 } | |
| 7549 int indirectCount = indirectSources.length; | |
| 7550 StringBuffer buffer = new StringBuffer(); | |
| 7551 buffer.write(library.definingCompilationUnit.displayName); | |
| 7552 if (indirectCount > 0) { | |
| 7553 buffer.write(" (via "); | |
| 7554 if (indirectCount > 1) { | |
| 7555 indirectSources.sort(); | |
| 7556 buffer.write(StringUtilities.printListOfQuotedNames(indirectSources)); | |
| 7557 } else { | |
| 7558 buffer.write(indirectSources[0]); | |
| 7559 } | |
| 7560 buffer.write(")"); | |
| 7561 } | |
| 7562 return buffer.toString(); | |
| 7563 } | |
| 7564 | |
| 7565 /** | |
| 7566 * Given a collection of elements (captured by the [foundElement]) that the | |
| 7567 * [identifier] (with the given [name]) resolved to, remove from the list all | |
| 7568 * of the names defined in the SDK and return the element(s) that remain. | |
| 7569 */ | |
| 7570 Element _removeSdkElements(Identifier identifier, String name, | |
| 7571 MultiplyDefinedElementImpl foundElement) { | |
| 7572 List<Element> conflictingElements = foundElement.conflictingElements; | |
| 7573 List<Element> nonSdkElements = new List<Element>(); | |
| 7574 Element sdkElement = null; | |
| 7575 for (Element member in conflictingElements) { | |
| 7576 if (member.library.isInSdk) { | |
| 7577 sdkElement = member; | |
| 7578 } else { | |
| 7579 nonSdkElements.add(member); | |
| 7580 } | |
| 7581 } | |
| 7582 if (sdkElement != null && nonSdkElements.length > 0) { | |
| 7583 String sdkLibName = _getLibraryName(sdkElement); | |
| 7584 String otherLibName = _getLibraryName(nonSdkElements[0]); | |
| 7585 errorListener.onError(new AnalysisError( | |
| 7586 getSource(identifier), | |
| 7587 identifier.offset, | |
| 7588 identifier.length, | |
| 7589 StaticWarningCode.CONFLICTING_DART_IMPORT, | |
| 7590 [name, sdkLibName, otherLibName])); | |
| 7591 } | |
| 7592 if (nonSdkElements.length == conflictingElements.length) { | |
| 7593 // None of the members were removed | |
| 7594 return foundElement; | |
| 7595 } else if (nonSdkElements.length == 1) { | |
| 7596 // All but one member was removed | |
| 7597 return nonSdkElements[0]; | |
| 7598 } else if (nonSdkElements.length == 0) { | |
| 7599 // All members were removed | |
| 7600 AnalysisEngine.instance.logger | |
| 7601 .logInformation("Multiply defined SDK element: $foundElement"); | |
| 7602 return foundElement; | |
| 7603 } | |
| 7604 return new MultiplyDefinedElementImpl( | |
| 7605 _definingLibrary.context, nonSdkElements); | |
| 7606 } | |
| 7607 } | |
| 7608 | |
| 7609 /** | |
| 7610 * Instances of the class `LibraryResolver` are used to resolve one or more mutu
ally dependent | |
| 7611 * libraries within a single context. | |
| 7612 */ | |
| 7613 class LibraryResolver { | |
| 7614 /** | |
| 7615 * The analysis context in which the libraries are being analyzed. | |
| 7616 */ | |
| 7617 final InternalAnalysisContext analysisContext; | |
| 7618 | |
| 7619 /** | |
| 7620 * The listener to which analysis errors will be reported, this error listener
is either | |
| 7621 * references [recordingErrorListener], or it unions the passed | |
| 7622 * [AnalysisErrorListener] with the [recordingErrorListener]. | |
| 7623 */ | |
| 7624 RecordingErrorListener _errorListener; | |
| 7625 | |
| 7626 /** | |
| 7627 * A source object representing the core library (dart:core). | |
| 7628 */ | |
| 7629 Source _coreLibrarySource; | |
| 7630 | |
| 7631 /** | |
| 7632 * A Source object representing the async library (dart:async). | |
| 7633 */ | |
| 7634 Source _asyncLibrarySource; | |
| 7635 | |
| 7636 /** | |
| 7637 * The object representing the core library. | |
| 7638 */ | |
| 7639 Library _coreLibrary; | |
| 7640 | |
| 7641 /** | |
| 7642 * The object representing the async library. | |
| 7643 */ | |
| 7644 Library _asyncLibrary; | |
| 7645 | |
| 7646 /** | |
| 7647 * The object used to access the types from the core library. | |
| 7648 */ | |
| 7649 TypeProvider _typeProvider; | |
| 7650 | |
| 7651 /** | |
| 7652 * The type system in use for the library | |
| 7653 */ | |
| 7654 TypeSystem _typeSystem; | |
| 7655 | |
| 7656 /** | |
| 7657 * A table mapping library sources to the information being maintained for tho
se libraries. | |
| 7658 */ | |
| 7659 HashMap<Source, Library> _libraryMap = new HashMap<Source, Library>(); | |
| 7660 | |
| 7661 /** | |
| 7662 * A collection containing the libraries that are being resolved together. | |
| 7663 */ | |
| 7664 Set<Library> _librariesInCycles; | |
| 7665 | |
| 7666 /** | |
| 7667 * Initialize a newly created library resolver to resolve libraries within the
given context. | |
| 7668 * | |
| 7669 * @param analysisContext the analysis context in which the library is being a
nalyzed | |
| 7670 */ | |
| 7671 LibraryResolver(this.analysisContext) { | |
| 7672 this._errorListener = new RecordingErrorListener(); | |
| 7673 _coreLibrarySource = | |
| 7674 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE); | |
| 7675 _asyncLibrarySource = | |
| 7676 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC); | |
| 7677 } | |
| 7678 | |
| 7679 /** | |
| 7680 * Return the listener to which analysis errors will be reported. | |
| 7681 * | |
| 7682 * @return the listener to which analysis errors will be reported | |
| 7683 */ | |
| 7684 RecordingErrorListener get errorListener => _errorListener; | |
| 7685 | |
| 7686 /** | |
| 7687 * Return an array containing information about all of the libraries that were
resolved. | |
| 7688 * | |
| 7689 * @return an array containing the libraries that were resolved | |
| 7690 */ | |
| 7691 Set<Library> get resolvedLibraries => _librariesInCycles; | |
| 7692 | |
| 7693 /** | |
| 7694 * The object used to access the types from the core library. | |
| 7695 */ | |
| 7696 TypeProvider get typeProvider => _typeProvider; | |
| 7697 | |
| 7698 /** | |
| 7699 * The type system in use. | |
| 7700 */ | |
| 7701 TypeSystem get typeSystem => _typeSystem; | |
| 7702 | |
| 7703 /** | |
| 7704 * Create an object to represent the information about the library defined by
the compilation unit | |
| 7705 * with the given source. | |
| 7706 * | |
| 7707 * @param librarySource the source of the library's defining compilation unit | |
| 7708 * @return the library object that was created | |
| 7709 * @throws AnalysisException if the library source is not valid | |
| 7710 */ | |
| 7711 Library createLibrary(Source librarySource) { | |
| 7712 Library library = | |
| 7713 new Library(analysisContext, _errorListener, librarySource); | |
| 7714 _libraryMap[librarySource] = library; | |
| 7715 return library; | |
| 7716 } | |
| 7717 | |
| 7718 /** | |
| 7719 * Resolve the library specified by the given source in the given context. The
library is assumed | |
| 7720 * to be embedded in the given source. | |
| 7721 * | |
| 7722 * @param librarySource the source specifying the defining compilation unit of
the library to be | |
| 7723 * resolved | |
| 7724 * @param unit the compilation unit representing the embedded library | |
| 7725 * @param fullAnalysis `true` if a full analysis should be performed | |
| 7726 * @return the element representing the resolved library | |
| 7727 * @throws AnalysisException if the library could not be resolved for some rea
son | |
| 7728 */ | |
| 7729 LibraryElement resolveEmbeddedLibrary( | |
| 7730 Source librarySource, CompilationUnit unit, bool fullAnalysis) { | |
| 7731 // | |
| 7732 // Create the objects representing the library being resolved and the core | |
| 7733 // library. | |
| 7734 // | |
| 7735 Library targetLibrary = _createLibraryWithUnit(librarySource, unit); | |
| 7736 _coreLibrary = _libraryMap[_coreLibrarySource]; | |
| 7737 if (_coreLibrary == null) { | |
| 7738 // This will only happen if the library being analyzed is the core | |
| 7739 // library. | |
| 7740 _coreLibrary = createLibrary(_coreLibrarySource); | |
| 7741 if (_coreLibrary == null) { | |
| 7742 LibraryResolver2.missingCoreLibrary( | |
| 7743 analysisContext, _coreLibrarySource); | |
| 7744 } | |
| 7745 } | |
| 7746 _asyncLibrary = _libraryMap[_asyncLibrarySource]; | |
| 7747 if (_asyncLibrary == null) { | |
| 7748 // This will only happen if the library being analyzed is the async | |
| 7749 // library. | |
| 7750 _asyncLibrary = createLibrary(_asyncLibrarySource); | |
| 7751 if (_asyncLibrary == null) { | |
| 7752 LibraryResolver2.missingAsyncLibrary( | |
| 7753 analysisContext, _asyncLibrarySource); | |
| 7754 } | |
| 7755 } | |
| 7756 // | |
| 7757 // Compute the set of libraries that need to be resolved together. | |
| 7758 // | |
| 7759 _computeEmbeddedLibraryDependencies(targetLibrary, unit); | |
| 7760 _librariesInCycles = _computeLibrariesInCycles(targetLibrary); | |
| 7761 // | |
| 7762 // Build the element models representing the libraries being resolved. | |
| 7763 // This is done in three steps: | |
| 7764 // | |
| 7765 // 1. Build the basic element models without making any connections | |
| 7766 // between elements other than the basic parent/child relationships. | |
| 7767 // This includes building the elements representing the libraries. | |
| 7768 // 2. Build the elements for the import and export directives. This | |
| 7769 // requires that we have the elements built for the referenced | |
| 7770 // libraries, but because of the possibility of circular references | |
| 7771 // needs to happen after all of the library elements have been created. | |
| 7772 // 3. Build the rest of the type model by connecting superclasses, mixins, | |
| 7773 // and interfaces. This requires that we be able to compute the names | |
| 7774 // visible in the libraries being resolved, which in turn requires that | |
| 7775 // we have resolved the import directives. | |
| 7776 // | |
| 7777 _buildElementModels(); | |
| 7778 LibraryElement coreElement = _coreLibrary.libraryElement; | |
| 7779 if (coreElement == null) { | |
| 7780 throw new AnalysisException("Could not resolve dart:core"); | |
| 7781 } | |
| 7782 LibraryElement asyncElement = _asyncLibrary.libraryElement; | |
| 7783 if (asyncElement == null) { | |
| 7784 throw new AnalysisException("Could not resolve dart:async"); | |
| 7785 } | |
| 7786 _buildDirectiveModels(); | |
| 7787 _typeProvider = new TypeProviderImpl(coreElement, asyncElement); | |
| 7788 _typeSystem = TypeSystem.create(analysisContext); | |
| 7789 _buildTypeHierarchies(); | |
| 7790 // | |
| 7791 // Perform resolution and type analysis. | |
| 7792 // | |
| 7793 // TODO(brianwilkerson) Decide whether we want to resolve all of the | |
| 7794 // libraries or whether we want to only resolve the target library. | |
| 7795 // The advantage to resolving everything is that we have already done part | |
| 7796 // of the work so we'll avoid duplicated effort. The disadvantage of | |
| 7797 // resolving everything is that we might do extra work that we don't | |
| 7798 // really care about. Another possibility is to add a parameter to this | |
| 7799 // method and punt the decision to the clients. | |
| 7800 // | |
| 7801 //if (analyzeAll) { | |
| 7802 resolveReferencesAndTypes(); | |
| 7803 //} else { | |
| 7804 // resolveReferencesAndTypes(targetLibrary); | |
| 7805 //} | |
| 7806 _performConstantEvaluation(); | |
| 7807 return targetLibrary.libraryElement; | |
| 7808 } | |
| 7809 | |
| 7810 /** | |
| 7811 * Resolve the library specified by the given source in the given context. | |
| 7812 * | |
| 7813 * Note that because Dart allows circular imports between libraries, it is pos
sible that more than | |
| 7814 * one library will need to be resolved. In such cases the error listener can
receive errors from | |
| 7815 * multiple libraries. | |
| 7816 * | |
| 7817 * @param librarySource the source specifying the defining compilation unit of
the library to be | |
| 7818 * resolved | |
| 7819 * @param fullAnalysis `true` if a full analysis should be performed | |
| 7820 * @return the element representing the resolved library | |
| 7821 * @throws AnalysisException if the library could not be resolved for some rea
son | |
| 7822 */ | |
| 7823 LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) { | |
| 7824 // | |
| 7825 // Create the object representing the library being resolved and compute | |
| 7826 // the dependency relationship. Note that all libraries depend implicitly | |
| 7827 // on core, and we inject an ersatz dependency on async, so once this is | |
| 7828 // done the core and async library elements will have been created. | |
| 7829 // | |
| 7830 Library targetLibrary = createLibrary(librarySource); | |
| 7831 _computeLibraryDependencies(targetLibrary); | |
| 7832 _coreLibrary = _libraryMap[_coreLibrarySource]; | |
| 7833 _asyncLibrary = _libraryMap[_asyncLibrarySource]; | |
| 7834 // | |
| 7835 // Compute the set of libraries that need to be resolved together. | |
| 7836 // | |
| 7837 _librariesInCycles = _computeLibrariesInCycles(targetLibrary); | |
| 7838 // | |
| 7839 // Build the element models representing the libraries being resolved. | |
| 7840 // This is done in three steps: | |
| 7841 // | |
| 7842 // 1. Build the basic element models without making any connections | |
| 7843 // between elements other than the basic parent/child relationships. | |
| 7844 // This includes building the elements representing the libraries, but | |
| 7845 // excludes members defined in enums. | |
| 7846 // 2. Build the elements for the import and export directives. This | |
| 7847 // requires that we have the elements built for the referenced | |
| 7848 // libraries, but because of the possibility of circular references | |
| 7849 // needs to happen after all of the library elements have been created. | |
| 7850 // 3. Build the members in enum declarations. | |
| 7851 // 4. Build the rest of the type model by connecting superclasses, mixins, | |
| 7852 // and interfaces. This requires that we be able to compute the names | |
| 7853 // visible in the libraries being resolved, which in turn requires that | |
| 7854 // we have resolved the import directives. | |
| 7855 // | |
| 7856 _buildElementModels(); | |
| 7857 LibraryElement coreElement = _coreLibrary.libraryElement; | |
| 7858 if (coreElement == null) { | |
| 7859 throw new AnalysisException("Could not resolve dart:core"); | |
| 7860 } | |
| 7861 LibraryElement asyncElement = _asyncLibrary.libraryElement; | |
| 7862 if (asyncElement == null) { | |
| 7863 throw new AnalysisException("Could not resolve dart:async"); | |
| 7864 } | |
| 7865 _buildDirectiveModels(); | |
| 7866 _typeProvider = new TypeProviderImpl(coreElement, asyncElement); | |
| 7867 _typeSystem = TypeSystem.create(analysisContext); | |
| 7868 _buildEnumMembers(); | |
| 7869 _buildTypeHierarchies(); | |
| 7870 // | |
| 7871 // Perform resolution and type analysis. | |
| 7872 // | |
| 7873 // TODO(brianwilkerson) Decide whether we want to resolve all of the | |
| 7874 // libraries or whether we want to only resolve the target library. The | |
| 7875 // advantage to resolving everything is that we have already done part of | |
| 7876 // the work so we'll avoid duplicated effort. The disadvantage of | |
| 7877 // resolving everything is that we might do extra work that we don't | |
| 7878 // really care about. Another possibility is to add a parameter to this | |
| 7879 // method and punt the decision to the clients. | |
| 7880 // | |
| 7881 //if (analyzeAll) { | |
| 7882 resolveReferencesAndTypes(); | |
| 7883 //} else { | |
| 7884 // resolveReferencesAndTypes(targetLibrary); | |
| 7885 //} | |
| 7886 _performConstantEvaluation(); | |
| 7887 return targetLibrary.libraryElement; | |
| 7888 } | |
| 7889 | |
| 7890 /** | |
| 7891 * Resolve the identifiers and perform type analysis in the libraries in the c
urrent cycle. | |
| 7892 * | |
| 7893 * @throws AnalysisException if any of the identifiers could not be resolved o
r if any of the | |
| 7894 * libraries could not have their types analyzed | |
| 7895 */ | |
| 7896 void resolveReferencesAndTypes() { | |
| 7897 for (Library library in _librariesInCycles) { | |
| 7898 _resolveReferencesAndTypesInLibrary(library); | |
| 7899 } | |
| 7900 } | |
| 7901 | |
| 7902 /** | |
| 7903 * Add a dependency to the given map from the referencing library to the refer
enced library. | |
| 7904 * | |
| 7905 * @param dependencyMap the map to which the dependency is to be added | |
| 7906 * @param referencingLibrary the library that references the referenced librar
y | |
| 7907 * @param referencedLibrary the library referenced by the referencing library | |
| 7908 */ | |
| 7909 void _addDependencyToMap(HashMap<Library, List<Library>> dependencyMap, | |
| 7910 Library referencingLibrary, Library referencedLibrary) { | |
| 7911 List<Library> dependentLibraries = dependencyMap[referencedLibrary]; | |
| 7912 if (dependentLibraries == null) { | |
| 7913 dependentLibraries = new List<Library>(); | |
| 7914 dependencyMap[referencedLibrary] = dependentLibraries; | |
| 7915 } | |
| 7916 dependentLibraries.add(referencingLibrary); | |
| 7917 } | |
| 7918 | |
| 7919 /** | |
| 7920 * Given a library that is part of a cycle that includes the root library, add
to the given set of | |
| 7921 * libraries all of the libraries reachable from the root library that are als
o included in the | |
| 7922 * cycle. | |
| 7923 * | |
| 7924 * @param library the library to be added to the collection of libraries in cy
cles | |
| 7925 * @param librariesInCycle a collection of the libraries that are in the cycle | |
| 7926 * @param dependencyMap a table mapping libraries to the collection of librari
es from which those | |
| 7927 * libraries are referenced | |
| 7928 */ | |
| 7929 void _addLibrariesInCycle(Library library, Set<Library> librariesInCycle, | |
| 7930 HashMap<Library, List<Library>> dependencyMap) { | |
| 7931 if (librariesInCycle.add(library)) { | |
| 7932 List<Library> dependentLibraries = dependencyMap[library]; | |
| 7933 if (dependentLibraries != null) { | |
| 7934 for (Library dependentLibrary in dependentLibraries) { | |
| 7935 _addLibrariesInCycle( | |
| 7936 dependentLibrary, librariesInCycle, dependencyMap); | |
| 7937 } | |
| 7938 } | |
| 7939 } | |
| 7940 } | |
| 7941 | |
| 7942 /** | |
| 7943 * Add the given library, and all libraries reachable from it that have not al
ready been visited, | |
| 7944 * to the given dependency map. | |
| 7945 * | |
| 7946 * @param library the library currently being added to the dependency map | |
| 7947 * @param dependencyMap the dependency map being computed | |
| 7948 * @param visitedLibraries the libraries that have already been visited, used
to prevent infinite | |
| 7949 * recursion | |
| 7950 */ | |
| 7951 void _addToDependencyMap( | |
| 7952 Library library, | |
| 7953 HashMap<Library, List<Library>> dependencyMap, | |
| 7954 Set<Library> visitedLibraries) { | |
| 7955 if (visitedLibraries.add(library)) { | |
| 7956 bool asyncFound = false; | |
| 7957 for (Library referencedLibrary in library.importsAndExports) { | |
| 7958 _addDependencyToMap(dependencyMap, library, referencedLibrary); | |
| 7959 _addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries); | |
| 7960 if (identical(referencedLibrary, _asyncLibrary)) { | |
| 7961 asyncFound = true; | |
| 7962 } | |
| 7963 } | |
| 7964 if (!library.explicitlyImportsCore && !identical(library, _coreLibrary)) { | |
| 7965 _addDependencyToMap(dependencyMap, library, _coreLibrary); | |
| 7966 } | |
| 7967 if (!asyncFound && !identical(library, _asyncLibrary)) { | |
| 7968 _addDependencyToMap(dependencyMap, library, _asyncLibrary); | |
| 7969 _addToDependencyMap(_asyncLibrary, dependencyMap, visitedLibraries); | |
| 7970 } | |
| 7971 } | |
| 7972 } | |
| 7973 | |
| 7974 /** | |
| 7975 * Build the element model representing the combinators declared by the given
directive. | |
| 7976 * | |
| 7977 * @param directive the directive that declares the combinators | |
| 7978 * @return an array containing the import combinators that were built | |
| 7979 */ | |
| 7980 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) { | |
| 7981 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>(); | |
| 7982 for (Combinator combinator in directive.combinators) { | |
| 7983 if (combinator is HideCombinator) { | |
| 7984 HideElementCombinatorImpl hide = new HideElementCombinatorImpl(); | |
| 7985 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames); | |
| 7986 combinators.add(hide); | |
| 7987 } else { | |
| 7988 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl(); | |
| 7989 show.offset = combinator.offset; | |
| 7990 show.end = combinator.end; | |
| 7991 show.shownNames = | |
| 7992 _getIdentifiers((combinator as ShowCombinator).shownNames); | |
| 7993 combinators.add(show); | |
| 7994 } | |
| 7995 } | |
| 7996 return combinators; | |
| 7997 } | |
| 7998 | |
| 7999 /** | |
| 8000 * Every library now has a corresponding [LibraryElement], so it is now possib
le to resolve | |
| 8001 * the import and export directives. | |
| 8002 * | |
| 8003 * @throws AnalysisException if the defining compilation unit for any of the l
ibraries could not | |
| 8004 * be accessed | |
| 8005 */ | |
| 8006 void _buildDirectiveModels() { | |
| 8007 for (Library library in _librariesInCycles) { | |
| 8008 HashMap<String, PrefixElementImpl> nameToPrefixMap = | |
| 8009 new HashMap<String, PrefixElementImpl>(); | |
| 8010 List<ImportElement> imports = new List<ImportElement>(); | |
| 8011 List<ExportElement> exports = new List<ExportElement>(); | |
| 8012 for (Directive directive in library.definingCompilationUnit.directives) { | |
| 8013 if (directive is ImportDirective) { | |
| 8014 ImportDirective importDirective = directive; | |
| 8015 String uriContent = importDirective.uriContent; | |
| 8016 if (DartUriResolver.isDartExtUri(uriContent)) { | |
| 8017 library.libraryElement.hasExtUri = true; | |
| 8018 } | |
| 8019 Source importedSource = importDirective.source; | |
| 8020 if (importedSource != null) { | |
| 8021 // The imported source will be null if the URI in the import | |
| 8022 // directive was invalid. | |
| 8023 Library importedLibrary = _libraryMap[importedSource]; | |
| 8024 if (importedLibrary != null) { | |
| 8025 ImportElementImpl importElement = | |
| 8026 new ImportElementImpl(directive.offset); | |
| 8027 StringLiteral uriLiteral = importDirective.uri; | |
| 8028 importElement.uriOffset = uriLiteral.offset; | |
| 8029 importElement.uriEnd = uriLiteral.end; | |
| 8030 importElement.uri = uriContent; | |
| 8031 importElement.deferred = importDirective.deferredKeyword != null; | |
| 8032 importElement.combinators = _buildCombinators(importDirective); | |
| 8033 LibraryElement importedLibraryElement = | |
| 8034 importedLibrary.libraryElement; | |
| 8035 if (importedLibraryElement != null) { | |
| 8036 importElement.importedLibrary = importedLibraryElement; | |
| 8037 } | |
| 8038 SimpleIdentifier prefixNode = directive.prefix; | |
| 8039 if (prefixNode != null) { | |
| 8040 importElement.prefixOffset = prefixNode.offset; | |
| 8041 String prefixName = prefixNode.name; | |
| 8042 PrefixElementImpl prefix = nameToPrefixMap[prefixName]; | |
| 8043 if (prefix == null) { | |
| 8044 prefix = new PrefixElementImpl.forNode(prefixNode); | |
| 8045 nameToPrefixMap[prefixName] = prefix; | |
| 8046 } | |
| 8047 importElement.prefix = prefix; | |
| 8048 prefixNode.staticElement = prefix; | |
| 8049 } | |
| 8050 directive.element = importElement; | |
| 8051 imports.add(importElement); | |
| 8052 if (analysisContext.computeKindOf(importedSource) != | |
| 8053 SourceKind.LIBRARY) { | |
| 8054 ErrorCode errorCode = (importElement.isDeferred | |
| 8055 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY | |
| 8056 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY); | |
| 8057 _errorListener.onError(new AnalysisError( | |
| 8058 library.librarySource, | |
| 8059 uriLiteral.offset, | |
| 8060 uriLiteral.length, | |
| 8061 errorCode, | |
| 8062 [uriLiteral.toSource()])); | |
| 8063 } | |
| 8064 } | |
| 8065 } | |
| 8066 } else if (directive is ExportDirective) { | |
| 8067 ExportDirective exportDirective = directive; | |
| 8068 Source exportedSource = exportDirective.source; | |
| 8069 if (exportedSource != null) { | |
| 8070 // The exported source will be null if the URI in the export | |
| 8071 // directive was invalid. | |
| 8072 Library exportedLibrary = _libraryMap[exportedSource]; | |
| 8073 if (exportedLibrary != null) { | |
| 8074 ExportElementImpl exportElement = | |
| 8075 new ExportElementImpl(directive.offset); | |
| 8076 StringLiteral uriLiteral = exportDirective.uri; | |
| 8077 exportElement.uriOffset = uriLiteral.offset; | |
| 8078 exportElement.uriEnd = uriLiteral.end; | |
| 8079 exportElement.uri = exportDirective.uriContent; | |
| 8080 exportElement.combinators = _buildCombinators(exportDirective); | |
| 8081 LibraryElement exportedLibraryElement = | |
| 8082 exportedLibrary.libraryElement; | |
| 8083 if (exportedLibraryElement != null) { | |
| 8084 exportElement.exportedLibrary = exportedLibraryElement; | |
| 8085 } | |
| 8086 directive.element = exportElement; | |
| 8087 exports.add(exportElement); | |
| 8088 if (analysisContext.computeKindOf(exportedSource) != | |
| 8089 SourceKind.LIBRARY) { | |
| 8090 _errorListener.onError(new AnalysisError( | |
| 8091 library.librarySource, | |
| 8092 uriLiteral.offset, | |
| 8093 uriLiteral.length, | |
| 8094 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, | |
| 8095 [uriLiteral.toSource()])); | |
| 8096 } | |
| 8097 } | |
| 8098 } | |
| 8099 } | |
| 8100 } | |
| 8101 Source librarySource = library.librarySource; | |
| 8102 if (!library.explicitlyImportsCore && | |
| 8103 _coreLibrarySource != librarySource) { | |
| 8104 ImportElementImpl importElement = new ImportElementImpl(-1); | |
| 8105 importElement.importedLibrary = _coreLibrary.libraryElement; | |
| 8106 importElement.synthetic = true; | |
| 8107 imports.add(importElement); | |
| 8108 } | |
| 8109 LibraryElementImpl libraryElement = library.libraryElement; | |
| 8110 libraryElement.imports = imports; | |
| 8111 libraryElement.exports = exports; | |
| 8112 if (libraryElement.entryPoint == null) { | |
| 8113 Namespace namespace = new NamespaceBuilder() | |
| 8114 .createExportNamespaceForLibrary(libraryElement); | |
| 8115 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME); | |
| 8116 if (element is FunctionElement) { | |
| 8117 libraryElement.entryPoint = element; | |
| 8118 } | |
| 8119 } | |
| 8120 } | |
| 8121 } | |
| 8122 | |
| 8123 /** | |
| 8124 * Build element models for all of the libraries in the current cycle. | |
| 8125 * | |
| 8126 * @throws AnalysisException if any of the element models cannot be built | |
| 8127 */ | |
| 8128 void _buildElementModels() { | |
| 8129 for (Library library in _librariesInCycles) { | |
| 8130 LibraryElementBuilder builder = | |
| 8131 new LibraryElementBuilder(analysisContext, errorListener); | |
| 8132 LibraryElementImpl libraryElement = builder.buildLibrary(library); | |
| 8133 library.libraryElement = libraryElement; | |
| 8134 } | |
| 8135 } | |
| 8136 | |
| 8137 /** | |
| 8138 * Build the members in enum declarations. This cannot be done while building
the rest of the | |
| 8139 * element model because it depends on being able to access core types, which
cannot happen until | |
| 8140 * the rest of the element model has been built (when resolving the core libra
ry). | |
| 8141 * | |
| 8142 * @throws AnalysisException if any of the enum members could not be built | |
| 8143 */ | |
| 8144 void _buildEnumMembers() { | |
| 8145 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8146 for (Library library in _librariesInCycles) { | |
| 8147 for (Source source in library.compilationUnitSources) { | |
| 8148 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider); | |
| 8149 library.getAST(source).accept(builder); | |
| 8150 } | |
| 8151 } | |
| 8152 }); | |
| 8153 } | |
| 8154 | |
| 8155 /** | |
| 8156 * Resolve the type hierarchy across all of the types declared in the librarie
s in the current | |
| 8157 * cycle. | |
| 8158 * | |
| 8159 * @throws AnalysisException if any of the type hierarchies could not be resol
ved | |
| 8160 */ | |
| 8161 void _buildTypeHierarchies() { | |
| 8162 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8163 for (Library library in _librariesInCycles) { | |
| 8164 for (Source source in library.compilationUnitSources) { | |
| 8165 TypeResolverVisitorFactory typeResolverVisitorFactory = | |
| 8166 analysisContext.typeResolverVisitorFactory; | |
| 8167 TypeResolverVisitor visitor = (typeResolverVisitorFactory == null) | |
| 8168 ? new TypeResolverVisitor(library.libraryElement, source, | |
| 8169 _typeProvider, library.errorListener, | |
| 8170 nameScope: library.libraryScope) | |
| 8171 : typeResolverVisitorFactory(library, source, _typeProvider); | |
| 8172 library.getAST(source).accept(visitor); | |
| 8173 } | |
| 8174 } | |
| 8175 }); | |
| 8176 } | |
| 8177 | |
| 8178 /** | |
| 8179 * Compute a dependency map of libraries reachable from the given library. A d
ependency map is a | |
| 8180 * table that maps individual libraries to a list of the libraries that either
import or export | |
| 8181 * those libraries. | |
| 8182 * | |
| 8183 * This map is used to compute all of the libraries involved in a cycle that i
nclude the root | |
| 8184 * library. Given that we only add libraries that are reachable from the root
library, when we | |
| 8185 * work backward we are guaranteed to only get libraries in the cycle. | |
| 8186 * | |
| 8187 * @param library the library currently being added to the dependency map | |
| 8188 */ | |
| 8189 HashMap<Library, List<Library>> _computeDependencyMap(Library library) { | |
| 8190 HashMap<Library, List<Library>> dependencyMap = | |
| 8191 new HashMap<Library, List<Library>>(); | |
| 8192 _addToDependencyMap(library, dependencyMap, new HashSet<Library>()); | |
| 8193 return dependencyMap; | |
| 8194 } | |
| 8195 | |
| 8196 /** | |
| 8197 * Recursively traverse the libraries reachable from the given library, creati
ng instances of the | |
| 8198 * class [Library] to represent them, and record the references in the library
objects. | |
| 8199 * | |
| 8200 * @param library the library to be processed to find libraries that have not
yet been traversed | |
| 8201 * @throws AnalysisException if some portion of the library graph could not be
traversed | |
| 8202 */ | |
| 8203 void _computeEmbeddedLibraryDependencies( | |
| 8204 Library library, CompilationUnit unit) { | |
| 8205 Source librarySource = library.librarySource; | |
| 8206 HashSet<Source> exportedSources = new HashSet<Source>(); | |
| 8207 HashSet<Source> importedSources = new HashSet<Source>(); | |
| 8208 for (Directive directive in unit.directives) { | |
| 8209 if (directive is ExportDirective) { | |
| 8210 Source exportSource = _resolveSource(librarySource, directive); | |
| 8211 if (exportSource != null) { | |
| 8212 exportedSources.add(exportSource); | |
| 8213 } | |
| 8214 } else if (directive is ImportDirective) { | |
| 8215 Source importSource = _resolveSource(librarySource, directive); | |
| 8216 if (importSource != null) { | |
| 8217 importedSources.add(importSource); | |
| 8218 } | |
| 8219 } | |
| 8220 } | |
| 8221 _computeLibraryDependenciesFromDirectives(library, | |
| 8222 new List.from(importedSources), new List.from(exportedSources)); | |
| 8223 } | |
| 8224 | |
| 8225 /** | |
| 8226 * Return a collection containing all of the libraries reachable from the give
n library that are | |
| 8227 * contained in a cycle that includes the given library. | |
| 8228 * | |
| 8229 * @param library the library that must be included in any cycles whose member
s are to be returned | |
| 8230 * @return all of the libraries referenced by the given library that have a ci
rcular reference | |
| 8231 * back to the given library | |
| 8232 */ | |
| 8233 Set<Library> _computeLibrariesInCycles(Library library) { | |
| 8234 HashMap<Library, List<Library>> dependencyMap = | |
| 8235 _computeDependencyMap(library); | |
| 8236 Set<Library> librariesInCycle = new HashSet<Library>(); | |
| 8237 _addLibrariesInCycle(library, librariesInCycle, dependencyMap); | |
| 8238 return librariesInCycle; | |
| 8239 } | |
| 8240 | |
| 8241 /** | |
| 8242 * Recursively traverse the libraries reachable from the given library, creati
ng instances of the | |
| 8243 * class [Library] to represent them, and record the references in the library
objects. | |
| 8244 * | |
| 8245 * @param library the library to be processed to find libraries that have not
yet been traversed | |
| 8246 * @throws AnalysisException if some portion of the library graph could not be
traversed | |
| 8247 */ | |
| 8248 void _computeLibraryDependencies(Library library) { | |
| 8249 Source librarySource = library.librarySource; | |
| 8250 _computeLibraryDependenciesFromDirectives( | |
| 8251 library, | |
| 8252 analysisContext.computeImportedLibraries(librarySource), | |
| 8253 analysisContext.computeExportedLibraries(librarySource)); | |
| 8254 } | |
| 8255 | |
| 8256 /** | |
| 8257 * Recursively traverse the libraries reachable from the given library, creati
ng instances of the | |
| 8258 * class [Library] to represent them, and record the references in the library
objects. | |
| 8259 * | |
| 8260 * @param library the library to be processed to find libraries that have not
yet been traversed | |
| 8261 * @param importedSources an array containing the sources that are imported in
to the given library | |
| 8262 * @param exportedSources an array containing the sources that are exported fr
om the given library | |
| 8263 * @throws AnalysisException if some portion of the library graph could not be
traversed | |
| 8264 */ | |
| 8265 void _computeLibraryDependenciesFromDirectives(Library library, | |
| 8266 List<Source> importedSources, List<Source> exportedSources) { | |
| 8267 List<Library> importedLibraries = new List<Library>(); | |
| 8268 bool explicitlyImportsCore = false; | |
| 8269 bool importsAsync = false; | |
| 8270 for (Source importedSource in importedSources) { | |
| 8271 if (importedSource == _coreLibrarySource) { | |
| 8272 explicitlyImportsCore = true; | |
| 8273 } | |
| 8274 if (importedSource == _asyncLibrarySource) { | |
| 8275 importsAsync = true; | |
| 8276 } | |
| 8277 Library importedLibrary = _libraryMap[importedSource]; | |
| 8278 if (importedLibrary == null) { | |
| 8279 importedLibrary = _createLibraryOrNull(importedSource); | |
| 8280 if (importedLibrary != null) { | |
| 8281 _computeLibraryDependencies(importedLibrary); | |
| 8282 } | |
| 8283 } | |
| 8284 if (importedLibrary != null) { | |
| 8285 importedLibraries.add(importedLibrary); | |
| 8286 } | |
| 8287 } | |
| 8288 library.importedLibraries = importedLibraries; | |
| 8289 List<Library> exportedLibraries = new List<Library>(); | |
| 8290 for (Source exportedSource in exportedSources) { | |
| 8291 Library exportedLibrary = _libraryMap[exportedSource]; | |
| 8292 if (exportedLibrary == null) { | |
| 8293 exportedLibrary = _createLibraryOrNull(exportedSource); | |
| 8294 if (exportedLibrary != null) { | |
| 8295 _computeLibraryDependencies(exportedLibrary); | |
| 8296 } | |
| 8297 } | |
| 8298 if (exportedLibrary != null) { | |
| 8299 exportedLibraries.add(exportedLibrary); | |
| 8300 } | |
| 8301 } | |
| 8302 library.exportedLibraries = exportedLibraries; | |
| 8303 library.explicitlyImportsCore = explicitlyImportsCore; | |
| 8304 if (!explicitlyImportsCore && _coreLibrarySource != library.librarySource) { | |
| 8305 Library importedLibrary = _libraryMap[_coreLibrarySource]; | |
| 8306 if (importedLibrary == null) { | |
| 8307 importedLibrary = _createLibraryOrNull(_coreLibrarySource); | |
| 8308 if (importedLibrary != null) { | |
| 8309 _computeLibraryDependencies(importedLibrary); | |
| 8310 } | |
| 8311 } | |
| 8312 } | |
| 8313 if (!importsAsync && _asyncLibrarySource != library.librarySource) { | |
| 8314 Library importedLibrary = _libraryMap[_asyncLibrarySource]; | |
| 8315 if (importedLibrary == null) { | |
| 8316 importedLibrary = _createLibraryOrNull(_asyncLibrarySource); | |
| 8317 if (importedLibrary != null) { | |
| 8318 _computeLibraryDependencies(importedLibrary); | |
| 8319 } | |
| 8320 } | |
| 8321 } | |
| 8322 } | |
| 8323 | |
| 8324 /** | |
| 8325 * Create an object to represent the information about the library defined by
the compilation unit | |
| 8326 * with the given source. Return the library object that was created, or `null
` if the | |
| 8327 * source is not valid. | |
| 8328 * | |
| 8329 * @param librarySource the source of the library's defining compilation unit | |
| 8330 * @return the library object that was created | |
| 8331 */ | |
| 8332 Library _createLibraryOrNull(Source librarySource) { | |
| 8333 if (!analysisContext.exists(librarySource)) { | |
| 8334 return null; | |
| 8335 } | |
| 8336 Library library = | |
| 8337 new Library(analysisContext, _errorListener, librarySource); | |
| 8338 _libraryMap[librarySource] = library; | |
| 8339 return library; | |
| 8340 } | |
| 8341 | |
| 8342 /** | |
| 8343 * Create an object to represent the information about the library defined by
the compilation unit | |
| 8344 * with the given source. | |
| 8345 * | |
| 8346 * @param librarySource the source of the library's defining compilation unit | |
| 8347 * @param unit the compilation unit that defines the library | |
| 8348 * @return the library object that was created | |
| 8349 * @throws AnalysisException if the library source is not valid | |
| 8350 */ | |
| 8351 Library _createLibraryWithUnit(Source librarySource, CompilationUnit unit) { | |
| 8352 Library library = | |
| 8353 new Library(analysisContext, _errorListener, librarySource); | |
| 8354 library.setDefiningCompilationUnit(unit); | |
| 8355 _libraryMap[librarySource] = library; | |
| 8356 return library; | |
| 8357 } | |
| 8358 | |
| 8359 /** | |
| 8360 * Return an array containing the lexical identifiers associated with the node
s in the given list. | |
| 8361 * | |
| 8362 * @param names the AST nodes representing the identifiers | |
| 8363 * @return the lexical identifiers associated with the nodes in the list | |
| 8364 */ | |
| 8365 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) { | |
| 8366 int count = names.length; | |
| 8367 List<String> identifiers = new List<String>(count); | |
| 8368 for (int i = 0; i < count; i++) { | |
| 8369 identifiers[i] = names[i].name; | |
| 8370 } | |
| 8371 return identifiers; | |
| 8372 } | |
| 8373 | |
| 8374 /** | |
| 8375 * Compute a value for all of the constants in the libraries being analyzed. | |
| 8376 */ | |
| 8377 void _performConstantEvaluation() { | |
| 8378 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8379 ConstantValueComputer computer = new ConstantValueComputer( | |
| 8380 analysisContext, | |
| 8381 _typeProvider, | |
| 8382 analysisContext.declaredVariables, | |
| 8383 null, | |
| 8384 _typeSystem); | |
| 8385 for (Library library in _librariesInCycles) { | |
| 8386 for (Source source in library.compilationUnitSources) { | |
| 8387 try { | |
| 8388 CompilationUnit unit = library.getAST(source); | |
| 8389 if (unit != null) { | |
| 8390 computer.add(unit, source, library.librarySource); | |
| 8391 } | |
| 8392 } on AnalysisException catch (exception, stackTrace) { | |
| 8393 AnalysisEngine.instance.logger.logError( | |
| 8394 "Internal Error: Could not access AST for ${source.fullName} dur
ing constant evaluation", | |
| 8395 new CaughtException(exception, stackTrace)); | |
| 8396 } | |
| 8397 } | |
| 8398 } | |
| 8399 computer.computeValues(); | |
| 8400 // As a temporary workaround for issue 21572, run ConstantVerifier now. | |
| 8401 // TODO(paulberry): remove this workaround once issue 21572 is fixed. | |
| 8402 for (Library library in _librariesInCycles) { | |
| 8403 for (Source source in library.compilationUnitSources) { | |
| 8404 try { | |
| 8405 CompilationUnit unit = library.getAST(source); | |
| 8406 ErrorReporter errorReporter = | |
| 8407 new ErrorReporter(_errorListener, source); | |
| 8408 ConstantVerifier constantVerifier = new ConstantVerifier( | |
| 8409 errorReporter, | |
| 8410 library.libraryElement, | |
| 8411 _typeProvider, | |
| 8412 analysisContext.declaredVariables); | |
| 8413 unit.accept(constantVerifier); | |
| 8414 } on AnalysisException catch (exception, stackTrace) { | |
| 8415 AnalysisEngine.instance.logger.logError( | |
| 8416 "Internal Error: Could not access AST for ${source.fullName} " | |
| 8417 "during constant verification", | |
| 8418 new CaughtException(exception, stackTrace)); | |
| 8419 } | |
| 8420 } | |
| 8421 } | |
| 8422 }); | |
| 8423 } | |
| 8424 | |
| 8425 /** | |
| 8426 * Resolve the identifiers and perform type analysis in the given library. | |
| 8427 * | |
| 8428 * @param library the library to be resolved | |
| 8429 * @throws AnalysisException if any of the identifiers could not be resolved o
r if the types in | |
| 8430 * the library cannot be analyzed | |
| 8431 */ | |
| 8432 void _resolveReferencesAndTypesInLibrary(Library library) { | |
| 8433 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8434 for (Source source in library.compilationUnitSources) { | |
| 8435 CompilationUnit ast = library.getAST(source); | |
| 8436 ast.accept(new VariableResolverVisitor(library.libraryElement, source, | |
| 8437 _typeProvider, library.errorListener, | |
| 8438 nameScope: library.libraryScope)); | |
| 8439 ResolverVisitorFactory visitorFactory = | |
| 8440 analysisContext.resolverVisitorFactory; | |
| 8441 ResolverVisitor visitor = visitorFactory != null | |
| 8442 ? visitorFactory(library, source, _typeProvider) | |
| 8443 : new ResolverVisitor(library.libraryElement, source, _typeProvider, | |
| 8444 library.errorListener, | |
| 8445 nameScope: library.libraryScope, | |
| 8446 inheritanceManager: library.inheritanceManager); | |
| 8447 ast.accept(visitor); | |
| 8448 } | |
| 8449 }); | |
| 8450 } | |
| 8451 | |
| 8452 /** | |
| 8453 * Return the result of resolving the URI of the given URI-based directive aga
inst the URI of the | |
| 8454 * given library, or `null` if the URI is not valid. | |
| 8455 * | |
| 8456 * @param librarySource the source representing the library containing the dir
ective | |
| 8457 * @param directive the directive which URI should be resolved | |
| 8458 * @return the result of resolving the URI against the URI of the library | |
| 8459 */ | |
| 8460 Source _resolveSource(Source librarySource, UriBasedDirective directive) { | |
| 8461 StringLiteral uriLiteral = directive.uri; | |
| 8462 if (uriLiteral is StringInterpolation) { | |
| 8463 return null; | |
| 8464 } | |
| 8465 String uriContent = uriLiteral.stringValue.trim(); | |
| 8466 if (uriContent == null || uriContent.isEmpty) { | |
| 8467 return null; | |
| 8468 } | |
| 8469 uriContent = Uri.encodeFull(uriContent); | |
| 8470 return analysisContext.sourceFactory.resolveUri(librarySource, uriContent); | |
| 8471 } | |
| 8472 } | |
| 8473 | |
| 8474 /** | |
| 8475 * Instances of the class `LibraryResolver` are used to resolve one or more mutu
ally dependent | |
| 8476 * libraries within a single context. | |
| 8477 */ | |
| 8478 class LibraryResolver2 { | |
| 8479 /** | |
| 8480 * The analysis context in which the libraries are being analyzed. | |
| 8481 */ | |
| 8482 final InternalAnalysisContext analysisContext; | |
| 8483 | |
| 8484 /** | |
| 8485 * The listener to which analysis errors will be reported, this error listener
is either | |
| 8486 * references [recordingErrorListener], or it unions the passed | |
| 8487 * [AnalysisErrorListener] with the [recordingErrorListener]. | |
| 8488 */ | |
| 8489 RecordingErrorListener _errorListener; | |
| 8490 | |
| 8491 /** | |
| 8492 * A source object representing the core library (dart:core). | |
| 8493 */ | |
| 8494 Source _coreLibrarySource; | |
| 8495 | |
| 8496 /** | |
| 8497 * A source object representing the async library (dart:async). | |
| 8498 */ | |
| 8499 Source _asyncLibrarySource; | |
| 8500 | |
| 8501 /** | |
| 8502 * The object representing the core library. | |
| 8503 */ | |
| 8504 ResolvableLibrary _coreLibrary; | |
| 8505 | |
| 8506 /** | |
| 8507 * The object representing the async library. | |
| 8508 */ | |
| 8509 ResolvableLibrary _asyncLibrary; | |
| 8510 | |
| 8511 /** | |
| 8512 * The object used to access the types from the core library. | |
| 8513 */ | |
| 8514 TypeProvider _typeProvider; | |
| 8515 | |
| 8516 /** | |
| 8517 * The type system in use for the library | |
| 8518 */ | |
| 8519 TypeSystem _typeSystem; | |
| 8520 | |
| 8521 /** | |
| 8522 * A table mapping library sources to the information being maintained for tho
se libraries. | |
| 8523 */ | |
| 8524 HashMap<Source, ResolvableLibrary> _libraryMap = | |
| 8525 new HashMap<Source, ResolvableLibrary>(); | |
| 8526 | |
| 8527 /** | |
| 8528 * A collection containing the libraries that are being resolved together. | |
| 8529 */ | |
| 8530 List<ResolvableLibrary> _librariesInCycle; | |
| 8531 | |
| 8532 /** | |
| 8533 * Initialize a newly created library resolver to resolve libraries within the
given context. | |
| 8534 * | |
| 8535 * @param analysisContext the analysis context in which the library is being a
nalyzed | |
| 8536 */ | |
| 8537 LibraryResolver2(this.analysisContext) { | |
| 8538 this._errorListener = new RecordingErrorListener(); | |
| 8539 _coreLibrarySource = | |
| 8540 analysisContext.sourceFactory.forUri(DartSdk.DART_CORE); | |
| 8541 _asyncLibrarySource = | |
| 8542 analysisContext.sourceFactory.forUri(DartSdk.DART_ASYNC); | |
| 8543 } | |
| 8544 | |
| 8545 /** | |
| 8546 * Return the listener to which analysis errors will be reported. | |
| 8547 * | |
| 8548 * @return the listener to which analysis errors will be reported | |
| 8549 */ | |
| 8550 RecordingErrorListener get errorListener => _errorListener; | |
| 8551 | |
| 8552 /** | |
| 8553 * Return an array containing information about all of the libraries that were
resolved. | |
| 8554 * | |
| 8555 * @return an array containing the libraries that were resolved | |
| 8556 */ | |
| 8557 List<ResolvableLibrary> get resolvedLibraries => _librariesInCycle; | |
| 8558 | |
| 8559 /** | |
| 8560 * Resolve the library specified by the given source in the given context. | |
| 8561 * | |
| 8562 * Note that because Dart allows circular imports between libraries, it is pos
sible that more than | |
| 8563 * one library will need to be resolved. In such cases the error listener can
receive errors from | |
| 8564 * multiple libraries. | |
| 8565 * | |
| 8566 * @param librarySource the source specifying the defining compilation unit of
the library to be | |
| 8567 * resolved | |
| 8568 * @param fullAnalysis `true` if a full analysis should be performed | |
| 8569 * @return the element representing the resolved library | |
| 8570 * @throws AnalysisException if the library could not be resolved for some rea
son | |
| 8571 */ | |
| 8572 LibraryElement resolveLibrary( | |
| 8573 Source librarySource, List<ResolvableLibrary> librariesInCycle) { | |
| 8574 // | |
| 8575 // Build the map of libraries that are known. | |
| 8576 // | |
| 8577 this._librariesInCycle = librariesInCycle; | |
| 8578 _libraryMap = _buildLibraryMap(); | |
| 8579 ResolvableLibrary targetLibrary = _libraryMap[librarySource]; | |
| 8580 _coreLibrary = _libraryMap[_coreLibrarySource]; | |
| 8581 _asyncLibrary = _libraryMap[_asyncLibrarySource]; | |
| 8582 // | |
| 8583 // Build the element models representing the libraries being resolved. | |
| 8584 // This is done in three steps: | |
| 8585 // | |
| 8586 // 1. Build the basic element models without making any connections | |
| 8587 // between elements other than the basic parent/child relationships. | |
| 8588 // This includes building the elements representing the libraries, but | |
| 8589 // excludes members defined in enums. | |
| 8590 // 2. Build the elements for the import and export directives. This | |
| 8591 // requires that we have the elements built for the referenced | |
| 8592 // libraries, but because of the possibility of circular references | |
| 8593 // needs to happen after all of the library elements have been created. | |
| 8594 // 3. Build the members in enum declarations. | |
| 8595 // 4. Build the rest of the type model by connecting superclasses, mixins, | |
| 8596 // and interfaces. This requires that we be able to compute the names | |
| 8597 // visible in the libraries being resolved, which in turn requires that | |
| 8598 // we have resolved the import directives. | |
| 8599 // | |
| 8600 _buildElementModels(); | |
| 8601 LibraryElement coreElement = _coreLibrary.libraryElement; | |
| 8602 if (coreElement == null) { | |
| 8603 missingCoreLibrary(analysisContext, _coreLibrarySource); | |
| 8604 } | |
| 8605 LibraryElement asyncElement = _asyncLibrary.libraryElement; | |
| 8606 if (asyncElement == null) { | |
| 8607 missingAsyncLibrary(analysisContext, _asyncLibrarySource); | |
| 8608 } | |
| 8609 _buildDirectiveModels(); | |
| 8610 _typeProvider = new TypeProviderImpl(coreElement, asyncElement); | |
| 8611 _typeSystem = TypeSystem.create(analysisContext); | |
| 8612 _buildEnumMembers(); | |
| 8613 _buildTypeHierarchies(); | |
| 8614 // | |
| 8615 // Perform resolution and type analysis. | |
| 8616 // | |
| 8617 // TODO(brianwilkerson) Decide whether we want to resolve all of the | |
| 8618 // libraries or whether we want to only resolve the target library. The | |
| 8619 // advantage to resolving everything is that we have already done part of | |
| 8620 // the work so we'll avoid duplicated effort. The disadvantage of | |
| 8621 // resolving everything is that we might do extra work that we don't | |
| 8622 // really care about. Another possibility is to add a parameter to this | |
| 8623 // method and punt the decision to the clients. | |
| 8624 // | |
| 8625 //if (analyzeAll) { | |
| 8626 _resolveReferencesAndTypes(); | |
| 8627 //} else { | |
| 8628 // resolveReferencesAndTypes(targetLibrary); | |
| 8629 //} | |
| 8630 _performConstantEvaluation(); | |
| 8631 return targetLibrary.libraryElement; | |
| 8632 } | |
| 8633 | |
| 8634 /** | |
| 8635 * Build the element model representing the combinators declared by the given
directive. | |
| 8636 * | |
| 8637 * @param directive the directive that declares the combinators | |
| 8638 * @return an array containing the import combinators that were built | |
| 8639 */ | |
| 8640 List<NamespaceCombinator> _buildCombinators(NamespaceDirective directive) { | |
| 8641 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>(); | |
| 8642 for (Combinator combinator in directive.combinators) { | |
| 8643 if (combinator is HideCombinator) { | |
| 8644 HideElementCombinatorImpl hide = new HideElementCombinatorImpl(); | |
| 8645 hide.hiddenNames = _getIdentifiers(combinator.hiddenNames); | |
| 8646 combinators.add(hide); | |
| 8647 } else { | |
| 8648 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl(); | |
| 8649 show.offset = combinator.offset; | |
| 8650 show.end = combinator.end; | |
| 8651 show.shownNames = | |
| 8652 _getIdentifiers((combinator as ShowCombinator).shownNames); | |
| 8653 combinators.add(show); | |
| 8654 } | |
| 8655 } | |
| 8656 return combinators; | |
| 8657 } | |
| 8658 | |
| 8659 /** | |
| 8660 * Every library now has a corresponding [LibraryElement], so it is now possib
le to resolve | |
| 8661 * the import and export directives. | |
| 8662 * | |
| 8663 * @throws AnalysisException if the defining compilation unit for any of the l
ibraries could not | |
| 8664 * be accessed | |
| 8665 */ | |
| 8666 void _buildDirectiveModels() { | |
| 8667 for (ResolvableLibrary library in _librariesInCycle) { | |
| 8668 HashMap<String, PrefixElementImpl> nameToPrefixMap = | |
| 8669 new HashMap<String, PrefixElementImpl>(); | |
| 8670 List<ImportElement> imports = new List<ImportElement>(); | |
| 8671 List<ExportElement> exports = new List<ExportElement>(); | |
| 8672 for (Directive directive in library.definingCompilationUnit.directives) { | |
| 8673 if (directive is ImportDirective) { | |
| 8674 ImportDirective importDirective = directive; | |
| 8675 String uriContent = importDirective.uriContent; | |
| 8676 if (DartUriResolver.isDartExtUri(uriContent)) { | |
| 8677 library.libraryElement.hasExtUri = true; | |
| 8678 } | |
| 8679 Source importedSource = importDirective.source; | |
| 8680 if (importedSource != null && | |
| 8681 analysisContext.exists(importedSource)) { | |
| 8682 // The imported source will be null if the URI in the import | |
| 8683 // directive was invalid. | |
| 8684 ResolvableLibrary importedLibrary = _libraryMap[importedSource]; | |
| 8685 if (importedLibrary != null) { | |
| 8686 ImportElementImpl importElement = | |
| 8687 new ImportElementImpl(directive.offset); | |
| 8688 StringLiteral uriLiteral = importDirective.uri; | |
| 8689 if (uriLiteral != null) { | |
| 8690 importElement.uriOffset = uriLiteral.offset; | |
| 8691 importElement.uriEnd = uriLiteral.end; | |
| 8692 } | |
| 8693 importElement.uri = uriContent; | |
| 8694 importElement.deferred = importDirective.deferredKeyword != null; | |
| 8695 importElement.combinators = _buildCombinators(importDirective); | |
| 8696 LibraryElement importedLibraryElement = | |
| 8697 importedLibrary.libraryElement; | |
| 8698 if (importedLibraryElement != null) { | |
| 8699 importElement.importedLibrary = importedLibraryElement; | |
| 8700 } | |
| 8701 SimpleIdentifier prefixNode = directive.prefix; | |
| 8702 if (prefixNode != null) { | |
| 8703 importElement.prefixOffset = prefixNode.offset; | |
| 8704 String prefixName = prefixNode.name; | |
| 8705 PrefixElementImpl prefix = nameToPrefixMap[prefixName]; | |
| 8706 if (prefix == null) { | |
| 8707 prefix = new PrefixElementImpl.forNode(prefixNode); | |
| 8708 nameToPrefixMap[prefixName] = prefix; | |
| 8709 } | |
| 8710 importElement.prefix = prefix; | |
| 8711 prefixNode.staticElement = prefix; | |
| 8712 } | |
| 8713 directive.element = importElement; | |
| 8714 imports.add(importElement); | |
| 8715 if (analysisContext.computeKindOf(importedSource) != | |
| 8716 SourceKind.LIBRARY) { | |
| 8717 ErrorCode errorCode = (importElement.isDeferred | |
| 8718 ? StaticWarningCode.IMPORT_OF_NON_LIBRARY | |
| 8719 : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY); | |
| 8720 _errorListener.onError(new AnalysisError( | |
| 8721 library.librarySource, | |
| 8722 uriLiteral.offset, | |
| 8723 uriLiteral.length, | |
| 8724 errorCode, | |
| 8725 [uriLiteral.toSource()])); | |
| 8726 } | |
| 8727 } | |
| 8728 } | |
| 8729 } else if (directive is ExportDirective) { | |
| 8730 ExportDirective exportDirective = directive; | |
| 8731 Source exportedSource = exportDirective.source; | |
| 8732 if (exportedSource != null && | |
| 8733 analysisContext.exists(exportedSource)) { | |
| 8734 // The exported source will be null if the URI in the export | |
| 8735 // directive was invalid. | |
| 8736 ResolvableLibrary exportedLibrary = _libraryMap[exportedSource]; | |
| 8737 if (exportedLibrary != null) { | |
| 8738 ExportElementImpl exportElement = | |
| 8739 new ExportElementImpl(directive.offset); | |
| 8740 StringLiteral uriLiteral = exportDirective.uri; | |
| 8741 if (uriLiteral != null) { | |
| 8742 exportElement.uriOffset = uriLiteral.offset; | |
| 8743 exportElement.uriEnd = uriLiteral.end; | |
| 8744 } | |
| 8745 exportElement.uri = exportDirective.uriContent; | |
| 8746 exportElement.combinators = _buildCombinators(exportDirective); | |
| 8747 LibraryElement exportedLibraryElement = | |
| 8748 exportedLibrary.libraryElement; | |
| 8749 if (exportedLibraryElement != null) { | |
| 8750 exportElement.exportedLibrary = exportedLibraryElement; | |
| 8751 } | |
| 8752 directive.element = exportElement; | |
| 8753 exports.add(exportElement); | |
| 8754 if (analysisContext.computeKindOf(exportedSource) != | |
| 8755 SourceKind.LIBRARY) { | |
| 8756 _errorListener.onError(new AnalysisError( | |
| 8757 library.librarySource, | |
| 8758 uriLiteral.offset, | |
| 8759 uriLiteral.length, | |
| 8760 CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, | |
| 8761 [uriLiteral.toSource()])); | |
| 8762 } | |
| 8763 } | |
| 8764 } | |
| 8765 } | |
| 8766 } | |
| 8767 Source librarySource = library.librarySource; | |
| 8768 if (!library.explicitlyImportsCore && | |
| 8769 _coreLibrarySource != librarySource) { | |
| 8770 ImportElementImpl importElement = new ImportElementImpl(-1); | |
| 8771 importElement.importedLibrary = _coreLibrary.libraryElement; | |
| 8772 importElement.synthetic = true; | |
| 8773 imports.add(importElement); | |
| 8774 } | |
| 8775 LibraryElementImpl libraryElement = library.libraryElement; | |
| 8776 libraryElement.imports = imports; | |
| 8777 libraryElement.exports = exports; | |
| 8778 if (libraryElement.entryPoint == null) { | |
| 8779 Namespace namespace = new NamespaceBuilder() | |
| 8780 .createExportNamespaceForLibrary(libraryElement); | |
| 8781 Element element = namespace.get(FunctionElement.MAIN_FUNCTION_NAME); | |
| 8782 if (element is FunctionElement) { | |
| 8783 libraryElement.entryPoint = element; | |
| 8784 } | |
| 8785 } | |
| 8786 } | |
| 8787 } | |
| 8788 | |
| 8789 /** | |
| 8790 * Build element models for all of the libraries in the current cycle. | |
| 8791 * | |
| 8792 * @throws AnalysisException if any of the element models cannot be built | |
| 8793 */ | |
| 8794 void _buildElementModels() { | |
| 8795 for (ResolvableLibrary library in _librariesInCycle) { | |
| 8796 LibraryElementBuilder builder = | |
| 8797 new LibraryElementBuilder(analysisContext, errorListener); | |
| 8798 builder.buildLibrary2(library); | |
| 8799 } | |
| 8800 } | |
| 8801 | |
| 8802 /** | |
| 8803 * Build the members in enum declarations. This cannot be done while building
the rest of the | |
| 8804 * element model because it depends on being able to access core types, which
cannot happen until | |
| 8805 * the rest of the element model has been built (when resolving the core libra
ry). | |
| 8806 * | |
| 8807 * @throws AnalysisException if any of the enum members could not be built | |
| 8808 */ | |
| 8809 void _buildEnumMembers() { | |
| 8810 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8811 for (ResolvableLibrary library in _librariesInCycle) { | |
| 8812 for (Source source in library.compilationUnitSources) { | |
| 8813 EnumMemberBuilder builder = new EnumMemberBuilder(_typeProvider); | |
| 8814 library.getAST(source).accept(builder); | |
| 8815 } | |
| 8816 } | |
| 8817 }); | |
| 8818 } | |
| 8819 | |
| 8820 HashMap<Source, ResolvableLibrary> _buildLibraryMap() { | |
| 8821 HashMap<Source, ResolvableLibrary> libraryMap = | |
| 8822 new HashMap<Source, ResolvableLibrary>(); | |
| 8823 int libraryCount = _librariesInCycle.length; | |
| 8824 for (int i = 0; i < libraryCount; i++) { | |
| 8825 ResolvableLibrary library = _librariesInCycle[i]; | |
| 8826 library.errorListener = _errorListener; | |
| 8827 libraryMap[library.librarySource] = library; | |
| 8828 List<ResolvableLibrary> dependencies = library.importsAndExports; | |
| 8829 int dependencyCount = dependencies.length; | |
| 8830 for (int j = 0; j < dependencyCount; j++) { | |
| 8831 ResolvableLibrary dependency = dependencies[j]; | |
| 8832 //dependency.setErrorListener(errorListener); | |
| 8833 libraryMap[dependency.librarySource] = dependency; | |
| 8834 } | |
| 8835 } | |
| 8836 return libraryMap; | |
| 8837 } | |
| 8838 | |
| 8839 /** | |
| 8840 * Resolve the type hierarchy across all of the types declared in the librarie
s in the current | |
| 8841 * cycle. | |
| 8842 * | |
| 8843 * @throws AnalysisException if any of the type hierarchies could not be resol
ved | |
| 8844 */ | |
| 8845 void _buildTypeHierarchies() { | |
| 8846 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8847 for (ResolvableLibrary library in _librariesInCycle) { | |
| 8848 for (ResolvableCompilationUnit unit | |
| 8849 in library.resolvableCompilationUnits) { | |
| 8850 Source source = unit.source; | |
| 8851 CompilationUnit ast = unit.compilationUnit; | |
| 8852 TypeResolverVisitor visitor = new TypeResolverVisitor( | |
| 8853 library.libraryElement, | |
| 8854 source, | |
| 8855 _typeProvider, | |
| 8856 library.libraryScope.errorListener, | |
| 8857 nameScope: library.libraryScope); | |
| 8858 ast.accept(visitor); | |
| 8859 } | |
| 8860 } | |
| 8861 }); | |
| 8862 } | |
| 8863 | |
| 8864 /** | |
| 8865 * Return an array containing the lexical identifiers associated with the node
s in the given list. | |
| 8866 * | |
| 8867 * @param names the AST nodes representing the identifiers | |
| 8868 * @return the lexical identifiers associated with the nodes in the list | |
| 8869 */ | |
| 8870 List<String> _getIdentifiers(NodeList<SimpleIdentifier> names) { | |
| 8871 int count = names.length; | |
| 8872 List<String> identifiers = new List<String>(count); | |
| 8873 for (int i = 0; i < count; i++) { | |
| 8874 identifiers[i] = names[i].name; | |
| 8875 } | |
| 8876 return identifiers; | |
| 8877 } | |
| 8878 | |
| 8879 /** | |
| 8880 * Compute a value for all of the constants in the libraries being analyzed. | |
| 8881 */ | |
| 8882 void _performConstantEvaluation() { | |
| 8883 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8884 ConstantValueComputer computer = new ConstantValueComputer( | |
| 8885 analysisContext, | |
| 8886 _typeProvider, | |
| 8887 analysisContext.declaredVariables, | |
| 8888 null, | |
| 8889 _typeSystem); | |
| 8890 for (ResolvableLibrary library in _librariesInCycle) { | |
| 8891 for (ResolvableCompilationUnit unit | |
| 8892 in library.resolvableCompilationUnits) { | |
| 8893 CompilationUnit ast = unit.compilationUnit; | |
| 8894 if (ast != null) { | |
| 8895 computer.add(ast, unit.source, library.librarySource); | |
| 8896 } | |
| 8897 } | |
| 8898 } | |
| 8899 computer.computeValues(); | |
| 8900 // As a temporary workaround for issue 21572, run ConstantVerifier now. | |
| 8901 // TODO(paulberry): remove this workaround once issue 21572 is fixed. | |
| 8902 for (ResolvableLibrary library in _librariesInCycle) { | |
| 8903 for (ResolvableCompilationUnit unit | |
| 8904 in library.resolvableCompilationUnits) { | |
| 8905 CompilationUnit ast = unit.compilationUnit; | |
| 8906 ErrorReporter errorReporter = | |
| 8907 new ErrorReporter(_errorListener, unit.source); | |
| 8908 ConstantVerifier constantVerifier = new ConstantVerifier( | |
| 8909 errorReporter, | |
| 8910 library.libraryElement, | |
| 8911 _typeProvider, | |
| 8912 analysisContext.declaredVariables); | |
| 8913 ast.accept(constantVerifier); | |
| 8914 } | |
| 8915 } | |
| 8916 }); | |
| 8917 } | |
| 8918 | |
| 8919 /** | |
| 8920 * Resolve the identifiers and perform type analysis in the libraries in the c
urrent cycle. | |
| 8921 * | |
| 8922 * @throws AnalysisException if any of the identifiers could not be resolved o
r if any of the | |
| 8923 * libraries could not have their types analyzed | |
| 8924 */ | |
| 8925 void _resolveReferencesAndTypes() { | |
| 8926 for (ResolvableLibrary library in _librariesInCycle) { | |
| 8927 _resolveReferencesAndTypesInLibrary(library); | |
| 8928 } | |
| 8929 } | |
| 8930 | |
| 8931 /** | |
| 8932 * Resolve the identifiers and perform type analysis in the given library. | |
| 8933 * | |
| 8934 * @param library the library to be resolved | |
| 8935 * @throws AnalysisException if any of the identifiers could not be resolved o
r if the types in | |
| 8936 * the library cannot be analyzed | |
| 8937 */ | |
| 8938 void _resolveReferencesAndTypesInLibrary(ResolvableLibrary library) { | |
| 8939 PerformanceStatistics.resolve.makeCurrentWhile(() { | |
| 8940 for (ResolvableCompilationUnit unit | |
| 8941 in library.resolvableCompilationUnits) { | |
| 8942 Source source = unit.source; | |
| 8943 CompilationUnit ast = unit.compilationUnit; | |
| 8944 ast.accept(new VariableResolverVisitor(library.libraryElement, source, | |
| 8945 _typeProvider, library.libraryScope.errorListener, | |
| 8946 nameScope: library.libraryScope)); | |
| 8947 ResolverVisitor visitor = new ResolverVisitor(library.libraryElement, | |
| 8948 source, _typeProvider, library._libraryScope.errorListener, | |
| 8949 nameScope: library._libraryScope, | |
| 8950 inheritanceManager: library.inheritanceManager); | |
| 8951 ast.accept(visitor); | |
| 8952 } | |
| 8953 }); | |
| 8954 } | |
| 8955 | |
| 8956 /** | |
| 8957 * Report that the async library could not be resolved in the given | |
| 8958 * [analysisContext] and throw an exception. [asyncLibrarySource] is the sour
ce | |
| 8959 * representing the async library. | |
| 8960 */ | |
| 8961 static void missingAsyncLibrary( | |
| 8962 AnalysisContext analysisContext, Source asyncLibrarySource) { | |
| 8963 throw new AnalysisException("Could not resolve dart:async"); | |
| 8964 } | |
| 8965 | |
| 8966 /** | |
| 8967 * Report that the core library could not be resolved in the given analysis co
ntext and throw an | |
| 8968 * exception. | |
| 8969 * | |
| 8970 * @param analysisContext the analysis context in which the failure occurred | |
| 8971 * @param coreLibrarySource the source representing the core library | |
| 8972 * @throws AnalysisException always | |
| 8973 */ | |
| 8974 static void missingCoreLibrary( | |
| 8975 AnalysisContext analysisContext, Source coreLibrarySource) { | |
| 8976 throw new AnalysisException("Could not resolve dart:core"); | |
| 8977 } | |
| 8978 } | |
| 8979 | |
| 8980 /** | |
| 8981 * Instances of the class `LibraryScope` implement a scope containing all of the
names defined | |
| 8982 * in a given library. | |
| 8983 */ | |
| 8984 class LibraryScope extends EnclosedScope { | |
| 8985 /** | |
| 8986 * Initialize a newly created scope representing the names defined in the give
n library. | |
| 8987 * | |
| 8988 * @param definingLibrary the element representing the library represented by
this scope | |
| 8989 * @param errorListener the listener that is to be informed when an error is e
ncountered | |
| 8990 */ | |
| 8991 LibraryScope( | |
| 8992 LibraryElement definingLibrary, AnalysisErrorListener errorListener) | |
| 8993 : super(new LibraryImportScope(definingLibrary, errorListener)) { | |
| 8994 _defineTopLevelNames(definingLibrary); | |
| 8995 } | |
| 8996 | |
| 8997 @override | |
| 8998 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { | |
| 8999 if (existing is PrefixElement) { | |
| 9000 // TODO(scheglov) consider providing actual 'nameOffset' from the | |
| 9001 // synthetic accessor | |
| 9002 int offset = duplicate.nameOffset; | |
| 9003 if (duplicate is PropertyAccessorElement) { | |
| 9004 PropertyAccessorElement accessor = duplicate; | |
| 9005 if (accessor.isSynthetic) { | |
| 9006 offset = accessor.variable.nameOffset; | |
| 9007 } | |
| 9008 } | |
| 9009 return new AnalysisError( | |
| 9010 duplicate.source, | |
| 9011 offset, | |
| 9012 duplicate.nameLength, | |
| 9013 CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER, | |
| 9014 [existing.displayName]); | |
| 9015 } | |
| 9016 return super.getErrorForDuplicate(existing, duplicate); | |
| 9017 } | |
| 9018 | |
| 9019 /** | |
| 9020 * Add to this scope all of the public top-level names that are defined in the
given compilation | |
| 9021 * unit. | |
| 9022 * | |
| 9023 * @param compilationUnit the compilation unit defining the top-level names to
be added to this | |
| 9024 * scope | |
| 9025 */ | |
| 9026 void _defineLocalNames(CompilationUnitElement compilationUnit) { | |
| 9027 for (PropertyAccessorElement element in compilationUnit.accessors) { | |
| 9028 define(element); | |
| 9029 } | |
| 9030 for (ClassElement element in compilationUnit.enums) { | |
| 9031 define(element); | |
| 9032 } | |
| 9033 for (FunctionElement element in compilationUnit.functions) { | |
| 9034 define(element); | |
| 9035 } | |
| 9036 for (FunctionTypeAliasElement element | |
| 9037 in compilationUnit.functionTypeAliases) { | |
| 9038 define(element); | |
| 9039 } | |
| 9040 for (ClassElement element in compilationUnit.types) { | |
| 9041 define(element); | |
| 9042 } | |
| 9043 } | |
| 9044 | |
| 9045 /** | |
| 9046 * Add to this scope all of the names that are explicitly defined in the given
library. | |
| 9047 * | |
| 9048 * @param definingLibrary the element representing the library that defines th
e names in this | |
| 9049 * scope | |
| 9050 */ | |
| 9051 void _defineTopLevelNames(LibraryElement definingLibrary) { | |
| 9052 for (PrefixElement prefix in definingLibrary.prefixes) { | |
| 9053 define(prefix); | |
| 9054 } | |
| 9055 _defineLocalNames(definingLibrary.definingCompilationUnit); | |
| 9056 for (CompilationUnitElement compilationUnit in definingLibrary.parts) { | |
| 9057 _defineLocalNames(compilationUnit); | |
| 9058 } | |
| 9059 } | |
| 9060 } | |
| 9061 | |
| 9062 /** | |
| 9063 * This class is used to replace uses of `HashMap<String, ExecutableElement>` | |
| 9064 * which are not as performant as this class. | |
| 9065 */ | |
| 9066 class MemberMap { | |
| 9067 /** | |
| 9068 * The current size of this map. | |
| 9069 */ | |
| 9070 int _size = 0; | |
| 9071 | |
| 9072 /** | |
| 9073 * The array of keys. | |
| 9074 */ | |
| 9075 List<String> _keys; | |
| 9076 | |
| 9077 /** | |
| 9078 * The array of ExecutableElement values. | |
| 9079 */ | |
| 9080 List<ExecutableElement> _values; | |
| 9081 | |
| 9082 /** | |
| 9083 * Initialize a newly created member map to have the given [initialCapacity]. | |
| 9084 * The map will grow if needed. | |
| 9085 */ | |
| 9086 MemberMap([int initialCapacity = 10]) { | |
| 9087 _initArrays(initialCapacity); | |
| 9088 } | |
| 9089 | |
| 9090 /** | |
| 9091 * This constructor takes an initial capacity of the map. | |
| 9092 * | |
| 9093 * @param initialCapacity the initial capacity | |
| 9094 */ | |
| 9095 @deprecated // Use new MemberMap(initialCapacity) | |
| 9096 MemberMap.con1(int initialCapacity) { | |
| 9097 _initArrays(initialCapacity); | |
| 9098 } | |
| 9099 | |
| 9100 /** | |
| 9101 * Copy constructor. | |
| 9102 */ | |
| 9103 @deprecated // Use new MemberMap.from(memberMap) | |
| 9104 MemberMap.con2(MemberMap memberMap) { | |
| 9105 _initArrays(memberMap._size + 5); | |
| 9106 for (int i = 0; i < memberMap._size; i++) { | |
| 9107 _keys[i] = memberMap._keys[i]; | |
| 9108 _values[i] = memberMap._values[i]; | |
| 9109 } | |
| 9110 _size = memberMap._size; | |
| 9111 } | |
| 9112 | |
| 9113 /** | |
| 9114 * Initialize a newly created member map to contain the same members as the | |
| 9115 * given [memberMap]. | |
| 9116 */ | |
| 9117 MemberMap.from(MemberMap memberMap) { | |
| 9118 _initArrays(memberMap._size + 5); | |
| 9119 for (int i = 0; i < memberMap._size; i++) { | |
| 9120 _keys[i] = memberMap._keys[i]; | |
| 9121 _values[i] = memberMap._values[i]; | |
| 9122 } | |
| 9123 _size = memberMap._size; | |
| 9124 } | |
| 9125 | |
| 9126 /** | |
| 9127 * The size of the map. | |
| 9128 * | |
| 9129 * @return the size of the map. | |
| 9130 */ | |
| 9131 int get size => _size; | |
| 9132 | |
| 9133 /** | |
| 9134 * Given some key, return the ExecutableElement value from the map, if the key
does not exist in | |
| 9135 * the map, `null` is returned. | |
| 9136 * | |
| 9137 * @param key some key to look up in the map | |
| 9138 * @return the associated ExecutableElement value from the map, if the key doe
s not exist in the | |
| 9139 * map, `null` is returned | |
| 9140 */ | |
| 9141 ExecutableElement get(String key) { | |
| 9142 for (int i = 0; i < _size; i++) { | |
| 9143 if (_keys[i] != null && _keys[i] == key) { | |
| 9144 return _values[i]; | |
| 9145 } | |
| 9146 } | |
| 9147 return null; | |
| 9148 } | |
| 9149 | |
| 9150 /** | |
| 9151 * Get and return the key at the specified location. If the key/value pair has
been removed from | |
| 9152 * the set, then `null` is returned. | |
| 9153 * | |
| 9154 * @param i some non-zero value less than size | |
| 9155 * @return the key at the passed index | |
| 9156 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe
d index is less than | |
| 9157 * zero or greater than or equal to the capacity of the arrays | |
| 9158 */ | |
| 9159 String getKey(int i) => _keys[i]; | |
| 9160 | |
| 9161 /** | |
| 9162 * Get and return the ExecutableElement at the specified location. If the key/
value pair has been | |
| 9163 * removed from the set, then then `null` is returned. | |
| 9164 * | |
| 9165 * @param i some non-zero value less than size | |
| 9166 * @return the key at the passed index | |
| 9167 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe
d index is less than | |
| 9168 * zero or greater than or equal to the capacity of the arrays | |
| 9169 */ | |
| 9170 ExecutableElement getValue(int i) => _values[i]; | |
| 9171 | |
| 9172 /** | |
| 9173 * Given some key/value pair, store the pair in the map. If the key exists alr
eady, then the new | |
| 9174 * value overrides the old value. | |
| 9175 * | |
| 9176 * @param key the key to store in the map | |
| 9177 * @param value the ExecutableElement value to store in the map | |
| 9178 */ | |
| 9179 void put(String key, ExecutableElement value) { | |
| 9180 // If we already have a value with this key, override the value | |
| 9181 for (int i = 0; i < _size; i++) { | |
| 9182 if (_keys[i] != null && _keys[i] == key) { | |
| 9183 _values[i] = value; | |
| 9184 return; | |
| 9185 } | |
| 9186 } | |
| 9187 // If needed, double the size of our arrays and copy values over in both | |
| 9188 // arrays | |
| 9189 if (_size == _keys.length) { | |
| 9190 int newArrayLength = _size * 2; | |
| 9191 List<String> keys_new_array = new List<String>(newArrayLength); | |
| 9192 List<ExecutableElement> values_new_array = | |
| 9193 new List<ExecutableElement>(newArrayLength); | |
| 9194 for (int i = 0; i < _size; i++) { | |
| 9195 keys_new_array[i] = _keys[i]; | |
| 9196 } | |
| 9197 for (int i = 0; i < _size; i++) { | |
| 9198 values_new_array[i] = _values[i]; | |
| 9199 } | |
| 9200 _keys = keys_new_array; | |
| 9201 _values = values_new_array; | |
| 9202 } | |
| 9203 // Put new value at end of array | |
| 9204 _keys[_size] = key; | |
| 9205 _values[_size] = value; | |
| 9206 _size++; | |
| 9207 } | |
| 9208 | |
| 9209 /** | |
| 9210 * Given some [String] key, this method replaces the associated key and value
pair with | |
| 9211 * `null`. The size is not decremented with this call, instead it is expected
that the users | |
| 9212 * check for `null`. | |
| 9213 * | |
| 9214 * @param key the key of the key/value pair to remove from the map | |
| 9215 */ | |
| 9216 void remove(String key) { | |
| 9217 for (int i = 0; i < _size; i++) { | |
| 9218 if (_keys[i] == key) { | |
| 9219 _keys[i] = null; | |
| 9220 _values[i] = null; | |
| 9221 return; | |
| 9222 } | |
| 9223 } | |
| 9224 } | |
| 9225 | |
| 9226 /** | |
| 9227 * Sets the ExecutableElement at the specified location. | |
| 9228 * | |
| 9229 * @param i some non-zero value less than size | |
| 9230 * @param value the ExecutableElement value to store in the map | |
| 9231 */ | |
| 9232 void setValue(int i, ExecutableElement value) { | |
| 9233 _values[i] = value; | |
| 9234 } | |
| 9235 | |
| 9236 /** | |
| 9237 * Initializes [keys] and [values]. | |
| 9238 */ | |
| 9239 void _initArrays(int initialCapacity) { | |
| 9240 _keys = new List<String>(initialCapacity); | |
| 9241 _values = new List<ExecutableElement>(initialCapacity); | |
| 9242 } | |
| 9243 } | |
| 9244 | |
| 9245 /** | |
| 9246 * Instances of the class `Namespace` implement a mapping of identifiers to the
elements | |
| 9247 * represented by those identifiers. Namespaces are the building blocks for scop
es. | |
| 9248 */ | |
| 9249 class Namespace { | |
| 9250 /** | |
| 9251 * An empty namespace. | |
| 9252 */ | |
| 9253 static Namespace EMPTY = new Namespace(new HashMap<String, Element>()); | |
| 9254 | |
| 9255 /** | |
| 9256 * A table mapping names that are defined in this namespace to the element rep
resenting the thing | |
| 9257 * declared with that name. | |
| 9258 */ | |
| 9259 final HashMap<String, Element> _definedNames; | |
| 9260 | |
| 9261 /** | |
| 9262 * Initialize a newly created namespace to have the given defined names. | |
| 9263 * | |
| 9264 * @param definedNames the mapping from names that are defined in this namespa
ce to the | |
| 9265 * corresponding elements | |
| 9266 */ | |
| 9267 Namespace(this._definedNames); | |
| 9268 | |
| 9269 /** | |
| 9270 * Return a table containing the same mappings as those defined by this namesp
ace. | |
| 9271 * | |
| 9272 * @return a table containing the same mappings as those defined by this names
pace | |
| 9273 */ | |
| 9274 Map<String, Element> get definedNames => _definedNames; | |
| 9275 | |
| 9276 /** | |
| 9277 * Return the element in this namespace that is available to the containing sc
ope using the given | |
| 9278 * name. | |
| 9279 * | |
| 9280 * @param name the name used to reference the | |
| 9281 * @return the element represented by the given identifier | |
| 9282 */ | |
| 9283 Element get(String name) => _definedNames[name]; | |
| 9284 } | |
| 9285 | |
| 9286 /** | |
| 9287 * Instances of the class `NamespaceBuilder` are used to build a `Namespace`. Na
mespace | |
| 9288 * builders are thread-safe and re-usable. | |
| 9289 */ | |
| 9290 class NamespaceBuilder { | |
| 9291 /** | |
| 9292 * Create a namespace representing the export namespace of the given [ExportEl
ement]. | |
| 9293 * | |
| 9294 * @param element the export element whose export namespace is to be created | |
| 9295 * @return the export namespace that was created | |
| 9296 */ | |
| 9297 Namespace createExportNamespaceForDirective(ExportElement element) { | |
| 9298 LibraryElement exportedLibrary = element.exportedLibrary; | |
| 9299 if (exportedLibrary == null) { | |
| 9300 // | |
| 9301 // The exported library will be null if the URI does not reference a valid | |
| 9302 // library. | |
| 9303 // | |
| 9304 return Namespace.EMPTY; | |
| 9305 } | |
| 9306 HashMap<String, Element> definedNames = | |
| 9307 _createExportMapping(exportedLibrary, new HashSet<LibraryElement>()); | |
| 9308 definedNames = _applyCombinators(definedNames, element.combinators); | |
| 9309 return new Namespace(definedNames); | |
| 9310 } | |
| 9311 | |
| 9312 /** | |
| 9313 * Create a namespace representing the export namespace of the given library. | |
| 9314 * | |
| 9315 * @param library the library whose export namespace is to be created | |
| 9316 * @return the export namespace that was created | |
| 9317 */ | |
| 9318 Namespace createExportNamespaceForLibrary(LibraryElement library) => | |
| 9319 new Namespace( | |
| 9320 _createExportMapping(library, new HashSet<LibraryElement>())); | |
| 9321 | |
| 9322 /** | |
| 9323 * Create a namespace representing the import namespace of the given library. | |
| 9324 * | |
| 9325 * @param library the library whose import namespace is to be created | |
| 9326 * @return the import namespace that was created | |
| 9327 */ | |
| 9328 Namespace createImportNamespaceForDirective(ImportElement element) { | |
| 9329 LibraryElement importedLibrary = element.importedLibrary; | |
| 9330 if (importedLibrary == null) { | |
| 9331 // | |
| 9332 // The imported library will be null if the URI does not reference a valid | |
| 9333 // library. | |
| 9334 // | |
| 9335 return Namespace.EMPTY; | |
| 9336 } | |
| 9337 HashMap<String, Element> definedNames = | |
| 9338 _createExportMapping(importedLibrary, new HashSet<LibraryElement>()); | |
| 9339 definedNames = _applyCombinators(definedNames, element.combinators); | |
| 9340 definedNames = _applyPrefix(definedNames, element.prefix); | |
| 9341 return new Namespace(definedNames); | |
| 9342 } | |
| 9343 | |
| 9344 /** | |
| 9345 * Create a namespace representing the public namespace of the given library. | |
| 9346 * | |
| 9347 * @param library the library whose public namespace is to be created | |
| 9348 * @return the public namespace that was created | |
| 9349 */ | |
| 9350 Namespace createPublicNamespaceForLibrary(LibraryElement library) { | |
| 9351 HashMap<String, Element> definedNames = new HashMap<String, Element>(); | |
| 9352 _addPublicNames(definedNames, library.definingCompilationUnit); | |
| 9353 for (CompilationUnitElement compilationUnit in library.parts) { | |
| 9354 _addPublicNames(definedNames, compilationUnit); | |
| 9355 } | |
| 9356 return new Namespace(definedNames); | |
| 9357 } | |
| 9358 | |
| 9359 /** | |
| 9360 * Add all of the names in the given namespace to the given mapping table. | |
| 9361 * | |
| 9362 * @param definedNames the mapping table to which the names in the given names
pace are to be added | |
| 9363 * @param namespace the namespace containing the names to be added to this nam
espace | |
| 9364 */ | |
| 9365 void _addAllFromNamespace( | |
| 9366 Map<String, Element> definedNames, Namespace namespace) { | |
| 9367 if (namespace != null) { | |
| 9368 definedNames.addAll(namespace.definedNames); | |
| 9369 } | |
| 9370 } | |
| 9371 | |
| 9372 /** | |
| 9373 * Add the given element to the given mapping table if it has a publicly visib
le name. | |
| 9374 * | |
| 9375 * @param definedNames the mapping table to which the public name is to be add
ed | |
| 9376 * @param element the element to be added | |
| 9377 */ | |
| 9378 void _addIfPublic(Map<String, Element> definedNames, Element element) { | |
| 9379 String name = element.name; | |
| 9380 if (name != null && !Scope.isPrivateName(name)) { | |
| 9381 definedNames[name] = element; | |
| 9382 } | |
| 9383 } | |
| 9384 | |
| 9385 /** | |
| 9386 * Add to the given mapping table all of the public top-level names that are d
efined in the given | |
| 9387 * compilation unit. | |
| 9388 * | |
| 9389 * @param definedNames the mapping table to which the public names are to be a
dded | |
| 9390 * @param compilationUnit the compilation unit defining the top-level names to
be added to this | |
| 9391 * namespace | |
| 9392 */ | |
| 9393 void _addPublicNames(Map<String, Element> definedNames, | |
| 9394 CompilationUnitElement compilationUnit) { | |
| 9395 for (PropertyAccessorElement element in compilationUnit.accessors) { | |
| 9396 _addIfPublic(definedNames, element); | |
| 9397 } | |
| 9398 for (ClassElement element in compilationUnit.enums) { | |
| 9399 _addIfPublic(definedNames, element); | |
| 9400 } | |
| 9401 for (FunctionElement element in compilationUnit.functions) { | |
| 9402 _addIfPublic(definedNames, element); | |
| 9403 } | |
| 9404 for (FunctionTypeAliasElement element | |
| 9405 in compilationUnit.functionTypeAliases) { | |
| 9406 _addIfPublic(definedNames, element); | |
| 9407 } | |
| 9408 for (ClassElement element in compilationUnit.types) { | |
| 9409 _addIfPublic(definedNames, element); | |
| 9410 } | |
| 9411 } | |
| 9412 | |
| 9413 /** | |
| 9414 * Apply the given combinators to all of the names in the given mapping table. | |
| 9415 * | |
| 9416 * @param definedNames the mapping table to which the namespace operations are
to be applied | |
| 9417 * @param combinators the combinators to be applied | |
| 9418 */ | |
| 9419 HashMap<String, Element> _applyCombinators( | |
| 9420 HashMap<String, Element> definedNames, | |
| 9421 List<NamespaceCombinator> combinators) { | |
| 9422 for (NamespaceCombinator combinator in combinators) { | |
| 9423 if (combinator is HideElementCombinator) { | |
| 9424 definedNames = _hide(definedNames, combinator.hiddenNames); | |
| 9425 } else if (combinator is ShowElementCombinator) { | |
| 9426 definedNames = _show(definedNames, combinator.shownNames); | |
| 9427 } else { | |
| 9428 // Internal error. | |
| 9429 AnalysisEngine.instance.logger | |
| 9430 .logError("Unknown type of combinator: ${combinator.runtimeType}"); | |
| 9431 } | |
| 9432 } | |
| 9433 return definedNames; | |
| 9434 } | |
| 9435 | |
| 9436 /** | |
| 9437 * Apply the given prefix to all of the names in the table of defined names. | |
| 9438 * | |
| 9439 * @param definedNames the names that were defined before this operation | |
| 9440 * @param prefixElement the element defining the prefix to be added to the nam
es | |
| 9441 */ | |
| 9442 HashMap<String, Element> _applyPrefix( | |
| 9443 HashMap<String, Element> definedNames, PrefixElement prefixElement) { | |
| 9444 if (prefixElement != null) { | |
| 9445 String prefix = prefixElement.name; | |
| 9446 HashMap<String, Element> newNames = new HashMap<String, Element>(); | |
| 9447 definedNames.forEach((String name, Element element) { | |
| 9448 newNames["$prefix.$name"] = element; | |
| 9449 }); | |
| 9450 return newNames; | |
| 9451 } else { | |
| 9452 return definedNames; | |
| 9453 } | |
| 9454 } | |
| 9455 | |
| 9456 /** | |
| 9457 * Create a mapping table representing the export namespace of the given libra
ry. | |
| 9458 * | |
| 9459 * @param library the library whose public namespace is to be created | |
| 9460 * @param visitedElements a set of libraries that do not need to be visited wh
en processing the | |
| 9461 * export directives of the given library because all of the names de
fined by them will | |
| 9462 * be added by another library | |
| 9463 * @return the mapping table that was created | |
| 9464 */ | |
| 9465 HashMap<String, Element> _createExportMapping( | |
| 9466 LibraryElement library, HashSet<LibraryElement> visitedElements) { | |
| 9467 // Check if the export namespace has been already computed. | |
| 9468 { | |
| 9469 Namespace exportNamespace = library.exportNamespace; | |
| 9470 if (exportNamespace != null) { | |
| 9471 return exportNamespace.definedNames; | |
| 9472 } | |
| 9473 } | |
| 9474 // TODO(scheglov) Remove this after switching to the new task model. | |
| 9475 visitedElements.add(library); | |
| 9476 try { | |
| 9477 HashMap<String, Element> definedNames = new HashMap<String, Element>(); | |
| 9478 for (ExportElement element in library.exports) { | |
| 9479 LibraryElement exportedLibrary = element.exportedLibrary; | |
| 9480 if (exportedLibrary != null && | |
| 9481 !visitedElements.contains(exportedLibrary)) { | |
| 9482 // | |
| 9483 // The exported library will be null if the URI does not reference a | |
| 9484 // valid library. | |
| 9485 // | |
| 9486 HashMap<String, Element> exportedNames = | |
| 9487 _createExportMapping(exportedLibrary, visitedElements); | |
| 9488 exportedNames = _applyCombinators(exportedNames, element.combinators); | |
| 9489 definedNames.addAll(exportedNames); | |
| 9490 } | |
| 9491 } | |
| 9492 _addAllFromNamespace( | |
| 9493 definedNames, | |
| 9494 (library.context as InternalAnalysisContext) | |
| 9495 .getPublicNamespace(library)); | |
| 9496 return definedNames; | |
| 9497 } finally { | |
| 9498 visitedElements.remove(library); | |
| 9499 } | |
| 9500 } | |
| 9501 | |
| 9502 /** | |
| 9503 * Return a new map of names which has all the names from [definedNames] | |
| 9504 * with exception of [hiddenNames]. | |
| 9505 */ | |
| 9506 Map<String, Element> _hide( | |
| 9507 HashMap<String, Element> definedNames, List<String> hiddenNames) { | |
| 9508 HashMap<String, Element> newNames = | |
| 9509 new HashMap<String, Element>.from(definedNames); | |
| 9510 for (String name in hiddenNames) { | |
| 9511 newNames.remove(name); | |
| 9512 newNames.remove("$name="); | |
| 9513 } | |
| 9514 return newNames; | |
| 9515 } | |
| 9516 | |
| 9517 /** | |
| 9518 * Return a new map of names which has only [shownNames] from [definedNames]. | |
| 9519 */ | |
| 9520 HashMap<String, Element> _show( | |
| 9521 HashMap<String, Element> definedNames, List<String> shownNames) { | |
| 9522 HashMap<String, Element> newNames = new HashMap<String, Element>(); | |
| 9523 for (String name in shownNames) { | |
| 9524 Element element = definedNames[name]; | |
| 9525 if (element != null) { | |
| 9526 newNames[name] = element; | |
| 9527 } | |
| 9528 String setterName = "$name="; | |
| 9529 element = definedNames[setterName]; | |
| 9530 if (element != null) { | |
| 9531 newNames[setterName] = element; | |
| 9532 } | |
| 9533 } | |
| 9534 return newNames; | |
| 9535 } | 5185 } |
| 9536 } | 5186 } |
| 9537 | 5187 |
| 9538 /** | 5188 /** |
| 9539 * Instances of the class `OverrideVerifier` visit all of the declarations in a
compilation | 5189 * Instances of the class `OverrideVerifier` visit all of the declarations in a
compilation |
| 9540 * unit to verify that if they have an override annotation it is being used corr
ectly. | 5190 * unit to verify that if they have an override annotation it is being used corr
ectly. |
| 9541 */ | 5191 */ |
| 9542 class OverrideVerifier extends RecursiveAstVisitor<Object> { | 5192 class OverrideVerifier extends RecursiveAstVisitor { |
| 9543 /** | 5193 /** |
| 9544 * The error reporter used to report errors. | 5194 * The error reporter used to report errors. |
| 9545 */ | 5195 */ |
| 9546 final ErrorReporter _errorReporter; | 5196 final ErrorReporter _errorReporter; |
| 9547 | 5197 |
| 9548 /** | 5198 /** |
| 9549 * The inheritance manager used to find overridden methods. | 5199 * The inheritance manager used to find overridden methods. |
| 9550 */ | 5200 */ |
| 9551 final InheritanceManager _manager; | 5201 final InheritanceManager _manager; |
| 9552 | 5202 |
| 9553 /** | 5203 /** |
| 9554 * Initialize a newly created verifier to look for inappropriate uses of the o
verride annotation. | 5204 * Initialize a newly created verifier to look for inappropriate uses of the o
verride annotation. |
| 9555 * | 5205 * |
| 9556 * @param errorReporter the error reporter used to report errors | 5206 * @param errorReporter the error reporter used to report errors |
| 9557 * @param manager the inheritance manager used to find overridden methods | 5207 * @param manager the inheritance manager used to find overridden methods |
| 9558 */ | 5208 */ |
| 9559 OverrideVerifier(this._errorReporter, this._manager); | 5209 OverrideVerifier(this._errorReporter, this._manager); |
| 9560 | 5210 |
| 9561 @override | 5211 @override |
| 9562 Object visitMethodDeclaration(MethodDeclaration node) { | 5212 visitFieldDeclaration(FieldDeclaration node) { |
| 5213 for (VariableDeclaration field in node.fields.variables) { |
| 5214 VariableElement fieldElement = field.element; |
| 5215 if (fieldElement is FieldElement && _isOverride(fieldElement)) { |
| 5216 PropertyAccessorElement getter = fieldElement.getter; |
| 5217 PropertyAccessorElement setter = fieldElement.setter; |
| 5218 if (!(getter != null && _getOverriddenMember(getter) != null || |
| 5219 setter != null && _getOverriddenMember(setter) != null)) { |
| 5220 _errorReporter.reportErrorForNode( |
| 5221 HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD, field.name); |
| 5222 } |
| 5223 } |
| 5224 } |
| 5225 } |
| 5226 |
| 5227 @override |
| 5228 visitMethodDeclaration(MethodDeclaration node) { |
| 9563 ExecutableElement element = node.element; | 5229 ExecutableElement element = node.element; |
| 9564 if (_isOverride(element)) { | 5230 if (_isOverride(element)) { |
| 9565 if (_getOverriddenMember(element) == null) { | 5231 if (_getOverriddenMember(element) == null) { |
| 9566 if (element is MethodElement) { | 5232 if (element is MethodElement) { |
| 9567 _errorReporter.reportErrorForNode( | 5233 _errorReporter.reportErrorForNode( |
| 9568 HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name); | 5234 HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name); |
| 9569 } else if (element is PropertyAccessorElement) { | 5235 } else if (element is PropertyAccessorElement) { |
| 9570 if (element.isGetter) { | 5236 if (element.isGetter) { |
| 9571 _errorReporter.reportErrorForNode( | 5237 _errorReporter.reportErrorForNode( |
| 9572 HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER, node.name); | 5238 HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER, node.name); |
| 9573 } else { | 5239 } else { |
| 9574 _errorReporter.reportErrorForNode( | 5240 _errorReporter.reportErrorForNode( |
| 9575 HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER, node.name); | 5241 HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER, node.name); |
| 9576 } | 5242 } |
| 9577 } | 5243 } |
| 9578 } | 5244 } |
| 9579 } | 5245 } |
| 9580 return super.visitMethodDeclaration(node); | |
| 9581 } | 5246 } |
| 9582 | 5247 |
| 9583 /** | 5248 /** |
| 9584 * Return the member that overrides the given member. | 5249 * Return the member that overrides the given member. |
| 9585 * | 5250 * |
| 9586 * @param member the member that overrides the returned member | 5251 * @param member the member that overrides the returned member |
| 9587 * @return the member that overrides the given member | 5252 * @return the member that overrides the given member |
| 9588 */ | 5253 */ |
| 9589 ExecutableElement _getOverriddenMember(ExecutableElement member) { | 5254 ExecutableElement _getOverriddenMember(ExecutableElement member) { |
| 9590 LibraryElement library = member.library; | 5255 LibraryElement library = member.library; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 9608 bool _isOverride(Element element) => element != null && element.isOverride; | 5273 bool _isOverride(Element element) => element != null && element.isOverride; |
| 9609 } | 5274 } |
| 9610 | 5275 |
| 9611 /** | 5276 /** |
| 9612 * An AST visitor that is used to resolve the some of the nodes within a single | 5277 * An AST visitor that is used to resolve the some of the nodes within a single |
| 9613 * compilation unit. The nodes that are skipped are those that are within | 5278 * compilation unit. The nodes that are skipped are those that are within |
| 9614 * function bodies. | 5279 * function bodies. |
| 9615 */ | 5280 */ |
| 9616 class PartialResolverVisitor extends ResolverVisitor { | 5281 class PartialResolverVisitor extends ResolverVisitor { |
| 9617 /** | 5282 /** |
| 9618 * A flag indicating whether the resolver is being run in strong mode. | |
| 9619 */ | |
| 9620 final bool strongMode; | |
| 9621 | |
| 9622 /** | |
| 9623 * The static variables and fields that have an initializer. These are the | 5283 * The static variables and fields that have an initializer. These are the |
| 9624 * variables that need to be re-resolved after static variables have their | 5284 * variables that need to be re-resolved after static variables have their |
| 9625 * types inferred. A subset of these variables are those whose types should | 5285 * types inferred. A subset of these variables are those whose types should |
| 9626 * be inferred. The list will be empty unless the resolver is being run in | 5286 * be inferred. |
| 9627 * strong mode. | 5287 */ |
| 9628 */ | 5288 final List<VariableElement> staticVariables = <VariableElement>[]; |
| 9629 final List<VariableElement> variablesAndFields = <VariableElement>[]; | |
| 9630 | |
| 9631 /** | |
| 9632 * A flag indicating whether we should discard errors while resolving the | |
| 9633 * initializer for variable declarations. We do this for top-level variables | |
| 9634 * and fields because their initializer will be re-resolved at a later time. | |
| 9635 */ | |
| 9636 bool discardErrorsInInitializer = false; | |
| 9637 | 5289 |
| 9638 /** | 5290 /** |
| 9639 * Initialize a newly created visitor to resolve the nodes in an AST node. | 5291 * Initialize a newly created visitor to resolve the nodes in an AST node. |
| 9640 * | 5292 * |
| 9641 * The [definingLibrary] is the element for the library containing the node | 5293 * The [definingLibrary] is the element for the library containing the node |
| 9642 * being visited. The [source] is the source representing the compilation unit | 5294 * being visited. The [source] is the source representing the compilation unit |
| 9643 * containing the node being visited. The [typeProvider] is the object used to | 5295 * containing the node being visited. The [typeProvider] is the object used to |
| 9644 * access the types from the core library. The [errorListener] is the error | 5296 * access the types from the core library. The [errorListener] is the error |
| 9645 * listener that will be informed of any errors that are found during | 5297 * listener that will be informed of any errors that are found during |
| 9646 * resolution. The [nameScope] is the scope used to resolve identifiers in the | 5298 * resolution. The [nameScope] is the scope used to resolve identifiers in the |
| 9647 * node that will first be visited. If `null` or unspecified, a new | 5299 * node that will first be visited. If `null` or unspecified, a new |
| 9648 * [LibraryScope] will be created based on [definingLibrary] and | 5300 * [LibraryScope] will be created based on [definingLibrary] and |
| 9649 * [typeProvider]. The [inheritanceManager] is used to perform inheritance | 5301 * [typeProvider]. The [inheritanceManager] is used to perform inheritance |
| 9650 * lookups. If `null` or unspecified, a new [InheritanceManager] will be | 5302 * lookups. If `null` or unspecified, a new [InheritanceManager] will be |
| 9651 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to | 5303 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to |
| 9652 * create the type analyzer. If `null` or unspecified, a type analyzer of | 5304 * create the type analyzer. If `null` or unspecified, a type analyzer of |
| 9653 * type [StaticTypeAnalyzer] will be created. | 5305 * type [StaticTypeAnalyzer] will be created. |
| 9654 */ | 5306 */ |
| 9655 PartialResolverVisitor(LibraryElement definingLibrary, Source source, | 5307 PartialResolverVisitor(LibraryElement definingLibrary, Source source, |
| 9656 TypeProvider typeProvider, AnalysisErrorListener errorListener, | 5308 TypeProvider typeProvider, AnalysisErrorListener errorListener, |
| 9657 {Scope nameScope, | 5309 {Scope nameScope}) |
| 9658 InheritanceManager inheritanceManager, | 5310 : super(definingLibrary, source, typeProvider, errorListener, |
| 9659 StaticTypeAnalyzerFactory typeAnalyzerFactory}) | 5311 nameScope: nameScope); |
| 9660 : strongMode = definingLibrary.context.analysisOptions.strongMode, | |
| 9661 super(definingLibrary, source, typeProvider, | |
| 9662 new DisablableErrorListener(errorListener)); | |
| 9663 | 5312 |
| 9664 @override | 5313 @override |
| 9665 Object visitBlockFunctionBody(BlockFunctionBody node) { | 5314 Object visitBlockFunctionBody(BlockFunctionBody node) { |
| 9666 if (_shouldBeSkipped(node)) { | 5315 if (_shouldBeSkipped(node)) { |
| 9667 return null; | 5316 return null; |
| 9668 } | 5317 } |
| 9669 return super.visitBlockFunctionBody(node); | 5318 return super.visitBlockFunctionBody(node); |
| 9670 } | 5319 } |
| 9671 | 5320 |
| 9672 @override | 5321 @override |
| 9673 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { | 5322 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 9674 if (_shouldBeSkipped(node)) { | 5323 if (_shouldBeSkipped(node)) { |
| 9675 return null; | 5324 return null; |
| 9676 } | 5325 } |
| 9677 return super.visitExpressionFunctionBody(node); | 5326 return super.visitExpressionFunctionBody(node); |
| 9678 } | 5327 } |
| 9679 | 5328 |
| 9680 @override | 5329 @override |
| 9681 Object visitFieldDeclaration(FieldDeclaration node) { | 5330 Object visitFieldDeclaration(FieldDeclaration node) { |
| 9682 if (strongMode && node.isStatic) { | 5331 if (node.isStatic) { |
| 9683 _addVariables(node.fields.variables); | 5332 _addStaticVariables(node.fields.variables); |
| 9684 bool wasDiscarding = discardErrorsInInitializer; | |
| 9685 discardErrorsInInitializer = true; | |
| 9686 try { | |
| 9687 return super.visitFieldDeclaration(node); | |
| 9688 } finally { | |
| 9689 discardErrorsInInitializer = wasDiscarding; | |
| 9690 } | |
| 9691 } | 5333 } |
| 9692 return super.visitFieldDeclaration(node); | 5334 return super.visitFieldDeclaration(node); |
| 9693 } | 5335 } |
| 9694 | 5336 |
| 9695 @override | 5337 @override |
| 9696 Object visitNode(AstNode node) { | 5338 Object visitNode(AstNode node) { |
| 9697 if (discardErrorsInInitializer) { | |
| 9698 AstNode parent = node.parent; | |
| 9699 if (parent is VariableDeclaration && parent.initializer == node) { | |
| 9700 DisablableErrorListener listener = errorListener; | |
| 9701 return listener.disableWhile(() => super.visitNode(node)); | |
| 9702 } | |
| 9703 } | |
| 9704 return super.visitNode(node); | 5339 return super.visitNode(node); |
| 9705 } | 5340 } |
| 9706 | 5341 |
| 9707 @override | 5342 @override |
| 9708 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | 5343 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 9709 if (strongMode) { | 5344 _addStaticVariables(node.variables.variables); |
| 9710 _addVariables(node.variables.variables); | |
| 9711 bool wasDiscarding = discardErrorsInInitializer; | |
| 9712 discardErrorsInInitializer = true; | |
| 9713 try { | |
| 9714 return super.visitTopLevelVariableDeclaration(node); | |
| 9715 } finally { | |
| 9716 discardErrorsInInitializer = wasDiscarding; | |
| 9717 } | |
| 9718 } | |
| 9719 return super.visitTopLevelVariableDeclaration(node); | 5345 return super.visitTopLevelVariableDeclaration(node); |
| 9720 } | 5346 } |
| 9721 | 5347 |
| 9722 /** | 5348 /** |
| 9723 * Add all of the [variables] with initializers to the list of variables whose | 5349 * Add all of the [variables] with initializers to the list of variables whose |
| 9724 * type can be inferred. Technically, we only infer the types of variables | 5350 * type can be inferred. Technically, we only infer the types of variables |
| 9725 * that do not have a static type, but all variables with initializers | 5351 * that do not have a static type, but all variables with initializers |
| 9726 * potentially need to be re-resolved after inference because they might | 5352 * potentially need to be re-resolved after inference because they might |
| 9727 * refer to a field whose type was inferred. | 5353 * refer to a field whose type was inferred. |
| 9728 */ | 5354 */ |
| 9729 void _addVariables(NodeList<VariableDeclaration> variables) { | 5355 void _addStaticVariables(List<VariableDeclaration> variables) { |
| 9730 for (VariableDeclaration variable in variables) { | 5356 int length = variables.length; |
| 9731 if (variable.initializer != null) { | 5357 for (int i = 0; i < length; i++) { |
| 9732 variablesAndFields.add(variable.element); | 5358 VariableDeclaration variable = variables[i]; |
| 5359 if (variable.name.name.isNotEmpty && variable.initializer != null) { |
| 5360 staticVariables.add(variable.element); |
| 9733 } | 5361 } |
| 9734 } | 5362 } |
| 9735 } | 5363 } |
| 9736 | 5364 |
| 9737 /** | 5365 /** |
| 9738 * Return `true` if the given function body should be skipped because it is | 5366 * Return `true` if the given function body should be skipped because it is |
| 9739 * the body of a top-level function, method or constructor. | 5367 * the body of a top-level function, method or constructor. |
| 9740 */ | 5368 */ |
| 9741 bool _shouldBeSkipped(FunctionBody body) { | 5369 bool _shouldBeSkipped(FunctionBody body) { |
| 9742 AstNode parent = body.parent; | 5370 AstNode parent = body.parent; |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9947 // return fullName.replaceAll(r'\', '/'); | 5575 // return fullName.replaceAll(r'\', '/'); |
| 9948 // } | 5576 // } |
| 9949 // } | 5577 // } |
| 9950 // return null; | 5578 // return null; |
| 9951 // } | 5579 // } |
| 9952 } | 5580 } |
| 9953 | 5581 |
| 9954 /** | 5582 /** |
| 9955 * Kind of the redirecting constructor. | 5583 * Kind of the redirecting constructor. |
| 9956 */ | 5584 */ |
| 9957 class RedirectingConstructorKind extends Enum<RedirectingConstructorKind> { | 5585 class RedirectingConstructorKind |
| 5586 implements Comparable<RedirectingConstructorKind> { |
| 9958 static const RedirectingConstructorKind CONST = | 5587 static const RedirectingConstructorKind CONST = |
| 9959 const RedirectingConstructorKind('CONST', 0); | 5588 const RedirectingConstructorKind('CONST', 0); |
| 9960 | 5589 |
| 9961 static const RedirectingConstructorKind NORMAL = | 5590 static const RedirectingConstructorKind NORMAL = |
| 9962 const RedirectingConstructorKind('NORMAL', 1); | 5591 const RedirectingConstructorKind('NORMAL', 1); |
| 9963 | 5592 |
| 9964 static const List<RedirectingConstructorKind> values = const [CONST, NORMAL]; | 5593 static const List<RedirectingConstructorKind> values = const [CONST, NORMAL]; |
| 9965 | 5594 |
| 9966 const RedirectingConstructorKind(String name, int ordinal) | 5595 /** |
| 9967 : super(name, ordinal); | 5596 * The name of this redirecting constructor kind. |
| 5597 */ |
| 5598 final String name; |
| 5599 |
| 5600 /** |
| 5601 * The ordinal value of the redirecting constructor kind. |
| 5602 */ |
| 5603 final int ordinal; |
| 5604 |
| 5605 const RedirectingConstructorKind(this.name, this.ordinal); |
| 5606 |
| 5607 @override |
| 5608 int get hashCode => ordinal; |
| 5609 |
| 5610 @override |
| 5611 int compareTo(RedirectingConstructorKind other) => ordinal - other.ordinal; |
| 5612 |
| 5613 @override |
| 5614 String toString() => name; |
| 9968 } | 5615 } |
| 9969 | 5616 |
| 9970 /** | 5617 /** |
| 9971 * A `ResolvableLibrary` represents a single library during the resolution of | |
| 9972 * some (possibly different) library. They are not intended to be used except | |
| 9973 * during the resolution process. | |
| 9974 */ | |
| 9975 class ResolvableLibrary { | |
| 9976 /** | |
| 9977 * An empty array that can be used to initialize lists of libraries. | |
| 9978 */ | |
| 9979 static List<ResolvableLibrary> _EMPTY_ARRAY = new List<ResolvableLibrary>(0); | |
| 9980 | |
| 9981 /** | |
| 9982 * The next artificial hash code. | |
| 9983 */ | |
| 9984 static int _NEXT_HASH_CODE = 0; | |
| 9985 | |
| 9986 /** | |
| 9987 * The artifitial hash code for this object. | |
| 9988 */ | |
| 9989 final int _hashCode = _nextHashCode(); | |
| 9990 | |
| 9991 /** | |
| 9992 * The source specifying the defining compilation unit of this library. | |
| 9993 */ | |
| 9994 final Source librarySource; | |
| 9995 | |
| 9996 /** | |
| 9997 * A list containing all of the libraries that are imported into this library. | |
| 9998 */ | |
| 9999 List<ResolvableLibrary> _importedLibraries = _EMPTY_ARRAY; | |
| 10000 | |
| 10001 /** | |
| 10002 * A flag indicating whether this library explicitly imports core. | |
| 10003 */ | |
| 10004 bool explicitlyImportsCore = false; | |
| 10005 | |
| 10006 /** | |
| 10007 * An array containing all of the libraries that are exported from this librar
y. | |
| 10008 */ | |
| 10009 List<ResolvableLibrary> _exportedLibraries = _EMPTY_ARRAY; | |
| 10010 | |
| 10011 /** | |
| 10012 * An array containing the compilation units that comprise this library. The | |
| 10013 * defining compilation unit is always first. | |
| 10014 */ | |
| 10015 List<ResolvableCompilationUnit> _compilationUnits; | |
| 10016 | |
| 10017 /** | |
| 10018 * The library element representing this library. | |
| 10019 */ | |
| 10020 LibraryElementImpl _libraryElement; | |
| 10021 | |
| 10022 /** | |
| 10023 * The listener to which analysis errors will be reported. | |
| 10024 */ | |
| 10025 AnalysisErrorListener _errorListener; | |
| 10026 | |
| 10027 /** | |
| 10028 * The inheritance manager which is used for member lookups in this library. | |
| 10029 */ | |
| 10030 InheritanceManager _inheritanceManager; | |
| 10031 | |
| 10032 /** | |
| 10033 * The library scope used when resolving elements within this library's compil
ation units. | |
| 10034 */ | |
| 10035 LibraryScope _libraryScope; | |
| 10036 | |
| 10037 /** | |
| 10038 * Initialize a newly created data holder that can maintain the data associate
d with a library. | |
| 10039 * | |
| 10040 * @param librarySource the source specifying the defining compilation unit of
this library | |
| 10041 * @param errorListener the listener to which analysis errors will be reported | |
| 10042 */ | |
| 10043 ResolvableLibrary(this.librarySource); | |
| 10044 | |
| 10045 /** | |
| 10046 * Return an array of the [CompilationUnit]s that make up the library. The fir
st unit is | |
| 10047 * always the defining unit. | |
| 10048 * | |
| 10049 * @return an array of the [CompilationUnit]s that make up the library. The fi
rst unit is | |
| 10050 * always the defining unit | |
| 10051 */ | |
| 10052 List<CompilationUnit> get compilationUnits { | |
| 10053 int count = _compilationUnits.length; | |
| 10054 List<CompilationUnit> units = new List<CompilationUnit>(count); | |
| 10055 for (int i = 0; i < count; i++) { | |
| 10056 units[i] = _compilationUnits[i].compilationUnit; | |
| 10057 } | |
| 10058 return units; | |
| 10059 } | |
| 10060 | |
| 10061 /** | |
| 10062 * Return an array containing the sources for the compilation units in this li
brary, including the | |
| 10063 * defining compilation unit. | |
| 10064 * | |
| 10065 * @return the sources for the compilation units in this library | |
| 10066 */ | |
| 10067 List<Source> get compilationUnitSources { | |
| 10068 int count = _compilationUnits.length; | |
| 10069 List<Source> sources = new List<Source>(count); | |
| 10070 for (int i = 0; i < count; i++) { | |
| 10071 sources[i] = _compilationUnits[i].source; | |
| 10072 } | |
| 10073 return sources; | |
| 10074 } | |
| 10075 | |
| 10076 /** | |
| 10077 * Return the AST structure associated with the defining compilation unit for
this library. | |
| 10078 * | |
| 10079 * @return the AST structure associated with the defining compilation unit for
this library | |
| 10080 * @throws AnalysisException if an AST structure could not be created for the
defining compilation | |
| 10081 * unit | |
| 10082 */ | |
| 10083 CompilationUnit get definingCompilationUnit => | |
| 10084 _compilationUnits[0].compilationUnit; | |
| 10085 | |
| 10086 /** | |
| 10087 * Set the listener to which analysis errors will be reported to be the given
listener. | |
| 10088 * | |
| 10089 * @param errorListener the listener to which analysis errors will be reported | |
| 10090 */ | |
| 10091 void set errorListener(AnalysisErrorListener errorListener) { | |
| 10092 this._errorListener = errorListener; | |
| 10093 } | |
| 10094 | |
| 10095 /** | |
| 10096 * Set the libraries that are exported by this library to be those in the give
n array. | |
| 10097 * | |
| 10098 * @param exportedLibraries the libraries that are exported by this library | |
| 10099 */ | |
| 10100 void set exportedLibraries(List<ResolvableLibrary> exportedLibraries) { | |
| 10101 this._exportedLibraries = exportedLibraries; | |
| 10102 } | |
| 10103 | |
| 10104 /** | |
| 10105 * Return an array containing the libraries that are exported from this librar
y. | |
| 10106 * | |
| 10107 * @return an array containing the libraries that are exported from this libra
ry | |
| 10108 */ | |
| 10109 List<ResolvableLibrary> get exports => _exportedLibraries; | |
| 10110 | |
| 10111 @override | |
| 10112 int get hashCode => _hashCode; | |
| 10113 | |
| 10114 /** | |
| 10115 * Set the libraries that are imported into this library to be those in the gi
ven array. | |
| 10116 * | |
| 10117 * @param importedLibraries the libraries that are imported into this library | |
| 10118 */ | |
| 10119 void set importedLibraries(List<ResolvableLibrary> importedLibraries) { | |
| 10120 this._importedLibraries = importedLibraries; | |
| 10121 } | |
| 10122 | |
| 10123 /** | |
| 10124 * Return an array containing the libraries that are imported into this librar
y. | |
| 10125 * | |
| 10126 * @return an array containing the libraries that are imported into this libra
ry | |
| 10127 */ | |
| 10128 List<ResolvableLibrary> get imports => _importedLibraries; | |
| 10129 | |
| 10130 /** | |
| 10131 * Return an array containing the libraries that are either imported or export
ed from this | |
| 10132 * library. | |
| 10133 * | |
| 10134 * @return the libraries that are either imported or exported from this librar
y | |
| 10135 */ | |
| 10136 List<ResolvableLibrary> get importsAndExports { | |
| 10137 HashSet<ResolvableLibrary> libraries = new HashSet<ResolvableLibrary>(); | |
| 10138 for (ResolvableLibrary library in _importedLibraries) { | |
| 10139 libraries.add(library); | |
| 10140 } | |
| 10141 for (ResolvableLibrary library in _exportedLibraries) { | |
| 10142 libraries.add(library); | |
| 10143 } | |
| 10144 return new List.from(libraries); | |
| 10145 } | |
| 10146 | |
| 10147 /** | |
| 10148 * Return the inheritance manager for this library. | |
| 10149 * | |
| 10150 * @return the inheritance manager for this library | |
| 10151 */ | |
| 10152 InheritanceManager get inheritanceManager { | |
| 10153 if (_inheritanceManager == null) { | |
| 10154 return _inheritanceManager = new InheritanceManager(_libraryElement); | |
| 10155 } | |
| 10156 return _inheritanceManager; | |
| 10157 } | |
| 10158 | |
| 10159 /** | |
| 10160 * Return the library element representing this library, creating it if necess
ary. | |
| 10161 * | |
| 10162 * @return the library element representing this library | |
| 10163 */ | |
| 10164 LibraryElementImpl get libraryElement => _libraryElement; | |
| 10165 | |
| 10166 /** | |
| 10167 * Set the library element representing this library to the given library elem
ent. | |
| 10168 * | |
| 10169 * @param libraryElement the library element representing this library | |
| 10170 */ | |
| 10171 void set libraryElement(LibraryElementImpl libraryElement) { | |
| 10172 this._libraryElement = libraryElement; | |
| 10173 if (_inheritanceManager != null) { | |
| 10174 _inheritanceManager.libraryElement = libraryElement; | |
| 10175 } | |
| 10176 } | |
| 10177 | |
| 10178 /** | |
| 10179 * Return the library scope used when resolving elements within this library's
compilation units. | |
| 10180 * | |
| 10181 * @return the library scope used when resolving elements within this library'
s compilation units | |
| 10182 */ | |
| 10183 LibraryScope get libraryScope { | |
| 10184 if (_libraryScope == null) { | |
| 10185 _libraryScope = new LibraryScope(_libraryElement, _errorListener); | |
| 10186 } | |
| 10187 return _libraryScope; | |
| 10188 } | |
| 10189 | |
| 10190 /** | |
| 10191 * Return an array containing the compilation units that comprise this library
. The defining | |
| 10192 * compilation unit is always first. | |
| 10193 * | |
| 10194 * @return the compilation units that comprise this library | |
| 10195 */ | |
| 10196 List<ResolvableCompilationUnit> get resolvableCompilationUnits => | |
| 10197 _compilationUnits; | |
| 10198 | |
| 10199 /** | |
| 10200 * Set the compilation unit in this library to the given compilation units. Th
e defining | |
| 10201 * compilation unit must be the first element of the array. | |
| 10202 * | |
| 10203 * @param units the compilation units in this library | |
| 10204 */ | |
| 10205 void set resolvableCompilationUnits(List<ResolvableCompilationUnit> units) { | |
| 10206 _compilationUnits = units; | |
| 10207 } | |
| 10208 | |
| 10209 /** | |
| 10210 * Return the AST structure associated with the given source, or `null` if the
source does | |
| 10211 * not represent a compilation unit that is included in this library. | |
| 10212 * | |
| 10213 * @param source the source representing the compilation unit whose AST is to
be returned | |
| 10214 * @return the AST structure associated with the given source | |
| 10215 * @throws AnalysisException if an AST structure could not be created for the
compilation unit | |
| 10216 */ | |
| 10217 CompilationUnit getAST(Source source) { | |
| 10218 int count = _compilationUnits.length; | |
| 10219 for (int i = 0; i < count; i++) { | |
| 10220 if (_compilationUnits[i].source == source) { | |
| 10221 return _compilationUnits[i].compilationUnit; | |
| 10222 } | |
| 10223 } | |
| 10224 return null; | |
| 10225 } | |
| 10226 | |
| 10227 @override | |
| 10228 String toString() => librarySource.shortName; | |
| 10229 | |
| 10230 static int _nextHashCode() { | |
| 10231 int next = (_NEXT_HASH_CODE + 1) & 0xFFFFFF; | |
| 10232 _NEXT_HASH_CODE = next; | |
| 10233 return next; | |
| 10234 } | |
| 10235 } | |
| 10236 | |
| 10237 /** | |
| 10238 * The enumeration `ResolverErrorCode` defines the error codes used for errors | 5618 * The enumeration `ResolverErrorCode` defines the error codes used for errors |
| 10239 * detected by the resolver. The convention for this class is for the name of | 5619 * detected by the resolver. The convention for this class is for the name of |
| 10240 * the error code to indicate the problem that caused the error to be generated | 5620 * the error code to indicate the problem that caused the error to be generated |
| 10241 * and for the error message to explain what is wrong and, when appropriate, how | 5621 * and for the error message to explain what is wrong and, when appropriate, how |
| 10242 * the problem can be corrected. | 5622 * the problem can be corrected. |
| 10243 */ | 5623 */ |
| 10244 class ResolverErrorCode extends ErrorCode { | 5624 class ResolverErrorCode extends ErrorCode { |
| 10245 static const ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER = | 5625 static const ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER = |
| 10246 const ResolverErrorCode('BREAK_LABEL_ON_SWITCH_MEMBER', | 5626 const ResolverErrorCode('BREAK_LABEL_ON_SWITCH_MEMBER', |
| 10247 "Break label resolves to case or default statement"); | 5627 "Break label resolves to case or default statement"); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 10269 @override | 5649 @override |
| 10270 ErrorType get type => ErrorType.COMPILE_TIME_ERROR; | 5650 ErrorType get type => ErrorType.COMPILE_TIME_ERROR; |
| 10271 } | 5651 } |
| 10272 | 5652 |
| 10273 /** | 5653 /** |
| 10274 * Instances of the class `ResolverVisitor` are used to resolve the nodes within
a single | 5654 * Instances of the class `ResolverVisitor` are used to resolve the nodes within
a single |
| 10275 * compilation unit. | 5655 * compilation unit. |
| 10276 */ | 5656 */ |
| 10277 class ResolverVisitor extends ScopedVisitor { | 5657 class ResolverVisitor extends ScopedVisitor { |
| 10278 /** | 5658 /** |
| 10279 * The manager for the inheritance mappings. | |
| 10280 */ | |
| 10281 InheritanceManager _inheritanceManager; | |
| 10282 | |
| 10283 /** | |
| 10284 * The object used to resolve the element associated with the current node. | 5659 * The object used to resolve the element associated with the current node. |
| 10285 */ | 5660 */ |
| 10286 ElementResolver elementResolver; | 5661 ElementResolver elementResolver; |
| 10287 | 5662 |
| 10288 /** | 5663 /** |
| 10289 * The object used to compute the type associated with the current node. | 5664 * The object used to compute the type associated with the current node. |
| 10290 */ | 5665 */ |
| 10291 StaticTypeAnalyzer typeAnalyzer; | 5666 StaticTypeAnalyzer typeAnalyzer; |
| 10292 | 5667 |
| 10293 /* | 5668 /** |
| 10294 * The type system in use during resolution. | 5669 * The type system in use during resolution. |
| 10295 */ | 5670 */ |
| 10296 TypeSystem typeSystem; | 5671 TypeSystem typeSystem; |
| 10297 | 5672 |
| 10298 /** | 5673 /** |
| 10299 * The class element representing the class containing the current node, | |
| 10300 * or `null` if the current node is not contained in a class. | |
| 10301 */ | |
| 10302 ClassElement enclosingClass = null; | |
| 10303 | |
| 10304 /** | |
| 10305 * The class declaration representing the class containing the current node, o
r `null` if | 5674 * The class declaration representing the class containing the current node, o
r `null` if |
| 10306 * the current node is not contained in a class. | 5675 * the current node is not contained in a class. |
| 10307 */ | 5676 */ |
| 10308 ClassDeclaration _enclosingClassDeclaration = null; | 5677 ClassDeclaration _enclosingClassDeclaration = null; |
| 10309 | 5678 |
| 10310 /** | 5679 /** |
| 10311 * The function type alias representing the function type containing the curre
nt node, or | 5680 * The function type alias representing the function type containing the curre
nt node, or |
| 10312 * `null` if the current node is not contained in a function type alias. | 5681 * `null` if the current node is not contained in a function type alias. |
| 10313 */ | 5682 */ |
| 10314 FunctionTypeAlias _enclosingFunctionTypeAlias = null; | 5683 FunctionTypeAlias _enclosingFunctionTypeAlias = null; |
| 10315 | 5684 |
| 10316 /** | 5685 /** |
| 10317 * The element representing the function containing the current node, or `null
` if the | 5686 * The element representing the function containing the current node, or `null
` if the |
| 10318 * current node is not contained in a function. | 5687 * current node is not contained in a function. |
| 10319 */ | 5688 */ |
| 10320 ExecutableElement _enclosingFunction = null; | 5689 ExecutableElement _enclosingFunction = null; |
| 10321 | 5690 |
| 10322 /** | 5691 InferenceContext inferenceContext = null; |
| 10323 * The [Comment] before a [FunctionDeclaration] or a [MethodDeclaration] that | |
| 10324 * cannot be resolved where we visited it, because it should be resolved in th
e scope of the body. | |
| 10325 */ | |
| 10326 Comment _commentBeforeFunction = null; | |
| 10327 | 5692 |
| 10328 /** | 5693 /** |
| 10329 * The object keeping track of which elements have had their types overridden. | 5694 * The object keeping track of which elements have had their types overridden. |
| 10330 */ | 5695 */ |
| 10331 TypeOverrideManager _overrideManager = new TypeOverrideManager(); | 5696 TypeOverrideManager _overrideManager = new TypeOverrideManager(); |
| 10332 | 5697 |
| 10333 /** | 5698 /** |
| 10334 * The object keeping track of which elements have had their types promoted. | 5699 * The object keeping track of which elements have had their types promoted. |
| 10335 */ | 5700 */ |
| 10336 TypePromotionManager _promoteManager = new TypePromotionManager(); | 5701 TypePromotionManager _promoteManager = new TypePromotionManager(); |
| 10337 | 5702 |
| 10338 /** | 5703 /** |
| 10339 * A comment before a function should be resolved in the context of the | 5704 * A comment before a function should be resolved in the context of the |
| 10340 * function. But when we incrementally resolve a comment, we don't want to | 5705 * function. But when we incrementally resolve a comment, we don't want to |
| 10341 * resolve the whole function. | 5706 * resolve the whole function. |
| 10342 * | 5707 * |
| 10343 * So, this flag is set to `true`, when just context of the function should | 5708 * So, this flag is set to `true`, when just context of the function should |
| 10344 * be built and the comment resolved. | 5709 * be built and the comment resolved. |
| 10345 */ | 5710 */ |
| 10346 bool resolveOnlyCommentInFunctionBody = false; | 5711 bool resolveOnlyCommentInFunctionBody = false; |
| 10347 | 5712 |
| 10348 /** | 5713 /** |
| 5714 * Body of the function currently being analyzed, if any. |
| 5715 */ |
| 5716 FunctionBody _currentFunctionBody; |
| 5717 |
| 5718 /** |
| 5719 * Are we running in strong mode or not. |
| 5720 */ |
| 5721 bool strongMode; |
| 5722 |
| 5723 /** |
| 10349 * Initialize a newly created visitor to resolve the nodes in an AST node. | 5724 * Initialize a newly created visitor to resolve the nodes in an AST node. |
| 10350 * | 5725 * |
| 10351 * The [definingLibrary] is the element for the library containing the node | 5726 * The [definingLibrary] is the element for the library containing the node |
| 10352 * being visited. The [source] is the source representing the compilation unit | 5727 * being visited. The [source] is the source representing the compilation unit |
| 10353 * containing the node being visited. The [typeProvider] is the object used to | 5728 * containing the node being visited. The [typeProvider] is the object used to |
| 10354 * access the types from the core library. The [errorListener] is the error | 5729 * access the types from the core library. The [errorListener] is the error |
| 10355 * listener that will be informed of any errors that are found during | 5730 * listener that will be informed of any errors that are found during |
| 10356 * resolution. The [nameScope] is the scope used to resolve identifiers in the | 5731 * resolution. The [nameScope] is the scope used to resolve identifiers in the |
| 10357 * node that will first be visited. If `null` or unspecified, a new | 5732 * node that will first be visited. If `null` or unspecified, a new |
| 10358 * [LibraryScope] will be created based on [definingLibrary] and | 5733 * [LibraryScope] will be created based on [definingLibrary] and |
| 10359 * [typeProvider]. The [inheritanceManager] is used to perform inheritance | 5734 * [typeProvider]. The [inheritanceManager] is used to perform inheritance |
| 10360 * lookups. If `null` or unspecified, a new [InheritanceManager] will be | 5735 * lookups. If `null` or unspecified, a new [InheritanceManager] will be |
| 10361 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to | 5736 * created based on [definingLibrary]. The [typeAnalyzerFactory] is used to |
| 10362 * create the type analyzer. If `null` or unspecified, a type analyzer of | 5737 * create the type analyzer. If `null` or unspecified, a type analyzer of |
| 10363 * type [StaticTypeAnalyzer] will be created. | 5738 * type [StaticTypeAnalyzer] will be created. |
| 10364 */ | 5739 */ |
| 10365 ResolverVisitor(LibraryElement definingLibrary, Source source, | 5740 ResolverVisitor(LibraryElement definingLibrary, Source source, |
| 10366 TypeProvider typeProvider, AnalysisErrorListener errorListener, | 5741 TypeProvider typeProvider, AnalysisErrorListener errorListener, |
| 10367 {Scope nameScope, | 5742 {Scope nameScope}) |
| 10368 InheritanceManager inheritanceManager, | |
| 10369 StaticTypeAnalyzerFactory typeAnalyzerFactory}) | |
| 10370 : super(definingLibrary, source, typeProvider, errorListener, | 5743 : super(definingLibrary, source, typeProvider, errorListener, |
| 10371 nameScope: nameScope) { | 5744 nameScope: nameScope) { |
| 10372 if (inheritanceManager == null) { | 5745 AnalysisOptions options = definingLibrary.context.analysisOptions; |
| 10373 this._inheritanceManager = new InheritanceManager(definingLibrary); | 5746 this.strongMode = options.strongMode; |
| 10374 } else { | |
| 10375 this._inheritanceManager = inheritanceManager; | |
| 10376 } | |
| 10377 this.elementResolver = new ElementResolver(this); | 5747 this.elementResolver = new ElementResolver(this); |
| 10378 this.typeSystem = definingLibrary.context.typeSystem; | 5748 this.typeSystem = definingLibrary.context.typeSystem; |
| 10379 if (typeAnalyzerFactory == null) { | 5749 bool strongModeHints = false; |
| 10380 this.typeAnalyzer = new StaticTypeAnalyzer(this); | 5750 if (options is AnalysisOptionsImpl) { |
| 10381 } else { | 5751 strongModeHints = options.strongModeHints; |
| 10382 this.typeAnalyzer = typeAnalyzerFactory(this); | |
| 10383 } | 5752 } |
| 5753 this.inferenceContext = new InferenceContext._( |
| 5754 errorReporter, typeProvider, typeSystem, strongModeHints); |
| 5755 this.typeAnalyzer = new StaticTypeAnalyzer(this); |
| 10384 } | 5756 } |
| 10385 | 5757 |
| 10386 /** | 5758 /** |
| 10387 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 10388 * | |
| 10389 * @param library the library containing the compilation unit being resolved | |
| 10390 * @param source the source representing the compilation unit being visited | |
| 10391 * @param typeProvider the object used to access the types from the core libra
ry | |
| 10392 * | |
| 10393 * Deprecated. Please use unnamed constructor instead. | |
| 10394 */ | |
| 10395 @deprecated | |
| 10396 ResolverVisitor.con1( | |
| 10397 Library library, Source source, TypeProvider typeProvider, | |
| 10398 {StaticTypeAnalyzerFactory typeAnalyzerFactory}) | |
| 10399 : this( | |
| 10400 library.libraryElement, source, typeProvider, library.errorListener, | |
| 10401 nameScope: library.libraryScope, | |
| 10402 inheritanceManager: library.inheritanceManager, | |
| 10403 typeAnalyzerFactory: typeAnalyzerFactory); | |
| 10404 | |
| 10405 /** | |
| 10406 * Return the element representing the function containing the current node, o
r `null` if | 5759 * Return the element representing the function containing the current node, o
r `null` if |
| 10407 * the current node is not contained in a function. | 5760 * the current node is not contained in a function. |
| 10408 * | 5761 * |
| 10409 * @return the element representing the function containing the current node | 5762 * @return the element representing the function containing the current node |
| 10410 */ | 5763 */ |
| 10411 ExecutableElement get enclosingFunction => _enclosingFunction; | 5764 ExecutableElement get enclosingFunction => _enclosingFunction; |
| 10412 | 5765 |
| 10413 /** | 5766 /** |
| 10414 * Return the object keeping track of which elements have had their types over
ridden. | 5767 * Return the object keeping track of which elements have had their types over
ridden. |
| 10415 * | 5768 * |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10462 } else if (expression is PropertyAccess) { | 5815 } else if (expression is PropertyAccess) { |
| 10463 element = expression.propertyName.staticElement; | 5816 element = expression.propertyName.staticElement; |
| 10464 } | 5817 } |
| 10465 if (element is VariableElement) { | 5818 if (element is VariableElement) { |
| 10466 return element; | 5819 return element; |
| 10467 } | 5820 } |
| 10468 return null; | 5821 return null; |
| 10469 } | 5822 } |
| 10470 | 5823 |
| 10471 /** | 5824 /** |
| 10472 * Return the static element associated with the given expression whose type c
an be promoted, or | 5825 * Return the static element associated with the given expression whose type |
| 10473 * `null` if there is no element whose type can be promoted. | 5826 * can be promoted, or `null` if there is no element whose type can be |
| 10474 * | 5827 * promoted. |
| 10475 * @param expression the expression with which the element is associated | |
| 10476 * @return the element associated with the given expression | |
| 10477 */ | 5828 */ |
| 10478 VariableElement getPromotionStaticElement(Expression expression) { | 5829 VariableElement getPromotionStaticElement(Expression expression) { |
| 10479 while (expression is ParenthesizedExpression) { | 5830 expression = expression?.unParenthesized; |
| 10480 expression = (expression as ParenthesizedExpression).expression; | 5831 if (expression is SimpleIdentifier) { |
| 10481 } | 5832 Element element = expression.staticElement; |
| 10482 if (expression is! SimpleIdentifier) { | 5833 if (element is VariableElement) { |
| 10483 return null; | 5834 ElementKind kind = element.kind; |
| 10484 } | 5835 if (kind == ElementKind.LOCAL_VARIABLE || |
| 10485 SimpleIdentifier identifier = expression as SimpleIdentifier; | 5836 kind == ElementKind.PARAMETER) { |
| 10486 Element element = identifier.staticElement; | 5837 return element; |
| 10487 if (element is! VariableElement) { | 5838 } |
| 10488 return null; | 5839 } |
| 10489 } | |
| 10490 ElementKind kind = element.kind; | |
| 10491 if (kind == ElementKind.LOCAL_VARIABLE) { | |
| 10492 return element as VariableElement; | |
| 10493 } | |
| 10494 if (kind == ElementKind.PARAMETER) { | |
| 10495 return element as VariableElement; | |
| 10496 } | 5840 } |
| 10497 return null; | 5841 return null; |
| 10498 } | 5842 } |
| 10499 | 5843 |
| 10500 /** | 5844 /** |
| 10501 * Prepares this [ResolverVisitor] to using it for incremental resolution. | 5845 * Prepares this [ResolverVisitor] to using it for incremental resolution. |
| 10502 */ | 5846 */ |
| 10503 void initForIncrementalResolution([Declaration declaration = null]) { | 5847 void initForIncrementalResolution() { |
| 10504 if (declaration != null) { | |
| 10505 Element element = declaration.element; | |
| 10506 if (element is ExecutableElement) { | |
| 10507 _enclosingFunction = element; | |
| 10508 } | |
| 10509 _commentBeforeFunction = declaration.documentationComment; | |
| 10510 } | |
| 10511 _overrideManager.enterScope(); | 5848 _overrideManager.enterScope(); |
| 10512 } | 5849 } |
| 10513 | 5850 |
| 10514 /** | 5851 /** |
| 5852 * Returns true if this method is `Future.then` or an override thereof. |
| 5853 * |
| 5854 * If so we will apply special typing rules in strong mode, to handle the |
| 5855 * implicit union of `S | Future<S>` |
| 5856 */ |
| 5857 bool isFutureThen(Element element) { |
| 5858 // If we are a method named then |
| 5859 if (element is MethodElement && element.name == 'then') { |
| 5860 DartType type = element.enclosingElement.type; |
| 5861 // On Future or a subtype, then we're good. |
| 5862 return (type.isDartAsyncFuture || isSubtypeOfFuture(type)); |
| 5863 } |
| 5864 return false; |
| 5865 } |
| 5866 |
| 5867 /** |
| 5868 * Returns true if this type is any subtype of the built in Future type. |
| 5869 */ |
| 5870 bool isSubtypeOfFuture(DartType type) => |
| 5871 typeSystem.isSubtypeOf(type, typeProvider.futureDynamicType); |
| 5872 |
| 5873 /** |
| 5874 * Given a downward inference type [fnType], and the declared |
| 5875 * [typeParameterList] for a function expression, determines if we can enable |
| 5876 * downward inference and if so, returns the function type to use for |
| 5877 * inference. |
| 5878 * |
| 5879 * This will return null if inference is not possible. This happens when |
| 5880 * there is no way we can find a subtype of the function type, given the |
| 5881 * provided type parameter list. |
| 5882 */ |
| 5883 FunctionType matchFunctionTypeParameters( |
| 5884 TypeParameterList typeParameterList, FunctionType fnType) { |
| 5885 if (typeParameterList == null) { |
| 5886 if (fnType.typeFormals.isEmpty) { |
| 5887 return fnType; |
| 5888 } |
| 5889 |
| 5890 // A non-generic function cannot be a subtype of a generic one. |
| 5891 return null; |
| 5892 } |
| 5893 |
| 5894 NodeList<TypeParameter> typeParameters = typeParameterList.typeParameters; |
| 5895 if (fnType.typeFormals.isEmpty) { |
| 5896 // TODO(jmesserly): this is a legal subtype. We don't currently infer |
| 5897 // here, but we could. This is similar to |
| 5898 // StrongTypeSystemImpl.inferFunctionTypeInstantiation, but we don't |
| 5899 // have the FunctionType yet for the current node, so it's not quite |
| 5900 // straightforward to apply. |
| 5901 return null; |
| 5902 } |
| 5903 |
| 5904 if (fnType.typeFormals.length != typeParameters.length) { |
| 5905 // A subtype cannot have different number of type formals. |
| 5906 return null; |
| 5907 } |
| 5908 |
| 5909 // Same number of type formals. Instantiate the function type so its |
| 5910 // parameter and return type are in terms of the surrounding context. |
| 5911 return fnType.instantiate(typeParameters |
| 5912 .map((TypeParameter t) => |
| 5913 (t.name.staticElement as TypeParameterElement).type) |
| 5914 .toList()); |
| 5915 } |
| 5916 |
| 5917 /** |
| 10515 * If it is appropriate to do so, override the current type of the static and
propagated elements | 5918 * If it is appropriate to do so, override the current type of the static and
propagated elements |
| 10516 * associated with the given expression with the given type. Generally speakin
g, it is appropriate | 5919 * associated with the given expression with the given type. Generally speakin
g, it is appropriate |
| 10517 * if the given type is more specific than the current type. | 5920 * if the given type is more specific than the current type. |
| 10518 * | 5921 * |
| 10519 * @param expression the expression used to access the static and propagated e
lements whose types | 5922 * @param expression the expression used to access the static and propagated e
lements whose types |
| 10520 * might be overridden | 5923 * might be overridden |
| 10521 * @param potentialType the potential type of the elements | 5924 * @param potentialType the potential type of the elements |
| 10522 * @param allowPrecisionLoss see @{code overrideVariable} docs | 5925 * @param allowPrecisionLoss see @{code overrideVariable} docs |
| 10523 */ | 5926 */ |
| 10524 void overrideExpression(Expression expression, DartType potentialType, | 5927 void overrideExpression(Expression expression, DartType potentialType, |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10596 } | 5999 } |
| 10597 return null; | 6000 return null; |
| 10598 } | 6001 } |
| 10599 | 6002 |
| 10600 /** | 6003 /** |
| 10601 * A client is about to resolve a member in the given class declaration. | 6004 * A client is about to resolve a member in the given class declaration. |
| 10602 */ | 6005 */ |
| 10603 void prepareToResolveMembersInClass(ClassDeclaration node) { | 6006 void prepareToResolveMembersInClass(ClassDeclaration node) { |
| 10604 _enclosingClassDeclaration = node; | 6007 _enclosingClassDeclaration = node; |
| 10605 enclosingClass = node.element; | 6008 enclosingClass = node.element; |
| 10606 typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type; | 6009 typeAnalyzer.thisType = enclosingClass?.type; |
| 10607 } | 6010 } |
| 10608 | 6011 |
| 10609 /** | 6012 /** |
| 10610 * If the given [type] is valid, strongly more specific than the | 6013 * If the given [type] is valid, strongly more specific than the |
| 10611 * existing static type of the given [expression], record it as a propagated | 6014 * existing static type of the given [expression], record it as a propagated |
| 10612 * type of the given [expression]. Otherwise, reset it to `null`. | 6015 * type of the given [expression]. Otherwise, reset it to `null`. |
| 10613 * | 6016 * |
| 10614 * If [hasOldPropagatedType] is `true` then the existing propagated type | 6017 * If [hasOldPropagatedType] is `true` then the existing propagated type |
| 10615 * should also is checked. | 6018 * should also is checked. |
| 10616 */ | 6019 */ |
| 10617 void recordPropagatedTypeIfBetter(Expression expression, DartType type, | 6020 void recordPropagatedTypeIfBetter(Expression expression, DartType type, |
| 10618 [bool hasOldPropagatedType = false]) { | 6021 [bool hasOldPropagatedType = false]) { |
| 10619 // Ensure that propagated type invalid. | 6022 // Ensure that propagated type invalid. |
| 10620 if (type == null || type.isDynamic || type.isBottom) { | 6023 if (strongMode || type == null || type.isDynamic || type.isBottom) { |
| 10621 if (!hasOldPropagatedType) { | 6024 if (!hasOldPropagatedType) { |
| 10622 expression.propagatedType = null; | 6025 expression.propagatedType = null; |
| 10623 } | 6026 } |
| 10624 return; | 6027 return; |
| 10625 } | 6028 } |
| 10626 // Ensure that propagated type is more specific than the static type. | 6029 // Ensure that propagated type is more specific than the static type. |
| 10627 DartType staticType = expression.staticType; | 6030 DartType staticType = expression.staticType; |
| 10628 if (type == staticType || !type.isMoreSpecificThan(staticType)) { | 6031 if (type == staticType || !type.isMoreSpecificThan(staticType)) { |
| 10629 expression.propagatedType = null; | 6032 expression.propagatedType = null; |
| 10630 return; | 6033 return; |
| 10631 } | 6034 } |
| 10632 // Ensure that the new propagated type is more specific than the old one. | 6035 // Ensure that the new propagated type is more specific than the old one. |
| 10633 if (hasOldPropagatedType) { | 6036 if (hasOldPropagatedType) { |
| 10634 DartType oldPropagatedType = expression.propagatedType; | 6037 DartType oldPropagatedType = expression.propagatedType; |
| 10635 if (oldPropagatedType != null && | 6038 if (oldPropagatedType != null && |
| 10636 !type.isMoreSpecificThan(oldPropagatedType)) { | 6039 !type.isMoreSpecificThan(oldPropagatedType)) { |
| 10637 return; | 6040 return; |
| 10638 } | 6041 } |
| 10639 } | 6042 } |
| 10640 // OK | 6043 // OK |
| 10641 expression.propagatedType = type; | 6044 expression.propagatedType = type; |
| 10642 } | 6045 } |
| 10643 | 6046 |
| 6047 /** |
| 6048 * Visit the given [comment] if it is not `null`. |
| 6049 */ |
| 6050 void safelyVisitComment(Comment comment) { |
| 6051 if (comment != null) { |
| 6052 super.visitComment(comment); |
| 6053 } |
| 6054 } |
| 6055 |
| 10644 @override | 6056 @override |
| 10645 Object visitAnnotation(Annotation node) { | 6057 Object visitAnnotation(Annotation node) { |
| 10646 AstNode parent = node.parent; | 6058 AstNode parent = node.parent; |
| 10647 if (identical(parent, _enclosingClassDeclaration) || | 6059 if (identical(parent, _enclosingClassDeclaration) || |
| 10648 identical(parent, _enclosingFunctionTypeAlias)) { | 6060 identical(parent, _enclosingFunctionTypeAlias)) { |
| 10649 return null; | 6061 return null; |
| 10650 } | 6062 } |
| 10651 return super.visitAnnotation(node); | 6063 node.name?.accept(this); |
| 6064 node.constructorName?.accept(this); |
| 6065 Element element = node.element; |
| 6066 if (element is ExecutableElement) { |
| 6067 InferenceContext.setType(node.arguments, element.type); |
| 6068 } |
| 6069 node.arguments?.accept(this); |
| 6070 node.accept(elementResolver); |
| 6071 node.accept(typeAnalyzer); |
| 6072 ElementAnnotationImpl elementAnnotationImpl = node.elementAnnotation; |
| 6073 if (elementAnnotationImpl == null) { |
| 6074 // Analyzer ignores annotations on "part of" directives. |
| 6075 assert(parent is PartOfDirective); |
| 6076 } else { |
| 6077 elementAnnotationImpl.annotationAst = |
| 6078 new ConstantAstCloner().cloneNode(node); |
| 6079 } |
| 6080 return null; |
| 10652 } | 6081 } |
| 10653 | 6082 |
| 10654 @override | 6083 @override |
| 6084 Object visitArgumentList(ArgumentList node) { |
| 6085 DartType callerType = InferenceContext.getType(node); |
| 6086 if (callerType is FunctionType) { |
| 6087 Map<String, DartType> namedParameterTypes = |
| 6088 callerType.namedParameterTypes; |
| 6089 List<DartType> normalParameterTypes = callerType.normalParameterTypes; |
| 6090 List<DartType> optionalParameterTypes = callerType.optionalParameterTypes; |
| 6091 int normalCount = normalParameterTypes.length; |
| 6092 int optionalCount = optionalParameterTypes.length; |
| 6093 |
| 6094 NodeList<Expression> arguments = node.arguments; |
| 6095 Iterable<Expression> positional = |
| 6096 arguments.takeWhile((l) => l is! NamedExpression); |
| 6097 Iterable<Expression> required = positional.take(normalCount); |
| 6098 Iterable<Expression> optional = |
| 6099 positional.skip(normalCount).take(optionalCount); |
| 6100 Iterable<Expression> named = |
| 6101 arguments.skipWhile((l) => l is! NamedExpression); |
| 6102 |
| 6103 //TODO(leafp): Consider using the parameter elements here instead. |
| 6104 //TODO(leafp): Make sure that the parameter elements are getting |
| 6105 // setup correctly with inference. |
| 6106 int index = 0; |
| 6107 for (Expression argument in required) { |
| 6108 InferenceContext.setType(argument, normalParameterTypes[index++]); |
| 6109 } |
| 6110 index = 0; |
| 6111 for (Expression argument in optional) { |
| 6112 InferenceContext.setType(argument, optionalParameterTypes[index++]); |
| 6113 } |
| 6114 |
| 6115 for (Expression argument in named) { |
| 6116 if (argument is NamedExpression) { |
| 6117 DartType type = namedParameterTypes[argument.name.label.name]; |
| 6118 if (type != null) { |
| 6119 InferenceContext.setType(argument, type); |
| 6120 } |
| 6121 } |
| 6122 } |
| 6123 } |
| 6124 return super.visitArgumentList(node); |
| 6125 } |
| 6126 |
| 6127 @override |
| 10655 Object visitAsExpression(AsExpression node) { | 6128 Object visitAsExpression(AsExpression node) { |
| 10656 super.visitAsExpression(node); | 6129 super.visitAsExpression(node); |
| 10657 // Since an as-statement doesn't actually change the type, we don't | 6130 // Since an as-statement doesn't actually change the type, we don't |
| 10658 // let it affect the propagated type when it would result in a loss | 6131 // let it affect the propagated type when it would result in a loss |
| 10659 // of precision. | 6132 // of precision. |
| 10660 overrideExpression(node.expression, node.type.type, false, false); | 6133 overrideExpression(node.expression, node.type.type, false, false); |
| 10661 return null; | 6134 return null; |
| 10662 } | 6135 } |
| 10663 | 6136 |
| 10664 @override | 6137 @override |
| 10665 Object visitAssertStatement(AssertStatement node) { | 6138 Object visitAssertStatement(AssertStatement node) { |
| 10666 super.visitAssertStatement(node); | 6139 super.visitAssertStatement(node); |
| 10667 _propagateTrueState(node.condition); | 6140 _propagateTrueState(node.condition); |
| 10668 return null; | 6141 return null; |
| 10669 } | 6142 } |
| 10670 | 6143 |
| 10671 @override | 6144 @override |
| 6145 Object visitAssignmentExpression(AssignmentExpression node) { |
| 6146 node.leftHandSide?.accept(this); |
| 6147 TokenType operator = node.operator.type; |
| 6148 if (operator == TokenType.EQ || |
| 6149 operator == TokenType.QUESTION_QUESTION_EQ) { |
| 6150 InferenceContext.setType( |
| 6151 node.rightHandSide, node.leftHandSide.staticType); |
| 6152 } |
| 6153 node.rightHandSide?.accept(this); |
| 6154 node.accept(elementResolver); |
| 6155 node.accept(typeAnalyzer); |
| 6156 return null; |
| 6157 } |
| 6158 |
| 6159 @override |
| 6160 Object visitAwaitExpression(AwaitExpression node) { |
| 6161 DartType contextType = InferenceContext.getContext(node); |
| 6162 if (contextType != null) { |
| 6163 var futureUnion = |
| 6164 FutureUnionType.from(contextType, typeProvider, typeSystem); |
| 6165 InferenceContext.setType(node.expression, futureUnion); |
| 6166 } |
| 6167 return super.visitAwaitExpression(node); |
| 6168 } |
| 6169 |
| 6170 @override |
| 10672 Object visitBinaryExpression(BinaryExpression node) { | 6171 Object visitBinaryExpression(BinaryExpression node) { |
| 10673 sc.TokenType operatorType = node.operator.type; | 6172 TokenType operatorType = node.operator.type; |
| 10674 Expression leftOperand = node.leftOperand; | 6173 Expression leftOperand = node.leftOperand; |
| 10675 Expression rightOperand = node.rightOperand; | 6174 Expression rightOperand = node.rightOperand; |
| 10676 if (operatorType == sc.TokenType.AMPERSAND_AMPERSAND) { | 6175 if (operatorType == TokenType.AMPERSAND_AMPERSAND) { |
| 10677 safelyVisit(leftOperand); | 6176 leftOperand?.accept(this); |
| 10678 if (rightOperand != null) { | 6177 if (rightOperand != null) { |
| 10679 _overrideManager.enterScope(); | 6178 _overrideManager.enterScope(); |
| 10680 try { | 6179 try { |
| 10681 _promoteManager.enterScope(); | 6180 _promoteManager.enterScope(); |
| 10682 try { | 6181 try { |
| 10683 _propagateTrueState(leftOperand); | 6182 _propagateTrueState(leftOperand); |
| 10684 // Type promotion. | 6183 // Type promotion. |
| 10685 _promoteTypes(leftOperand); | 6184 _promoteTypes(leftOperand); |
| 10686 _clearTypePromotionsIfPotentiallyMutatedIn(leftOperand); | 6185 _clearTypePromotionsIfPotentiallyMutatedIn(leftOperand); |
| 10687 _clearTypePromotionsIfPotentiallyMutatedIn(rightOperand); | 6186 _clearTypePromotionsIfPotentiallyMutatedIn(rightOperand); |
| 10688 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( | 6187 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( |
| 10689 rightOperand); | 6188 rightOperand); |
| 10690 // Visit right operand. | 6189 // Visit right operand. |
| 10691 rightOperand.accept(this); | 6190 rightOperand.accept(this); |
| 10692 } finally { | 6191 } finally { |
| 10693 _promoteManager.exitScope(); | 6192 _promoteManager.exitScope(); |
| 10694 } | 6193 } |
| 10695 } finally { | 6194 } finally { |
| 10696 _overrideManager.exitScope(); | 6195 _overrideManager.exitScope(); |
| 10697 } | 6196 } |
| 10698 } | 6197 } |
| 10699 } else if (operatorType == sc.TokenType.BAR_BAR) { | 6198 } else if (operatorType == TokenType.BAR_BAR) { |
| 10700 safelyVisit(leftOperand); | 6199 leftOperand?.accept(this); |
| 10701 if (rightOperand != null) { | 6200 if (rightOperand != null) { |
| 10702 _overrideManager.enterScope(); | 6201 _overrideManager.enterScope(); |
| 10703 try { | 6202 try { |
| 10704 _propagateFalseState(leftOperand); | 6203 _propagateFalseState(leftOperand); |
| 10705 rightOperand.accept(this); | 6204 rightOperand.accept(this); |
| 10706 } finally { | 6205 } finally { |
| 10707 _overrideManager.exitScope(); | 6206 _overrideManager.exitScope(); |
| 10708 } | 6207 } |
| 10709 } | 6208 } |
| 10710 } else { | 6209 } else { |
| 10711 safelyVisit(leftOperand); | 6210 // TODO(leafp): Do downwards inference using the declared type |
| 10712 safelyVisit(rightOperand); | 6211 // of the binary operator for other cases. |
| 6212 if (operatorType == TokenType.QUESTION_QUESTION) { |
| 6213 InferenceContext.setTypeFromNode(leftOperand, node); |
| 6214 } |
| 6215 leftOperand?.accept(this); |
| 6216 if (operatorType == TokenType.QUESTION_QUESTION) { |
| 6217 // Set the right side, either from the context, or using the information |
| 6218 // from the left side if it is more precise. |
| 6219 DartType contextType = InferenceContext.getContext(node); |
| 6220 DartType leftType = leftOperand?.staticType; |
| 6221 if (contextType == null || contextType.isDynamic) { |
| 6222 contextType = leftType; |
| 6223 } |
| 6224 InferenceContext.setType(rightOperand, contextType); |
| 6225 } |
| 6226 rightOperand?.accept(this); |
| 10713 } | 6227 } |
| 10714 node.accept(elementResolver); | 6228 node.accept(elementResolver); |
| 10715 node.accept(typeAnalyzer); | 6229 node.accept(typeAnalyzer); |
| 10716 return null; | 6230 return null; |
| 10717 } | 6231 } |
| 10718 | 6232 |
| 10719 @override | 6233 @override |
| 10720 Object visitBlockFunctionBody(BlockFunctionBody node) { | 6234 Object visitBlockFunctionBody(BlockFunctionBody node) { |
| 10721 safelyVisit(_commentBeforeFunction); | |
| 10722 _overrideManager.enterScope(); | 6235 _overrideManager.enterScope(); |
| 10723 try { | 6236 try { |
| 6237 inferenceContext.pushReturnContext(node); |
| 10724 super.visitBlockFunctionBody(node); | 6238 super.visitBlockFunctionBody(node); |
| 10725 } finally { | 6239 } finally { |
| 10726 _overrideManager.exitScope(); | 6240 _overrideManager.exitScope(); |
| 6241 inferenceContext.popReturnContext(node); |
| 10727 } | 6242 } |
| 10728 return null; | 6243 return null; |
| 10729 } | 6244 } |
| 10730 | 6245 |
| 10731 @override | 6246 @override |
| 10732 Object visitBreakStatement(BreakStatement node) { | 6247 Object visitBreakStatement(BreakStatement node) { |
| 10733 // | 6248 // |
| 10734 // We do not visit the label because it needs to be visited in the context | 6249 // We do not visit the label because it needs to be visited in the context |
| 10735 // of the statement. | 6250 // of the statement. |
| 10736 // | 6251 // |
| 10737 node.accept(elementResolver); | 6252 node.accept(elementResolver); |
| 10738 node.accept(typeAnalyzer); | 6253 node.accept(typeAnalyzer); |
| 10739 return null; | 6254 return null; |
| 10740 } | 6255 } |
| 10741 | 6256 |
| 10742 @override | 6257 @override |
| 6258 Object visitCascadeExpression(CascadeExpression node) { |
| 6259 InferenceContext.setTypeFromNode(node.target, node); |
| 6260 return super.visitCascadeExpression(node); |
| 6261 } |
| 6262 |
| 6263 @override |
| 10743 Object visitClassDeclaration(ClassDeclaration node) { | 6264 Object visitClassDeclaration(ClassDeclaration node) { |
| 10744 // | 6265 // |
| 10745 // Resolve the metadata in the library scope. | 6266 // Resolve the metadata in the library scope. |
| 10746 // | 6267 // |
| 10747 if (node.metadata != null) { | 6268 node.metadata?.accept(this); |
| 10748 node.metadata.accept(this); | |
| 10749 } | |
| 10750 _enclosingClassDeclaration = node; | 6269 _enclosingClassDeclaration = node; |
| 10751 // | 6270 // |
| 10752 // Continue the class resolution. | 6271 // Continue the class resolution. |
| 10753 // | 6272 // |
| 10754 ClassElement outerType = enclosingClass; | 6273 ClassElement outerType = enclosingClass; |
| 10755 try { | 6274 try { |
| 10756 enclosingClass = node.element; | 6275 enclosingClass = node.element; |
| 10757 typeAnalyzer.thisType = | 6276 typeAnalyzer.thisType = enclosingClass?.type; |
| 10758 enclosingClass == null ? null : enclosingClass.type; | |
| 10759 super.visitClassDeclaration(node); | 6277 super.visitClassDeclaration(node); |
| 10760 node.accept(elementResolver); | 6278 node.accept(elementResolver); |
| 10761 node.accept(typeAnalyzer); | 6279 node.accept(typeAnalyzer); |
| 10762 } finally { | 6280 } finally { |
| 10763 typeAnalyzer.thisType = outerType == null ? null : outerType.type; | 6281 typeAnalyzer.thisType = outerType?.type; |
| 10764 enclosingClass = outerType; | 6282 enclosingClass = outerType; |
| 10765 _enclosingClassDeclaration = null; | 6283 _enclosingClassDeclaration = null; |
| 10766 } | 6284 } |
| 10767 return null; | 6285 return null; |
| 10768 } | 6286 } |
| 10769 | 6287 |
| 10770 /** | 6288 /** |
| 10771 * Implementation of this method should be synchronized with | 6289 * Implementation of this method should be synchronized with |
| 10772 * [visitClassDeclaration]. | 6290 * [visitClassDeclaration]. |
| 10773 */ | 6291 */ |
| 10774 visitClassDeclarationIncrementally(ClassDeclaration node) { | 6292 visitClassDeclarationIncrementally(ClassDeclaration node) { |
| 10775 // | 6293 // |
| 10776 // Resolve the metadata in the library scope. | 6294 // Resolve the metadata in the library scope. |
| 10777 // | 6295 // |
| 10778 if (node.metadata != null) { | 6296 node.metadata?.accept(this); |
| 10779 node.metadata.accept(this); | |
| 10780 } | |
| 10781 _enclosingClassDeclaration = node; | 6297 _enclosingClassDeclaration = node; |
| 10782 // | 6298 // |
| 10783 // Continue the class resolution. | 6299 // Continue the class resolution. |
| 10784 // | 6300 // |
| 10785 enclosingClass = node.element; | 6301 enclosingClass = node.element; |
| 10786 typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type; | 6302 typeAnalyzer.thisType = enclosingClass?.type; |
| 10787 node.accept(elementResolver); | 6303 node.accept(elementResolver); |
| 10788 node.accept(typeAnalyzer); | 6304 node.accept(typeAnalyzer); |
| 10789 } | 6305 } |
| 10790 | 6306 |
| 10791 @override | 6307 @override |
| 10792 Object visitComment(Comment node) { | 6308 Object visitComment(Comment node) { |
| 10793 if (node.parent is FunctionDeclaration || | 6309 AstNode parent = node.parent; |
| 10794 node.parent is ConstructorDeclaration || | 6310 if (parent is FunctionDeclaration || |
| 10795 node.parent is MethodDeclaration) { | 6311 parent is FunctionTypeAlias || |
| 10796 if (!identical(node, _commentBeforeFunction)) { | 6312 parent is ConstructorDeclaration || |
| 10797 _commentBeforeFunction = node; | 6313 parent is MethodDeclaration) { |
| 10798 return null; | 6314 return null; |
| 10799 } | |
| 10800 } | 6315 } |
| 10801 super.visitComment(node); | 6316 super.visitComment(node); |
| 10802 _commentBeforeFunction = null; | |
| 10803 return null; | 6317 return null; |
| 10804 } | 6318 } |
| 10805 | 6319 |
| 10806 @override | 6320 @override |
| 10807 Object visitCommentReference(CommentReference node) { | 6321 Object visitCommentReference(CommentReference node) { |
| 10808 // | 6322 // |
| 10809 // We do not visit the identifier because it needs to be visited in the | 6323 // We do not visit the identifier because it needs to be visited in the |
| 10810 // context of the reference. | 6324 // context of the reference. |
| 10811 // | 6325 // |
| 10812 node.accept(elementResolver); | 6326 node.accept(elementResolver); |
| 10813 node.accept(typeAnalyzer); | 6327 node.accept(typeAnalyzer); |
| 10814 return null; | 6328 return null; |
| 10815 } | 6329 } |
| 10816 | 6330 |
| 10817 @override | 6331 @override |
| 10818 Object visitCompilationUnit(CompilationUnit node) { | 6332 Object visitCompilationUnit(CompilationUnit node) { |
| 10819 // | |
| 10820 // TODO(brianwilkerson) The goal of the code below is to visit the | |
| 10821 // declarations in such an order that we can infer type information for | |
| 10822 // top-level variables before we visit references to them. This is better | |
| 10823 // than making no effort, but still doesn't completely satisfy that goal | |
| 10824 // (consider for example "final var a = b; final var b = 0;"; we'll infer a | |
| 10825 // type of 'int' for 'b', but not for 'a' because of the order of the | |
| 10826 // visits). Ideally we would create a dependency graph, but that would | |
| 10827 // require references to be resolved, which they are not. | |
| 10828 // | |
| 10829 _overrideManager.enterScope(); | 6333 _overrideManager.enterScope(); |
| 10830 try { | 6334 try { |
| 10831 NodeList<Directive> directives = node.directives; | 6335 NodeList<Directive> directives = node.directives; |
| 10832 int directiveCount = directives.length; | 6336 int directiveCount = directives.length; |
| 10833 for (int i = 0; i < directiveCount; i++) { | 6337 for (int i = 0; i < directiveCount; i++) { |
| 10834 directives[i].accept(this); | 6338 directives[i].accept(this); |
| 10835 } | 6339 } |
| 10836 NodeList<CompilationUnitMember> declarations = node.declarations; | 6340 NodeList<CompilationUnitMember> declarations = node.declarations; |
| 10837 int declarationCount = declarations.length; | 6341 int declarationCount = declarations.length; |
| 10838 for (int i = 0; i < declarationCount; i++) { | 6342 for (int i = 0; i < declarationCount; i++) { |
| 10839 CompilationUnitMember declaration = declarations[i]; | 6343 declarations[i].accept(this); |
| 10840 if (declaration is! ClassDeclaration) { | |
| 10841 declaration.accept(this); | |
| 10842 } | |
| 10843 } | |
| 10844 for (int i = 0; i < declarationCount; i++) { | |
| 10845 CompilationUnitMember declaration = declarations[i]; | |
| 10846 if (declaration is ClassDeclaration) { | |
| 10847 declaration.accept(this); | |
| 10848 } | |
| 10849 } | 6344 } |
| 10850 } finally { | 6345 } finally { |
| 10851 _overrideManager.exitScope(); | 6346 _overrideManager.exitScope(); |
| 10852 } | 6347 } |
| 10853 node.accept(elementResolver); | 6348 node.accept(elementResolver); |
| 10854 node.accept(typeAnalyzer); | 6349 node.accept(typeAnalyzer); |
| 10855 return null; | 6350 return null; |
| 10856 } | 6351 } |
| 10857 | 6352 |
| 10858 @override | 6353 @override |
| 10859 Object visitConditionalExpression(ConditionalExpression node) { | 6354 Object visitConditionalExpression(ConditionalExpression node) { |
| 10860 Expression condition = node.condition; | 6355 Expression condition = node.condition; |
| 10861 safelyVisit(condition); | 6356 condition?.accept(this); |
| 10862 Expression thenExpression = node.thenExpression; | 6357 Expression thenExpression = node.thenExpression; |
| 10863 if (thenExpression != null) { | 6358 if (thenExpression != null) { |
| 10864 _overrideManager.enterScope(); | 6359 _overrideManager.enterScope(); |
| 10865 try { | 6360 try { |
| 10866 _promoteManager.enterScope(); | 6361 _promoteManager.enterScope(); |
| 10867 try { | 6362 try { |
| 10868 _propagateTrueState(condition); | 6363 _propagateTrueState(condition); |
| 10869 // Type promotion. | 6364 // Type promotion. |
| 10870 _promoteTypes(condition); | 6365 _promoteTypes(condition); |
| 10871 _clearTypePromotionsIfPotentiallyMutatedIn(thenExpression); | 6366 _clearTypePromotionsIfPotentiallyMutatedIn(thenExpression); |
| 10872 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( | 6367 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( |
| 10873 thenExpression); | 6368 thenExpression); |
| 10874 // Visit "then" expression. | 6369 // Visit "then" expression. |
| 6370 InferenceContext.setTypeFromNode(thenExpression, node); |
| 10875 thenExpression.accept(this); | 6371 thenExpression.accept(this); |
| 10876 } finally { | 6372 } finally { |
| 10877 _promoteManager.exitScope(); | 6373 _promoteManager.exitScope(); |
| 10878 } | 6374 } |
| 10879 } finally { | 6375 } finally { |
| 10880 _overrideManager.exitScope(); | 6376 _overrideManager.exitScope(); |
| 10881 } | 6377 } |
| 10882 } | 6378 } |
| 10883 Expression elseExpression = node.elseExpression; | 6379 Expression elseExpression = node.elseExpression; |
| 10884 if (elseExpression != null) { | 6380 if (elseExpression != null) { |
| 10885 _overrideManager.enterScope(); | 6381 _overrideManager.enterScope(); |
| 10886 try { | 6382 try { |
| 10887 _propagateFalseState(condition); | 6383 _propagateFalseState(condition); |
| 6384 InferenceContext.setTypeFromNode(elseExpression, node); |
| 10888 elseExpression.accept(this); | 6385 elseExpression.accept(this); |
| 10889 } finally { | 6386 } finally { |
| 10890 _overrideManager.exitScope(); | 6387 _overrideManager.exitScope(); |
| 10891 } | 6388 } |
| 10892 } | 6389 } |
| 10893 node.accept(elementResolver); | 6390 node.accept(elementResolver); |
| 10894 node.accept(typeAnalyzer); | 6391 node.accept(typeAnalyzer); |
| 10895 bool thenIsAbrupt = _isAbruptTerminationExpression(thenExpression); | 6392 bool thenIsAbrupt = _isAbruptTerminationExpression(thenExpression); |
| 10896 bool elseIsAbrupt = _isAbruptTerminationExpression(elseExpression); | 6393 bool elseIsAbrupt = _isAbruptTerminationExpression(elseExpression); |
| 10897 if (elseIsAbrupt && !thenIsAbrupt) { | 6394 if (elseIsAbrupt && !thenIsAbrupt) { |
| 10898 _propagateTrueState(condition); | 6395 _propagateTrueState(condition); |
| 10899 _propagateState(thenExpression); | 6396 _propagateState(thenExpression); |
| 10900 } else if (thenIsAbrupt && !elseIsAbrupt) { | 6397 } else if (thenIsAbrupt && !elseIsAbrupt) { |
| 10901 _propagateFalseState(condition); | 6398 _propagateFalseState(condition); |
| 10902 _propagateState(elseExpression); | 6399 _propagateState(elseExpression); |
| 10903 } | 6400 } |
| 10904 return null; | 6401 return null; |
| 10905 } | 6402 } |
| 10906 | 6403 |
| 10907 @override | 6404 @override |
| 10908 Object visitConstructorDeclaration(ConstructorDeclaration node) { | 6405 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 10909 ExecutableElement outerFunction = _enclosingFunction; | 6406 ExecutableElement outerFunction = _enclosingFunction; |
| 6407 FunctionBody outerFunctionBody = _currentFunctionBody; |
| 10910 try { | 6408 try { |
| 6409 _currentFunctionBody = node.body; |
| 10911 _enclosingFunction = node.element; | 6410 _enclosingFunction = node.element; |
| 6411 FunctionType type = _enclosingFunction.type; |
| 6412 InferenceContext.setType(node.body, type.returnType); |
| 10912 super.visitConstructorDeclaration(node); | 6413 super.visitConstructorDeclaration(node); |
| 10913 } finally { | 6414 } finally { |
| 6415 _currentFunctionBody = outerFunctionBody; |
| 10914 _enclosingFunction = outerFunction; | 6416 _enclosingFunction = outerFunction; |
| 10915 } | 6417 } |
| 10916 ConstructorElementImpl constructor = node.element; | 6418 ConstructorElementImpl constructor = node.element; |
| 10917 constructor.constantInitializers = | 6419 constructor.constantInitializers = |
| 10918 new ConstantAstCloner().cloneNodeList(node.initializers); | 6420 new ConstantAstCloner().cloneNodeList(node.initializers); |
| 10919 return null; | 6421 return null; |
| 10920 } | 6422 } |
| 10921 | 6423 |
| 10922 @override | 6424 @override |
| 6425 void visitConstructorDeclarationInScope(ConstructorDeclaration node) { |
| 6426 super.visitConstructorDeclarationInScope(node); |
| 6427 // Because of needing a different scope for the initializer list, the |
| 6428 // overridden implementation of this method cannot cause the visitNode |
| 6429 // method to be invoked. As a result, we have to hard-code using the |
| 6430 // element resolver and type analyzer to visit the constructor declaration. |
| 6431 node.accept(elementResolver); |
| 6432 node.accept(typeAnalyzer); |
| 6433 safelyVisitComment(node.documentationComment); |
| 6434 } |
| 6435 |
| 6436 @override |
| 10923 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | 6437 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| 10924 // | 6438 // |
| 10925 // We visit the expression, but do not visit the field name because it needs | 6439 // We visit the expression, but do not visit the field name because it needs |
| 10926 // to be visited in the context of the constructor field initializer node. | 6440 // to be visited in the context of the constructor field initializer node. |
| 10927 // | 6441 // |
| 10928 safelyVisit(node.expression); | 6442 FieldElement fieldElement = enclosingClass.getField(node.fieldName.name); |
| 6443 InferenceContext.setType(node.expression, fieldElement?.type); |
| 6444 node.expression?.accept(this); |
| 10929 node.accept(elementResolver); | 6445 node.accept(elementResolver); |
| 10930 node.accept(typeAnalyzer); | 6446 node.accept(typeAnalyzer); |
| 10931 return null; | 6447 return null; |
| 10932 } | 6448 } |
| 10933 | 6449 |
| 10934 @override | 6450 @override |
| 10935 Object visitConstructorName(ConstructorName node) { | 6451 Object visitConstructorName(ConstructorName node) { |
| 10936 // | 6452 // |
| 10937 // We do not visit either the type name, because it won't be visited anyway, | 6453 // We do not visit either the type name, because it won't be visited anyway, |
| 10938 // or the name, because it needs to be visited in the context of the | 6454 // or the name, because it needs to be visited in the context of the |
| (...skipping 10 matching lines...) Expand all Loading... |
| 10949 // We do not visit the label because it needs to be visited in the context | 6465 // We do not visit the label because it needs to be visited in the context |
| 10950 // of the statement. | 6466 // of the statement. |
| 10951 // | 6467 // |
| 10952 node.accept(elementResolver); | 6468 node.accept(elementResolver); |
| 10953 node.accept(typeAnalyzer); | 6469 node.accept(typeAnalyzer); |
| 10954 return null; | 6470 return null; |
| 10955 } | 6471 } |
| 10956 | 6472 |
| 10957 @override | 6473 @override |
| 10958 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | 6474 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 6475 InferenceContext.setType(node.defaultValue, node.parameter.element?.type); |
| 10959 super.visitDefaultFormalParameter(node); | 6476 super.visitDefaultFormalParameter(node); |
| 10960 ParameterElement element = node.element; | 6477 ParameterElement element = node.element; |
| 10961 if (element.initializer != null && node.defaultValue != null) { | 6478 if (element.initializer != null && node.defaultValue != null) { |
| 10962 (element.initializer as FunctionElementImpl).returnType = | 6479 (element.initializer as FunctionElementImpl).returnType = |
| 10963 node.defaultValue.staticType; | 6480 node.defaultValue.staticType; |
| 10964 } | 6481 } |
| 10965 FormalParameterList parent = node.parent; | 6482 // Clone the ASTs for default formal parameters, so that we can use them |
| 10966 AstNode grandparent = parent.parent; | 6483 // during constant evaluation. |
| 10967 if (grandparent is ConstructorDeclaration && | 6484 if (!LibraryElementImpl.hasResolutionCapability( |
| 10968 grandparent.constKeyword != null) { | 6485 definingLibrary, LibraryResolutionCapability.constantExpressions)) { |
| 10969 // For const constructors, we need to clone the ASTs for default formal | |
| 10970 // parameters, so that we can use them during constant evaluation. | |
| 10971 ParameterElement element = node.element; | |
| 10972 (element as ConstVariableElement).constantInitializer = | 6486 (element as ConstVariableElement).constantInitializer = |
| 10973 new ConstantAstCloner().cloneNode(node.defaultValue); | 6487 new ConstantAstCloner().cloneNode(node.defaultValue); |
| 10974 } | 6488 } |
| 10975 return null; | 6489 return null; |
| 10976 } | 6490 } |
| 10977 | 6491 |
| 10978 @override | 6492 @override |
| 10979 Object visitDoStatement(DoStatement node) { | 6493 Object visitDoStatement(DoStatement node) { |
| 10980 _overrideManager.enterScope(); | 6494 _overrideManager.enterScope(); |
| 10981 try { | 6495 try { |
| 10982 super.visitDoStatement(node); | 6496 super.visitDoStatement(node); |
| 10983 } finally { | 6497 } finally { |
| 10984 _overrideManager.exitScope(); | 6498 _overrideManager.exitScope(); |
| 10985 } | 6499 } |
| 10986 // TODO(brianwilkerson) If the loop can only be exited because the condition | 6500 // TODO(brianwilkerson) If the loop can only be exited because the condition |
| 10987 // is false, then propagateFalseState(node.getCondition()); | 6501 // is false, then propagateFalseState(node.getCondition()); |
| 10988 return null; | 6502 return null; |
| 10989 } | 6503 } |
| 10990 | 6504 |
| 10991 @override | 6505 @override |
| 10992 Object visitEmptyFunctionBody(EmptyFunctionBody node) { | 6506 Object visitEmptyFunctionBody(EmptyFunctionBody node) { |
| 10993 safelyVisit(_commentBeforeFunction); | |
| 10994 if (resolveOnlyCommentInFunctionBody) { | 6507 if (resolveOnlyCommentInFunctionBody) { |
| 10995 return null; | 6508 return null; |
| 10996 } | 6509 } |
| 10997 return super.visitEmptyFunctionBody(node); | 6510 return super.visitEmptyFunctionBody(node); |
| 10998 } | 6511 } |
| 10999 | 6512 |
| 11000 @override | 6513 @override |
| 11001 Object visitEnumDeclaration(EnumDeclaration node) { | 6514 Object visitEnumDeclaration(EnumDeclaration node) { |
| 11002 // | 6515 // |
| 11003 // Resolve the metadata in the library scope | 6516 // Resolve the metadata in the library scope |
| 11004 // and associate the annotations with the element. | 6517 // and associate the annotations with the element. |
| 11005 // | 6518 // |
| 11006 if (node.metadata != null) { | 6519 if (node.metadata != null) { |
| 11007 node.metadata.accept(this); | 6520 node.metadata.accept(this); |
| 11008 ElementResolver.setMetadata(node.element, node); | 6521 ElementResolver.resolveMetadata(node); |
| 11009 } | 6522 } |
| 11010 // | 6523 // |
| 11011 // Continue the enum resolution. | 6524 // Continue the enum resolution. |
| 11012 // | 6525 // |
| 11013 ClassElement outerType = enclosingClass; | 6526 ClassElement outerType = enclosingClass; |
| 11014 try { | 6527 try { |
| 11015 enclosingClass = node.element; | 6528 enclosingClass = node.element; |
| 11016 typeAnalyzer.thisType = | 6529 typeAnalyzer.thisType = enclosingClass?.type; |
| 11017 enclosingClass == null ? null : enclosingClass.type; | |
| 11018 super.visitEnumDeclaration(node); | 6530 super.visitEnumDeclaration(node); |
| 11019 node.accept(elementResolver); | 6531 node.accept(elementResolver); |
| 11020 node.accept(typeAnalyzer); | 6532 node.accept(typeAnalyzer); |
| 11021 } finally { | 6533 } finally { |
| 11022 typeAnalyzer.thisType = outerType == null ? null : outerType.type; | 6534 typeAnalyzer.thisType = outerType?.type; |
| 11023 enclosingClass = outerType; | 6535 enclosingClass = outerType; |
| 11024 _enclosingClassDeclaration = null; | 6536 _enclosingClassDeclaration = null; |
| 11025 } | 6537 } |
| 11026 return null; | 6538 return null; |
| 11027 } | 6539 } |
| 11028 | 6540 |
| 11029 @override | 6541 @override |
| 11030 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { | 6542 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 11031 safelyVisit(_commentBeforeFunction); | |
| 11032 if (resolveOnlyCommentInFunctionBody) { | 6543 if (resolveOnlyCommentInFunctionBody) { |
| 11033 return null; | 6544 return null; |
| 11034 } | 6545 } |
| 11035 _overrideManager.enterScope(); | 6546 _overrideManager.enterScope(); |
| 11036 try { | 6547 try { |
| 6548 InferenceContext.setTypeFromNode(node.expression, node); |
| 11037 super.visitExpressionFunctionBody(node); | 6549 super.visitExpressionFunctionBody(node); |
| 11038 } finally { | 6550 } finally { |
| 11039 _overrideManager.exitScope(); | 6551 _overrideManager.exitScope(); |
| 11040 } | 6552 } |
| 11041 return null; | 6553 return null; |
| 11042 } | 6554 } |
| 11043 | 6555 |
| 11044 @override | 6556 @override |
| 11045 Object visitFieldDeclaration(FieldDeclaration node) { | 6557 Object visitFieldDeclaration(FieldDeclaration node) { |
| 11046 _overrideManager.enterScope(); | 6558 _overrideManager.enterScope(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 11066 return null; | 6578 return null; |
| 11067 } | 6579 } |
| 11068 | 6580 |
| 11069 @override | 6581 @override |
| 11070 void visitForEachStatementInScope(ForEachStatement node) { | 6582 void visitForEachStatementInScope(ForEachStatement node) { |
| 11071 // | 6583 // |
| 11072 // We visit the iterator before the loop variable because the loop variable | 6584 // We visit the iterator before the loop variable because the loop variable |
| 11073 // cannot be in scope while visiting the iterator. | 6585 // cannot be in scope while visiting the iterator. |
| 11074 // | 6586 // |
| 11075 Expression iterable = node.iterable; | 6587 Expression iterable = node.iterable; |
| 11076 safelyVisit(iterable); | |
| 11077 DeclaredIdentifier loopVariable = node.loopVariable; | 6588 DeclaredIdentifier loopVariable = node.loopVariable; |
| 11078 SimpleIdentifier identifier = node.identifier; | 6589 SimpleIdentifier identifier = node.identifier; |
| 11079 safelyVisit(loopVariable); | 6590 if (loopVariable?.type?.type != null) { |
| 11080 safelyVisit(identifier); | 6591 InterfaceType targetType = (node.awaitKeyword == null) |
| 6592 ? typeProvider.iterableType |
| 6593 : typeProvider.streamType; |
| 6594 InferenceContext.setType( |
| 6595 iterable, targetType.instantiate([loopVariable.type.type])); |
| 6596 } |
| 6597 iterable?.accept(this); |
| 6598 loopVariable?.accept(this); |
| 6599 identifier?.accept(this); |
| 11081 Statement body = node.body; | 6600 Statement body = node.body; |
| 11082 if (body != null) { | 6601 if (body != null) { |
| 11083 _overrideManager.enterScope(); | 6602 _overrideManager.enterScope(); |
| 11084 try { | 6603 try { |
| 11085 if (loopVariable != null && iterable != null) { | 6604 if (loopVariable != null && iterable != null) { |
| 11086 LocalVariableElement loopElement = loopVariable.element; | 6605 LocalVariableElement loopElement = loopVariable.element; |
| 11087 if (loopElement != null) { | 6606 if (loopElement != null) { |
| 11088 DartType propagatedType = null; | 6607 DartType propagatedType = null; |
| 11089 if (node.awaitKeyword == null) { | 6608 if (node.awaitKeyword == null) { |
| 11090 propagatedType = _getIteratorElementType(iterable); | 6609 propagatedType = _getIteratorElementType(iterable); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 11120 try { | 6639 try { |
| 11121 super.visitForStatement(node); | 6640 super.visitForStatement(node); |
| 11122 } finally { | 6641 } finally { |
| 11123 _overrideManager.exitScope(); | 6642 _overrideManager.exitScope(); |
| 11124 } | 6643 } |
| 11125 return null; | 6644 return null; |
| 11126 } | 6645 } |
| 11127 | 6646 |
| 11128 @override | 6647 @override |
| 11129 void visitForStatementInScope(ForStatement node) { | 6648 void visitForStatementInScope(ForStatement node) { |
| 11130 safelyVisit(node.variables); | 6649 node.variables?.accept(this); |
| 11131 safelyVisit(node.initialization); | 6650 node.initialization?.accept(this); |
| 11132 safelyVisit(node.condition); | 6651 node.condition?.accept(this); |
| 11133 _overrideManager.enterScope(); | 6652 _overrideManager.enterScope(); |
| 11134 try { | 6653 try { |
| 11135 _propagateTrueState(node.condition); | 6654 _propagateTrueState(node.condition); |
| 11136 visitStatementInScope(node.body); | 6655 visitStatementInScope(node.body); |
| 11137 node.updaters.accept(this); | 6656 node.updaters.accept(this); |
| 11138 } finally { | 6657 } finally { |
| 11139 _overrideManager.exitScope(); | 6658 _overrideManager.exitScope(); |
| 11140 } | 6659 } |
| 11141 // TODO(brianwilkerson) If the loop can only be exited because the condition | 6660 // TODO(brianwilkerson) If the loop can only be exited because the condition |
| 11142 // is false, then propagateFalseState(condition); | 6661 // is false, then propagateFalseState(condition); |
| 11143 } | 6662 } |
| 11144 | 6663 |
| 11145 @override | 6664 @override |
| 11146 Object visitFunctionDeclaration(FunctionDeclaration node) { | 6665 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 11147 ExecutableElement outerFunction = _enclosingFunction; | 6666 ExecutableElement outerFunction = _enclosingFunction; |
| 6667 FunctionBody outerFunctionBody = _currentFunctionBody; |
| 11148 try { | 6668 try { |
| 11149 SimpleIdentifier functionName = node.name; | 6669 SimpleIdentifier functionName = node.name; |
| 6670 _currentFunctionBody = node.functionExpression.body; |
| 11150 _enclosingFunction = functionName.staticElement as ExecutableElement; | 6671 _enclosingFunction = functionName.staticElement as ExecutableElement; |
| 6672 InferenceContext.setType( |
| 6673 node.functionExpression, _enclosingFunction.type); |
| 11151 super.visitFunctionDeclaration(node); | 6674 super.visitFunctionDeclaration(node); |
| 11152 } finally { | 6675 } finally { |
| 6676 _currentFunctionBody = outerFunctionBody; |
| 11153 _enclosingFunction = outerFunction; | 6677 _enclosingFunction = outerFunction; |
| 11154 } | 6678 } |
| 11155 return null; | 6679 return null; |
| 11156 } | 6680 } |
| 11157 | 6681 |
| 11158 @override | 6682 @override |
| 6683 void visitFunctionDeclarationInScope(FunctionDeclaration node) { |
| 6684 super.visitFunctionDeclarationInScope(node); |
| 6685 safelyVisitComment(node.documentationComment); |
| 6686 } |
| 6687 |
| 6688 @override |
| 11159 Object visitFunctionExpression(FunctionExpression node) { | 6689 Object visitFunctionExpression(FunctionExpression node) { |
| 11160 ExecutableElement outerFunction = _enclosingFunction; | 6690 ExecutableElement outerFunction = _enclosingFunction; |
| 6691 FunctionBody outerFunctionBody = _currentFunctionBody; |
| 11161 try { | 6692 try { |
| 6693 _currentFunctionBody = node.body; |
| 11162 _enclosingFunction = node.element; | 6694 _enclosingFunction = node.element; |
| 11163 _overrideManager.enterScope(); | 6695 _overrideManager.enterScope(); |
| 11164 try { | 6696 try { |
| 6697 DartType functionType = InferenceContext.getType(node); |
| 6698 if (functionType is FunctionType) { |
| 6699 functionType = |
| 6700 matchFunctionTypeParameters(node.typeParameters, functionType); |
| 6701 if (functionType is FunctionType) { |
| 6702 _inferFormalParameterList(node.parameters, functionType); |
| 6703 |
| 6704 DartType returnType; |
| 6705 if (isFutureThen(node.staticParameterElement?.enclosingElement)) { |
| 6706 var futureThenType = |
| 6707 InferenceContext.getContext(node.parent) as FunctionType; |
| 6708 |
| 6709 // Pretend the return type of Future<T>.then<S> first parameter is |
| 6710 // |
| 6711 // T -> (S | Future<S>) |
| 6712 // |
| 6713 // We can't represent this in Dart so we populate it here during |
| 6714 // inference. |
| 6715 var typeParamS = |
| 6716 futureThenType.returnType.flattenFutures(typeSystem); |
| 6717 returnType = |
| 6718 FutureUnionType.from(typeParamS, typeProvider, typeSystem); |
| 6719 } else { |
| 6720 returnType = _computeReturnOrYieldType(functionType.returnType); |
| 6721 } |
| 6722 |
| 6723 InferenceContext.setType(node.body, returnType); |
| 6724 } |
| 6725 } |
| 11165 super.visitFunctionExpression(node); | 6726 super.visitFunctionExpression(node); |
| 11166 } finally { | 6727 } finally { |
| 11167 _overrideManager.exitScope(); | 6728 _overrideManager.exitScope(); |
| 11168 } | 6729 } |
| 11169 } finally { | 6730 } finally { |
| 6731 _currentFunctionBody = outerFunctionBody; |
| 11170 _enclosingFunction = outerFunction; | 6732 _enclosingFunction = outerFunction; |
| 11171 } | 6733 } |
| 11172 return null; | 6734 return null; |
| 11173 } | 6735 } |
| 11174 | 6736 |
| 11175 @override | 6737 @override |
| 11176 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | 6738 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 11177 safelyVisit(node.function); | 6739 node.function?.accept(this); |
| 11178 node.accept(elementResolver); | 6740 node.accept(elementResolver); |
| 11179 _inferFunctionExpressionsParametersTypes(node.argumentList); | 6741 _inferArgumentTypesFromContext(node); |
| 11180 safelyVisit(node.argumentList); | 6742 node.argumentList?.accept(this); |
| 11181 node.accept(typeAnalyzer); | 6743 node.accept(typeAnalyzer); |
| 11182 return null; | 6744 return null; |
| 11183 } | 6745 } |
| 11184 | 6746 |
| 11185 @override | 6747 @override |
| 11186 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 6748 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 11187 // Resolve the metadata in the library scope. | 6749 // Resolve the metadata in the library scope. |
| 11188 if (node.metadata != null) { | 6750 if (node.metadata != null) { |
| 11189 node.metadata.accept(this); | 6751 node.metadata.accept(this); |
| 11190 } | 6752 } |
| 11191 FunctionTypeAlias outerAlias = _enclosingFunctionTypeAlias; | 6753 FunctionTypeAlias outerAlias = _enclosingFunctionTypeAlias; |
| 11192 _enclosingFunctionTypeAlias = node; | 6754 _enclosingFunctionTypeAlias = node; |
| 11193 try { | 6755 try { |
| 11194 super.visitFunctionTypeAlias(node); | 6756 super.visitFunctionTypeAlias(node); |
| 11195 } finally { | 6757 } finally { |
| 11196 _enclosingFunctionTypeAlias = outerAlias; | 6758 _enclosingFunctionTypeAlias = outerAlias; |
| 11197 } | 6759 } |
| 11198 return null; | 6760 return null; |
| 11199 } | 6761 } |
| 11200 | 6762 |
| 11201 @override | 6763 @override |
| 6764 void visitFunctionTypeAliasInScope(FunctionTypeAlias node) { |
| 6765 super.visitFunctionTypeAliasInScope(node); |
| 6766 safelyVisitComment(node.documentationComment); |
| 6767 } |
| 6768 |
| 6769 @override |
| 11202 Object visitHideCombinator(HideCombinator node) => null; | 6770 Object visitHideCombinator(HideCombinator node) => null; |
| 11203 | 6771 |
| 11204 @override | 6772 @override |
| 11205 Object visitIfStatement(IfStatement node) { | 6773 Object visitIfStatement(IfStatement node) { |
| 11206 Expression condition = node.condition; | 6774 Expression condition = node.condition; |
| 11207 safelyVisit(condition); | 6775 condition?.accept(this); |
| 11208 Map<VariableElement, DartType> thenOverrides = | 6776 Map<VariableElement, DartType> thenOverrides = |
| 11209 new HashMap<VariableElement, DartType>(); | 6777 const <VariableElement, DartType>{}; |
| 11210 Statement thenStatement = node.thenStatement; | 6778 Statement thenStatement = node.thenStatement; |
| 11211 if (thenStatement != null) { | 6779 if (thenStatement != null) { |
| 11212 _overrideManager.enterScope(); | 6780 _overrideManager.enterScope(); |
| 11213 try { | 6781 try { |
| 11214 _promoteManager.enterScope(); | 6782 _promoteManager.enterScope(); |
| 11215 try { | 6783 try { |
| 11216 _propagateTrueState(condition); | 6784 _propagateTrueState(condition); |
| 11217 // Type promotion. | 6785 // Type promotion. |
| 11218 _promoteTypes(condition); | 6786 _promoteTypes(condition); |
| 11219 _clearTypePromotionsIfPotentiallyMutatedIn(thenStatement); | 6787 _clearTypePromotionsIfPotentiallyMutatedIn(thenStatement); |
| 11220 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( | 6788 _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( |
| 11221 thenStatement); | 6789 thenStatement); |
| 11222 // Visit "then". | 6790 // Visit "then". |
| 11223 visitStatementInScope(thenStatement); | 6791 visitStatementInScope(thenStatement); |
| 11224 } finally { | 6792 } finally { |
| 11225 _promoteManager.exitScope(); | 6793 _promoteManager.exitScope(); |
| 11226 } | 6794 } |
| 11227 } finally { | 6795 } finally { |
| 11228 thenOverrides = _overrideManager.captureLocalOverrides(); | 6796 thenOverrides = _overrideManager.captureLocalOverrides(); |
| 11229 _overrideManager.exitScope(); | 6797 _overrideManager.exitScope(); |
| 11230 } | 6798 } |
| 11231 } | 6799 } |
| 11232 Map<VariableElement, DartType> elseOverrides = | 6800 Map<VariableElement, DartType> elseOverrides = |
| 11233 new HashMap<VariableElement, DartType>(); | 6801 const <VariableElement, DartType>{}; |
| 11234 Statement elseStatement = node.elseStatement; | 6802 Statement elseStatement = node.elseStatement; |
| 11235 if (elseStatement != null) { | 6803 if (elseStatement != null) { |
| 11236 _overrideManager.enterScope(); | 6804 _overrideManager.enterScope(); |
| 11237 try { | 6805 try { |
| 11238 _propagateFalseState(condition); | 6806 _propagateFalseState(condition); |
| 11239 visitStatementInScope(elseStatement); | 6807 visitStatementInScope(elseStatement); |
| 11240 } finally { | 6808 } finally { |
| 11241 elseOverrides = _overrideManager.captureLocalOverrides(); | 6809 elseOverrides = _overrideManager.captureLocalOverrides(); |
| 11242 _overrideManager.exitScope(); | 6810 _overrideManager.exitScope(); |
| 11243 } | 6811 } |
| 11244 } | 6812 } |
| 11245 node.accept(elementResolver); | 6813 node.accept(elementResolver); |
| 11246 node.accept(typeAnalyzer); | 6814 node.accept(typeAnalyzer); |
| 11247 // Join overrides. | 6815 // Join overrides. |
| 11248 bool thenIsAbrupt = _isAbruptTerminationStatement(thenStatement); | 6816 bool thenIsAbrupt = _isAbruptTerminationStatement(thenStatement); |
| 11249 bool elseIsAbrupt = _isAbruptTerminationStatement(elseStatement); | 6817 bool elseIsAbrupt = _isAbruptTerminationStatement(elseStatement); |
| 11250 if (elseIsAbrupt && !thenIsAbrupt) { | 6818 if (elseIsAbrupt && !thenIsAbrupt) { |
| 11251 _propagateTrueState(condition); | 6819 _propagateTrueState(condition); |
| 11252 _overrideManager.applyOverrides(thenOverrides); | 6820 _overrideManager.applyOverrides(thenOverrides); |
| 11253 } else if (thenIsAbrupt && !elseIsAbrupt) { | 6821 } else if (thenIsAbrupt && !elseIsAbrupt) { |
| 11254 _propagateFalseState(condition); | 6822 _propagateFalseState(condition); |
| 11255 _overrideManager.applyOverrides(elseOverrides); | 6823 _overrideManager.applyOverrides(elseOverrides); |
| 11256 } else if (!thenIsAbrupt && !elseIsAbrupt) { | 6824 } else if (!thenIsAbrupt && !elseIsAbrupt) { |
| 11257 List<Map<VariableElement, DartType>> perBranchOverrides = | 6825 List<Map<VariableElement, DartType>> perBranchOverrides = |
| 11258 new List<Map<VariableElement, DartType>>(); | 6826 <Map<VariableElement, DartType>>[]; |
| 11259 perBranchOverrides.add(thenOverrides); | 6827 perBranchOverrides.add(thenOverrides); |
| 11260 perBranchOverrides.add(elseOverrides); | 6828 perBranchOverrides.add(elseOverrides); |
| 11261 _overrideManager.mergeOverrides(perBranchOverrides); | 6829 _overrideManager.mergeOverrides(perBranchOverrides); |
| 11262 } | 6830 } |
| 11263 return null; | 6831 return null; |
| 11264 } | 6832 } |
| 11265 | 6833 |
| 11266 @override | 6834 @override |
| 6835 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 6836 TypeName classTypeName = node.constructorName.type; |
| 6837 // TODO(leafp): Currently, we may re-infer types here, since we |
| 6838 // sometimes resolve multiple times. We should really check that we |
| 6839 // have not already inferred something. However, the obvious ways to |
| 6840 // check this don't work, since we may have been instantiated |
| 6841 // to bounds in an earlier phase, and we *do* want to do inference |
| 6842 // in that case. |
| 6843 if (classTypeName.typeArguments == null) { |
| 6844 // Given a union of context types ` T0 | T1 | ... | Tn`, find the first |
| 6845 // valid instantiation `new C<Ti>`, if it exists. |
| 6846 // TODO(jmesserly): if we support union types for real, `new C<Ti | Tj>` |
| 6847 // will become a valid possibility. Right now the only allowed union is |
| 6848 // `T | Future<T>` so we can take a simple approach. |
| 6849 for (var contextType in InferenceContext.getTypes(node)) { |
| 6850 if (contextType is InterfaceType && |
| 6851 contextType.typeArguments != null && |
| 6852 contextType.typeArguments.isNotEmpty) { |
| 6853 // TODO(jmesserly): for generic methods we use the |
| 6854 // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to |
| 6855 // be a tad more powerful than matchTypes. |
| 6856 // |
| 6857 // For example it can infer this case: |
| 6858 // |
| 6859 // class E<S, T> extends A<C<S>, T> { ... } |
| 6860 // A<C<int>, String> a0 = /*infer<int, String>*/new E("hello"); |
| 6861 // |
| 6862 // See _inferArgumentTypesFromContext in this file for use of it. |
| 6863 List<DartType> targs = |
| 6864 inferenceContext.matchTypes(classTypeName.type, contextType); |
| 6865 if (targs != null && targs.any((t) => !t.isDynamic)) { |
| 6866 ClassElement classElement = classTypeName.type.element; |
| 6867 InterfaceType rawType = classElement.type; |
| 6868 InterfaceType fullType = |
| 6869 rawType.substitute2(targs, rawType.typeArguments); |
| 6870 // The element resolver uses the type on the constructor name, so |
| 6871 // infer it first |
| 6872 typeAnalyzer.inferConstructorName(node.constructorName, fullType); |
| 6873 break; |
| 6874 } |
| 6875 } |
| 6876 } |
| 6877 } |
| 6878 node.constructorName?.accept(this); |
| 6879 FunctionType constructorType = node.constructorName.staticElement?.type; |
| 6880 if (constructorType != null) { |
| 6881 InferenceContext.setType(node.argumentList, constructorType); |
| 6882 } |
| 6883 node.argumentList?.accept(this); |
| 6884 node.accept(elementResolver); |
| 6885 node.accept(typeAnalyzer); |
| 6886 return null; |
| 6887 } |
| 6888 |
| 6889 @override |
| 11267 Object visitLabel(Label node) => null; | 6890 Object visitLabel(Label node) => null; |
| 11268 | 6891 |
| 11269 @override | 6892 @override |
| 11270 Object visitLibraryIdentifier(LibraryIdentifier node) => null; | 6893 Object visitLibraryIdentifier(LibraryIdentifier node) => null; |
| 11271 | 6894 |
| 11272 @override | 6895 @override |
| 6896 Object visitListLiteral(ListLiteral node) { |
| 6897 DartType contextType = InferenceContext.getType(node); |
| 6898 List<DartType> targs = null; |
| 6899 if (node.typeArguments != null) { |
| 6900 targs = node.typeArguments.arguments.map((t) => t.type).toList(); |
| 6901 } else if (contextType is InterfaceType) { |
| 6902 InterfaceType listD = |
| 6903 typeProvider.listType.instantiate([typeProvider.dynamicType]); |
| 6904 targs = inferenceContext.matchTypes(listD, contextType); |
| 6905 } |
| 6906 if (targs != null && targs.length == 1 && !targs[0].isDynamic) { |
| 6907 DartType eType = targs[0]; |
| 6908 InterfaceType listT = typeProvider.listType.instantiate([eType]); |
| 6909 for (Expression child in node.elements) { |
| 6910 InferenceContext.setType(child, eType); |
| 6911 } |
| 6912 InferenceContext.setType(node, listT); |
| 6913 } else { |
| 6914 InferenceContext.clearType(node); |
| 6915 } |
| 6916 super.visitListLiteral(node); |
| 6917 return null; |
| 6918 } |
| 6919 |
| 6920 @override |
| 6921 Object visitMapLiteral(MapLiteral node) { |
| 6922 DartType contextType = InferenceContext.getType(node); |
| 6923 List<DartType> targs = null; |
| 6924 if (node.typeArguments != null) { |
| 6925 targs = node.typeArguments.arguments.map((t) => t.type).toList(); |
| 6926 } else if (contextType is InterfaceType) { |
| 6927 InterfaceType mapD = typeProvider.mapType |
| 6928 .instantiate([typeProvider.dynamicType, typeProvider.dynamicType]); |
| 6929 targs = inferenceContext.matchTypes(mapD, contextType); |
| 6930 } |
| 6931 if (targs != null && targs.length == 2 && targs.any((t) => !t.isDynamic)) { |
| 6932 DartType kType = targs[0]; |
| 6933 DartType vType = targs[1]; |
| 6934 InterfaceType mapT = typeProvider.mapType.instantiate([kType, vType]); |
| 6935 for (MapLiteralEntry entry in node.entries) { |
| 6936 InferenceContext.setType(entry.key, kType); |
| 6937 InferenceContext.setType(entry.value, vType); |
| 6938 } |
| 6939 InferenceContext.setType(node, mapT); |
| 6940 } else { |
| 6941 InferenceContext.clearType(node); |
| 6942 } |
| 6943 super.visitMapLiteral(node); |
| 6944 return null; |
| 6945 } |
| 6946 |
| 6947 @override |
| 11273 Object visitMethodDeclaration(MethodDeclaration node) { | 6948 Object visitMethodDeclaration(MethodDeclaration node) { |
| 11274 ExecutableElement outerFunction = _enclosingFunction; | 6949 ExecutableElement outerFunction = _enclosingFunction; |
| 6950 FunctionBody outerFunctionBody = _currentFunctionBody; |
| 11275 try { | 6951 try { |
| 6952 _currentFunctionBody = node.body; |
| 11276 _enclosingFunction = node.element; | 6953 _enclosingFunction = node.element; |
| 6954 DartType returnType = |
| 6955 _computeReturnOrYieldType(_enclosingFunction.type?.returnType); |
| 6956 InferenceContext.setType(node.body, returnType); |
| 11277 super.visitMethodDeclaration(node); | 6957 super.visitMethodDeclaration(node); |
| 11278 } finally { | 6958 } finally { |
| 6959 _currentFunctionBody = outerFunctionBody; |
| 11279 _enclosingFunction = outerFunction; | 6960 _enclosingFunction = outerFunction; |
| 11280 } | 6961 } |
| 11281 return null; | 6962 return null; |
| 11282 } | 6963 } |
| 11283 | 6964 |
| 11284 @override | 6965 @override |
| 6966 void visitMethodDeclarationInScope(MethodDeclaration node) { |
| 6967 super.visitMethodDeclarationInScope(node); |
| 6968 safelyVisitComment(node.documentationComment); |
| 6969 } |
| 6970 |
| 6971 @override |
| 11285 Object visitMethodInvocation(MethodInvocation node) { | 6972 Object visitMethodInvocation(MethodInvocation node) { |
| 11286 // | 6973 // |
| 11287 // We visit the target and argument list, but do not visit the method name | 6974 // We visit the target and argument list, but do not visit the method name |
| 11288 // because it needs to be visited in the context of the invocation. | 6975 // because it needs to be visited in the context of the invocation. |
| 11289 // | 6976 // |
| 11290 safelyVisit(node.target); | 6977 node.target?.accept(this); |
| 6978 node.typeArguments?.accept(this); |
| 11291 node.accept(elementResolver); | 6979 node.accept(elementResolver); |
| 11292 _inferFunctionExpressionsParametersTypes(node.argumentList); | 6980 _inferArgumentTypesFromContext(node); |
| 11293 safelyVisit(node.argumentList); | 6981 node.argumentList?.accept(this); |
| 11294 node.accept(typeAnalyzer); | 6982 node.accept(typeAnalyzer); |
| 11295 return null; | 6983 return null; |
| 11296 } | 6984 } |
| 11297 | 6985 |
| 11298 @override | 6986 @override |
| 6987 Object visitNamedExpression(NamedExpression node) { |
| 6988 InferenceContext.setTypeFromNode(node.expression, node); |
| 6989 return super.visitNamedExpression(node); |
| 6990 } |
| 6991 |
| 6992 @override |
| 11299 Object visitNode(AstNode node) { | 6993 Object visitNode(AstNode node) { |
| 11300 node.visitChildren(this); | 6994 node.visitChildren(this); |
| 11301 node.accept(elementResolver); | 6995 node.accept(elementResolver); |
| 11302 node.accept(typeAnalyzer); | 6996 node.accept(typeAnalyzer); |
| 11303 return null; | 6997 return null; |
| 11304 } | 6998 } |
| 11305 | 6999 |
| 11306 @override | 7000 @override |
| 7001 Object visitParenthesizedExpression(ParenthesizedExpression node) { |
| 7002 InferenceContext.setTypeFromNode(node.expression, node); |
| 7003 return super.visitParenthesizedExpression(node); |
| 7004 } |
| 7005 |
| 7006 @override |
| 11307 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | 7007 Object visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 11308 // | 7008 // |
| 11309 // We visit the prefix, but do not visit the identifier because it needs to | 7009 // We visit the prefix, but do not visit the identifier because it needs to |
| 11310 // be visited in the context of the prefix. | 7010 // be visited in the context of the prefix. |
| 11311 // | 7011 // |
| 11312 safelyVisit(node.prefix); | 7012 node.prefix?.accept(this); |
| 11313 node.accept(elementResolver); | 7013 node.accept(elementResolver); |
| 11314 node.accept(typeAnalyzer); | 7014 node.accept(typeAnalyzer); |
| 11315 return null; | 7015 return null; |
| 11316 } | 7016 } |
| 11317 | 7017 |
| 11318 @override | 7018 @override |
| 11319 Object visitPropertyAccess(PropertyAccess node) { | 7019 Object visitPropertyAccess(PropertyAccess node) { |
| 11320 // | 7020 // |
| 11321 // We visit the target, but do not visit the property name because it needs | 7021 // We visit the target, but do not visit the property name because it needs |
| 11322 // to be visited in the context of the property access node. | 7022 // to be visited in the context of the property access node. |
| 11323 // | 7023 // |
| 11324 safelyVisit(node.target); | 7024 node.target?.accept(this); |
| 11325 node.accept(elementResolver); | 7025 node.accept(elementResolver); |
| 11326 node.accept(typeAnalyzer); | 7026 node.accept(typeAnalyzer); |
| 11327 return null; | 7027 return null; |
| 11328 } | 7028 } |
| 11329 | 7029 |
| 11330 @override | 7030 @override |
| 11331 Object visitRedirectingConstructorInvocation( | 7031 Object visitRedirectingConstructorInvocation( |
| 11332 RedirectingConstructorInvocation node) { | 7032 RedirectingConstructorInvocation node) { |
| 11333 // | 7033 // |
| 11334 // We visit the argument list, but do not visit the optional identifier | 7034 // We visit the argument list, but do not visit the optional identifier |
| 11335 // because it needs to be visited in the context of the constructor | 7035 // because it needs to be visited in the context of the constructor |
| 11336 // invocation. | 7036 // invocation. |
| 11337 // | 7037 // |
| 11338 safelyVisit(node.argumentList); | 7038 InferenceContext.setType(node.argumentList, node.staticElement?.type); |
| 7039 node.argumentList?.accept(this); |
| 11339 node.accept(elementResolver); | 7040 node.accept(elementResolver); |
| 11340 node.accept(typeAnalyzer); | 7041 node.accept(typeAnalyzer); |
| 11341 return null; | 7042 return null; |
| 11342 } | 7043 } |
| 11343 | 7044 |
| 11344 @override | 7045 @override |
| 7046 Object visitReturnStatement(ReturnStatement node) { |
| 7047 Expression e = node.expression; |
| 7048 InferenceContext.setType(e, inferenceContext.returnContext); |
| 7049 super.visitReturnStatement(node); |
| 7050 DartType type = e?.staticType; |
| 7051 // Generators cannot return values, so don't try to do any inference if |
| 7052 // we're processing erroneous code. |
| 7053 if (type != null && _enclosingFunction?.isGenerator == false) { |
| 7054 if (_enclosingFunction.isAsynchronous) { |
| 7055 type = type.flattenFutures(typeSystem); |
| 7056 } |
| 7057 inferenceContext.addReturnOrYieldType(type); |
| 7058 } |
| 7059 return null; |
| 7060 } |
| 7061 |
| 7062 @override |
| 11345 Object visitShowCombinator(ShowCombinator node) => null; | 7063 Object visitShowCombinator(ShowCombinator node) => null; |
| 11346 | 7064 |
| 11347 @override | 7065 @override |
| 11348 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | 7066 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 11349 // | 7067 // |
| 11350 // We visit the argument list, but do not visit the optional identifier | 7068 // We visit the argument list, but do not visit the optional identifier |
| 11351 // because it needs to be visited in the context of the constructor | 7069 // because it needs to be visited in the context of the constructor |
| 11352 // invocation. | 7070 // invocation. |
| 11353 // | 7071 // |
| 11354 safelyVisit(node.argumentList); | 7072 InferenceContext.setType(node.argumentList, node.staticElement?.type); |
| 7073 node.argumentList?.accept(this); |
| 11355 node.accept(elementResolver); | 7074 node.accept(elementResolver); |
| 11356 node.accept(typeAnalyzer); | 7075 node.accept(typeAnalyzer); |
| 11357 return null; | 7076 return null; |
| 11358 } | 7077 } |
| 11359 | 7078 |
| 11360 @override | 7079 @override |
| 11361 Object visitSwitchCase(SwitchCase node) { | 7080 Object visitSwitchCase(SwitchCase node) { |
| 11362 _overrideManager.enterScope(); | 7081 _overrideManager.enterScope(); |
| 11363 try { | 7082 try { |
| 11364 super.visitSwitchCase(node); | 7083 super.visitSwitchCase(node); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 11391 _overrideManager.applyOverrides(overrides); | 7110 _overrideManager.applyOverrides(overrides); |
| 11392 } | 7111 } |
| 11393 return null; | 7112 return null; |
| 11394 } | 7113 } |
| 11395 | 7114 |
| 11396 @override | 7115 @override |
| 11397 Object visitTypeName(TypeName node) => null; | 7116 Object visitTypeName(TypeName node) => null; |
| 11398 | 7117 |
| 11399 @override | 7118 @override |
| 11400 Object visitVariableDeclaration(VariableDeclaration node) { | 7119 Object visitVariableDeclaration(VariableDeclaration node) { |
| 7120 InferenceContext.setTypeFromNode(node.initializer, node); |
| 11401 super.visitVariableDeclaration(node); | 7121 super.visitVariableDeclaration(node); |
| 11402 VariableElement element = node.element; | 7122 VariableElement element = node.element; |
| 11403 if (element.initializer != null && node.initializer != null) { | 7123 if (element.initializer != null && node.initializer != null) { |
| 11404 (element.initializer as FunctionElementImpl).returnType = | 7124 (element.initializer as FunctionElementImpl).returnType = |
| 11405 node.initializer.staticType; | 7125 node.initializer.staticType; |
| 11406 } | 7126 } |
| 11407 // Note: in addition to cloning the initializers for const variables, we | 7127 // Note: in addition to cloning the initializers for const variables, we |
| 11408 // have to clone the initializers for non-static final fields (because if | 7128 // have to clone the initializers for non-static final fields (because if |
| 11409 // they occur in a class with a const constructor, they will be needed to | 7129 // they occur in a class with a const constructor, they will be needed to |
| 11410 // evaluate the const constructor). | 7130 // evaluate the const constructor). |
| 11411 if ((element.isConst || | 7131 if ((element.isConst || |
| 11412 (element is FieldElement && | 7132 (element is FieldElement && |
| 11413 element.isFinal && | 7133 element.isFinal && |
| 11414 !element.isStatic)) && | 7134 !element.isStatic)) && |
| 11415 node.initializer != null) { | 7135 node.initializer != null) { |
| 11416 (element as ConstVariableElement).constantInitializer = | 7136 (element as ConstVariableElement).constantInitializer = |
| 11417 new ConstantAstCloner().cloneNode(node.initializer); | 7137 new ConstantAstCloner().cloneNode(node.initializer); |
| 11418 } | 7138 } |
| 11419 return null; | 7139 return null; |
| 11420 } | 7140 } |
| 11421 | 7141 |
| 11422 @override | 7142 @override |
| 7143 visitVariableDeclarationList(VariableDeclarationList node) { |
| 7144 for (VariableDeclaration decl in node.variables) { |
| 7145 InferenceContext.setType(decl, decl.element?.type); |
| 7146 } |
| 7147 super.visitVariableDeclarationList(node); |
| 7148 } |
| 7149 |
| 7150 @override |
| 11423 Object visitWhileStatement(WhileStatement node) { | 7151 Object visitWhileStatement(WhileStatement node) { |
| 11424 // Note: since we don't call the base class, we have to maintain | 7152 // Note: since we don't call the base class, we have to maintain |
| 11425 // _implicitLabelScope ourselves. | 7153 // _implicitLabelScope ourselves. |
| 11426 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; | 7154 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; |
| 11427 try { | 7155 try { |
| 11428 _implicitLabelScope = _implicitLabelScope.nest(node); | 7156 _implicitLabelScope = _implicitLabelScope.nest(node); |
| 11429 Expression condition = node.condition; | 7157 Expression condition = node.condition; |
| 11430 safelyVisit(condition); | 7158 condition?.accept(this); |
| 11431 Statement body = node.body; | 7159 Statement body = node.body; |
| 11432 if (body != null) { | 7160 if (body != null) { |
| 11433 _overrideManager.enterScope(); | 7161 _overrideManager.enterScope(); |
| 11434 try { | 7162 try { |
| 11435 _propagateTrueState(condition); | 7163 _propagateTrueState(condition); |
| 11436 visitStatementInScope(body); | 7164 visitStatementInScope(body); |
| 11437 } finally { | 7165 } finally { |
| 11438 _overrideManager.exitScope(); | 7166 _overrideManager.exitScope(); |
| 11439 } | 7167 } |
| 11440 } | 7168 } |
| 11441 } finally { | 7169 } finally { |
| 11442 _implicitLabelScope = outerImplicitScope; | 7170 _implicitLabelScope = outerImplicitScope; |
| 11443 } | 7171 } |
| 11444 // TODO(brianwilkerson) If the loop can only be exited because the condition | 7172 // TODO(brianwilkerson) If the loop can only be exited because the condition |
| 11445 // is false, then propagateFalseState(condition); | 7173 // is false, then propagateFalseState(condition); |
| 11446 node.accept(elementResolver); | 7174 node.accept(elementResolver); |
| 11447 node.accept(typeAnalyzer); | 7175 node.accept(typeAnalyzer); |
| 11448 return null; | 7176 return null; |
| 11449 } | 7177 } |
| 11450 | 7178 |
| 7179 @override |
| 7180 Object visitYieldStatement(YieldStatement node) { |
| 7181 Expression e = node.expression; |
| 7182 DartType returnType = inferenceContext.returnContext; |
| 7183 bool isGenerator = _enclosingFunction?.isGenerator ?? false; |
| 7184 if (returnType != null && isGenerator) { |
| 7185 // If we're not in a generator ([a]sync*, then we shouldn't have a yield. |
| 7186 // so don't infer |
| 7187 |
| 7188 // If this just a yield, then we just pass on the element type |
| 7189 DartType type = returnType; |
| 7190 if (node.star != null) { |
| 7191 // If this is a yield*, then we wrap the element return type |
| 7192 // If it's synchronous, we expect Iterable<T>, otherwise Stream<T> |
| 7193 InterfaceType wrapperType = _enclosingFunction.isSynchronous |
| 7194 ? typeProvider.iterableType |
| 7195 : typeProvider.streamType; |
| 7196 type = wrapperType.instantiate(<DartType>[type]); |
| 7197 } |
| 7198 InferenceContext.setType(e, type); |
| 7199 } |
| 7200 super.visitYieldStatement(node); |
| 7201 DartType type = e?.staticType; |
| 7202 if (type != null && isGenerator) { |
| 7203 // If this just a yield, then we just pass on the element type |
| 7204 if (node.star != null) { |
| 7205 // If this is a yield*, then we unwrap the element return type |
| 7206 // If it's synchronous, we expect Iterable<T>, otherwise Stream<T> |
| 7207 InterfaceType wrapperType = _enclosingFunction.isSynchronous |
| 7208 ? typeProvider.iterableType |
| 7209 : typeProvider.streamType; |
| 7210 type = typeSystem.mostSpecificTypeArgument(type, wrapperType); |
| 7211 } |
| 7212 if (type != null) { |
| 7213 inferenceContext.addReturnOrYieldType(type); |
| 7214 } |
| 7215 } |
| 7216 return null; |
| 7217 } |
| 7218 |
| 11451 /** | 7219 /** |
| 11452 * Checks each promoted variable in the current scope for compliance with the
following | 7220 * Checks each promoted variable in the current scope for compliance with the
following |
| 11453 * specification statement: | 7221 * specification statement: |
| 11454 * | 7222 * |
| 11455 * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> t
hen the variable | 7223 * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> t
hen the variable |
| 11456 * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>. | 7224 * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>. |
| 11457 */ | 7225 */ |
| 11458 void _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( | 7226 void _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated( |
| 11459 AstNode target) { | 7227 AstNode target) { |
| 11460 for (Element element in _promoteManager.promotedElements) { | 7228 for (Element element in _promoteManager.promotedElements) { |
| 11461 if ((element as VariableElementImpl).isPotentiallyMutatedInScope) { | 7229 if (_currentFunctionBody.isPotentiallyMutatedInScope(element)) { |
| 11462 if (_isVariableAccessedInClosure(element, target)) { | 7230 if (_isVariableAccessedInClosure(element, target)) { |
| 11463 _promoteManager.setType(element, null); | 7231 _promoteManager.setType(element, null); |
| 11464 } | 7232 } |
| 11465 } | 7233 } |
| 11466 } | 7234 } |
| 11467 } | 7235 } |
| 11468 | 7236 |
| 11469 /** | 7237 /** |
| 11470 * Checks each promoted variable in the current scope for compliance with the
following | 7238 * Checks each promoted variable in the current scope for compliance with the
following |
| 11471 * specification statement: | 7239 * specification statement: |
| 11472 * | 7240 * |
| 11473 * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a clo
sure. | 7241 * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a clo
sure. |
| 11474 */ | 7242 */ |
| 11475 void _clearTypePromotionsIfPotentiallyMutatedIn(AstNode target) { | 7243 void _clearTypePromotionsIfPotentiallyMutatedIn(AstNode target) { |
| 11476 for (Element element in _promoteManager.promotedElements) { | 7244 for (Element element in _promoteManager.promotedElements) { |
| 11477 if (_isVariablePotentiallyMutatedIn(element, target)) { | 7245 if (_isVariablePotentiallyMutatedIn(element, target)) { |
| 11478 _promoteManager.setType(element, null); | 7246 _promoteManager.setType(element, null); |
| 11479 } | 7247 } |
| 11480 } | 7248 } |
| 11481 } | 7249 } |
| 11482 | 7250 |
| 11483 /** | 7251 /** |
| 7252 * Given the declared return type of a function, compute the type of the |
| 7253 * values which should be returned or yielded as appropriate. If a type |
| 7254 * cannot be computed from the declared return type, return null. |
| 7255 */ |
| 7256 DartType _computeReturnOrYieldType(DartType declaredType) { |
| 7257 bool isGenerator = _enclosingFunction.isGenerator; |
| 7258 bool isAsynchronous = _enclosingFunction.isAsynchronous; |
| 7259 |
| 7260 // Ordinary functions just return their declared types. |
| 7261 if (!isGenerator && !isAsynchronous) { |
| 7262 return declaredType; |
| 7263 } |
| 7264 if (declaredType is InterfaceType) { |
| 7265 if (isGenerator) { |
| 7266 // If it's sync* we expect Iterable<T> |
| 7267 // If it's async* we expect Stream<T> |
| 7268 InterfaceType rawType = isAsynchronous |
| 7269 ? typeProvider.streamDynamicType |
| 7270 : typeProvider.iterableDynamicType; |
| 7271 // Match the types to instantiate the type arguments if possible |
| 7272 List<DartType> typeArgs = |
| 7273 inferenceContext.matchTypes(rawType, declaredType); |
| 7274 return (typeArgs?.length == 1) ? typeArgs[0] : null; |
| 7275 } |
| 7276 // async functions expect `Future<T> | T` |
| 7277 var futureTypeParam = declaredType.flattenFutures(typeSystem); |
| 7278 return FutureUnionType.from(futureTypeParam, typeProvider, typeSystem); |
| 7279 } |
| 7280 return declaredType; |
| 7281 } |
| 7282 |
| 7283 /** |
| 11484 * The given expression is the expression used to compute the iterator for a | 7284 * The given expression is the expression used to compute the iterator for a |
| 11485 * for-each statement. Attempt to compute the type of objects that will be | 7285 * for-each statement. Attempt to compute the type of objects that will be |
| 11486 * assigned to the loop variable and return that type. Return `null` if the | 7286 * assigned to the loop variable and return that type. Return `null` if the |
| 11487 * type could not be determined. The [iteratorExpression] is the expression | 7287 * type could not be determined. The [iteratorExpression] is the expression |
| 11488 * that will return the Iterable being iterated over. | 7288 * that will return the Iterable being iterated over. |
| 11489 */ | 7289 */ |
| 11490 DartType _getIteratorElementType(Expression iteratorExpression) { | 7290 DartType _getIteratorElementType(Expression iteratorExpression) { |
| 11491 DartType expressionType = iteratorExpression.bestType; | 7291 DartType expressionType = iteratorExpression.bestType; |
| 11492 if (expressionType is InterfaceType) { | 7292 if (expressionType is InterfaceType) { |
| 11493 InterfaceType interfaceType = expressionType; | 7293 PropertyAccessorElement iteratorFunction = |
| 11494 FunctionType iteratorFunction = | 7294 expressionType.lookUpInheritedGetter("iterator"); |
| 11495 _inheritanceManager.lookupMemberType(interfaceType, "iterator"); | |
| 11496 if (iteratorFunction == null) { | 7295 if (iteratorFunction == null) { |
| 11497 // TODO(brianwilkerson) Should we report this error? | 7296 // TODO(brianwilkerson) Should we report this error? |
| 11498 return null; | 7297 return null; |
| 11499 } | 7298 } |
| 11500 DartType iteratorType = iteratorFunction.returnType; | 7299 DartType iteratorType = iteratorFunction.returnType; |
| 11501 if (iteratorType is InterfaceType) { | 7300 if (iteratorType is InterfaceType) { |
| 11502 InterfaceType iteratorInterfaceType = iteratorType; | 7301 PropertyAccessorElement currentFunction = |
| 11503 FunctionType currentFunction = _inheritanceManager.lookupMemberType( | 7302 iteratorType.lookUpInheritedGetter("current"); |
| 11504 iteratorInterfaceType, "current"); | |
| 11505 if (currentFunction == null) { | 7303 if (currentFunction == null) { |
| 11506 // TODO(brianwilkerson) Should we report this error? | 7304 // TODO(brianwilkerson) Should we report this error? |
| 11507 return null; | 7305 return null; |
| 11508 } | 7306 } |
| 11509 return currentFunction.returnType; | 7307 return currentFunction.returnType; |
| 11510 } | 7308 } |
| 11511 } | 7309 } |
| 11512 return null; | 7310 return null; |
| 11513 } | 7311 } |
| 11514 | 7312 |
| 11515 /** | 7313 /** |
| 11516 * The given expression is the expression used to compute the stream for an | 7314 * The given expression is the expression used to compute the stream for an |
| 11517 * asyncronous for-each statement. Attempt to compute the type of objects that | 7315 * asynchronous for-each statement. Attempt to compute the type of objects |
| 11518 * will be assigned to the loop variable and return that type. Return `null` | 7316 * that will be assigned to the loop variable and return that type. |
| 11519 * if the type could not be determined. The [streamExpression] is the | 7317 * Return `null` if the type could not be determined. The [streamExpression] |
| 11520 * expression that will return the stream being iterated over. | 7318 * is the expression that will return the stream being iterated over. |
| 11521 */ | 7319 */ |
| 11522 DartType _getStreamElementType(Expression streamExpression) { | 7320 DartType _getStreamElementType(Expression streamExpression) { |
| 11523 DartType streamType = streamExpression.bestType; | 7321 DartType streamType = streamExpression.bestType; |
| 11524 if (streamType is InterfaceType) { | 7322 if (streamType is InterfaceType) { |
| 11525 FunctionType listenFunction = | 7323 MethodElement listenFunction = streamType.lookUpInheritedMethod("listen"); |
| 11526 _inheritanceManager.lookupMemberType(streamType, "listen"); | |
| 11527 if (listenFunction == null) { | 7324 if (listenFunction == null) { |
| 11528 return null; | 7325 return null; |
| 11529 } | 7326 } |
| 11530 List<ParameterElement> listenParameters = listenFunction.parameters; | 7327 List<ParameterElement> listenParameters = listenFunction.parameters; |
| 11531 if (listenParameters == null || listenParameters.length < 1) { | 7328 if (listenParameters == null || listenParameters.length < 1) { |
| 11532 return null; | 7329 return null; |
| 11533 } | 7330 } |
| 11534 DartType onDataType = listenParameters[0].type; | 7331 DartType onDataType = listenParameters[0].type; |
| 11535 if (onDataType is FunctionType) { | 7332 if (onDataType is FunctionType) { |
| 11536 List<ParameterElement> onDataParameters = onDataType.parameters; | 7333 List<ParameterElement> onDataParameters = onDataType.parameters; |
| 11537 if (onDataParameters == null || onDataParameters.length < 1) { | 7334 if (onDataParameters == null || onDataParameters.isEmpty) { |
| 11538 return null; | 7335 return null; |
| 11539 } | 7336 } |
| 11540 DartType eventType = onDataParameters[0].type; | 7337 return onDataParameters[0].type; |
| 11541 // TODO(paulberry): checking that typeParameters.isNotEmpty is a | |
| 11542 // band-aid fix for dartbug.com/24191. Figure out what the correct | |
| 11543 // logic should be. | |
| 11544 if (streamType.typeParameters.isNotEmpty && | |
| 11545 eventType.element == streamType.typeParameters[0]) { | |
| 11546 return streamType.typeArguments[0]; | |
| 11547 } | |
| 11548 } | 7338 } |
| 11549 } | 7339 } |
| 11550 return null; | 7340 return null; |
| 11551 } | 7341 } |
| 11552 | 7342 |
| 7343 void _inferArgumentTypesFromContext(InvocationExpression node) { |
| 7344 if (!strongMode) { |
| 7345 // Use propagated type inference for lambdas if not in strong mode. |
| 7346 _inferFunctionExpressionsParametersTypes(node.argumentList); |
| 7347 return; |
| 7348 } |
| 7349 |
| 7350 DartType contextType = node.staticInvokeType; |
| 7351 if (contextType is FunctionType) { |
| 7352 DartType originalType = node.function.staticType; |
| 7353 DartType returnContextType = InferenceContext.getContext(node); |
| 7354 TypeSystem ts = typeSystem; |
| 7355 if (returnContextType != null && |
| 7356 node.typeArguments == null && |
| 7357 originalType is FunctionType && |
| 7358 originalType.typeFormals.isNotEmpty && |
| 7359 ts is StrongTypeSystemImpl) { |
| 7360 contextType = ts.inferGenericFunctionCall( |
| 7361 typeProvider, |
| 7362 originalType, |
| 7363 DartType.EMPTY_LIST, |
| 7364 DartType.EMPTY_LIST, |
| 7365 originalType.returnType, |
| 7366 returnContextType); |
| 7367 } |
| 7368 |
| 7369 InferenceContext.setType(node.argumentList, contextType); |
| 7370 } |
| 7371 } |
| 7372 |
| 7373 void _inferFormalParameterList(FormalParameterList node, DartType type) { |
| 7374 if (typeAnalyzer.inferFormalParameterList(node, type)) { |
| 7375 // TODO(leafp): This gets dropped on the floor if we're in the field |
| 7376 // inference task. We should probably keep these infos. |
| 7377 // |
| 7378 // TODO(jmesserly): this is reporting the context type, and therefore not |
| 7379 // necessarily the correct inferred type for the lambda. |
| 7380 // |
| 7381 // For example, `([x]) {}` could be passed to `int -> void` but its type |
| 7382 // will really be `([int]) -> void`. Similar issue for named arguments. |
| 7383 // It can also happen if the return type is inferred later on to be |
| 7384 // more precise. |
| 7385 // |
| 7386 // This reporting bug defeats the deduplication of error messages and |
| 7387 // results in the same inference message being reported twice. |
| 7388 // |
| 7389 // To get this right, we'd have to delay reporting until we have the |
| 7390 // complete type including return type. |
| 7391 inferenceContext.recordInference(node.parent, type); |
| 7392 } |
| 7393 } |
| 7394 |
| 11553 /** | 7395 /** |
| 11554 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters
types and its | 7396 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters
types and its |
| 11555 * required type is [FunctionType], then infer parameters types from [Function
Type]. | 7397 * required type is [FunctionType], then infer parameters types from [Function
Type]. |
| 11556 */ | 7398 */ |
| 11557 void _inferFunctionExpressionParametersTypes( | 7399 void _inferFunctionExpressionParametersTypes( |
| 11558 Expression mayBeClosure, DartType mayByFunctionType) { | 7400 Expression mayBeClosure, DartType mayByFunctionType) { |
| 11559 // prepare closure | 7401 // prepare closure |
| 11560 if (mayBeClosure is! FunctionExpression) { | 7402 if (mayBeClosure is! FunctionExpression) { |
| 11561 return; | 7403 return; |
| 11562 } | 7404 } |
| 11563 FunctionExpression closure = mayBeClosure as FunctionExpression; | 7405 FunctionExpression closure = mayBeClosure as FunctionExpression; |
| 11564 // prepare expected closure type | 7406 // prepare expected closure type |
| 11565 if (mayByFunctionType is! FunctionType) { | 7407 if (mayByFunctionType is! FunctionType) { |
| 11566 return; | 7408 return; |
| 11567 } | 7409 } |
| 11568 FunctionType expectedClosureType = mayByFunctionType as FunctionType; | 7410 FunctionType expectedClosureType = mayByFunctionType as FunctionType; |
| 11569 // If the expectedClosureType is not more specific than the static type, | 7411 // If the expectedClosureType is not more specific than the static type, |
| 11570 // return. | 7412 // return. |
| 11571 DartType staticClosureType = | 7413 DartType staticClosureType = closure.element?.type; |
| 11572 closure.element != null ? closure.element.type : null; | |
| 11573 if (staticClosureType != null && | 7414 if (staticClosureType != null && |
| 11574 !expectedClosureType.isMoreSpecificThan(staticClosureType)) { | 7415 !FunctionTypeImpl.relate( |
| 7416 expectedClosureType, |
| 7417 staticClosureType, |
| 7418 (DartType t, DartType s, _, __) => |
| 7419 (t as TypeImpl).isMoreSpecificThan(s), |
| 7420 new TypeSystemImpl().instantiateToBounds, |
| 7421 returnRelation: (s, t) => true)) { |
| 11575 return; | 7422 return; |
| 11576 } | 7423 } |
| 11577 // set propagated type for the closure | 7424 // set propagated type for the closure |
| 11578 closure.propagatedType = expectedClosureType; | 7425 if (!strongMode) { |
| 7426 closure.propagatedType = expectedClosureType; |
| 7427 } |
| 11579 // set inferred types for parameters | 7428 // set inferred types for parameters |
| 11580 NodeList<FormalParameter> parameters = closure.parameters.parameters; | 7429 NodeList<FormalParameter> parameters = closure.parameters.parameters; |
| 11581 List<ParameterElement> expectedParameters = expectedClosureType.parameters; | 7430 List<ParameterElement> expectedParameters = expectedClosureType.parameters; |
| 11582 for (int i = 0; | 7431 for (int i = 0; |
| 11583 i < parameters.length && i < expectedParameters.length; | 7432 i < parameters.length && i < expectedParameters.length; |
| 11584 i++) { | 7433 i++) { |
| 11585 FormalParameter parameter = parameters[i]; | 7434 FormalParameter parameter = parameters[i]; |
| 11586 ParameterElement element = parameter.element; | 7435 ParameterElement element = parameter.element; |
| 11587 DartType currentType = _overrideManager.getBestType(element); | 7436 DartType currentType = _overrideManager.getBestType(element); |
| 11588 // may be override the type | 7437 // may be override the type |
| 11589 DartType expectedType = expectedParameters[i].type; | 7438 DartType expectedType = expectedParameters[i].type; |
| 11590 if (currentType == null || expectedType.isMoreSpecificThan(currentType)) { | 7439 if (currentType == null || expectedType.isMoreSpecificThan(currentType)) { |
| 11591 _overrideManager.setType(element, expectedType); | 7440 _overrideManager.setType(element, expectedType); |
| 11592 } | 7441 } |
| 11593 } | 7442 } |
| 11594 } | 7443 } |
| 11595 | 7444 |
| 11596 /** | 7445 /** |
| 11597 * Try to infer types of parameters of the [FunctionExpression] arguments. | 7446 * Try to infer types of parameters of the [FunctionExpression] arguments. |
| 11598 */ | 7447 */ |
| 11599 void _inferFunctionExpressionsParametersTypes(ArgumentList argumentList) { | 7448 void _inferFunctionExpressionsParametersTypes(ArgumentList argumentList) { |
| 11600 for (Expression argument in argumentList.arguments) { | 7449 NodeList<Expression> arguments = argumentList.arguments; |
| 7450 int length = arguments.length; |
| 7451 for (int i = 0; i < length; i++) { |
| 7452 Expression argument = arguments[i]; |
| 11601 ParameterElement parameter = argument.propagatedParameterElement; | 7453 ParameterElement parameter = argument.propagatedParameterElement; |
| 11602 if (parameter == null) { | 7454 if (parameter == null) { |
| 11603 parameter = argument.staticParameterElement; | 7455 parameter = argument.staticParameterElement; |
| 11604 } | 7456 } |
| 11605 if (parameter != null) { | 7457 if (parameter != null) { |
| 11606 _inferFunctionExpressionParametersTypes(argument, parameter.type); | 7458 _inferFunctionExpressionParametersTypes(argument, parameter.type); |
| 11607 } | 7459 } |
| 11608 } | 7460 } |
| 11609 } | 7461 } |
| 11610 | 7462 |
| 11611 /** | 7463 /** |
| 11612 * Return `true` if the given expression terminates abruptly (that is, if any
expression | 7464 * Return `true` if the given expression terminates abruptly (that is, if any
expression |
| 11613 * following the given expression will not be reached). | 7465 * following the given expression will not be reached). |
| 11614 * | 7466 * |
| 11615 * @param expression the expression being tested | 7467 * @param expression the expression being tested |
| 11616 * @return `true` if the given expression terminates abruptly | 7468 * @return `true` if the given expression terminates abruptly |
| 11617 */ | 7469 */ |
| 11618 bool _isAbruptTerminationExpression(Expression expression) { | 7470 bool _isAbruptTerminationExpression(Expression expression) { |
| 11619 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we | 7471 // TODO(brianwilkerson) This needs to be significantly improved. Ideally we |
| 11620 // would eventually turn this into a method on Expression that returns a | 7472 // would eventually turn this into a method on Expression that returns a |
| 11621 // termination indication (normal, abrupt with no exception, abrupt with an | 7473 // termination indication (normal, abrupt with no exception, abrupt with an |
| 11622 // exception). | 7474 // exception). |
| 11623 while (expression is ParenthesizedExpression) { | 7475 expression = expression?.unParenthesized; |
| 11624 expression = (expression as ParenthesizedExpression).expression; | |
| 11625 } | |
| 11626 return expression is ThrowExpression || expression is RethrowExpression; | 7476 return expression is ThrowExpression || expression is RethrowExpression; |
| 11627 } | 7477 } |
| 11628 | 7478 |
| 11629 /** | 7479 /** |
| 11630 * Return `true` if the given statement terminates abruptly (that is, if any s
tatement | 7480 * Return `true` if the given statement terminates abruptly (that is, if any s
tatement |
| 11631 * following the given statement will not be reached). | 7481 * following the given statement will not be reached). |
| 11632 * | 7482 * |
| 11633 * @param statement the statement being tested | 7483 * @param statement the statement being tested |
| 11634 * @return `true` if the given statement terminates abruptly | 7484 * @return `true` if the given statement terminates abruptly |
| 11635 */ | 7485 */ |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11716 * type is more specific than the current type. | 7566 * type is more specific than the current type. |
| 11717 * | 7567 * |
| 11718 * @param expression the expression used to access the static element whose ty
pes might be | 7568 * @param expression the expression used to access the static element whose ty
pes might be |
| 11719 * promoted | 7569 * promoted |
| 11720 * @param potentialType the potential type of the elements | 7570 * @param potentialType the potential type of the elements |
| 11721 */ | 7571 */ |
| 11722 void _promote(Expression expression, DartType potentialType) { | 7572 void _promote(Expression expression, DartType potentialType) { |
| 11723 VariableElement element = getPromotionStaticElement(expression); | 7573 VariableElement element = getPromotionStaticElement(expression); |
| 11724 if (element != null) { | 7574 if (element != null) { |
| 11725 // may be mutated somewhere in closure | 7575 // may be mutated somewhere in closure |
| 11726 if (element.isPotentiallyMutatedInClosure) { | 7576 if (_currentFunctionBody.isPotentiallyMutatedInClosure(element)) { |
| 11727 return; | 7577 return; |
| 11728 } | 7578 } |
| 11729 // prepare current variable type | 7579 // prepare current variable type |
| 11730 DartType type = _promoteManager.getType(element); | 7580 DartType type = _promoteManager.getType(element) ?? |
| 11731 if (type == null) { | 7581 expression.staticType ?? |
| 11732 type = expression.staticType; | 7582 DynamicTypeImpl.instance; |
| 7583 |
| 7584 potentialType ??= DynamicTypeImpl.instance; |
| 7585 |
| 7586 // Check if we can promote to potentialType from type. |
| 7587 if (typeSystem.canPromoteToType(potentialType, type)) { |
| 7588 // Do promote type of variable. |
| 7589 _promoteManager.setType(element, potentialType); |
| 11733 } | 7590 } |
| 11734 // Declared type should not be "dynamic". | |
| 11735 if (type == null || type.isDynamic) { | |
| 11736 return; | |
| 11737 } | |
| 11738 // Promoted type should not be "dynamic". | |
| 11739 if (potentialType == null || potentialType.isDynamic) { | |
| 11740 return; | |
| 11741 } | |
| 11742 // Promoted type should be more specific than declared. | |
| 11743 if (!potentialType.isMoreSpecificThan(type)) { | |
| 11744 return; | |
| 11745 } | |
| 11746 // Do promote type of variable. | |
| 11747 _promoteManager.setType(element, potentialType); | |
| 11748 } | 7591 } |
| 11749 } | 7592 } |
| 11750 | 7593 |
| 11751 /** | 7594 /** |
| 11752 * Promotes type information using given condition. | 7595 * Promotes type information using given condition. |
| 11753 */ | 7596 */ |
| 11754 void _promoteTypes(Expression condition) { | 7597 void _promoteTypes(Expression condition) { |
| 11755 if (condition is BinaryExpression) { | 7598 if (condition is BinaryExpression) { |
| 11756 BinaryExpression binary = condition; | 7599 if (condition.operator.type == TokenType.AMPERSAND_AMPERSAND) { |
| 11757 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) { | 7600 Expression left = condition.leftOperand; |
| 11758 Expression left = binary.leftOperand; | 7601 Expression right = condition.rightOperand; |
| 11759 Expression right = binary.rightOperand; | |
| 11760 _promoteTypes(left); | 7602 _promoteTypes(left); |
| 11761 _promoteTypes(right); | 7603 _promoteTypes(right); |
| 11762 _clearTypePromotionsIfPotentiallyMutatedIn(right); | 7604 _clearTypePromotionsIfPotentiallyMutatedIn(right); |
| 11763 } | 7605 } |
| 11764 } else if (condition is IsExpression) { | 7606 } else if (condition is IsExpression) { |
| 11765 IsExpression is2 = condition; | 7607 if (condition.notOperator == null) { |
| 11766 if (is2.notOperator == null) { | 7608 _promote(condition.expression, condition.type.type); |
| 11767 _promote(is2.expression, is2.type.type); | |
| 11768 } | 7609 } |
| 11769 } else if (condition is ParenthesizedExpression) { | 7610 } else if (condition is ParenthesizedExpression) { |
| 11770 _promoteTypes(condition.expression); | 7611 _promoteTypes(condition.expression); |
| 11771 } | 7612 } |
| 11772 } | 7613 } |
| 11773 | 7614 |
| 11774 /** | 7615 /** |
| 11775 * Propagate any type information that results from knowing that the given con
dition will have | 7616 * Propagate any type information that results from knowing that the given con
dition will have |
| 11776 * been evaluated to 'false'. | 7617 * been evaluated to 'false'. |
| 11777 * | 7618 * |
| 11778 * @param condition the condition that will have evaluated to 'false' | 7619 * @param condition the condition that will have evaluated to 'false' |
| 11779 */ | 7620 */ |
| 11780 void _propagateFalseState(Expression condition) { | 7621 void _propagateFalseState(Expression condition) { |
| 11781 if (condition is BinaryExpression) { | 7622 if (condition is BinaryExpression) { |
| 11782 BinaryExpression binary = condition; | 7623 if (condition.operator.type == TokenType.BAR_BAR) { |
| 11783 if (binary.operator.type == sc.TokenType.BAR_BAR) { | 7624 _propagateFalseState(condition.leftOperand); |
| 11784 _propagateFalseState(binary.leftOperand); | 7625 _propagateFalseState(condition.rightOperand); |
| 11785 _propagateFalseState(binary.rightOperand); | |
| 11786 } | 7626 } |
| 11787 } else if (condition is IsExpression) { | 7627 } else if (condition is IsExpression) { |
| 11788 IsExpression is2 = condition; | 7628 if (condition.notOperator != null) { |
| 11789 if (is2.notOperator != null) { | |
| 11790 // Since an is-statement doesn't actually change the type, we don't | 7629 // Since an is-statement doesn't actually change the type, we don't |
| 11791 // let it affect the propagated type when it would result in a loss | 7630 // let it affect the propagated type when it would result in a loss |
| 11792 // of precision. | 7631 // of precision. |
| 11793 overrideExpression(is2.expression, is2.type.type, false, false); | 7632 overrideExpression( |
| 7633 condition.expression, condition.type.type, false, false); |
| 11794 } | 7634 } |
| 11795 } else if (condition is PrefixExpression) { | 7635 } else if (condition is PrefixExpression) { |
| 11796 PrefixExpression prefix = condition; | 7636 if (condition.operator.type == TokenType.BANG) { |
| 11797 if (prefix.operator.type == sc.TokenType.BANG) { | 7637 _propagateTrueState(condition.operand); |
| 11798 _propagateTrueState(prefix.operand); | |
| 11799 } | 7638 } |
| 11800 } else if (condition is ParenthesizedExpression) { | 7639 } else if (condition is ParenthesizedExpression) { |
| 11801 _propagateFalseState(condition.expression); | 7640 _propagateFalseState(condition.expression); |
| 11802 } | 7641 } |
| 11803 } | 7642 } |
| 11804 | 7643 |
| 11805 /** | 7644 /** |
| 11806 * Propagate any type information that results from knowing that the given exp
ression will have | 7645 * Propagate any type information that results from knowing that the given exp
ression will have |
| 11807 * been evaluated without altering the flow of execution. | 7646 * been evaluated without altering the flow of execution. |
| 11808 * | 7647 * |
| 11809 * @param expression the expression that will have been evaluated | 7648 * @param expression the expression that will have been evaluated |
| 11810 */ | 7649 */ |
| 11811 void _propagateState(Expression expression) { | 7650 void _propagateState(Expression expression) { |
| 11812 // TODO(brianwilkerson) Implement this. | 7651 // TODO(brianwilkerson) Implement this. |
| 11813 } | 7652 } |
| 11814 | 7653 |
| 11815 /** | 7654 /** |
| 11816 * Propagate any type information that results from knowing that the given con
dition will have | 7655 * Propagate any type information that results from knowing that the given con
dition will have |
| 11817 * been evaluated to 'true'. | 7656 * been evaluated to 'true'. |
| 11818 * | 7657 * |
| 11819 * @param condition the condition that will have evaluated to 'true' | 7658 * @param condition the condition that will have evaluated to 'true' |
| 11820 */ | 7659 */ |
| 11821 void _propagateTrueState(Expression condition) { | 7660 void _propagateTrueState(Expression condition) { |
| 11822 if (condition is BinaryExpression) { | 7661 if (condition is BinaryExpression) { |
| 11823 BinaryExpression binary = condition; | 7662 if (condition.operator.type == TokenType.AMPERSAND_AMPERSAND) { |
| 11824 if (binary.operator.type == sc.TokenType.AMPERSAND_AMPERSAND) { | 7663 _propagateTrueState(condition.leftOperand); |
| 11825 _propagateTrueState(binary.leftOperand); | 7664 _propagateTrueState(condition.rightOperand); |
| 11826 _propagateTrueState(binary.rightOperand); | |
| 11827 } | 7665 } |
| 11828 } else if (condition is IsExpression) { | 7666 } else if (condition is IsExpression) { |
| 11829 IsExpression is2 = condition; | 7667 if (condition.notOperator == null) { |
| 11830 if (is2.notOperator == null) { | |
| 11831 // Since an is-statement doesn't actually change the type, we don't | 7668 // Since an is-statement doesn't actually change the type, we don't |
| 11832 // let it affect the propagated type when it would result in a loss | 7669 // let it affect the propagated type when it would result in a loss |
| 11833 // of precision. | 7670 // of precision. |
| 11834 overrideExpression(is2.expression, is2.type.type, false, false); | 7671 overrideExpression( |
| 7672 condition.expression, condition.type.type, false, false); |
| 11835 } | 7673 } |
| 11836 } else if (condition is PrefixExpression) { | 7674 } else if (condition is PrefixExpression) { |
| 11837 PrefixExpression prefix = condition; | 7675 if (condition.operator.type == TokenType.BANG) { |
| 11838 if (prefix.operator.type == sc.TokenType.BANG) { | 7676 _propagateFalseState(condition.operand); |
| 11839 _propagateFalseState(prefix.operand); | |
| 11840 } | 7677 } |
| 11841 } else if (condition is ParenthesizedExpression) { | 7678 } else if (condition is ParenthesizedExpression) { |
| 11842 _propagateTrueState(condition.expression); | 7679 _propagateTrueState(condition.expression); |
| 11843 } | 7680 } |
| 11844 } | 7681 } |
| 11845 } | |
| 11846 | |
| 11847 /** | |
| 11848 * The abstract class `Scope` defines the behavior common to name scopes used by
the resolver | |
| 11849 * to determine which names are visible at any given point in the code. | |
| 11850 */ | |
| 11851 abstract class Scope { | |
| 11852 /** | |
| 11853 * The prefix used to mark an identifier as being private to its library. | |
| 11854 */ | |
| 11855 static int PRIVATE_NAME_PREFIX = 0x5F; | |
| 11856 | 7682 |
| 11857 /** | 7683 /** |
| 11858 * The suffix added to the declared name of a setter when looking up the sette
r. Used to | 7684 * Given an [argumentList] and the [parameters] related to the element that |
| 11859 * disambiguate between a getter and a setter that have the same name. | 7685 * will be invoked using those arguments, compute the list of parameters that |
| 7686 * correspond to the list of arguments. |
| 7687 * |
| 7688 * An error will be reported to [onError] if any of the arguments cannot be |
| 7689 * matched to a parameter. onError can be null to ignore the error. |
| 7690 * |
| 7691 * The flag [reportAsError] should be `true` if a compile-time error should be |
| 7692 * reported; or `false` if a compile-time warning should be reported. |
| 7693 * |
| 7694 * Returns the parameters that correspond to the arguments. If no parameter |
| 7695 * matched an argument, that position will be `null` in the list. |
| 11860 */ | 7696 */ |
| 11861 static String SETTER_SUFFIX = "="; | 7697 static List<ParameterElement> resolveArgumentsToParameters( |
| 11862 | 7698 ArgumentList argumentList, |
| 11863 /** | 7699 List<ParameterElement> parameters, |
| 11864 * The name used to look up the method used to implement the unary minus opera
tor. Used to | 7700 void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]), |
| 11865 * disambiguate between the unary and binary operators. | 7701 {bool reportAsError: false}) { |
| 11866 */ | 7702 if (parameters.isEmpty && argumentList.arguments.isEmpty) { |
| 11867 static String UNARY_MINUS = "unary-"; | 7703 return const <ParameterElement>[]; |
| 11868 | 7704 } |
| 11869 /** | 7705 int requiredParameterCount = 0; |
| 11870 * A table mapping names that are defined in this scope to the element represe
nting the thing | 7706 int unnamedParameterCount = 0; |
| 11871 * declared with that name. | 7707 List<ParameterElement> unnamedParameters = new List<ParameterElement>(); |
| 11872 */ | 7708 HashMap<String, ParameterElement> namedParameters = null; |
| 11873 HashMap<String, Element> _definedNames = new HashMap<String, Element>(); | 7709 int length = parameters.length; |
| 11874 | 7710 for (int i = 0; i < length; i++) { |
| 11875 /** | 7711 ParameterElement parameter = parameters[i]; |
| 11876 * A flag indicating whether there are any names defined in this scope. | 7712 ParameterKind kind = parameter.parameterKind; |
| 11877 */ | 7713 if (kind == ParameterKind.REQUIRED) { |
| 11878 bool _hasName = false; | 7714 unnamedParameters.add(parameter); |
| 11879 | 7715 unnamedParameterCount++; |
| 11880 /** | 7716 requiredParameterCount++; |
| 11881 * Return the scope in which this scope is lexically enclosed. | 7717 } else if (kind == ParameterKind.POSITIONAL) { |
| 11882 * | 7718 unnamedParameters.add(parameter); |
| 11883 * @return the scope in which this scope is lexically enclosed | 7719 unnamedParameterCount++; |
| 11884 */ | |
| 11885 Scope get enclosingScope => null; | |
| 11886 | |
| 11887 /** | |
| 11888 * Return the listener that is to be informed when an error is encountered. | |
| 11889 * | |
| 11890 * @return the listener that is to be informed when an error is encountered | |
| 11891 */ | |
| 11892 AnalysisErrorListener get errorListener; | |
| 11893 | |
| 11894 /** | |
| 11895 * Add the given element to this scope. If there is already an element with th
e given name defined | |
| 11896 * in this scope, then an error will be generated and the original element wil
l continue to be | |
| 11897 * mapped to the name. If there is an element with the given name in an enclos
ing scope, then a | |
| 11898 * warning will be generated but the given element will hide the inherited ele
ment. | |
| 11899 * | |
| 11900 * @param element the element to be added to this scope | |
| 11901 */ | |
| 11902 void define(Element element) { | |
| 11903 String name = _getName(element); | |
| 11904 if (name != null && !name.isEmpty) { | |
| 11905 if (_definedNames.containsKey(name)) { | |
| 11906 errorListener | |
| 11907 .onError(getErrorForDuplicate(_definedNames[name], element)); | |
| 11908 } else { | 7720 } else { |
| 11909 _definedNames[name] = element; | 7721 namedParameters ??= new HashMap<String, ParameterElement>(); |
| 11910 _hasName = true; | 7722 namedParameters[parameter.name] = parameter; |
| 11911 } | 7723 } |
| 11912 } | 7724 } |
| 11913 } | 7725 int unnamedIndex = 0; |
| 11914 | 7726 NodeList<Expression> arguments = argumentList.arguments; |
| 11915 /** | 7727 int argumentCount = arguments.length; |
| 11916 * Add the given element to this scope without checking for duplication or hid
ing. | 7728 List<ParameterElement> resolvedParameters = |
| 11917 * | 7729 new List<ParameterElement>(argumentCount); |
| 11918 * @param name the name of the element to be added | 7730 int positionalArgumentCount = 0; |
| 11919 * @param element the element to be added to this scope | 7731 HashSet<String> usedNames = null; |
| 11920 */ | 7732 bool noBlankArguments = true; |
| 11921 void defineNameWithoutChecking(String name, Element element) { | 7733 for (int i = 0; i < argumentCount; i++) { |
| 11922 _definedNames[name] = element; | 7734 Expression argument = arguments[i]; |
| 11923 _hasName = true; | 7735 if (argument is NamedExpression) { |
| 11924 } | 7736 SimpleIdentifier nameNode = argument.name.label; |
| 11925 | 7737 String name = nameNode.name; |
| 11926 /** | 7738 ParameterElement element = |
| 11927 * Add the given element to this scope without checking for duplication or hid
ing. | 7739 namedParameters != null ? namedParameters[name] : null; |
| 11928 * | 7740 if (element == null) { |
| 11929 * @param element the element to be added to this scope | 7741 ErrorCode errorCode = (reportAsError |
| 11930 */ | 7742 ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER |
| 11931 void defineWithoutChecking(Element element) { | 7743 : StaticWarningCode.UNDEFINED_NAMED_PARAMETER); |
| 11932 _definedNames[_getName(element)] = element; | 7744 if (onError != null) { |
| 11933 _hasName = true; | 7745 onError(errorCode, nameNode, [name]); |
| 11934 } | 7746 } |
| 11935 | 7747 } else { |
| 11936 /** | 7748 resolvedParameters[i] = element; |
| 11937 * Return the error code to be used when reporting that a name being defined l
ocally conflicts | 7749 nameNode.staticElement = element; |
| 11938 * with another element of the same name in the local scope. | 7750 } |
| 11939 * | 7751 usedNames ??= new HashSet<String>(); |
| 11940 * @param existing the first element to be declared with the conflicting name | 7752 if (!usedNames.add(name)) { |
| 11941 * @param duplicate another element declared with the conflicting name | 7753 if (onError != null) { |
| 11942 * @return the error code used to report duplicate names within a scope | 7754 onError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, |
| 11943 */ | 7755 [name]); |
| 11944 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { | 7756 } |
| 11945 // TODO(brianwilkerson) Customize the error message based on the types of | 7757 } |
| 11946 // elements that share the same name. | 7758 } else { |
| 11947 // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being | 7759 if (argument is SimpleIdentifier && argument.name.isEmpty) { |
| 11948 // generated. | 7760 noBlankArguments = false; |
| 11949 Source source = duplicate.source; | 7761 } |
| 11950 return new AnalysisError(source, duplicate.nameOffset, duplicate.nameLength, | 7762 positionalArgumentCount++; |
| 11951 CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]); | 7763 if (unnamedIndex < unnamedParameterCount) { |
| 11952 } | 7764 resolvedParameters[i] = unnamedParameters[unnamedIndex++]; |
| 11953 | 7765 } |
| 11954 /** | |
| 11955 * Return the source that contains the given identifier, or the source associa
ted with this scope | |
| 11956 * if the source containing the identifier could not be determined. | |
| 11957 * | |
| 11958 * @param identifier the identifier whose source is to be returned | |
| 11959 * @return the source that contains the given identifier | |
| 11960 */ | |
| 11961 Source getSource(AstNode node) { | |
| 11962 CompilationUnit unit = node.getAncestor((node) => node is CompilationUnit); | |
| 11963 if (unit != null) { | |
| 11964 CompilationUnitElement unitElement = unit.element; | |
| 11965 if (unitElement != null) { | |
| 11966 return unitElement.source; | |
| 11967 } | 7766 } |
| 11968 } | 7767 } |
| 11969 return null; | 7768 if (positionalArgumentCount < requiredParameterCount && noBlankArguments) { |
| 11970 } | 7769 ErrorCode errorCode = (reportAsError |
| 11971 | 7770 ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS |
| 11972 /** | 7771 : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS); |
| 11973 * Return the element with which the given name is associated, or `null` if th
e name is not | 7772 if (onError != null) { |
| 11974 * defined within this scope. | 7773 onError(errorCode, argumentList, |
| 11975 * | 7774 [requiredParameterCount, positionalArgumentCount]); |
| 11976 * @param identifier the identifier node to lookup element for, used to report
correct kind of a | 7775 } |
| 11977 * problem and associate problem with | 7776 } else if (positionalArgumentCount > unnamedParameterCount && |
| 11978 * @param name the name associated with the element to be returned | 7777 noBlankArguments) { |
| 11979 * @param referencingLibrary the library that contains the reference to the na
me, used to | 7778 ErrorCode errorCode = (reportAsError |
| 11980 * implement library-level privacy | 7779 ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS |
| 11981 * @return the element with which the given name is associated | 7780 : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS); |
| 11982 */ | 7781 if (onError != null) { |
| 11983 Element internalLookup( | 7782 onError(errorCode, argumentList, |
| 11984 Identifier identifier, String name, LibraryElement referencingLibrary); | 7783 [unnamedParameterCount, positionalArgumentCount]); |
| 11985 | |
| 11986 /** | |
| 11987 * Return the element with which the given name is associated, or `null` if th
e name is not | |
| 11988 * defined within this scope. This method only returns elements that are direc
tly defined within | |
| 11989 * this scope, not elements that are defined in an enclosing scope. | |
| 11990 * | |
| 11991 * @param name the name associated with the element to be returned | |
| 11992 * @param referencingLibrary the library that contains the reference to the na
me, used to | |
| 11993 * implement library-level privacy | |
| 11994 * @return the element with which the given name is associated | |
| 11995 */ | |
| 11996 Element localLookup(String name, LibraryElement referencingLibrary) { | |
| 11997 if (_hasName) { | |
| 11998 return _definedNames[name]; | |
| 11999 } | |
| 12000 return null; | |
| 12001 } | |
| 12002 | |
| 12003 /** | |
| 12004 * Return the element with which the given identifier is associated, or `null`
if the name | |
| 12005 * is not defined within this scope. | |
| 12006 * | |
| 12007 * @param identifier the identifier associated with the element to be returned | |
| 12008 * @param referencingLibrary the library that contains the reference to the na
me, used to | |
| 12009 * implement library-level privacy | |
| 12010 * @return the element with which the given identifier is associated | |
| 12011 */ | |
| 12012 Element lookup(Identifier identifier, LibraryElement referencingLibrary) => | |
| 12013 internalLookup(identifier, identifier.name, referencingLibrary); | |
| 12014 | |
| 12015 /** | |
| 12016 * Return the name that will be used to look up the given element. | |
| 12017 * | |
| 12018 * @param element the element whose look-up name is to be returned | |
| 12019 * @return the name that will be used to look up the given element | |
| 12020 */ | |
| 12021 String _getName(Element element) { | |
| 12022 if (element is MethodElement) { | |
| 12023 MethodElement method = element; | |
| 12024 if (method.name == "-" && method.parameters.length == 0) { | |
| 12025 return UNARY_MINUS; | |
| 12026 } | 7784 } |
| 12027 } | 7785 } |
| 12028 return element.name; | 7786 return resolvedParameters; |
| 12029 } | 7787 } |
| 12030 | |
| 12031 /** | |
| 12032 * Return `true` if the given name is a library-private name. | |
| 12033 * | |
| 12034 * @param name the name being tested | |
| 12035 * @return `true` if the given name is a library-private name | |
| 12036 */ | |
| 12037 static bool isPrivateName(String name) => | |
| 12038 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX); | |
| 12039 } | 7788 } |
| 12040 | 7789 |
| 12041 /** | 7790 /** |
| 12042 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST
structure is | 7791 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST
structure is |
| 12043 * being visited. | 7792 * being visited. |
| 7793 */ |
| 7794 /** |
| 7795 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST
structure is |
| 7796 * being visited. |
| 12044 */ | 7797 */ |
| 12045 abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { | 7798 abstract class ScopedVisitor extends UnifyingAstVisitor<Object> { |
| 12046 /** | 7799 /** |
| 12047 * The element for the library containing the compilation unit being visited. | 7800 * The element for the library containing the compilation unit being visited. |
| 12048 */ | 7801 */ |
| 12049 final LibraryElement definingLibrary; | 7802 final LibraryElement definingLibrary; |
| 12050 | 7803 |
| 12051 /** | 7804 /** |
| 12052 * The source representing the compilation unit being visited. | 7805 * The source representing the compilation unit being visited. |
| 12053 */ | 7806 */ |
| 12054 final Source source; | 7807 final Source source; |
| 12055 | 7808 |
| 12056 /** | 7809 /** |
| 12057 * The error listener that will be informed of any errors that are found durin
g resolution. | 7810 * The object used to access the types from the core library. |
| 12058 */ | 7811 */ |
| 12059 final AnalysisErrorListener errorListener; | 7812 final TypeProvider typeProvider; |
| 7813 |
| 7814 /** |
| 7815 * The error reporter that will be informed of any errors that are found |
| 7816 * during resolution. |
| 7817 */ |
| 7818 final ErrorReporter errorReporter; |
| 12060 | 7819 |
| 12061 /** | 7820 /** |
| 12062 * The scope used to resolve identifiers. | 7821 * The scope used to resolve identifiers. |
| 12063 */ | 7822 */ |
| 12064 Scope nameScope; | 7823 Scope nameScope; |
| 12065 | 7824 |
| 12066 /** | 7825 /** |
| 12067 * The object used to access the types from the core library. | |
| 12068 */ | |
| 12069 final TypeProvider typeProvider; | |
| 12070 | |
| 12071 /** | |
| 12072 * The scope used to resolve unlabeled `break` and `continue` statements. | 7826 * The scope used to resolve unlabeled `break` and `continue` statements. |
| 12073 */ | 7827 */ |
| 12074 ImplicitLabelScope _implicitLabelScope = ImplicitLabelScope.ROOT; | 7828 ImplicitLabelScope _implicitLabelScope = ImplicitLabelScope.ROOT; |
| 12075 | 7829 |
| 12076 /** | 7830 /** |
| 12077 * The scope used to resolve labels for `break` and `continue` statements, or | 7831 * The scope used to resolve labels for `break` and `continue` statements, or |
| 12078 * `null` if no labels have been defined in the current context. | 7832 * `null` if no labels have been defined in the current context. |
| 12079 */ | 7833 */ |
| 12080 LabelScope labelScope; | 7834 LabelScope labelScope; |
| 12081 | 7835 |
| 12082 /** | 7836 /** |
| 7837 * A flag indicating whether to enable support for allowing access to field |
| 7838 * formal parameters in a constructor's initializer list. |
| 7839 */ |
| 7840 bool enableInitializingFormalAccess = false; |
| 7841 |
| 7842 /** |
| 12083 * The class containing the AST nodes being visited, | 7843 * The class containing the AST nodes being visited, |
| 12084 * or `null` if we are not in the scope of a class. | 7844 * or `null` if we are not in the scope of a class. |
| 12085 */ | 7845 */ |
| 12086 ClassElement enclosingClass; | 7846 ClassElement enclosingClass; |
| 12087 | 7847 |
| 12088 /** | 7848 /** |
| 12089 * Initialize a newly created visitor to resolve the nodes in a compilation | 7849 * Initialize a newly created visitor to resolve the nodes in a compilation |
| 12090 * unit. | 7850 * unit. |
| 12091 * | 7851 * |
| 12092 * [definingLibrary] is the element for the library containing the | 7852 * [definingLibrary] is the element for the library containing the |
| 12093 * compilation unit being visited. | 7853 * compilation unit being visited. |
| 12094 * [source] is the source representing the compilation unit being visited. | 7854 * [source] is the source representing the compilation unit being visited. |
| 12095 * [typeProvider] is the object used to access the types from the core | 7855 * [typeProvider] is the object used to access the types from the core |
| 12096 * library. | 7856 * library. |
| 12097 * [errorListener] is the error listener that will be informed of any errors | 7857 * [errorListener] is the error listener that will be informed of any errors |
| 12098 * that are found during resolution. | 7858 * that are found during resolution. |
| 12099 * [nameScope] is the scope used to resolve identifiers in the node that will | 7859 * [nameScope] is the scope used to resolve identifiers in the node that will |
| 12100 * first be visited. If `null` or unspecified, a new [LibraryScope] will be | 7860 * first be visited. If `null` or unspecified, a new [LibraryScope] will be |
| 12101 * created based on [definingLibrary] and [typeProvider]. | 7861 * created based on [definingLibrary] and [typeProvider]. |
| 12102 */ | 7862 */ |
| 12103 ScopedVisitor( | 7863 ScopedVisitor(this.definingLibrary, Source source, this.typeProvider, |
| 12104 this.definingLibrary, this.source, this.typeProvider, this.errorListener, | 7864 AnalysisErrorListener errorListener, |
| 12105 {Scope nameScope}) { | 7865 {Scope nameScope}) |
| 7866 : source = source, |
| 7867 errorReporter = new ErrorReporter(errorListener, source) { |
| 12106 if (nameScope == null) { | 7868 if (nameScope == null) { |
| 12107 this.nameScope = new LibraryScope(definingLibrary, errorListener); | 7869 this.nameScope = new LibraryScope(definingLibrary); |
| 12108 } else { | 7870 } else { |
| 12109 this.nameScope = nameScope; | 7871 this.nameScope = nameScope; |
| 12110 } | 7872 } |
| 7873 enableInitializingFormalAccess = |
| 7874 definingLibrary.context.analysisOptions.enableInitializingFormalAccess; |
| 12111 } | 7875 } |
| 12112 | 7876 |
| 12113 /** | 7877 /** |
| 12114 * Return the implicit label scope in which the current node is being | 7878 * Return the implicit label scope in which the current node is being |
| 12115 * resolved. | 7879 * resolved. |
| 12116 */ | 7880 */ |
| 12117 ImplicitLabelScope get implicitLabelScope => _implicitLabelScope; | 7881 ImplicitLabelScope get implicitLabelScope => _implicitLabelScope; |
| 12118 | 7882 |
| 12119 /** | 7883 /** |
| 12120 * Replaces the current [Scope] with the enclosing [Scope]. | 7884 * Replaces the current [Scope] with the enclosing [Scope]. |
| 12121 * | 7885 * |
| 12122 * @return the enclosing [Scope]. | 7886 * @return the enclosing [Scope]. |
| 12123 */ | 7887 */ |
| 12124 Scope popNameScope() { | 7888 Scope popNameScope() { |
| 12125 nameScope = nameScope.enclosingScope; | 7889 nameScope = nameScope.enclosingScope; |
| 12126 return nameScope; | 7890 return nameScope; |
| 12127 } | 7891 } |
| 12128 | 7892 |
| 12129 /** | 7893 /** |
| 12130 * Pushes a new [Scope] into the visitor. | 7894 * Pushes a new [Scope] into the visitor. |
| 12131 * | 7895 * |
| 12132 * @return the new [Scope]. | 7896 * @return the new [Scope]. |
| 12133 */ | 7897 */ |
| 12134 Scope pushNameScope() { | 7898 Scope pushNameScope() { |
| 12135 Scope newScope = new EnclosedScope(nameScope); | 7899 Scope newScope = new EnclosedScope(nameScope); |
| 12136 nameScope = newScope; | 7900 nameScope = newScope; |
| 12137 return nameScope; | 7901 return nameScope; |
| 12138 } | 7902 } |
| 12139 | 7903 |
| 12140 /** | |
| 12141 * Report an error with the given error code and arguments. | |
| 12142 * | |
| 12143 * @param errorCode the error code of the error to be reported | |
| 12144 * @param node the node specifying the location of the error | |
| 12145 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 12146 */ | |
| 12147 void reportErrorForNode(ErrorCode errorCode, AstNode node, | |
| 12148 [List<Object> arguments]) { | |
| 12149 errorListener.onError(new AnalysisError( | |
| 12150 source, node.offset, node.length, errorCode, arguments)); | |
| 12151 } | |
| 12152 | |
| 12153 /** | |
| 12154 * Report an error with the given error code and arguments. | |
| 12155 * | |
| 12156 * @param errorCode the error code of the error to be reported | |
| 12157 * @param offset the offset of the location of the error | |
| 12158 * @param length the length of the location of the error | |
| 12159 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 12160 */ | |
| 12161 void reportErrorForOffset(ErrorCode errorCode, int offset, int length, | |
| 12162 [List<Object> arguments]) { | |
| 12163 errorListener.onError( | |
| 12164 new AnalysisError(source, offset, length, errorCode, arguments)); | |
| 12165 } | |
| 12166 | |
| 12167 /** | |
| 12168 * Report an error with the given error code and arguments. | |
| 12169 * | |
| 12170 * @param errorCode the error code of the error to be reported | |
| 12171 * @param token the token specifying the location of the error | |
| 12172 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 12173 */ | |
| 12174 void reportErrorForToken(ErrorCode errorCode, sc.Token token, | |
| 12175 [List<Object> arguments]) { | |
| 12176 errorListener.onError(new AnalysisError( | |
| 12177 source, token.offset, token.length, errorCode, arguments)); | |
| 12178 } | |
| 12179 | |
| 12180 /** | |
| 12181 * Visit the given AST node if it is not null. | |
| 12182 * | |
| 12183 * @param node the node to be visited | |
| 12184 */ | |
| 12185 void safelyVisit(AstNode node) { | |
| 12186 if (node != null) { | |
| 12187 node.accept(this); | |
| 12188 } | |
| 12189 } | |
| 12190 | |
| 12191 @override | 7904 @override |
| 12192 Object visitBlock(Block node) { | 7905 Object visitBlock(Block node) { |
| 12193 Scope outerScope = nameScope; | 7906 Scope outerScope = nameScope; |
| 12194 try { | 7907 try { |
| 12195 EnclosedScope enclosedScope = new EnclosedScope(nameScope); | 7908 EnclosedScope enclosedScope = new BlockScope(nameScope, node); |
| 12196 _hideNamesDefinedInBlock(enclosedScope, node); | |
| 12197 nameScope = enclosedScope; | 7909 nameScope = enclosedScope; |
| 12198 super.visitBlock(node); | 7910 super.visitBlock(node); |
| 12199 } finally { | 7911 } finally { |
| 12200 nameScope = outerScope; | 7912 nameScope = outerScope; |
| 12201 } | 7913 } |
| 12202 return null; | 7914 return null; |
| 12203 } | 7915 } |
| 12204 | 7916 |
| 12205 @override | 7917 @override |
| 12206 Object visitBlockFunctionBody(BlockFunctionBody node) { | 7918 Object visitBlockFunctionBody(BlockFunctionBody node) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12258 enclosingClass = outerClass; | 7970 enclosingClass = outerClass; |
| 12259 } | 7971 } |
| 12260 } | 7972 } |
| 12261 } finally { | 7973 } finally { |
| 12262 nameScope = outerScope; | 7974 nameScope = outerScope; |
| 12263 } | 7975 } |
| 12264 return null; | 7976 return null; |
| 12265 } | 7977 } |
| 12266 | 7978 |
| 12267 void visitClassDeclarationInScope(ClassDeclaration node) { | 7979 void visitClassDeclarationInScope(ClassDeclaration node) { |
| 12268 safelyVisit(node.name); | 7980 node.name?.accept(this); |
| 12269 safelyVisit(node.typeParameters); | 7981 node.typeParameters?.accept(this); |
| 12270 safelyVisit(node.extendsClause); | 7982 node.extendsClause?.accept(this); |
| 12271 safelyVisit(node.withClause); | 7983 node.withClause?.accept(this); |
| 12272 safelyVisit(node.implementsClause); | 7984 node.implementsClause?.accept(this); |
| 12273 safelyVisit(node.nativeClause); | 7985 node.nativeClause?.accept(this); |
| 12274 } | 7986 } |
| 12275 | 7987 |
| 12276 void visitClassMembersInScope(ClassDeclaration node) { | 7988 void visitClassMembersInScope(ClassDeclaration node) { |
| 12277 safelyVisit(node.documentationComment); | 7989 node.documentationComment?.accept(this); |
| 12278 node.metadata.accept(this); | 7990 node.metadata.accept(this); |
| 12279 node.members.accept(this); | 7991 node.members.accept(this); |
| 12280 } | 7992 } |
| 12281 | 7993 |
| 12282 @override | 7994 @override |
| 12283 Object visitClassTypeAlias(ClassTypeAlias node) { | 7995 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 12284 Scope outerScope = nameScope; | 7996 Scope outerScope = nameScope; |
| 12285 try { | 7997 try { |
| 12286 ClassElement element = node.element; | 7998 ClassElement element = node.element; |
| 12287 nameScope = | 7999 nameScope = |
| 12288 new ClassScope(new TypeParameterScope(nameScope, element), element); | 8000 new ClassScope(new TypeParameterScope(nameScope, element), element); |
| 12289 super.visitClassTypeAlias(node); | 8001 super.visitClassTypeAlias(node); |
| 12290 } finally { | 8002 } finally { |
| 12291 nameScope = outerScope; | 8003 nameScope = outerScope; |
| 12292 } | 8004 } |
| 12293 return null; | 8005 return null; |
| 12294 } | 8006 } |
| 12295 | 8007 |
| 12296 @override | 8008 @override |
| 12297 Object visitConstructorDeclaration(ConstructorDeclaration node) { | 8009 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 12298 ConstructorElement constructorElement = node.element; | 8010 ConstructorElement constructorElement = node.element; |
| 8011 if (constructorElement == null) { |
| 8012 StringBuffer buffer = new StringBuffer(); |
| 8013 buffer.write("Missing element for constructor "); |
| 8014 buffer.write(node.returnType.name); |
| 8015 if (node.name != null) { |
| 8016 buffer.write("."); |
| 8017 buffer.write(node.name.name); |
| 8018 } |
| 8019 buffer.write(" in "); |
| 8020 buffer.write(definingLibrary.source.fullName); |
| 8021 AnalysisEngine.instance.logger.logInformation(buffer.toString(), |
| 8022 new CaughtException(new AnalysisException(), null)); |
| 8023 } |
| 12299 Scope outerScope = nameScope; | 8024 Scope outerScope = nameScope; |
| 12300 try { | 8025 try { |
| 12301 if (constructorElement == null) { | 8026 if (constructorElement != null) { |
| 12302 StringBuffer buffer = new StringBuffer(); | |
| 12303 buffer.write("Missing element for constructor "); | |
| 12304 buffer.write(node.returnType.name); | |
| 12305 if (node.name != null) { | |
| 12306 buffer.write("."); | |
| 12307 buffer.write(node.name.name); | |
| 12308 } | |
| 12309 buffer.write(" in "); | |
| 12310 buffer.write(definingLibrary.source.fullName); | |
| 12311 AnalysisEngine.instance.logger.logInformation(buffer.toString(), | |
| 12312 new CaughtException(new AnalysisException(), null)); | |
| 12313 } else { | |
| 12314 nameScope = new FunctionScope(nameScope, constructorElement); | 8027 nameScope = new FunctionScope(nameScope, constructorElement); |
| 12315 } | 8028 } |
| 12316 super.visitConstructorDeclaration(node); | 8029 node.documentationComment?.accept(this); |
| 8030 node.metadata.accept(this); |
| 8031 node.returnType?.accept(this); |
| 8032 node.name?.accept(this); |
| 8033 node.parameters?.accept(this); |
| 8034 Scope functionScope = nameScope; |
| 8035 try { |
| 8036 if (constructorElement != null && enableInitializingFormalAccess) { |
| 8037 nameScope = |
| 8038 new ConstructorInitializerScope(nameScope, constructorElement); |
| 8039 } |
| 8040 node.initializers.accept(this); |
| 8041 } finally { |
| 8042 nameScope = functionScope; |
| 8043 } |
| 8044 node.redirectedConstructor?.accept(this); |
| 8045 visitConstructorDeclarationInScope(node); |
| 12317 } finally { | 8046 } finally { |
| 12318 nameScope = outerScope; | 8047 nameScope = outerScope; |
| 12319 } | 8048 } |
| 12320 return null; | 8049 return null; |
| 12321 } | 8050 } |
| 12322 | 8051 |
| 8052 void visitConstructorDeclarationInScope(ConstructorDeclaration node) { |
| 8053 node.body?.accept(this); |
| 8054 } |
| 8055 |
| 12323 @override | 8056 @override |
| 12324 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | 8057 Object visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 12325 VariableElement element = node.element; | 8058 VariableElement element = node.element; |
| 12326 if (element != null) { | 8059 if (element != null) { |
| 12327 nameScope.define(element); | 8060 nameScope.define(element); |
| 12328 } | 8061 } |
| 12329 super.visitDeclaredIdentifier(node); | 8062 super.visitDeclaredIdentifier(node); |
| 12330 return null; | 8063 return null; |
| 12331 } | 8064 } |
| 12332 | 8065 |
| 12333 @override | 8066 @override |
| 12334 Object visitDoStatement(DoStatement node) { | 8067 Object visitDoStatement(DoStatement node) { |
| 12335 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; | 8068 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; |
| 12336 try { | 8069 try { |
| 12337 _implicitLabelScope = _implicitLabelScope.nest(node); | 8070 _implicitLabelScope = _implicitLabelScope.nest(node); |
| 12338 visitStatementInScope(node.body); | 8071 visitStatementInScope(node.body); |
| 12339 safelyVisit(node.condition); | 8072 node.condition?.accept(this); |
| 12340 } finally { | 8073 } finally { |
| 12341 _implicitLabelScope = outerImplicitScope; | 8074 _implicitLabelScope = outerImplicitScope; |
| 12342 } | 8075 } |
| 12343 return null; | 8076 return null; |
| 12344 } | 8077 } |
| 12345 | 8078 |
| 12346 @override | 8079 @override |
| 12347 Object visitEnumDeclaration(EnumDeclaration node) { | 8080 Object visitEnumDeclaration(EnumDeclaration node) { |
| 12348 ClassElement classElement = node.element; | 8081 ClassElement classElement = node.element; |
| 12349 Scope outerScope = nameScope; | 8082 Scope outerScope = nameScope; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 12363 enclosingClass = outerClass; | 8096 enclosingClass = outerClass; |
| 12364 } | 8097 } |
| 12365 } | 8098 } |
| 12366 } finally { | 8099 } finally { |
| 12367 nameScope = outerScope; | 8100 nameScope = outerScope; |
| 12368 } | 8101 } |
| 12369 return null; | 8102 return null; |
| 12370 } | 8103 } |
| 12371 | 8104 |
| 12372 void visitEnumMembersInScope(EnumDeclaration node) { | 8105 void visitEnumMembersInScope(EnumDeclaration node) { |
| 12373 safelyVisit(node.documentationComment); | 8106 node.documentationComment?.accept(this); |
| 12374 node.metadata.accept(this); | 8107 node.metadata.accept(this); |
| 12375 node.constants.accept(this); | 8108 node.constants.accept(this); |
| 12376 } | 8109 } |
| 12377 | 8110 |
| 12378 @override | 8111 @override |
| 12379 Object visitForEachStatement(ForEachStatement node) { | 8112 Object visitForEachStatement(ForEachStatement node) { |
| 12380 Scope outerNameScope = nameScope; | 8113 Scope outerNameScope = nameScope; |
| 12381 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; | 8114 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; |
| 12382 try { | 8115 try { |
| 12383 nameScope = new EnclosedScope(nameScope); | 8116 nameScope = new EnclosedScope(nameScope); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 12395 * the inherited visit method so that ResolverVisitor can intervene when type
propagation is | 8128 * the inherited visit method so that ResolverVisitor can intervene when type
propagation is |
| 12396 * enabled. | 8129 * enabled. |
| 12397 * | 8130 * |
| 12398 * @param node the statement to be visited | 8131 * @param node the statement to be visited |
| 12399 */ | 8132 */ |
| 12400 void visitForEachStatementInScope(ForEachStatement node) { | 8133 void visitForEachStatementInScope(ForEachStatement node) { |
| 12401 // | 8134 // |
| 12402 // We visit the iterator before the loop variable because the loop variable | 8135 // We visit the iterator before the loop variable because the loop variable |
| 12403 // cannot be in scope while visiting the iterator. | 8136 // cannot be in scope while visiting the iterator. |
| 12404 // | 8137 // |
| 12405 safelyVisit(node.identifier); | 8138 node.identifier?.accept(this); |
| 12406 safelyVisit(node.iterable); | 8139 node.iterable?.accept(this); |
| 12407 safelyVisit(node.loopVariable); | 8140 node.loopVariable?.accept(this); |
| 12408 visitStatementInScope(node.body); | 8141 visitStatementInScope(node.body); |
| 12409 } | 8142 } |
| 12410 | 8143 |
| 12411 @override | 8144 @override |
| 12412 Object visitFormalParameterList(FormalParameterList node) { | 8145 Object visitFormalParameterList(FormalParameterList node) { |
| 12413 super.visitFormalParameterList(node); | 8146 super.visitFormalParameterList(node); |
| 12414 // We finished resolving function signature, now include formal parameters | 8147 // We finished resolving function signature, now include formal parameters |
| 12415 // scope. Note: we must not do this if the parent is a | 8148 // scope. Note: we must not do this if the parent is a |
| 12416 // FunctionTypedFormalParameter, because in that case we aren't finished | 8149 // FunctionTypedFormalParameter, because in that case we aren't finished |
| 12417 // resolving the full function signature, just a part of it. | 8150 // resolving the full function signature, just a part of it. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 12441 } | 8174 } |
| 12442 | 8175 |
| 12443 /** | 8176 /** |
| 12444 * Visit the given statement after it's scope has been created. This replaces
the normal call to | 8177 * Visit the given statement after it's scope has been created. This replaces
the normal call to |
| 12445 * the inherited visit method so that ResolverVisitor can intervene when type
propagation is | 8178 * the inherited visit method so that ResolverVisitor can intervene when type
propagation is |
| 12446 * enabled. | 8179 * enabled. |
| 12447 * | 8180 * |
| 12448 * @param node the statement to be visited | 8181 * @param node the statement to be visited |
| 12449 */ | 8182 */ |
| 12450 void visitForStatementInScope(ForStatement node) { | 8183 void visitForStatementInScope(ForStatement node) { |
| 12451 safelyVisit(node.variables); | 8184 node.variables?.accept(this); |
| 12452 safelyVisit(node.initialization); | 8185 node.initialization?.accept(this); |
| 12453 safelyVisit(node.condition); | 8186 node.condition?.accept(this); |
| 12454 node.updaters.accept(this); | 8187 node.updaters.accept(this); |
| 12455 visitStatementInScope(node.body); | 8188 visitStatementInScope(node.body); |
| 12456 } | 8189 } |
| 12457 | 8190 |
| 12458 @override | 8191 @override |
| 12459 Object visitFunctionDeclaration(FunctionDeclaration node) { | 8192 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 12460 ExecutableElement functionElement = node.element; | 8193 ExecutableElement functionElement = node.element; |
| 12461 if (functionElement != null && | 8194 if (functionElement != null && |
| 12462 functionElement.enclosingElement is! CompilationUnitElement) { | 8195 functionElement.enclosingElement is! CompilationUnitElement) { |
| 12463 nameScope.define(functionElement); | 8196 nameScope.define(functionElement); |
| 12464 } | 8197 } |
| 12465 Scope outerScope = nameScope; | 8198 Scope outerScope = nameScope; |
| 12466 try { | 8199 try { |
| 12467 if (functionElement == null) { | 8200 if (functionElement == null) { |
| 12468 AnalysisEngine.instance.logger.logInformation( | 8201 AnalysisEngine.instance.logger.logInformation( |
| 12469 "Missing element for top-level function ${node.name.name} in ${defin
ingLibrary.source.fullName}", | 8202 "Missing element for top-level function ${node.name.name} in ${defin
ingLibrary.source.fullName}", |
| 12470 new CaughtException(new AnalysisException(), null)); | 8203 new CaughtException(new AnalysisException(), null)); |
| 12471 } else { | 8204 } else { |
| 12472 nameScope = new FunctionScope(nameScope, functionElement); | 8205 nameScope = new FunctionScope(nameScope, functionElement); |
| 12473 } | 8206 } |
| 12474 super.visitFunctionDeclaration(node); | 8207 visitFunctionDeclarationInScope(node); |
| 12475 } finally { | 8208 } finally { |
| 12476 nameScope = outerScope; | 8209 nameScope = outerScope; |
| 12477 } | 8210 } |
| 12478 return null; | 8211 return null; |
| 12479 } | 8212 } |
| 12480 | 8213 |
| 8214 void visitFunctionDeclarationInScope(FunctionDeclaration node) { |
| 8215 super.visitFunctionDeclaration(node); |
| 8216 } |
| 8217 |
| 12481 @override | 8218 @override |
| 12482 Object visitFunctionExpression(FunctionExpression node) { | 8219 Object visitFunctionExpression(FunctionExpression node) { |
| 12483 if (node.parent is FunctionDeclaration) { | 8220 if (node.parent is FunctionDeclaration) { |
| 12484 // We have already created a function scope and don't need to do so again. | 8221 // We have already created a function scope and don't need to do so again. |
| 12485 super.visitFunctionExpression(node); | 8222 super.visitFunctionExpression(node); |
| 12486 } else { | 8223 } else { |
| 12487 Scope outerScope = nameScope; | 8224 Scope outerScope = nameScope; |
| 12488 try { | 8225 try { |
| 12489 ExecutableElement functionElement = node.element; | 8226 ExecutableElement functionElement = node.element; |
| 12490 if (functionElement == null) { | 8227 if (functionElement == null) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 12513 } | 8250 } |
| 12514 } | 8251 } |
| 12515 return null; | 8252 return null; |
| 12516 } | 8253 } |
| 12517 | 8254 |
| 12518 @override | 8255 @override |
| 12519 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 8256 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 12520 Scope outerScope = nameScope; | 8257 Scope outerScope = nameScope; |
| 12521 try { | 8258 try { |
| 12522 nameScope = new FunctionTypeScope(nameScope, node.element); | 8259 nameScope = new FunctionTypeScope(nameScope, node.element); |
| 12523 super.visitFunctionTypeAlias(node); | 8260 visitFunctionTypeAliasInScope(node); |
| 12524 } finally { | 8261 } finally { |
| 12525 nameScope = outerScope; | 8262 nameScope = outerScope; |
| 12526 } | 8263 } |
| 12527 return null; | 8264 return null; |
| 12528 } | 8265 } |
| 12529 | 8266 |
| 8267 void visitFunctionTypeAliasInScope(FunctionTypeAlias node) { |
| 8268 super.visitFunctionTypeAlias(node); |
| 8269 } |
| 8270 |
| 12530 @override | 8271 @override |
| 12531 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | 8272 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 12532 Scope outerScope = nameScope; | 8273 Scope outerScope = nameScope; |
| 12533 try { | 8274 try { |
| 12534 ParameterElement parameterElement = node.element; | 8275 ParameterElement parameterElement = node.element; |
| 12535 if (parameterElement == null) { | 8276 if (parameterElement == null) { |
| 12536 AnalysisEngine.instance.logger.logInformation( | 8277 AnalysisEngine.instance.logger.logInformation( |
| 12537 "Missing element for function typed formal parameter ${node.identifi
er.name} in ${definingLibrary.source.fullName}", | 8278 "Missing element for function typed formal parameter ${node.identifi
er.name} in ${definingLibrary.source.fullName}", |
| 12538 new CaughtException(new AnalysisException(), null)); | 8279 new CaughtException(new AnalysisException(), null)); |
| 12539 } else { | 8280 } else { |
| 12540 nameScope = new EnclosedScope(nameScope); | 8281 nameScope = new EnclosedScope(nameScope); |
| 12541 for (TypeParameterElement typeParameter | 8282 List<TypeParameterElement> typeParameters = |
| 12542 in parameterElement.typeParameters) { | 8283 parameterElement.typeParameters; |
| 12543 nameScope.define(typeParameter); | 8284 int length = typeParameters.length; |
| 8285 for (int i = 0; i < length; i++) { |
| 8286 nameScope.define(typeParameters[i]); |
| 12544 } | 8287 } |
| 12545 } | 8288 } |
| 12546 super.visitFunctionTypedFormalParameter(node); | 8289 super.visitFunctionTypedFormalParameter(node); |
| 12547 } finally { | 8290 } finally { |
| 12548 nameScope = outerScope; | 8291 nameScope = outerScope; |
| 12549 } | 8292 } |
| 12550 return null; | 8293 return null; |
| 12551 } | 8294 } |
| 12552 | 8295 |
| 12553 @override | 8296 @override |
| 12554 Object visitIfStatement(IfStatement node) { | 8297 Object visitIfStatement(IfStatement node) { |
| 12555 safelyVisit(node.condition); | 8298 node.condition?.accept(this); |
| 12556 visitStatementInScope(node.thenStatement); | 8299 visitStatementInScope(node.thenStatement); |
| 12557 visitStatementInScope(node.elseStatement); | 8300 visitStatementInScope(node.elseStatement); |
| 12558 return null; | 8301 return null; |
| 12559 } | 8302 } |
| 12560 | 8303 |
| 12561 @override | 8304 @override |
| 12562 Object visitLabeledStatement(LabeledStatement node) { | 8305 Object visitLabeledStatement(LabeledStatement node) { |
| 12563 LabelScope outerScope = _addScopesFor(node.labels, node.unlabeled); | 8306 LabelScope outerScope = _addScopesFor(node.labels, node.unlabeled); |
| 12564 try { | 8307 try { |
| 12565 super.visitLabeledStatement(node); | 8308 super.visitLabeledStatement(node); |
| 12566 } finally { | 8309 } finally { |
| 12567 labelScope = outerScope; | 8310 labelScope = outerScope; |
| 12568 } | 8311 } |
| 12569 return null; | 8312 return null; |
| 12570 } | 8313 } |
| 12571 | 8314 |
| 12572 @override | 8315 @override |
| 12573 Object visitMethodDeclaration(MethodDeclaration node) { | 8316 Object visitMethodDeclaration(MethodDeclaration node) { |
| 12574 Scope outerScope = nameScope; | 8317 Scope outerScope = nameScope; |
| 12575 try { | 8318 try { |
| 12576 ExecutableElement methodElement = node.element; | 8319 ExecutableElement methodElement = node.element; |
| 12577 if (methodElement == null) { | 8320 if (methodElement == null) { |
| 12578 AnalysisEngine.instance.logger.logInformation( | 8321 AnalysisEngine.instance.logger.logInformation( |
| 12579 "Missing element for method ${node.name.name} in ${definingLibrary.s
ource.fullName}", | 8322 "Missing element for method ${node.name.name} in ${definingLibrary.s
ource.fullName}", |
| 12580 new CaughtException(new AnalysisException(), null)); | 8323 new CaughtException(new AnalysisException(), null)); |
| 12581 } else { | 8324 } else { |
| 12582 nameScope = new FunctionScope(nameScope, methodElement); | 8325 nameScope = new FunctionScope(nameScope, methodElement); |
| 12583 } | 8326 } |
| 12584 super.visitMethodDeclaration(node); | 8327 visitMethodDeclarationInScope(node); |
| 12585 } finally { | 8328 } finally { |
| 12586 nameScope = outerScope; | 8329 nameScope = outerScope; |
| 12587 } | 8330 } |
| 12588 return null; | 8331 return null; |
| 12589 } | 8332 } |
| 12590 | 8333 |
| 8334 void visitMethodDeclarationInScope(MethodDeclaration node) { |
| 8335 super.visitMethodDeclaration(node); |
| 8336 } |
| 8337 |
| 12591 /** | 8338 /** |
| 12592 * Visit the given statement after it's scope has been created. This is used b
y ResolverVisitor to | 8339 * Visit the given statement after it's scope has been created. This is used b
y ResolverVisitor to |
| 12593 * correctly visit the 'then' and 'else' statements of an 'if' statement. | 8340 * correctly visit the 'then' and 'else' statements of an 'if' statement. |
| 12594 * | 8341 * |
| 12595 * @param node the statement to be visited | 8342 * @param node the statement to be visited |
| 12596 */ | 8343 */ |
| 12597 void visitStatementInScope(Statement node) { | 8344 void visitStatementInScope(Statement node) { |
| 12598 if (node is Block) { | 8345 if (node is Block) { |
| 12599 // Don't create a scope around a block because the block will create it's | 8346 // Don't create a scope around a block because the block will create it's |
| 12600 // own scope. | 8347 // own scope. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12665 VariableElement element = node.element; | 8412 VariableElement element = node.element; |
| 12666 if (element != null) { | 8413 if (element != null) { |
| 12667 nameScope.define(element); | 8414 nameScope.define(element); |
| 12668 } | 8415 } |
| 12669 } | 8416 } |
| 12670 return null; | 8417 return null; |
| 12671 } | 8418 } |
| 12672 | 8419 |
| 12673 @override | 8420 @override |
| 12674 Object visitWhileStatement(WhileStatement node) { | 8421 Object visitWhileStatement(WhileStatement node) { |
| 12675 safelyVisit(node.condition); | 8422 node.condition?.accept(this); |
| 12676 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; | 8423 ImplicitLabelScope outerImplicitScope = _implicitLabelScope; |
| 12677 try { | 8424 try { |
| 12678 _implicitLabelScope = _implicitLabelScope.nest(node); | 8425 _implicitLabelScope = _implicitLabelScope.nest(node); |
| 12679 visitStatementInScope(node.body); | 8426 visitStatementInScope(node.body); |
| 12680 } finally { | 8427 } finally { |
| 12681 _implicitLabelScope = outerImplicitScope; | 8428 _implicitLabelScope = outerImplicitScope; |
| 12682 } | 8429 } |
| 12683 return null; | 8430 return null; |
| 12684 } | 8431 } |
| 12685 | 8432 |
| 12686 /** | 8433 /** |
| 12687 * Add scopes for each of the given labels. | 8434 * Add scopes for each of the given labels. |
| 12688 * | 8435 * |
| 12689 * @param labels the labels for which new scopes are to be added | 8436 * @param labels the labels for which new scopes are to be added |
| 12690 * @return the scope that was in effect before the new scopes were added | 8437 * @return the scope that was in effect before the new scopes were added |
| 12691 */ | 8438 */ |
| 12692 LabelScope _addScopesFor(NodeList<Label> labels, AstNode node) { | 8439 LabelScope _addScopesFor(NodeList<Label> labels, AstNode node) { |
| 12693 LabelScope outerScope = labelScope; | 8440 LabelScope outerScope = labelScope; |
| 12694 for (Label label in labels) { | 8441 for (Label label in labels) { |
| 12695 SimpleIdentifier labelNameNode = label.label; | 8442 SimpleIdentifier labelNameNode = label.label; |
| 12696 String labelName = labelNameNode.name; | 8443 String labelName = labelNameNode.name; |
| 12697 LabelElement labelElement = labelNameNode.staticElement as LabelElement; | 8444 LabelElement labelElement = labelNameNode.staticElement as LabelElement; |
| 12698 labelScope = new LabelScope(labelScope, labelName, node, labelElement); | 8445 labelScope = new LabelScope(labelScope, labelName, node, labelElement); |
| 12699 } | 8446 } |
| 12700 return outerScope; | 8447 return outerScope; |
| 12701 } | 8448 } |
| 12702 | |
| 12703 /** | |
| 12704 * Marks the local declarations of the given [Block] hidden in the enclosing s
cope. | |
| 12705 * According to the scoping rules name is hidden if block defines it, but name
is defined after | |
| 12706 * its declaration statement. | |
| 12707 */ | |
| 12708 void _hideNamesDefinedInBlock(EnclosedScope scope, Block block) { | |
| 12709 NodeList<Statement> statements = block.statements; | |
| 12710 int statementCount = statements.length; | |
| 12711 for (int i = 0; i < statementCount; i++) { | |
| 12712 Statement statement = statements[i]; | |
| 12713 if (statement is VariableDeclarationStatement) { | |
| 12714 VariableDeclarationStatement vds = statement; | |
| 12715 NodeList<VariableDeclaration> variables = vds.variables.variables; | |
| 12716 int variableCount = variables.length; | |
| 12717 for (int j = 0; j < variableCount; j++) { | |
| 12718 scope.hide(variables[j].element); | |
| 12719 } | |
| 12720 } else if (statement is FunctionDeclarationStatement) { | |
| 12721 FunctionDeclarationStatement fds = statement; | |
| 12722 scope.hide(fds.functionDeclaration.element); | |
| 12723 } | |
| 12724 } | |
| 12725 } | |
| 12726 } | |
| 12727 | |
| 12728 /** | |
| 12729 * Implementation of [TypeSystem] using the strong mode rules. | |
| 12730 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md | |
| 12731 */ | |
| 12732 class StrongTypeSystemImpl implements TypeSystem { | |
| 12733 final _specTypeSystem = new TypeSystemImpl(); | |
| 12734 | |
| 12735 StrongTypeSystemImpl(); | |
| 12736 | |
| 12737 @override | |
| 12738 DartType getLeastUpperBound( | |
| 12739 TypeProvider typeProvider, DartType type1, DartType type2) { | |
| 12740 // TODO(leafp): Implement a strong mode version of this. | |
| 12741 return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2); | |
| 12742 } | |
| 12743 | |
| 12744 // TODO(leafp): Document the rules in play here | |
| 12745 @override | |
| 12746 bool isAssignableTo(DartType fromType, DartType toType) { | |
| 12747 // An actual subtype | |
| 12748 if (isSubtypeOf(fromType, toType)) { | |
| 12749 return true; | |
| 12750 } | |
| 12751 | |
| 12752 // Don't allow implicit downcasts between function types | |
| 12753 // and call method objects, as these will almost always fail. | |
| 12754 if ((fromType is FunctionType && _getCallMethodType(toType) != null) || | |
| 12755 (toType is FunctionType && _getCallMethodType(fromType) != null)) { | |
| 12756 return false; | |
| 12757 } | |
| 12758 | |
| 12759 // If the subtype relation goes the other way, allow the implicit downcast. | |
| 12760 // TODO(leafp): Emit warnings and hints for these in some way. | |
| 12761 // TODO(leafp): Consider adding a flag to disable these? Or just rely on | |
| 12762 // --warnings-as-errors? | |
| 12763 if (isSubtypeOf(toType, fromType) || | |
| 12764 _specTypeSystem.isAssignableTo(toType, fromType)) { | |
| 12765 // TODO(leafp): error if type is known to be exact (literal, | |
| 12766 // instance creation). | |
| 12767 // TODO(leafp): Warn on composite downcast. | |
| 12768 // TODO(leafp): hint on object/dynamic downcast. | |
| 12769 // TODO(leafp): Consider allowing assignment casts. | |
| 12770 return true; | |
| 12771 } | |
| 12772 | |
| 12773 return false; | |
| 12774 } | |
| 12775 | |
| 12776 @override | |
| 12777 bool isSubtypeOf(DartType leftType, DartType rightType) { | |
| 12778 return _isSubtypeOf(leftType, rightType, null); | |
| 12779 } | |
| 12780 | |
| 12781 FunctionType _getCallMethodType(DartType t) { | |
| 12782 if (t is InterfaceType) { | |
| 12783 ClassElement element = t.element; | |
| 12784 InheritanceManager manager = new InheritanceManager(element.library); | |
| 12785 FunctionType callType = manager.lookupMemberType(t, "call"); | |
| 12786 return callType; | |
| 12787 } | |
| 12788 return null; | |
| 12789 } | |
| 12790 | |
| 12791 // Given a type t, if t is an interface type with a call method | |
| 12792 // defined, return the function type for the call method, otherwise | |
| 12793 // return null. | |
| 12794 _GuardedSubtypeChecker<DartType> _guard( | |
| 12795 _GuardedSubtypeChecker<DartType> check) { | |
| 12796 return (DartType t1, DartType t2, Set<Element> visited) { | |
| 12797 Element element = t1.element; | |
| 12798 if (visited == null) { | |
| 12799 visited = new HashSet<Element>(); | |
| 12800 } | |
| 12801 if (element == null || !visited.add(element)) { | |
| 12802 return false; | |
| 12803 } | |
| 12804 try { | |
| 12805 return check(t1, t2, visited); | |
| 12806 } finally { | |
| 12807 visited.remove(element); | |
| 12808 } | |
| 12809 }; | |
| 12810 } | |
| 12811 | |
| 12812 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { | |
| 12813 return (t.isDynamic && dynamicIsBottom) || t.isBottom; | |
| 12814 } | |
| 12815 | |
| 12816 // Guard against loops in the class hierarchy | |
| 12817 /** | |
| 12818 * Check that [f1] is a subtype of [f2]. | |
| 12819 * [fuzzyArrows] indicates whether or not the f1 and f2 should be | |
| 12820 * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated | |
| 12821 * as bottom). | |
| 12822 */ | |
| 12823 bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2, | |
| 12824 {bool fuzzyArrows: true}) { | |
| 12825 final r1s = f1.normalParameterTypes; | |
| 12826 final o1s = f1.optionalParameterTypes; | |
| 12827 final n1s = f1.namedParameterTypes; | |
| 12828 final r2s = f2.normalParameterTypes; | |
| 12829 final o2s = f2.optionalParameterTypes; | |
| 12830 final n2s = f2.namedParameterTypes; | |
| 12831 final ret1 = f1.returnType; | |
| 12832 final ret2 = f2.returnType; | |
| 12833 | |
| 12834 // A -> B <: C -> D if C <: A and | |
| 12835 // either D is void or B <: D | |
| 12836 if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) { | |
| 12837 return false; | |
| 12838 } | |
| 12839 | |
| 12840 // Reject if one has named and the other has optional | |
| 12841 if (n1s.length > 0 && o2s.length > 0) { | |
| 12842 return false; | |
| 12843 } | |
| 12844 if (n2s.length > 0 && o1s.length > 0) { | |
| 12845 return false; | |
| 12846 } | |
| 12847 | |
| 12848 // Rebind _isSubtypeOf for convenience | |
| 12849 _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) => | |
| 12850 _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows); | |
| 12851 | |
| 12852 // f2 has named parameters | |
| 12853 if (n2s.length > 0) { | |
| 12854 // Check that every named parameter in f2 has a match in f1 | |
| 12855 for (String k2 in n2s.keys) { | |
| 12856 if (!n1s.containsKey(k2)) { | |
| 12857 return false; | |
| 12858 } | |
| 12859 if (!parameterSubtype(n2s[k2], n1s[k2])) { | |
| 12860 return false; | |
| 12861 } | |
| 12862 } | |
| 12863 } | |
| 12864 // If we get here, we either have no named parameters, | |
| 12865 // or else the named parameters match and we have no optional | |
| 12866 // parameters | |
| 12867 | |
| 12868 // If f1 has more required parameters, reject | |
| 12869 if (r1s.length > r2s.length) { | |
| 12870 return false; | |
| 12871 } | |
| 12872 | |
| 12873 // If f2 has more required + optional parameters, reject | |
| 12874 if (r2s.length + o2s.length > r1s.length + o1s.length) { | |
| 12875 return false; | |
| 12876 } | |
| 12877 | |
| 12878 // The parameter lists must look like the following at this point | |
| 12879 // where rrr is a region of required, and ooo is a region of optionals. | |
| 12880 // f1: rrr ooo ooo ooo | |
| 12881 // f2: rrr rrr ooo | |
| 12882 int rr = r1s.length; // required in both | |
| 12883 int or = r2s.length - r1s.length; // optional in f1, required in f2 | |
| 12884 int oo = o2s.length; // optional in both | |
| 12885 | |
| 12886 for (int i = 0; i < rr; ++i) { | |
| 12887 if (!parameterSubtype(r2s[i], r1s[i])) { | |
| 12888 return false; | |
| 12889 } | |
| 12890 } | |
| 12891 for (int i = 0, j = rr; i < or; ++i, ++j) { | |
| 12892 if (!parameterSubtype(r2s[j], o1s[i])) { | |
| 12893 return false; | |
| 12894 } | |
| 12895 } | |
| 12896 for (int i = or, j = 0; i < oo; ++i, ++j) { | |
| 12897 if (!parameterSubtype(o2s[j], o1s[i])) { | |
| 12898 return false; | |
| 12899 } | |
| 12900 } | |
| 12901 return true; | |
| 12902 } | |
| 12903 | |
| 12904 bool _isInterfaceSubtypeOf( | |
| 12905 InterfaceType i1, InterfaceType i2, Set<Element> visited) { | |
| 12906 // Guard recursive calls | |
| 12907 _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype = | |
| 12908 _guard(_isInterfaceSubtypeOf); | |
| 12909 | |
| 12910 if (i1 == i2) { | |
| 12911 return true; | |
| 12912 } | |
| 12913 | |
| 12914 if (i1.element == i2.element) { | |
| 12915 List<DartType> tArgs1 = i1.typeArguments; | |
| 12916 List<DartType> tArgs2 = i2.typeArguments; | |
| 12917 | |
| 12918 assert(tArgs1.length == tArgs2.length); | |
| 12919 | |
| 12920 for (int i = 0; i < tArgs1.length; i++) { | |
| 12921 DartType t1 = tArgs1[i]; | |
| 12922 DartType t2 = tArgs2[i]; | |
| 12923 if (!isSubtypeOf(t1, t2)) { | |
| 12924 return false; | |
| 12925 } | |
| 12926 } | |
| 12927 return true; | |
| 12928 } | |
| 12929 | |
| 12930 if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) { | |
| 12931 return true; | |
| 12932 } | |
| 12933 | |
| 12934 if (i1.isObject) { | |
| 12935 return false; | |
| 12936 } | |
| 12937 | |
| 12938 if (guardedInterfaceSubtype(i1.superclass, i2, visited)) { | |
| 12939 return true; | |
| 12940 } | |
| 12941 | |
| 12942 for (final parent in i1.interfaces) { | |
| 12943 if (guardedInterfaceSubtype(parent, i2, visited)) { | |
| 12944 return true; | |
| 12945 } | |
| 12946 } | |
| 12947 | |
| 12948 for (final parent in i1.mixins) { | |
| 12949 if (guardedInterfaceSubtype(parent, i2, visited)) { | |
| 12950 return true; | |
| 12951 } | |
| 12952 } | |
| 12953 | |
| 12954 return false; | |
| 12955 } | |
| 12956 | |
| 12957 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, | |
| 12958 {bool dynamicIsBottom: false}) { | |
| 12959 // Guard recursive calls | |
| 12960 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); | |
| 12961 | |
| 12962 if (t1 == t2) { | |
| 12963 return true; | |
| 12964 } | |
| 12965 | |
| 12966 // The types are void, dynamic, bottom, interface types, function types | |
| 12967 // and type parameters. We proceed by eliminating these different classes | |
| 12968 // from consideration. | |
| 12969 | |
| 12970 // Trivially true. | |
| 12971 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || | |
| 12972 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { | |
| 12973 return true; | |
| 12974 } | |
| 12975 | |
| 12976 // Trivially false. | |
| 12977 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || | |
| 12978 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { | |
| 12979 return false; | |
| 12980 } | |
| 12981 | |
| 12982 // S <: T where S is a type variable | |
| 12983 // T is not dynamic or object (handled above) | |
| 12984 // S != T (handled above) | |
| 12985 // So only true if bound of S is S' and | |
| 12986 // S' <: T | |
| 12987 if (t1 is TypeParameterType) { | |
| 12988 DartType bound = t1.element.bound; | |
| 12989 if (bound == null) return false; | |
| 12990 return guardedSubtype(bound, t2, visited); | |
| 12991 } | |
| 12992 | |
| 12993 if (t2 is TypeParameterType) { | |
| 12994 return false; | |
| 12995 } | |
| 12996 | |
| 12997 if (t1.isVoid || t2.isVoid) { | |
| 12998 return false; | |
| 12999 } | |
| 13000 | |
| 13001 // We've eliminated void, dynamic, bottom, and type parameters. The only | |
| 13002 // cases are the combinations of interface type and function type. | |
| 13003 | |
| 13004 // A function type can only subtype an interface type if | |
| 13005 // the interface type is Function | |
| 13006 if (t1 is FunctionType && t2 is InterfaceType) { | |
| 13007 return t2.isDartCoreFunction; | |
| 13008 } | |
| 13009 | |
| 13010 // An interface type can only subtype a function type if | |
| 13011 // the interface type declares a call method with a type | |
| 13012 // which is a super type of the function type. | |
| 13013 if (t1 is InterfaceType && t2 is FunctionType) { | |
| 13014 var callType = _getCallMethodType(t1); | |
| 13015 return (callType != null) && _isFunctionSubtypeOf(callType, t2); | |
| 13016 } | |
| 13017 | |
| 13018 // Two interface types | |
| 13019 if (t1 is InterfaceType && t2 is InterfaceType) { | |
| 13020 return _isInterfaceSubtypeOf(t1, t2, visited); | |
| 13021 } | |
| 13022 | |
| 13023 return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType); | |
| 13024 } | |
| 13025 | |
| 13026 // TODO(leafp): Document the rules in play here | |
| 13027 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { | |
| 13028 return (t.isDynamic && !dynamicIsBottom) || t.isObject; | |
| 13029 } | |
| 13030 } | 8449 } |
| 13031 | 8450 |
| 13032 /** | 8451 /** |
| 13033 * Instances of this class manage the knowledge of what the set of subtypes are
for a given type. | 8452 * Instances of this class manage the knowledge of what the set of subtypes are
for a given type. |
| 13034 */ | 8453 */ |
| 13035 class SubtypeManager { | 8454 class SubtypeManager { |
| 13036 /** | 8455 /** |
| 13037 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype
s of the | 8456 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype
s of the |
| 13038 * key. | 8457 * key. |
| 13039 */ | 8458 */ |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13081 */ | 8500 */ |
| 13082 void _computeSubtypesInClass(ClassElement classElement) { | 8501 void _computeSubtypesInClass(ClassElement classElement) { |
| 13083 InterfaceType supertypeType = classElement.supertype; | 8502 InterfaceType supertypeType = classElement.supertype; |
| 13084 if (supertypeType != null) { | 8503 if (supertypeType != null) { |
| 13085 ClassElement supertypeElement = supertypeType.element; | 8504 ClassElement supertypeElement = supertypeType.element; |
| 13086 if (supertypeElement != null) { | 8505 if (supertypeElement != null) { |
| 13087 _putInSubtypeMap(supertypeElement, classElement); | 8506 _putInSubtypeMap(supertypeElement, classElement); |
| 13088 } | 8507 } |
| 13089 } | 8508 } |
| 13090 List<InterfaceType> interfaceTypes = classElement.interfaces; | 8509 List<InterfaceType> interfaceTypes = classElement.interfaces; |
| 13091 for (InterfaceType interfaceType in interfaceTypes) { | 8510 int interfaceLength = interfaceTypes.length; |
| 8511 for (int i = 0; i < interfaceLength; i++) { |
| 8512 InterfaceType interfaceType = interfaceTypes[i]; |
| 13092 ClassElement interfaceElement = interfaceType.element; | 8513 ClassElement interfaceElement = interfaceType.element; |
| 13093 if (interfaceElement != null) { | 8514 if (interfaceElement != null) { |
| 13094 _putInSubtypeMap(interfaceElement, classElement); | 8515 _putInSubtypeMap(interfaceElement, classElement); |
| 13095 } | 8516 } |
| 13096 } | 8517 } |
| 13097 List<InterfaceType> mixinTypes = classElement.mixins; | 8518 List<InterfaceType> mixinTypes = classElement.mixins; |
| 13098 for (InterfaceType mixinType in mixinTypes) { | 8519 int mixinLength = mixinTypes.length; |
| 8520 for (int i = 0; i < mixinLength; i++) { |
| 8521 InterfaceType mixinType = mixinTypes[i]; |
| 13099 ClassElement mixinElement = mixinType.element; | 8522 ClassElement mixinElement = mixinType.element; |
| 13100 if (mixinElement != null) { | 8523 if (mixinElement != null) { |
| 13101 _putInSubtypeMap(mixinElement, classElement); | 8524 _putInSubtypeMap(mixinElement, classElement); |
| 13102 } | 8525 } |
| 13103 } | 8526 } |
| 13104 } | 8527 } |
| 13105 | 8528 |
| 13106 /** | 8529 /** |
| 13107 * Given some [CompilationUnitElement], this method calls | 8530 * Given some [CompilationUnitElement], this method calls |
| 13108 * [computeAllSubtypes] on all of the [ClassElement]s in the | 8531 * [computeAllSubtypes] on all of the [ClassElement]s in the |
| 13109 * compilation unit. | 8532 * compilation unit. |
| 13110 * | 8533 * |
| 13111 * @param unitElement the compilation unit element | 8534 * @param unitElement the compilation unit element |
| 13112 */ | 8535 */ |
| 13113 void _computeSubtypesInCompilationUnit(CompilationUnitElement unitElement) { | 8536 void _computeSubtypesInCompilationUnit(CompilationUnitElement unitElement) { |
| 13114 List<ClassElement> classElements = unitElement.types; | 8537 List<ClassElement> classElements = unitElement.types; |
| 13115 for (ClassElement classElement in classElements) { | 8538 int length = classElements.length; |
| 8539 for (int i = 0; i < length; i++) { |
| 8540 ClassElement classElement = classElements[i]; |
| 13116 _computeSubtypesInClass(classElement); | 8541 _computeSubtypesInClass(classElement); |
| 13117 } | 8542 } |
| 13118 } | 8543 } |
| 13119 | 8544 |
| 13120 /** | 8545 /** |
| 13121 * Given some [LibraryElement], this method calls | 8546 * Given some [LibraryElement], this method calls |
| 13122 * [computeAllSubtypes] on all of the [ClassElement]s in the | 8547 * [computeAllSubtypes] on all of the [ClassElement]s in the |
| 13123 * compilation unit, and itself for all imported and exported libraries. All v
isited libraries are | 8548 * compilation unit, and itself for all imported and exported libraries. All v
isited libraries are |
| 13124 * added to the [visitedLibraries] set. | 8549 * added to the [visitedLibraries] set. |
| 13125 * | 8550 * |
| 13126 * @param libraryElement the library element | 8551 * @param libraryElement the library element |
| 13127 */ | 8552 */ |
| 13128 void _computeSubtypesInLibrary(LibraryElement libraryElement) { | 8553 void _computeSubtypesInLibrary(LibraryElement libraryElement) { |
| 13129 if (libraryElement == null || _visitedLibraries.contains(libraryElement)) { | 8554 if (libraryElement == null || _visitedLibraries.contains(libraryElement)) { |
| 13130 return; | 8555 return; |
| 13131 } | 8556 } |
| 13132 _visitedLibraries.add(libraryElement); | 8557 _visitedLibraries.add(libraryElement); |
| 13133 _computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit); | 8558 _computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit); |
| 13134 List<CompilationUnitElement> parts = libraryElement.parts; | 8559 List<CompilationUnitElement> parts = libraryElement.parts; |
| 13135 for (CompilationUnitElement part in parts) { | 8560 int partLength = parts.length; |
| 8561 for (int i = 0; i < partLength; i++) { |
| 8562 CompilationUnitElement part = parts[i]; |
| 13136 _computeSubtypesInCompilationUnit(part); | 8563 _computeSubtypesInCompilationUnit(part); |
| 13137 } | 8564 } |
| 13138 List<LibraryElement> imports = libraryElement.importedLibraries; | 8565 List<LibraryElement> imports = libraryElement.importedLibraries; |
| 13139 for (LibraryElement importElt in imports) { | 8566 int importLength = imports.length; |
| 8567 for (int i = 0; i < importLength; i++) { |
| 8568 LibraryElement importElt = imports[i]; |
| 13140 _computeSubtypesInLibrary(importElt.library); | 8569 _computeSubtypesInLibrary(importElt.library); |
| 13141 } | 8570 } |
| 13142 List<LibraryElement> exports = libraryElement.exportedLibraries; | 8571 List<LibraryElement> exports = libraryElement.exportedLibraries; |
| 13143 for (LibraryElement exportElt in exports) { | 8572 int exportLength = exports.length; |
| 8573 for (int i = 0; i < exportLength; i++) { |
| 8574 LibraryElement exportElt = exports[i]; |
| 13144 _computeSubtypesInLibrary(exportElt.library); | 8575 _computeSubtypesInLibrary(exportElt.library); |
| 13145 } | 8576 } |
| 13146 } | 8577 } |
| 13147 | 8578 |
| 13148 /** | 8579 /** |
| 13149 * Add some key/ value pair into the [subtypeMap] map. | 8580 * Add some key/ value pair into the [subtypeMap] map. |
| 13150 * | 8581 * |
| 13151 * @param supertypeElement the key for the [subtypeMap] map | 8582 * @param supertypeElement the key for the [subtypeMap] map |
| 13152 * @param subtypeElement the value for the [subtypeMap] map | 8583 * @param subtypeElement the value for the [subtypeMap] map |
| 13153 */ | 8584 */ |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13211 void findIn(CompilationUnit unit) { | 8642 void findIn(CompilationUnit unit) { |
| 13212 _gatherTodoComments(unit.beginToken); | 8643 _gatherTodoComments(unit.beginToken); |
| 13213 } | 8644 } |
| 13214 | 8645 |
| 13215 /** | 8646 /** |
| 13216 * Search the comment tokens reachable from the given token and create errors
for each to-do | 8647 * Search the comment tokens reachable from the given token and create errors
for each to-do |
| 13217 * comment. | 8648 * comment. |
| 13218 * | 8649 * |
| 13219 * @param token the head of the list of tokens being searched | 8650 * @param token the head of the list of tokens being searched |
| 13220 */ | 8651 */ |
| 13221 void _gatherTodoComments(sc.Token token) { | 8652 void _gatherTodoComments(Token token) { |
| 13222 while (token != null && token.type != sc.TokenType.EOF) { | 8653 while (token != null && token.type != TokenType.EOF) { |
| 13223 sc.Token commentToken = token.precedingComments; | 8654 Token commentToken = token.precedingComments; |
| 13224 while (commentToken != null) { | 8655 while (commentToken != null) { |
| 13225 if (commentToken.type == sc.TokenType.SINGLE_LINE_COMMENT || | 8656 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT || |
| 13226 commentToken.type == sc.TokenType.MULTI_LINE_COMMENT) { | 8657 commentToken.type == TokenType.MULTI_LINE_COMMENT) { |
| 13227 _scrapeTodoComment(commentToken); | 8658 _scrapeTodoComment(commentToken); |
| 13228 } | 8659 } |
| 13229 commentToken = commentToken.next; | 8660 commentToken = commentToken.next; |
| 13230 } | 8661 } |
| 13231 token = token.next; | 8662 token = token.next; |
| 13232 } | 8663 } |
| 13233 } | 8664 } |
| 13234 | 8665 |
| 13235 /** | 8666 /** |
| 13236 * Look for user defined tasks in comments and convert them into info level an
alysis issues. | 8667 * Look for user defined tasks in comments and convert them into info level an
alysis issues. |
| 13237 * | 8668 * |
| 13238 * @param commentToken the comment token to analyze | 8669 * @param commentToken the comment token to analyze |
| 13239 */ | 8670 */ |
| 13240 void _scrapeTodoComment(sc.Token commentToken) { | 8671 void _scrapeTodoComment(Token commentToken) { |
| 13241 JavaPatternMatcher matcher = | 8672 Iterable<Match> matches = |
| 13242 new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme); | 8673 TodoCode.TODO_REGEX.allMatches(commentToken.lexeme); |
| 13243 if (matcher.find()) { | 8674 for (Match match in matches) { |
| 13244 int offset = | 8675 int offset = commentToken.offset + match.start + match.group(1).length; |
| 13245 commentToken.offset + matcher.start() + matcher.group(1).length; | 8676 int length = match.group(2).length; |
| 13246 int length = matcher.group(2).length; | |
| 13247 _errorReporter.reportErrorForOffset( | 8677 _errorReporter.reportErrorForOffset( |
| 13248 TodoCode.TODO, offset, length, [matcher.group(2)]); | 8678 TodoCode.TODO, offset, length, [match.group(2)]); |
| 13249 } | 8679 } |
| 13250 } | 8680 } |
| 13251 } | 8681 } |
| 13252 | 8682 |
| 8683 /** |
| 8684 * Helper for resolving [TypeName]s. |
| 8685 * |
| 8686 * The client must set [nameScope] before calling [resolveTypeName]. |
| 8687 */ |
| 8688 class TypeNameResolver { |
| 8689 final TypeSystem typeSystem; |
| 8690 final DartType dynamicType; |
| 8691 final DartType undefinedType; |
| 8692 final LibraryElement definingLibrary; |
| 8693 final Source source; |
| 8694 final AnalysisErrorListener errorListener; |
| 8695 |
| 8696 Scope nameScope; |
| 8697 |
| 8698 TypeNameResolver(this.typeSystem, TypeProvider typeProvider, |
| 8699 this.definingLibrary, this.source, this.errorListener) |
| 8700 : dynamicType = typeProvider.dynamicType, |
| 8701 undefinedType = typeProvider.undefinedType; |
| 8702 |
| 8703 /** |
| 8704 * Report an error with the given error code and arguments. |
| 8705 * |
| 8706 * @param errorCode the error code of the error to be reported |
| 8707 * @param node the node specifying the location of the error |
| 8708 * @param arguments the arguments to the error, used to compose the error mess
age |
| 8709 */ |
| 8710 void reportErrorForNode(ErrorCode errorCode, AstNode node, |
| 8711 [List<Object> arguments]) { |
| 8712 errorListener.onError(new AnalysisError( |
| 8713 source, node.offset, node.length, errorCode, arguments)); |
| 8714 } |
| 8715 |
| 8716 /** |
| 8717 * Resolve the given [TypeName] - set its element and static type. Only the |
| 8718 * given [node] is resolved, all its children must be already resolved. |
| 8719 * |
| 8720 * The client must set [nameScope] before calling [resolveTypeName]. |
| 8721 */ |
| 8722 void resolveTypeName(TypeName node) { |
| 8723 Identifier typeName = node.name; |
| 8724 _setElement(typeName, null); // Clear old Elements from previous run. |
| 8725 TypeArgumentList argumentList = node.typeArguments; |
| 8726 Element element = nameScope.lookup(typeName, definingLibrary); |
| 8727 if (element == null) { |
| 8728 // |
| 8729 // Check to see whether the type name is either 'dynamic' or 'void', |
| 8730 // neither of which are in the name scope and hence will not be found by |
| 8731 // normal means. |
| 8732 // |
| 8733 if (typeName.name == dynamicType.name) { |
| 8734 _setElement(typeName, dynamicType.element); |
| 8735 // if (argumentList != null) { |
| 8736 // // TODO(brianwilkerson) Report this error |
| 8737 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU
MENTS, node, dynamicType.getName(), 0, argumentList.getArguments().size()); |
| 8738 // } |
| 8739 typeName.staticType = dynamicType; |
| 8740 node.type = dynamicType; |
| 8741 return; |
| 8742 } |
| 8743 VoidTypeImpl voidType = VoidTypeImpl.instance; |
| 8744 if (typeName.name == voidType.name) { |
| 8745 // There is no element for 'void'. |
| 8746 // if (argumentList != null) { |
| 8747 // // TODO(brianwilkerson) Report this error |
| 8748 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU
MENTS, node, voidType.getName(), 0, argumentList.getArguments().size()); |
| 8749 // } |
| 8750 typeName.staticType = voidType; |
| 8751 node.type = voidType; |
| 8752 return; |
| 8753 } |
| 8754 if (nameScope.shouldIgnoreUndefined(typeName)) { |
| 8755 typeName.staticType = undefinedType; |
| 8756 node.type = undefinedType; |
| 8757 return; |
| 8758 } |
| 8759 // |
| 8760 // If not, the look to see whether we might have created the wrong AST |
| 8761 // structure for a constructor name. If so, fix the AST structure and then |
| 8762 // proceed. |
| 8763 // |
| 8764 AstNode parent = node.parent; |
| 8765 if (typeName is PrefixedIdentifier && |
| 8766 parent is ConstructorName && |
| 8767 argumentList == null) { |
| 8768 ConstructorName name = parent; |
| 8769 if (name.name == null) { |
| 8770 PrefixedIdentifier prefixedIdentifier = |
| 8771 typeName as PrefixedIdentifier; |
| 8772 SimpleIdentifier prefix = prefixedIdentifier.prefix; |
| 8773 element = nameScope.lookup(prefix, definingLibrary); |
| 8774 if (element is PrefixElement) { |
| 8775 if (nameScope.shouldIgnoreUndefined(typeName)) { |
| 8776 typeName.staticType = undefinedType; |
| 8777 node.type = undefinedType; |
| 8778 return; |
| 8779 } |
| 8780 AstNode grandParent = parent.parent; |
| 8781 if (grandParent is InstanceCreationExpression && |
| 8782 grandParent.isConst) { |
| 8783 // If, if this is a const expression, then generate a |
| 8784 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error. |
| 8785 reportErrorForNode( |
| 8786 CompileTimeErrorCode.CONST_WITH_NON_TYPE, |
| 8787 prefixedIdentifier.identifier, |
| 8788 [prefixedIdentifier.identifier.name]); |
| 8789 } else { |
| 8790 // Else, if this expression is a new expression, report a |
| 8791 // NEW_WITH_NON_TYPE warning. |
| 8792 reportErrorForNode( |
| 8793 StaticWarningCode.NEW_WITH_NON_TYPE, |
| 8794 prefixedIdentifier.identifier, |
| 8795 [prefixedIdentifier.identifier.name]); |
| 8796 } |
| 8797 _setElement(prefix, element); |
| 8798 return; |
| 8799 } else if (element != null) { |
| 8800 // |
| 8801 // Rewrite the constructor name. The parser, when it sees a |
| 8802 // constructor named "a.b", cannot tell whether "a" is a prefix and |
| 8803 // "b" is a class name, or whether "a" is a class name and "b" is a |
| 8804 // constructor name. It arbitrarily chooses the former, but in this |
| 8805 // case was wrong. |
| 8806 // |
| 8807 name.name = prefixedIdentifier.identifier; |
| 8808 name.period = prefixedIdentifier.period; |
| 8809 node.name = prefix; |
| 8810 typeName = prefix; |
| 8811 } |
| 8812 } |
| 8813 } |
| 8814 if (nameScope.shouldIgnoreUndefined(typeName)) { |
| 8815 typeName.staticType = undefinedType; |
| 8816 node.type = undefinedType; |
| 8817 return; |
| 8818 } |
| 8819 } |
| 8820 // check element |
| 8821 bool elementValid = element is! MultiplyDefinedElement; |
| 8822 if (elementValid && |
| 8823 element is! ClassElement && |
| 8824 _isTypeNameInInstanceCreationExpression(node)) { |
| 8825 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName); |
| 8826 InstanceCreationExpression creation = |
| 8827 node.parent.parent as InstanceCreationExpression; |
| 8828 if (creation.isConst) { |
| 8829 if (element == null) { |
| 8830 reportErrorForNode( |
| 8831 CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]); |
| 8832 } else { |
| 8833 reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE, |
| 8834 typeNameSimple, [typeName]); |
| 8835 } |
| 8836 elementValid = false; |
| 8837 } else { |
| 8838 if (element != null) { |
| 8839 reportErrorForNode( |
| 8840 StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]); |
| 8841 elementValid = false; |
| 8842 } |
| 8843 } |
| 8844 } |
| 8845 if (elementValid && element == null) { |
| 8846 // We couldn't resolve the type name. |
| 8847 // TODO(jwren) Consider moving the check for |
| 8848 // CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE from the |
| 8849 // ErrorVerifier, so that we don't have two errors on a built in |
| 8850 // identifier being used as a class name. |
| 8851 // See CompileTimeErrorCodeTest.test_builtInIdentifierAsType(). |
| 8852 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName); |
| 8853 RedirectingConstructorKind redirectingConstructorKind; |
| 8854 if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) { |
| 8855 reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, |
| 8856 typeName, [typeName.name]); |
| 8857 } else if (typeNameSimple.name == "boolean") { |
| 8858 reportErrorForNode( |
| 8859 StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []); |
| 8860 } else if (_isTypeNameInCatchClause(node)) { |
| 8861 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, |
| 8862 [typeName.name]); |
| 8863 } else if (_isTypeNameInAsExpression(node)) { |
| 8864 reportErrorForNode( |
| 8865 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]); |
| 8866 } else if (_isTypeNameInIsExpression(node)) { |
| 8867 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME, |
| 8868 typeName, [typeName.name]); |
| 8869 } else if ((redirectingConstructorKind = |
| 8870 _getRedirectingConstructorKind(node)) != |
| 8871 null) { |
| 8872 ErrorCode errorCode = |
| 8873 (redirectingConstructorKind == RedirectingConstructorKind.CONST |
| 8874 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS |
| 8875 : StaticWarningCode.REDIRECT_TO_NON_CLASS); |
| 8876 reportErrorForNode(errorCode, typeName, [typeName.name]); |
| 8877 } else if (_isTypeNameInTypeArgumentList(node)) { |
| 8878 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, |
| 8879 typeName, [typeName.name]); |
| 8880 } else { |
| 8881 reportErrorForNode( |
| 8882 StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]); |
| 8883 } |
| 8884 elementValid = false; |
| 8885 } |
| 8886 if (!elementValid) { |
| 8887 if (element is MultiplyDefinedElement) { |
| 8888 _setElement(typeName, element); |
| 8889 } |
| 8890 typeName.staticType = undefinedType; |
| 8891 node.type = undefinedType; |
| 8892 return; |
| 8893 } |
| 8894 DartType type = null; |
| 8895 if (element is ClassElement) { |
| 8896 _setElement(typeName, element); |
| 8897 type = element.type; |
| 8898 } else if (element is FunctionTypeAliasElement) { |
| 8899 _setElement(typeName, element); |
| 8900 type = element.type; |
| 8901 } else if (element is TypeParameterElement) { |
| 8902 _setElement(typeName, element); |
| 8903 type = element.type; |
| 8904 // if (argumentList != null) { |
| 8905 // // Type parameters cannot have type arguments. |
| 8906 // // TODO(brianwilkerson) Report this error. |
| 8907 // // resolver.reportError(ResolverErrorCode.?, keyType); |
| 8908 // } |
| 8909 } else if (element is MultiplyDefinedElement) { |
| 8910 List<Element> elements = element.conflictingElements; |
| 8911 type = _getTypeWhenMultiplyDefined(elements); |
| 8912 if (type != null) { |
| 8913 node.type = type; |
| 8914 } |
| 8915 } else { |
| 8916 // The name does not represent a type. |
| 8917 RedirectingConstructorKind redirectingConstructorKind; |
| 8918 if (_isTypeNameInCatchClause(node)) { |
| 8919 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, |
| 8920 [typeName.name]); |
| 8921 } else if (_isTypeNameInAsExpression(node)) { |
| 8922 reportErrorForNode( |
| 8923 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]); |
| 8924 } else if (_isTypeNameInIsExpression(node)) { |
| 8925 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName, |
| 8926 [typeName.name]); |
| 8927 } else if ((redirectingConstructorKind = |
| 8928 _getRedirectingConstructorKind(node)) != |
| 8929 null) { |
| 8930 ErrorCode errorCode = |
| 8931 (redirectingConstructorKind == RedirectingConstructorKind.CONST |
| 8932 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS |
| 8933 : StaticWarningCode.REDIRECT_TO_NON_CLASS); |
| 8934 reportErrorForNode(errorCode, typeName, [typeName.name]); |
| 8935 } else if (_isTypeNameInTypeArgumentList(node)) { |
| 8936 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, |
| 8937 typeName, [typeName.name]); |
| 8938 } else { |
| 8939 AstNode parent = typeName.parent; |
| 8940 while (parent is TypeName) { |
| 8941 parent = parent.parent; |
| 8942 } |
| 8943 if (parent is ExtendsClause || |
| 8944 parent is ImplementsClause || |
| 8945 parent is WithClause || |
| 8946 parent is ClassTypeAlias) { |
| 8947 // Ignored. The error will be reported elsewhere. |
| 8948 } else if (element is LocalVariableElement || |
| 8949 (element is FunctionElement && |
| 8950 element.enclosingElement is ExecutableElement)) { |
| 8951 reportErrorForNode(CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, |
| 8952 typeName, [typeName.name]); |
| 8953 } else { |
| 8954 reportErrorForNode( |
| 8955 StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]); |
| 8956 } |
| 8957 } |
| 8958 typeName.staticType = dynamicType; |
| 8959 node.type = dynamicType; |
| 8960 return; |
| 8961 } |
| 8962 if (argumentList != null) { |
| 8963 NodeList<TypeName> arguments = argumentList.arguments; |
| 8964 int argumentCount = arguments.length; |
| 8965 List<DartType> parameters = typeSystem.typeFormalsAsTypes(type); |
| 8966 int parameterCount = parameters.length; |
| 8967 List<DartType> typeArguments = new List<DartType>(parameterCount); |
| 8968 if (argumentCount == parameterCount) { |
| 8969 for (int i = 0; i < parameterCount; i++) { |
| 8970 TypeName argumentTypeName = arguments[i]; |
| 8971 DartType argumentType = _getType(argumentTypeName); |
| 8972 if (argumentType == null) { |
| 8973 argumentType = dynamicType; |
| 8974 } |
| 8975 typeArguments[i] = argumentType; |
| 8976 } |
| 8977 } else { |
| 8978 reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node, |
| 8979 [typeName.name, parameterCount, argumentCount]); |
| 8980 for (int i = 0; i < parameterCount; i++) { |
| 8981 typeArguments[i] = dynamicType; |
| 8982 } |
| 8983 } |
| 8984 type = typeSystem.instantiateType(type, typeArguments); |
| 8985 } else { |
| 8986 type = typeSystem.instantiateToBounds(type); |
| 8987 } |
| 8988 typeName.staticType = type; |
| 8989 node.type = type; |
| 8990 } |
| 8991 |
| 8992 /** |
| 8993 * The number of type arguments in the given type name does not match the numb
er of parameters in |
| 8994 * the corresponding class element. Return the error code that should be used
to report this |
| 8995 * error. |
| 8996 * |
| 8997 * @param node the type name with the wrong number of type arguments |
| 8998 * @return the error code that should be used to report that the wrong number
of type arguments |
| 8999 * were provided |
| 9000 */ |
| 9001 ErrorCode _getInvalidTypeParametersErrorCode(TypeName node) { |
| 9002 AstNode parent = node.parent; |
| 9003 if (parent is ConstructorName) { |
| 9004 parent = parent.parent; |
| 9005 if (parent is InstanceCreationExpression) { |
| 9006 if (parent.isConst) { |
| 9007 return CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS; |
| 9008 } else { |
| 9009 return StaticWarningCode.NEW_WITH_INVALID_TYPE_PARAMETERS; |
| 9010 } |
| 9011 } |
| 9012 } |
| 9013 return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS; |
| 9014 } |
| 9015 |
| 9016 /** |
| 9017 * Checks if the given type name is the target in a redirected constructor. |
| 9018 * |
| 9019 * @param typeName the type name to analyze |
| 9020 * @return some [RedirectingConstructorKind] if the given type name is used as
the type in a |
| 9021 * redirected constructor, or `null` otherwise |
| 9022 */ |
| 9023 RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) { |
| 9024 AstNode parent = typeName.parent; |
| 9025 if (parent is ConstructorName) { |
| 9026 AstNode grandParent = parent.parent; |
| 9027 if (grandParent is ConstructorDeclaration) { |
| 9028 if (identical(grandParent.redirectedConstructor, parent)) { |
| 9029 if (grandParent.constKeyword != null) { |
| 9030 return RedirectingConstructorKind.CONST; |
| 9031 } |
| 9032 return RedirectingConstructorKind.NORMAL; |
| 9033 } |
| 9034 } |
| 9035 } |
| 9036 return null; |
| 9037 } |
| 9038 |
| 9039 /** |
| 9040 * Return the type represented by the given type name. |
| 9041 * |
| 9042 * @param typeName the type name representing the type to be returned |
| 9043 * @return the type represented by the type name |
| 9044 */ |
| 9045 DartType _getType(TypeName typeName) { |
| 9046 DartType type = typeName.type; |
| 9047 if (type == null) { |
| 9048 return undefinedType; |
| 9049 } |
| 9050 return type; |
| 9051 } |
| 9052 |
| 9053 /** |
| 9054 * Returns the simple identifier of the given (may be qualified) type name. |
| 9055 * |
| 9056 * @param typeName the (may be qualified) qualified type name |
| 9057 * @return the simple identifier of the given (may be qualified) type name. |
| 9058 */ |
| 9059 SimpleIdentifier _getTypeSimpleIdentifier(Identifier typeName) { |
| 9060 if (typeName is SimpleIdentifier) { |
| 9061 return typeName; |
| 9062 } else { |
| 9063 return (typeName as PrefixedIdentifier).identifier; |
| 9064 } |
| 9065 } |
| 9066 |
| 9067 /** |
| 9068 * Given the multiple elements to which a single name could potentially be res
olved, return the |
| 9069 * single interface type that should be used, or `null` if there is no clear c
hoice. |
| 9070 * |
| 9071 * @param elements the elements to which a single name could potentially be re
solved |
| 9072 * @return the single interface type that should be used for the type name |
| 9073 */ |
| 9074 InterfaceType _getTypeWhenMultiplyDefined(List<Element> elements) { |
| 9075 InterfaceType type = null; |
| 9076 int length = elements.length; |
| 9077 for (int i = 0; i < length; i++) { |
| 9078 Element element = elements[i]; |
| 9079 if (element is ClassElement) { |
| 9080 if (type != null) { |
| 9081 return null; |
| 9082 } |
| 9083 type = element.type; |
| 9084 } |
| 9085 } |
| 9086 return type; |
| 9087 } |
| 9088 |
| 9089 /** |
| 9090 * Checks if the given type name is used as the type in an as expression. |
| 9091 * |
| 9092 * @param typeName the type name to analyzer |
| 9093 * @return `true` if the given type name is used as the type in an as expressi
on |
| 9094 */ |
| 9095 bool _isTypeNameInAsExpression(TypeName typeName) { |
| 9096 AstNode parent = typeName.parent; |
| 9097 if (parent is AsExpression) { |
| 9098 return identical(parent.type, typeName); |
| 9099 } |
| 9100 return false; |
| 9101 } |
| 9102 |
| 9103 /** |
| 9104 * Checks if the given type name is used as the exception type in a catch clau
se. |
| 9105 * |
| 9106 * @param typeName the type name to analyzer |
| 9107 * @return `true` if the given type name is used as the exception type in a ca
tch clause |
| 9108 */ |
| 9109 bool _isTypeNameInCatchClause(TypeName typeName) { |
| 9110 AstNode parent = typeName.parent; |
| 9111 if (parent is CatchClause) { |
| 9112 return identical(parent.exceptionType, typeName); |
| 9113 } |
| 9114 return false; |
| 9115 } |
| 9116 |
| 9117 /** |
| 9118 * Checks if the given type name is used as the type in an instance creation e
xpression. |
| 9119 * |
| 9120 * @param typeName the type name to analyzer |
| 9121 * @return `true` if the given type name is used as the type in an instance cr
eation |
| 9122 * expression |
| 9123 */ |
| 9124 bool _isTypeNameInInstanceCreationExpression(TypeName typeName) { |
| 9125 AstNode parent = typeName.parent; |
| 9126 if (parent is ConstructorName && |
| 9127 parent.parent is InstanceCreationExpression) { |
| 9128 return parent != null && identical(parent.type, typeName); |
| 9129 } |
| 9130 return false; |
| 9131 } |
| 9132 |
| 9133 /** |
| 9134 * Checks if the given type name is used as the type in an is expression. |
| 9135 * |
| 9136 * @param typeName the type name to analyzer |
| 9137 * @return `true` if the given type name is used as the type in an is expressi
on |
| 9138 */ |
| 9139 bool _isTypeNameInIsExpression(TypeName typeName) { |
| 9140 AstNode parent = typeName.parent; |
| 9141 if (parent is IsExpression) { |
| 9142 return identical(parent.type, typeName); |
| 9143 } |
| 9144 return false; |
| 9145 } |
| 9146 |
| 9147 /** |
| 9148 * Checks if the given type name used in a type argument list. |
| 9149 * |
| 9150 * @param typeName the type name to analyzer |
| 9151 * @return `true` if the given type name is in a type argument list |
| 9152 */ |
| 9153 bool _isTypeNameInTypeArgumentList(TypeName typeName) => |
| 9154 typeName.parent is TypeArgumentList; |
| 9155 |
| 9156 /** |
| 9157 * Records the new Element for a TypeName's Identifier. |
| 9158 * |
| 9159 * A null may be passed in to indicate that the element can't be resolved. |
| 9160 * (During a re-run of a task, it's important to clear any previous value |
| 9161 * of the element.) |
| 9162 */ |
| 9163 void _setElement(Identifier typeName, Element element) { |
| 9164 if (typeName is SimpleIdentifier) { |
| 9165 typeName.staticElement = element; |
| 9166 } else if (typeName is PrefixedIdentifier) { |
| 9167 typeName.identifier.staticElement = element; |
| 9168 SimpleIdentifier prefix = typeName.prefix; |
| 9169 prefix.staticElement = nameScope.lookup(prefix, definingLibrary); |
| 9170 } |
| 9171 } |
| 9172 |
| 9173 /** |
| 9174 * @return `true` if the name of the given [TypeName] is an built-in identifie
r. |
| 9175 */ |
| 9176 static bool _isBuiltInIdentifier(TypeName node) { |
| 9177 Token token = node.name.beginToken; |
| 9178 return token.type == TokenType.KEYWORD; |
| 9179 } |
| 9180 |
| 9181 /** |
| 9182 * @return `true` if given [TypeName] is used as a type annotation. |
| 9183 */ |
| 9184 static bool _isTypeAnnotation(TypeName node) { |
| 9185 AstNode parent = node.parent; |
| 9186 if (parent is VariableDeclarationList) { |
| 9187 return identical(parent.type, node); |
| 9188 } else if (parent is FieldFormalParameter) { |
| 9189 return identical(parent.type, node); |
| 9190 } else if (parent is SimpleFormalParameter) { |
| 9191 return identical(parent.type, node); |
| 9192 } |
| 9193 return false; |
| 9194 } |
| 9195 } |
| 9196 |
| 13253 /** | 9197 /** |
| 13254 * Instances of the class `TypeOverrideManager` manage the ability to override t
he type of an | 9198 * Instances of the class `TypeOverrideManager` manage the ability to override t
he type of an |
| 13255 * element within a given context. | 9199 * element within a given context. |
| 13256 */ | 9200 */ |
| 13257 class TypeOverrideManager { | 9201 class TypeOverrideManager { |
| 13258 /** | 9202 /** |
| 13259 * The current override scope, or `null` if no scope has been entered. | 9203 * The current override scope, or `null` if no scope has been entered. |
| 13260 */ | 9204 */ |
| 13261 TypeOverrideManager_TypeOverrideScope currentScope; | 9205 TypeOverrideManager_TypeOverrideScope currentScope; |
| 13262 | 9206 |
| 13263 /** | 9207 /** |
| 13264 * Apply a set of overrides that were previously captured. | 9208 * Apply a set of overrides that were previously captured. |
| 13265 * | 9209 * |
| 13266 * @param overrides the overrides to be applied | 9210 * @param overrides the overrides to be applied |
| 13267 */ | 9211 */ |
| 13268 void applyOverrides(Map<VariableElement, DartType> overrides) { | 9212 void applyOverrides(Map<VariableElement, DartType> overrides) { |
| 13269 if (currentScope == null) { | 9213 if (currentScope == null) { |
| 13270 throw new IllegalStateException("Cannot apply overrides without a scope"); | 9214 throw new StateError("Cannot apply overrides without a scope"); |
| 13271 } | 9215 } |
| 13272 currentScope.applyOverrides(overrides); | 9216 currentScope.applyOverrides(overrides); |
| 13273 } | 9217 } |
| 13274 | 9218 |
| 13275 /** | 9219 /** |
| 13276 * Return a table mapping the elements whose type is overridden in the current
scope to the | 9220 * Return a table mapping the elements whose type is overridden in the current
scope to the |
| 13277 * overriding type. | 9221 * overriding type. |
| 13278 * | 9222 * |
| 13279 * @return the overrides in the current scope | 9223 * @return the overrides in the current scope |
| 13280 */ | 9224 */ |
| 13281 Map<VariableElement, DartType> captureLocalOverrides() { | 9225 Map<VariableElement, DartType> captureLocalOverrides() { |
| 13282 if (currentScope == null) { | 9226 if (currentScope == null) { |
| 13283 throw new IllegalStateException( | 9227 throw new StateError("Cannot capture local overrides without a scope"); |
| 13284 "Cannot capture local overrides without a scope"); | |
| 13285 } | 9228 } |
| 13286 return currentScope.captureLocalOverrides(); | 9229 return currentScope.captureLocalOverrides(); |
| 13287 } | 9230 } |
| 13288 | 9231 |
| 13289 /** | 9232 /** |
| 13290 * Return a map from the elements for the variables in the given list that hav
e their types | 9233 * Return a map from the elements for the variables in the given list that hav
e their types |
| 13291 * overridden to the overriding type. | 9234 * overridden to the overriding type. |
| 13292 * | 9235 * |
| 13293 * @param variableList the list of variables whose overriding types are to be
captured | 9236 * @param variableList the list of variables whose overriding types are to be
captured |
| 13294 * @return a table mapping elements to their overriding types | 9237 * @return a table mapping elements to their overriding types |
| 13295 */ | 9238 */ |
| 13296 Map<VariableElement, DartType> captureOverrides( | 9239 Map<VariableElement, DartType> captureOverrides( |
| 13297 VariableDeclarationList variableList) { | 9240 VariableDeclarationList variableList) { |
| 13298 if (currentScope == null) { | 9241 if (currentScope == null) { |
| 13299 throw new IllegalStateException( | 9242 throw new StateError("Cannot capture overrides without a scope"); |
| 13300 "Cannot capture overrides without a scope"); | |
| 13301 } | 9243 } |
| 13302 return currentScope.captureOverrides(variableList); | 9244 return currentScope.captureOverrides(variableList); |
| 13303 } | 9245 } |
| 13304 | 9246 |
| 13305 /** | 9247 /** |
| 13306 * Enter a new override scope. | 9248 * Enter a new override scope. |
| 13307 */ | 9249 */ |
| 13308 void enterScope() { | 9250 void enterScope() { |
| 13309 currentScope = new TypeOverrideManager_TypeOverrideScope(currentScope); | 9251 currentScope = new TypeOverrideManager_TypeOverrideScope(currentScope); |
| 13310 } | 9252 } |
| 13311 | 9253 |
| 13312 /** | 9254 /** |
| 13313 * Exit the current override scope. | 9255 * Exit the current override scope. |
| 13314 */ | 9256 */ |
| 13315 void exitScope() { | 9257 void exitScope() { |
| 13316 if (currentScope == null) { | 9258 if (currentScope == null) { |
| 13317 throw new IllegalStateException("No scope to exit"); | 9259 throw new StateError("No scope to exit"); |
| 13318 } | 9260 } |
| 13319 currentScope = currentScope._outerScope; | 9261 currentScope = currentScope._outerScope; |
| 13320 } | 9262 } |
| 13321 | 9263 |
| 13322 /** | 9264 /** |
| 13323 * Return the best type information available for the given element. If the ty
pe of the element | 9265 * Return the best type information available for the given element. If the ty
pe of the element |
| 13324 * has been overridden, then return the overriding type. Otherwise, return the
static type. | 9266 * has been overridden, then return the overriding type. Otherwise, return the
static type. |
| 13325 * | 9267 * |
| 13326 * @param element the element for which type information is to be returned | 9268 * @param element the element for which type information is to be returned |
| 13327 * @return the best type information available for the given element | 9269 * @return the best type information available for the given element |
| 13328 */ | 9270 */ |
| 13329 DartType getBestType(VariableElement element) { | 9271 DartType getBestType(VariableElement element) { |
| 13330 DartType bestType = getType(element); | 9272 DartType bestType = getType(element); |
| 13331 return bestType == null ? element.type : bestType; | 9273 return bestType ?? element.type; |
| 13332 } | 9274 } |
| 13333 | 9275 |
| 13334 /** | 9276 /** |
| 13335 * Return the overridden type of the given element, or `null` if the type of t
he element has | 9277 * Return the overridden type of the given element, or `null` if the type of t
he element has |
| 13336 * not been overridden. | 9278 * not been overridden. |
| 13337 * | 9279 * |
| 13338 * @param element the element whose type might have been overridden | 9280 * @param element the element whose type might have been overridden |
| 13339 * @return the overridden type of the given element | 9281 * @return the overridden type of the given element |
| 13340 */ | 9282 */ |
| 13341 DartType getType(Element element) { | 9283 DartType getType(Element element) { |
| 13342 if (currentScope == null) { | 9284 if (currentScope == null) { |
| 13343 return null; | 9285 return null; |
| 13344 } | 9286 } |
| 13345 return currentScope.getType(element); | 9287 return currentScope.getType(element); |
| 13346 } | 9288 } |
| 13347 | 9289 |
| 13348 /** | 9290 /** |
| 13349 * Update overrides assuming [perBranchOverrides] is the collection of | 9291 * Update overrides assuming [perBranchOverrides] is the collection of |
| 13350 * per-branch overrides for *all* branches flowing into a join point. | 9292 * per-branch overrides for *all* branches flowing into a join point. |
| 13351 * | 9293 * |
| 13352 * If a variable type in any of branches is not the same as its type before | 9294 * If a variable type in any of branches is not the same as its type before |
| 13353 * the branching, then its propagated type is reset to `null`. | 9295 * the branching, then its propagated type is reset to `null`. |
| 13354 */ | 9296 */ |
| 13355 void mergeOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) { | 9297 void mergeOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) { |
| 13356 for (Map<VariableElement, DartType> branch in perBranchOverrides) { | 9298 int length = perBranchOverrides.length; |
| 9299 for (int i = 0; i < length; i++) { |
| 9300 Map<VariableElement, DartType> branch = perBranchOverrides[i]; |
| 13357 branch.forEach((VariableElement variable, DartType branchType) { | 9301 branch.forEach((VariableElement variable, DartType branchType) { |
| 13358 DartType currentType = currentScope.getType(variable); | 9302 DartType currentType = currentScope.getType(variable); |
| 13359 if (currentType != branchType) { | 9303 if (currentType != branchType) { |
| 13360 currentScope.resetType(variable); | 9304 currentScope.resetType(variable); |
| 13361 } | 9305 } |
| 13362 }); | 9306 }); |
| 13363 } | 9307 } |
| 13364 } | 9308 } |
| 13365 | 9309 |
| 13366 /** | 9310 /** |
| 13367 * Set the overridden type of the given element to the given type | 9311 * Set the overridden type of the given element to the given type |
| 13368 * | 9312 * |
| 13369 * @param element the element whose type might have been overridden | 9313 * @param element the element whose type might have been overridden |
| 13370 * @param type the overridden type of the given element | 9314 * @param type the overridden type of the given element |
| 13371 */ | 9315 */ |
| 13372 void setType(VariableElement element, DartType type) { | 9316 void setType(VariableElement element, DartType type) { |
| 13373 if (currentScope == null) { | 9317 if (currentScope == null) { |
| 13374 throw new IllegalStateException("Cannot override without a scope"); | 9318 throw new StateError("Cannot override without a scope"); |
| 13375 } | 9319 } |
| 13376 currentScope.setType(element, type); | 9320 currentScope.setType(element, type); |
| 13377 } | 9321 } |
| 13378 } | 9322 } |
| 13379 | 9323 |
| 13380 /** | 9324 /** |
| 13381 * Instances of the class `TypeOverrideScope` represent a scope in which the typ
es of | 9325 * Instances of the class `TypeOverrideScope` represent a scope in which the typ
es of |
| 13382 * elements can be overridden. | 9326 * elements can be overridden. |
| 13383 */ | 9327 */ |
| 13384 class TypeOverrideManager_TypeOverrideScope { | 9328 class TypeOverrideManager_TypeOverrideScope { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13443 } | 9387 } |
| 13444 | 9388 |
| 13445 /** | 9389 /** |
| 13446 * Return the overridden type of the given element, or `null` if the type of t
he element | 9390 * Return the overridden type of the given element, or `null` if the type of t
he element |
| 13447 * has not been overridden. | 9391 * has not been overridden. |
| 13448 * | 9392 * |
| 13449 * @param element the element whose type might have been overridden | 9393 * @param element the element whose type might have been overridden |
| 13450 * @return the overridden type of the given element | 9394 * @return the overridden type of the given element |
| 13451 */ | 9395 */ |
| 13452 DartType getType(Element element) { | 9396 DartType getType(Element element) { |
| 13453 if (element is PropertyAccessorElement) { | 9397 Element nonAccessor = |
| 13454 element = (element as PropertyAccessorElement).variable; | 9398 element is PropertyAccessorElement ? element.variable : element; |
| 13455 } | 9399 DartType type = _overridenTypes[nonAccessor]; |
| 13456 DartType type = _overridenTypes[element]; | 9400 if (_overridenTypes.containsKey(nonAccessor)) { |
| 13457 if (_overridenTypes.containsKey(element)) { | |
| 13458 return type; | 9401 return type; |
| 13459 } | 9402 } |
| 13460 if (type != null) { | 9403 return type ?? _outerScope?.getType(element); |
| 13461 return type; | |
| 13462 } else if (_outerScope != null) { | |
| 13463 return _outerScope.getType(element); | |
| 13464 } | |
| 13465 return null; | |
| 13466 } | 9404 } |
| 13467 | 9405 |
| 13468 /** | 9406 /** |
| 13469 * Clears the overridden type of the given [element]. | 9407 * Clears the overridden type of the given [element]. |
| 13470 */ | 9408 */ |
| 13471 void resetType(VariableElement element) { | 9409 void resetType(VariableElement element) { |
| 13472 _overridenTypes[element] = null; | 9410 _overridenTypes[element] = null; |
| 13473 } | 9411 } |
| 13474 | 9412 |
| 13475 /** | 9413 /** |
| 13476 * Set the overridden type of the given element to the given type | 9414 * Set the overridden type of the given element to the given type |
| 13477 * | 9415 * |
| 13478 * @param element the element whose type might have been overridden | 9416 * @param element the element whose type might have been overridden |
| 13479 * @param type the overridden type of the given element | 9417 * @param type the overridden type of the given element |
| 13480 */ | 9418 */ |
| 13481 void setType(VariableElement element, DartType type) { | 9419 void setType(VariableElement element, DartType type) { |
| 13482 _overridenTypes[element] = type; | 9420 _overridenTypes[element] = type; |
| 13483 } | 9421 } |
| 13484 } | 9422 } |
| 13485 | 9423 |
| 13486 /** | 9424 /** |
| 13487 * Instances of the class `TypeParameterScope` implement the scope defined by th
e type | 9425 * This class resolves bounds of type parameters of classes, class and function |
| 13488 * parameters in a class. | 9426 * type aliases. |
| 13489 */ | 9427 */ |
| 13490 class TypeParameterScope extends EnclosedScope { | 9428 class TypeParameterBoundsResolver { |
| 9429 final TypeProvider typeProvider; |
| 9430 final LibraryElement library; |
| 9431 final Source source; |
| 9432 final AnalysisErrorListener errorListener; |
| 9433 |
| 9434 Scope libraryScope = null; |
| 9435 TypeNameResolver typeNameResolver = null; |
| 9436 |
| 9437 TypeParameterBoundsResolver( |
| 9438 this.typeProvider, this.library, this.source, this.errorListener); |
| 9439 |
| 13491 /** | 9440 /** |
| 13492 * Initialize a newly created scope enclosed within another scope. | 9441 * Resolve bounds of type parameters of classes, class and function type |
| 13493 * | 9442 * aliases. |
| 13494 * @param enclosingScope the scope in which this scope is lexically enclosed | |
| 13495 * @param typeElement the element representing the type represented by this sc
ope | |
| 13496 */ | 9443 */ |
| 13497 TypeParameterScope(Scope enclosingScope, ClassElement typeElement) | 9444 void resolveTypeBounds(CompilationUnit unit) { |
| 13498 : super(enclosingScope) { | 9445 for (CompilationUnitMember unitMember in unit.declarations) { |
| 13499 if (typeElement == null) { | 9446 if (unitMember is ClassDeclaration) { |
| 13500 throw new IllegalArgumentException("class element cannot be null"); | 9447 _resolveTypeParameters(unitMember.typeParameters, |
| 9448 () => new TypeParameterScope(libraryScope, unitMember.element)); |
| 9449 } else if (unitMember is ClassTypeAlias) { |
| 9450 _resolveTypeParameters(unitMember.typeParameters, |
| 9451 () => new TypeParameterScope(libraryScope, unitMember.element)); |
| 9452 } else if (unitMember is FunctionTypeAlias) { |
| 9453 _resolveTypeParameters(unitMember.typeParameters, |
| 9454 () => new FunctionTypeScope(libraryScope, unitMember.element)); |
| 9455 } |
| 13501 } | 9456 } |
| 13502 _defineTypeParameters(typeElement); | |
| 13503 } | 9457 } |
| 13504 | 9458 |
| 13505 /** | 9459 void _resolveTypeName(TypeName typeName) { |
| 13506 * Define the type parameters for the class. | 9460 typeName.typeArguments?.arguments?.forEach(_resolveTypeName); |
| 13507 * | 9461 typeNameResolver.resolveTypeName(typeName); |
| 13508 * @param typeElement the element representing the type represented by this sc
ope | 9462 // TODO(scheglov) report error when don't apply type bounds for type bounds |
| 13509 */ | 9463 } |
| 13510 void _defineTypeParameters(ClassElement typeElement) { | 9464 |
| 13511 for (TypeParameterElement typeParameter in typeElement.typeParameters) { | 9465 void _resolveTypeParameters( |
| 13512 define(typeParameter); | 9466 TypeParameterList typeParameters, Scope createTypeParametersScope()) { |
| 9467 if (typeParameters != null) { |
| 9468 Scope typeParametersScope = null; |
| 9469 for (TypeParameter typeParameter in typeParameters.typeParameters) { |
| 9470 TypeName bound = typeParameter.bound; |
| 9471 if (bound != null) { |
| 9472 Element typeParameterElement = typeParameter.name.staticElement; |
| 9473 if (typeParameterElement is TypeParameterElementImpl) { |
| 9474 if (LibraryElementImpl.hasResolutionCapability( |
| 9475 library, LibraryResolutionCapability.resolvedTypeNames)) { |
| 9476 bound.type = typeParameterElement.bound; |
| 9477 } else { |
| 9478 libraryScope ??= new LibraryScope(library); |
| 9479 typeParametersScope ??= createTypeParametersScope(); |
| 9480 typeNameResolver ??= new TypeNameResolver(new TypeSystemImpl(), |
| 9481 typeProvider, library, source, errorListener); |
| 9482 typeNameResolver.nameScope = typeParametersScope; |
| 9483 _resolveTypeName(bound); |
| 9484 typeParameterElement.bound = bound.type; |
| 9485 } |
| 9486 } |
| 9487 } |
| 9488 } |
| 13513 } | 9489 } |
| 13514 } | 9490 } |
| 13515 } | 9491 } |
| 13516 | 9492 |
| 13517 /** | 9493 /** |
| 13518 * Instances of the class `TypePromotionManager` manage the ability to promote t
ypes of local | 9494 * Instances of the class `TypePromotionManager` manage the ability to promote t
ypes of local |
| 13519 * variables and formal parameters from their declared types based on control fl
ow. | 9495 * variables and formal parameters from their declared types based on control fl
ow. |
| 13520 */ | 9496 */ |
| 13521 class TypePromotionManager { | 9497 class TypePromotionManager { |
| 13522 /** | 9498 /** |
| (...skipping 11 matching lines...) Expand all Loading... |
| 13534 */ | 9510 */ |
| 13535 void enterScope() { | 9511 void enterScope() { |
| 13536 currentScope = new TypePromotionManager_TypePromoteScope(currentScope); | 9512 currentScope = new TypePromotionManager_TypePromoteScope(currentScope); |
| 13537 } | 9513 } |
| 13538 | 9514 |
| 13539 /** | 9515 /** |
| 13540 * Exit the current promotion scope. | 9516 * Exit the current promotion scope. |
| 13541 */ | 9517 */ |
| 13542 void exitScope() { | 9518 void exitScope() { |
| 13543 if (currentScope == null) { | 9519 if (currentScope == null) { |
| 13544 throw new IllegalStateException("No scope to exit"); | 9520 throw new StateError("No scope to exit"); |
| 13545 } | 9521 } |
| 13546 currentScope = currentScope._outerScope; | 9522 currentScope = currentScope._outerScope; |
| 13547 } | 9523 } |
| 13548 | 9524 |
| 13549 /** | 9525 /** |
| 13550 * Returns static type of the given variable - declared or promoted. | 9526 * Return the static type of the given [variable] - declared or promoted. |
| 13551 * | |
| 13552 * @return the static type of the given variable - declared or promoted | |
| 13553 */ | 9527 */ |
| 13554 DartType getStaticType(VariableElement variable) { | 9528 DartType getStaticType(VariableElement variable) => |
| 13555 DartType staticType = getType(variable); | 9529 getType(variable) ?? variable.type; |
| 13556 if (staticType == null) { | |
| 13557 staticType = variable.type; | |
| 13558 } | |
| 13559 return staticType; | |
| 13560 } | |
| 13561 | 9530 |
| 13562 /** | 9531 /** |
| 13563 * Return the promoted type of the given element, or `null` if the type of the
element has | 9532 * Return the promoted type of the given [element], or `null` if the type of |
| 13564 * not been promoted. | 9533 * the element has not been promoted. |
| 13565 * | |
| 13566 * @param element the element whose type might have been promoted | |
| 13567 * @return the promoted type of the given element | |
| 13568 */ | 9534 */ |
| 13569 DartType getType(Element element) { | 9535 DartType getType(Element element) => currentScope?.getType(element); |
| 13570 if (currentScope == null) { | |
| 13571 return null; | |
| 13572 } | |
| 13573 return currentScope.getType(element); | |
| 13574 } | |
| 13575 | 9536 |
| 13576 /** | 9537 /** |
| 13577 * Set the promoted type of the given element to the given type. | 9538 * Set the promoted type of the given element to the given type. |
| 13578 * | 9539 * |
| 13579 * @param element the element whose type might have been promoted | 9540 * @param element the element whose type might have been promoted |
| 13580 * @param type the promoted type of the given element | 9541 * @param type the promoted type of the given element |
| 13581 */ | 9542 */ |
| 13582 void setType(Element element, DartType type) { | 9543 void setType(Element element, DartType type) { |
| 13583 if (currentScope == null) { | 9544 if (currentScope == null) { |
| 13584 throw new IllegalStateException("Cannot promote without a scope"); | 9545 throw new StateError("Cannot promote without a scope"); |
| 13585 } | 9546 } |
| 13586 currentScope.setType(element, type); | 9547 currentScope.setType(element, type); |
| 13587 } | 9548 } |
| 13588 } | 9549 } |
| 13589 | 9550 |
| 13590 /** | 9551 /** |
| 13591 * Instances of the class `TypePromoteScope` represent a scope in which the type
s of | 9552 * Instances of the class `TypePromoteScope` represent a scope in which the type
s of |
| 13592 * elements can be promoted. | 9553 * elements can be promoted. |
| 13593 */ | 9554 */ |
| 13594 class TypePromotionManager_TypePromoteScope { | 9555 class TypePromotionManager_TypePromoteScope { |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13773 | 9734 |
| 13774 /** | 9735 /** |
| 13775 * Return the type representing the built-in type 'Type'. | 9736 * Return the type representing the built-in type 'Type'. |
| 13776 */ | 9737 */ |
| 13777 InterfaceType get typeType; | 9738 InterfaceType get typeType; |
| 13778 | 9739 |
| 13779 /** | 9740 /** |
| 13780 * Return the type representing typenames that can't be resolved. | 9741 * Return the type representing typenames that can't be resolved. |
| 13781 */ | 9742 */ |
| 13782 DartType get undefinedType; | 9743 DartType get undefinedType; |
| 9744 |
| 9745 /** |
| 9746 * Return 'true' if [id] is the name of a getter on |
| 9747 * the Object type. |
| 9748 */ |
| 9749 bool isObjectGetter(String id); |
| 9750 |
| 9751 /** |
| 9752 * Return 'true' if [id] is the name of a method or getter on |
| 9753 * the Object type. |
| 9754 */ |
| 9755 bool isObjectMember(String id); |
| 9756 |
| 9757 /** |
| 9758 * Return 'true' if [id] is the name of a method on |
| 9759 * the Object type. |
| 9760 */ |
| 9761 bool isObjectMethod(String id); |
| 9762 } |
| 9763 |
| 9764 /** |
| 9765 * Provide common functionality shared by the various TypeProvider |
| 9766 * implementations. |
| 9767 */ |
| 9768 abstract class TypeProviderBase implements TypeProvider { |
| 9769 @override |
| 9770 List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[ |
| 9771 nullType, |
| 9772 numType, |
| 9773 intType, |
| 9774 doubleType, |
| 9775 boolType, |
| 9776 stringType |
| 9777 ]; |
| 9778 |
| 9779 @override |
| 9780 bool isObjectGetter(String id) { |
| 9781 PropertyAccessorElement element = objectType.element.getGetter(id); |
| 9782 return (element != null && !element.isStatic); |
| 9783 } |
| 9784 |
| 9785 @override |
| 9786 bool isObjectMember(String id) { |
| 9787 return isObjectGetter(id) || isObjectMethod(id); |
| 9788 } |
| 9789 |
| 9790 @override |
| 9791 bool isObjectMethod(String id) { |
| 9792 MethodElement element = objectType.element.getMethod(id); |
| 9793 return (element != null && !element.isStatic); |
| 9794 } |
| 13783 } | 9795 } |
| 13784 | 9796 |
| 13785 /** | 9797 /** |
| 13786 * Instances of the class `TypeProviderImpl` provide access to types defined by
the language | 9798 * Instances of the class `TypeProviderImpl` provide access to types defined by
the language |
| 13787 * by looking for those types in the element model for the core library. | 9799 * by looking for those types in the element model for the core library. |
| 13788 */ | 9800 */ |
| 13789 class TypeProviderImpl implements TypeProvider { | 9801 class TypeProviderImpl extends TypeProviderBase { |
| 13790 /** | 9802 /** |
| 13791 * The type representing the built-in type 'bool'. | 9803 * The type representing the built-in type 'bool'. |
| 13792 */ | 9804 */ |
| 13793 InterfaceType _boolType; | 9805 InterfaceType _boolType; |
| 13794 | 9806 |
| 13795 /** | 9807 /** |
| 13796 * The type representing the type 'bottom'. | 9808 * The type representing the type 'bottom'. |
| 13797 */ | 9809 */ |
| 13798 DartType _bottomType; | 9810 DartType _bottomType; |
| 13799 | 9811 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13902 */ | 9914 */ |
| 13903 InterfaceType _symbolType; | 9915 InterfaceType _symbolType; |
| 13904 | 9916 |
| 13905 /** | 9917 /** |
| 13906 * The type representing the built-in type 'Type'. | 9918 * The type representing the built-in type 'Type'. |
| 13907 */ | 9919 */ |
| 13908 InterfaceType _typeType; | 9920 InterfaceType _typeType; |
| 13909 | 9921 |
| 13910 /** | 9922 /** |
| 13911 * The type representing typenames that can't be resolved. | 9923 * The type representing typenames that can't be resolved. |
| 13912 */ | |
| 13913 DartType _undefinedType; | |
| 13914 | |
| 13915 /** | |
| 13916 * Initialize a newly created type provider to provide the types defined in | |
| 13917 * the given [coreLibrary] and [asyncLibrary]. | |
| 13918 */ | |
| 13919 TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) { | |
| 13920 Namespace coreNamespace = | |
| 13921 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary); | |
| 13922 Namespace asyncNamespace = | |
| 13923 new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary); | |
| 13924 _initializeFrom(coreNamespace, asyncNamespace); | |
| 13925 } | |
| 13926 | |
| 13927 /** | |
| 13928 * Initialize a newly created type provider to provide the types defined in | |
| 13929 * the given [Namespace]s. | |
| 13930 */ | |
| 13931 TypeProviderImpl.forNamespaces( | |
| 13932 Namespace coreNamespace, Namespace asyncNamespace) { | |
| 13933 _initializeFrom(coreNamespace, asyncNamespace); | |
| 13934 } | |
| 13935 | |
| 13936 @override | |
| 13937 InterfaceType get boolType => _boolType; | |
| 13938 | |
| 13939 @override | |
| 13940 DartType get bottomType => _bottomType; | |
| 13941 | |
| 13942 @override | |
| 13943 InterfaceType get deprecatedType => _deprecatedType; | |
| 13944 | |
| 13945 @override | |
| 13946 InterfaceType get doubleType => _doubleType; | |
| 13947 | |
| 13948 @override | |
| 13949 DartType get dynamicType => _dynamicType; | |
| 13950 | |
| 13951 @override | |
| 13952 InterfaceType get functionType => _functionType; | |
| 13953 | |
| 13954 @override | |
| 13955 InterfaceType get futureDynamicType => _futureDynamicType; | |
| 13956 | |
| 13957 @override | |
| 13958 InterfaceType get futureNullType => _futureNullType; | |
| 13959 | |
| 13960 @override | |
| 13961 InterfaceType get futureType => _futureType; | |
| 13962 | |
| 13963 @override | |
| 13964 InterfaceType get intType => _intType; | |
| 13965 | |
| 13966 @override | |
| 13967 InterfaceType get iterableDynamicType => _iterableDynamicType; | |
| 13968 | |
| 13969 @override | |
| 13970 InterfaceType get iterableType => _iterableType; | |
| 13971 | |
| 13972 @override | |
| 13973 InterfaceType get listType => _listType; | |
| 13974 | |
| 13975 @override | |
| 13976 InterfaceType get mapType => _mapType; | |
| 13977 | |
| 13978 @override | |
| 13979 List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[ | |
| 13980 nullType, | |
| 13981 numType, | |
| 13982 intType, | |
| 13983 doubleType, | |
| 13984 boolType, | |
| 13985 stringType | |
| 13986 ]; | |
| 13987 | |
| 13988 @override | |
| 13989 DartObjectImpl get nullObject { | |
| 13990 if (_nullObject == null) { | |
| 13991 _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE); | |
| 13992 } | |
| 13993 return _nullObject; | |
| 13994 } | |
| 13995 | |
| 13996 @override | |
| 13997 InterfaceType get nullType => _nullType; | |
| 13998 | |
| 13999 @override | |
| 14000 InterfaceType get numType => _numType; | |
| 14001 | |
| 14002 @override | |
| 14003 InterfaceType get objectType => _objectType; | |
| 14004 | |
| 14005 @override | |
| 14006 InterfaceType get stackTraceType => _stackTraceType; | |
| 14007 | |
| 14008 @override | |
| 14009 InterfaceType get streamDynamicType => _streamDynamicType; | |
| 14010 | |
| 14011 @override | |
| 14012 InterfaceType get streamType => _streamType; | |
| 14013 | |
| 14014 @override | |
| 14015 InterfaceType get stringType => _stringType; | |
| 14016 | |
| 14017 @override | |
| 14018 InterfaceType get symbolType => _symbolType; | |
| 14019 | |
| 14020 @override | |
| 14021 InterfaceType get typeType => _typeType; | |
| 14022 | |
| 14023 @override | |
| 14024 DartType get undefinedType => _undefinedType; | |
| 14025 | |
| 14026 /** | |
| 14027 * Return the type with the given name from the given namespace, or `null` if
there is no | |
| 14028 * class with the given name. | |
| 14029 * | |
| 14030 * @param namespace the namespace in which to search for the given name | |
| 14031 * @param typeName the name of the type being searched for | |
| 14032 * @return the type that was found | |
| 14033 */ | |
| 14034 InterfaceType _getType(Namespace namespace, String typeName) { | |
| 14035 Element element = namespace.get(typeName); | |
| 14036 if (element == null) { | |
| 14037 AnalysisEngine.instance.logger | |
| 14038 .logInformation("No definition of type $typeName"); | |
| 14039 return null; | |
| 14040 } | |
| 14041 return (element as ClassElement).type; | |
| 14042 } | |
| 14043 | |
| 14044 /** | |
| 14045 * Initialize the types provided by this type provider from the given | |
| 14046 * [Namespace]s. | |
| 14047 */ | |
| 14048 void _initializeFrom(Namespace coreNamespace, Namespace asyncNamespace) { | |
| 14049 _boolType = _getType(coreNamespace, "bool"); | |
| 14050 _bottomType = BottomTypeImpl.instance; | |
| 14051 _deprecatedType = _getType(coreNamespace, "Deprecated"); | |
| 14052 _doubleType = _getType(coreNamespace, "double"); | |
| 14053 _dynamicType = DynamicTypeImpl.instance; | |
| 14054 _functionType = _getType(coreNamespace, "Function"); | |
| 14055 _futureType = _getType(asyncNamespace, "Future"); | |
| 14056 _intType = _getType(coreNamespace, "int"); | |
| 14057 _iterableType = _getType(coreNamespace, "Iterable"); | |
| 14058 _listType = _getType(coreNamespace, "List"); | |
| 14059 _mapType = _getType(coreNamespace, "Map"); | |
| 14060 _nullType = _getType(coreNamespace, "Null"); | |
| 14061 _numType = _getType(coreNamespace, "num"); | |
| 14062 _objectType = _getType(coreNamespace, "Object"); | |
| 14063 _stackTraceType = _getType(coreNamespace, "StackTrace"); | |
| 14064 _streamType = _getType(asyncNamespace, "Stream"); | |
| 14065 _stringType = _getType(coreNamespace, "String"); | |
| 14066 _symbolType = _getType(coreNamespace, "Symbol"); | |
| 14067 _typeType = _getType(coreNamespace, "Type"); | |
| 14068 _undefinedType = UndefinedTypeImpl.instance; | |
| 14069 _futureDynamicType = _futureType.substitute4(<DartType>[_dynamicType]); | |
| 14070 _futureNullType = _futureType.substitute4(<DartType>[_nullType]); | |
| 14071 _iterableDynamicType = _iterableType.substitute4(<DartType>[_dynamicType]); | |
| 14072 _streamDynamicType = _streamType.substitute4(<DartType>[_dynamicType]); | |
| 14073 } | |
| 14074 } | |
| 14075 | |
| 14076 /** | |
| 14077 * Instances of the class `TypeResolverVisitor` are used to resolve the types as
sociated with | |
| 14078 * the elements in the element model. This includes the types of superclasses, m
ixins, interfaces, | |
| 14079 * fields, methods, parameters, and local variables. As a side-effect, this also
finishes building | |
| 14080 * the type hierarchy. | |
| 14081 */ | |
| 14082 class TypeResolverVisitor extends ScopedVisitor { | |
| 14083 /** | |
| 14084 * The type representing the type 'dynamic'. | |
| 14085 */ | |
| 14086 DartType _dynamicType; | |
| 14087 | |
| 14088 /** | |
| 14089 * The type representing typenames that can't be resolved. | |
| 14090 */ | 9924 */ |
| 14091 DartType _undefinedType; | 9925 DartType _undefinedType; |
| 14092 | 9926 |
| 14093 /** | 9927 /** |
| 9928 * Initialize a newly created type provider to provide the types defined in |
| 9929 * the given [coreLibrary] and [asyncLibrary]. |
| 9930 */ |
| 9931 TypeProviderImpl(LibraryElement coreLibrary, LibraryElement asyncLibrary) { |
| 9932 Namespace coreNamespace = |
| 9933 new NamespaceBuilder().createPublicNamespaceForLibrary(coreLibrary); |
| 9934 Namespace asyncNamespace = |
| 9935 new NamespaceBuilder().createPublicNamespaceForLibrary(asyncLibrary); |
| 9936 _initializeFrom(coreNamespace, asyncNamespace); |
| 9937 } |
| 9938 |
| 9939 /** |
| 9940 * Initialize a newly created type provider to provide the types defined in |
| 9941 * the given [Namespace]s. |
| 9942 */ |
| 9943 TypeProviderImpl.forNamespaces( |
| 9944 Namespace coreNamespace, Namespace asyncNamespace) { |
| 9945 _initializeFrom(coreNamespace, asyncNamespace); |
| 9946 } |
| 9947 |
| 9948 @override |
| 9949 InterfaceType get boolType => _boolType; |
| 9950 |
| 9951 @override |
| 9952 DartType get bottomType => _bottomType; |
| 9953 |
| 9954 @override |
| 9955 InterfaceType get deprecatedType => _deprecatedType; |
| 9956 |
| 9957 @override |
| 9958 InterfaceType get doubleType => _doubleType; |
| 9959 |
| 9960 @override |
| 9961 DartType get dynamicType => _dynamicType; |
| 9962 |
| 9963 @override |
| 9964 InterfaceType get functionType => _functionType; |
| 9965 |
| 9966 @override |
| 9967 InterfaceType get futureDynamicType => _futureDynamicType; |
| 9968 |
| 9969 @override |
| 9970 InterfaceType get futureNullType => _futureNullType; |
| 9971 |
| 9972 @override |
| 9973 InterfaceType get futureType => _futureType; |
| 9974 |
| 9975 @override |
| 9976 InterfaceType get intType => _intType; |
| 9977 |
| 9978 @override |
| 9979 InterfaceType get iterableDynamicType => _iterableDynamicType; |
| 9980 |
| 9981 @override |
| 9982 InterfaceType get iterableType => _iterableType; |
| 9983 |
| 9984 @override |
| 9985 InterfaceType get listType => _listType; |
| 9986 |
| 9987 @override |
| 9988 InterfaceType get mapType => _mapType; |
| 9989 |
| 9990 @override |
| 9991 DartObjectImpl get nullObject { |
| 9992 if (_nullObject == null) { |
| 9993 _nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE); |
| 9994 } |
| 9995 return _nullObject; |
| 9996 } |
| 9997 |
| 9998 @override |
| 9999 InterfaceType get nullType => _nullType; |
| 10000 |
| 10001 @override |
| 10002 InterfaceType get numType => _numType; |
| 10003 |
| 10004 @override |
| 10005 InterfaceType get objectType => _objectType; |
| 10006 |
| 10007 @override |
| 10008 InterfaceType get stackTraceType => _stackTraceType; |
| 10009 |
| 10010 @override |
| 10011 InterfaceType get streamDynamicType => _streamDynamicType; |
| 10012 |
| 10013 @override |
| 10014 InterfaceType get streamType => _streamType; |
| 10015 |
| 10016 @override |
| 10017 InterfaceType get stringType => _stringType; |
| 10018 |
| 10019 @override |
| 10020 InterfaceType get symbolType => _symbolType; |
| 10021 |
| 10022 @override |
| 10023 InterfaceType get typeType => _typeType; |
| 10024 |
| 10025 @override |
| 10026 DartType get undefinedType => _undefinedType; |
| 10027 |
| 10028 /** |
| 10029 * Return the type with the given name from the given namespace, or `null` if
there is no |
| 10030 * class with the given name. |
| 10031 * |
| 10032 * @param namespace the namespace in which to search for the given name |
| 10033 * @param typeName the name of the type being searched for |
| 10034 * @return the type that was found |
| 10035 */ |
| 10036 InterfaceType _getType(Namespace namespace, String typeName) { |
| 10037 Element element = namespace.get(typeName); |
| 10038 if (element == null) { |
| 10039 AnalysisEngine.instance.logger |
| 10040 .logInformation("No definition of type $typeName"); |
| 10041 return null; |
| 10042 } |
| 10043 return (element as ClassElement).type; |
| 10044 } |
| 10045 |
| 10046 /** |
| 10047 * Initialize the types provided by this type provider from the given |
| 10048 * [Namespace]s. |
| 10049 */ |
| 10050 void _initializeFrom(Namespace coreNamespace, Namespace asyncNamespace) { |
| 10051 _boolType = _getType(coreNamespace, "bool"); |
| 10052 _bottomType = BottomTypeImpl.instance; |
| 10053 _deprecatedType = _getType(coreNamespace, "Deprecated"); |
| 10054 _doubleType = _getType(coreNamespace, "double"); |
| 10055 _dynamicType = DynamicTypeImpl.instance; |
| 10056 _functionType = _getType(coreNamespace, "Function"); |
| 10057 _futureType = _getType(asyncNamespace, "Future"); |
| 10058 _intType = _getType(coreNamespace, "int"); |
| 10059 _iterableType = _getType(coreNamespace, "Iterable"); |
| 10060 _listType = _getType(coreNamespace, "List"); |
| 10061 _mapType = _getType(coreNamespace, "Map"); |
| 10062 _nullType = _getType(coreNamespace, "Null"); |
| 10063 _numType = _getType(coreNamespace, "num"); |
| 10064 _objectType = _getType(coreNamespace, "Object"); |
| 10065 _stackTraceType = _getType(coreNamespace, "StackTrace"); |
| 10066 _streamType = _getType(asyncNamespace, "Stream"); |
| 10067 _stringType = _getType(coreNamespace, "String"); |
| 10068 _symbolType = _getType(coreNamespace, "Symbol"); |
| 10069 _typeType = _getType(coreNamespace, "Type"); |
| 10070 _undefinedType = UndefinedTypeImpl.instance; |
| 10071 _futureDynamicType = _futureType.instantiate(<DartType>[_dynamicType]); |
| 10072 _futureNullType = _futureType.instantiate(<DartType>[_nullType]); |
| 10073 _iterableDynamicType = _iterableType.instantiate(<DartType>[_dynamicType]); |
| 10074 _streamDynamicType = _streamType.instantiate(<DartType>[_dynamicType]); |
| 10075 } |
| 10076 } |
| 10077 |
| 10078 /** |
| 10079 * Instances of the class `TypeResolverVisitor` are used to resolve the types as
sociated with |
| 10080 * the elements in the element model. This includes the types of superclasses, m
ixins, interfaces, |
| 10081 * fields, methods, parameters, and local variables. As a side-effect, this also
finishes building |
| 10082 * the type hierarchy. |
| 10083 */ |
| 10084 class TypeResolverVisitor extends ScopedVisitor { |
| 10085 /** |
| 10086 * The type representing the type 'dynamic'. |
| 10087 */ |
| 10088 DartType _dynamicType; |
| 10089 |
| 10090 /** |
| 10091 * The type representing typenames that can't be resolved. |
| 10092 */ |
| 10093 DartType _undefinedType; |
| 10094 |
| 10095 /** |
| 14094 * The flag specifying if currently visited class references 'super' expressio
n. | 10096 * The flag specifying if currently visited class references 'super' expressio
n. |
| 14095 */ | 10097 */ |
| 14096 bool _hasReferenceToSuper = false; | 10098 bool _hasReferenceToSuper = false; |
| 14097 | 10099 |
| 14098 /** | 10100 /** |
| 10101 * True if we're analyzing in strong mode. |
| 10102 */ |
| 10103 bool _strongMode; |
| 10104 |
| 10105 /** |
| 10106 * Type type system in use for this resolver pass. |
| 10107 */ |
| 10108 TypeSystem _typeSystem; |
| 10109 |
| 10110 /** |
| 10111 * The helper to resolve [TypeName]s. |
| 10112 */ |
| 10113 TypeNameResolver _typeNameResolver; |
| 10114 |
| 10115 /** |
| 14099 * Initialize a newly created visitor to resolve the nodes in an AST node. | 10116 * Initialize a newly created visitor to resolve the nodes in an AST node. |
| 14100 * | 10117 * |
| 14101 * [definingLibrary] is the element for the library containing the node being | 10118 * [definingLibrary] is the element for the library containing the node being |
| 14102 * visited. | 10119 * visited. |
| 14103 * [source] is the source representing the compilation unit containing the | 10120 * [source] is the source representing the compilation unit containing the |
| 14104 * node being visited. | 10121 * node being visited. |
| 14105 * [typeProvider] is the object used to access the types from the core | 10122 * [typeProvider] is the object used to access the types from the core |
| 14106 * library. | 10123 * library. |
| 14107 * [errorListener] is the error listener that will be informed of any errors | 10124 * [errorListener] is the error listener that will be informed of any errors |
| 14108 * that are found during resolution. | 10125 * that are found during resolution. |
| 14109 * [nameScope] is the scope used to resolve identifiers in the node that will | 10126 * [nameScope] is the scope used to resolve identifiers in the node that will |
| 14110 * first be visited. If `null` or unspecified, a new [LibraryScope] will be | 10127 * first be visited. If `null` or unspecified, a new [LibraryScope] will be |
| 14111 * created based on [definingLibrary] and [typeProvider]. | 10128 * created based on [definingLibrary] and [typeProvider]. |
| 14112 */ | 10129 */ |
| 14113 TypeResolverVisitor(LibraryElement definingLibrary, Source source, | 10130 TypeResolverVisitor(LibraryElement definingLibrary, Source source, |
| 14114 TypeProvider typeProvider, AnalysisErrorListener errorListener, | 10131 TypeProvider typeProvider, AnalysisErrorListener errorListener, |
| 14115 {Scope nameScope}) | 10132 {Scope nameScope}) |
| 14116 : super(definingLibrary, source, typeProvider, errorListener, | 10133 : super(definingLibrary, source, typeProvider, errorListener, |
| 14117 nameScope: nameScope) { | 10134 nameScope: nameScope) { |
| 14118 _dynamicType = typeProvider.dynamicType; | 10135 _dynamicType = typeProvider.dynamicType; |
| 14119 _undefinedType = typeProvider.undefinedType; | 10136 _undefinedType = typeProvider.undefinedType; |
| 10137 _strongMode = definingLibrary.context.analysisOptions.strongMode; |
| 10138 _typeSystem = TypeSystem.create(definingLibrary.context); |
| 10139 _typeNameResolver = new TypeNameResolver( |
| 10140 _typeSystem, typeProvider, definingLibrary, source, errorListener); |
| 14120 } | 10141 } |
| 14121 | 10142 |
| 14122 @override | 10143 @override |
| 14123 Object visitAnnotation(Annotation node) { | 10144 Object visitAnnotation(Annotation node) { |
| 14124 // | 10145 // |
| 14125 // Visit annotations, if the annotation is @proxy, on a class, and "proxy" | 10146 // Visit annotations, if the annotation is @proxy, on a class, and "proxy" |
| 14126 // resolves to the proxy annotation in dart.core, then create create the | 10147 // resolves to the proxy annotation in dart.core, then resolve the |
| 14127 // ElementAnnotationImpl and set it as the metadata on the enclosing class. | 10148 // ElementAnnotation. |
| 14128 // | 10149 // |
| 14129 // Element resolution is done in the ElementResolver, and this work will be | 10150 // Element resolution is done in the ElementResolver, and this work will be |
| 14130 // done in the general case for all annotations in the ElementResolver. | 10151 // done in the general case for all annotations in the ElementResolver. |
| 14131 // The reason we resolve this particular element early is so that | 10152 // The reason we resolve this particular element early is so that |
| 14132 // ClassElement.isProxy() returns the correct information during all | 10153 // ClassElement.isProxy() returns the correct information during all |
| 14133 // phases of the ElementResolver. | 10154 // phases of the ElementResolver. |
| 14134 // | 10155 // |
| 14135 super.visitAnnotation(node); | 10156 super.visitAnnotation(node); |
| 14136 Identifier identifier = node.name; | 10157 Identifier identifier = node.name; |
| 14137 if (identifier.name.endsWith(ElementAnnotationImpl.PROXY_VARIABLE_NAME) && | 10158 if (identifier.name.endsWith(ElementAnnotationImpl.PROXY_VARIABLE_NAME) && |
| 14138 node.parent is ClassDeclaration) { | 10159 node.parent is ClassDeclaration) { |
| 14139 Element element = nameScope.lookup(identifier, definingLibrary); | 10160 Element element = nameScope.lookup(identifier, definingLibrary); |
| 14140 if (element != null && | 10161 if (element != null && |
| 14141 element.library.isDartCore && | 10162 element.library.isDartCore && |
| 14142 element is PropertyAccessorElement) { | 10163 element is PropertyAccessorElement) { |
| 14143 // This is the @proxy from dart.core | 10164 // This is the @proxy from dart.core |
| 14144 ClassDeclaration classDeclaration = node.parent as ClassDeclaration; | 10165 ElementAnnotationImpl elementAnnotation = node.elementAnnotation; |
| 14145 ElementAnnotationImpl elementAnnotation = | 10166 elementAnnotation.element = element; |
| 14146 new ElementAnnotationImpl(element); | |
| 14147 node.elementAnnotation = elementAnnotation; | |
| 14148 (classDeclaration.element as ClassElementImpl).metadata = | |
| 14149 <ElementAnnotationImpl>[elementAnnotation]; | |
| 14150 } | 10167 } |
| 14151 } | 10168 } |
| 14152 return null; | 10169 return null; |
| 14153 } | 10170 } |
| 14154 | 10171 |
| 14155 @override | 10172 @override |
| 14156 Object visitCatchClause(CatchClause node) { | 10173 Object visitCatchClause(CatchClause node) { |
| 14157 super.visitCatchClause(node); | 10174 super.visitCatchClause(node); |
| 14158 SimpleIdentifier exception = node.exceptionParameter; | 10175 SimpleIdentifier exception = node.exceptionParameter; |
| 14159 if (exception != null) { | 10176 if (exception != null) { |
| 14160 // If an 'on' clause is provided the type of the exception parameter is | 10177 // If an 'on' clause is provided the type of the exception parameter is |
| 14161 // the type in the 'on' clause. Otherwise, the type of the exception | 10178 // the type in the 'on' clause. Otherwise, the type of the exception |
| 14162 // parameter is 'Object'. | 10179 // parameter is 'Object'. |
| 14163 TypeName exceptionTypeName = node.exceptionType; | 10180 TypeName exceptionTypeName = node.exceptionType; |
| 14164 DartType exceptionType; | 10181 DartType exceptionType; |
| 14165 if (exceptionTypeName == null) { | 10182 if (exceptionTypeName == null) { |
| 14166 exceptionType = typeProvider.dynamicType; | 10183 exceptionType = typeProvider.dynamicType; |
| 14167 } else { | 10184 } else { |
| 14168 exceptionType = _getType(exceptionTypeName); | 10185 exceptionType = _typeNameResolver._getType(exceptionTypeName); |
| 14169 } | 10186 } |
| 14170 _recordType(exception, exceptionType); | 10187 _recordType(exception, exceptionType); |
| 14171 Element element = exception.staticElement; | 10188 Element element = exception.staticElement; |
| 14172 if (element is VariableElementImpl) { | 10189 if (element is VariableElementImpl) { |
| 14173 element.type = exceptionType; | 10190 element.type = exceptionType; |
| 14174 } else { | 10191 } else { |
| 14175 // TODO(brianwilkerson) Report the internal error | 10192 // TODO(brianwilkerson) Report the internal error |
| 14176 } | 10193 } |
| 14177 } | 10194 } |
| 14178 SimpleIdentifier stackTrace = node.stackTraceParameter; | 10195 SimpleIdentifier stackTrace = node.stackTraceParameter; |
| 14179 if (stackTrace != null) { | 10196 if (stackTrace != null) { |
| 14180 _recordType(stackTrace, typeProvider.stackTraceType); | 10197 _recordType(stackTrace, typeProvider.stackTraceType); |
| 14181 Element element = stackTrace.staticElement; | 10198 Element element = stackTrace.staticElement; |
| 14182 if (element is VariableElementImpl) { | 10199 if (element is VariableElementImpl) { |
| 14183 element.type = typeProvider.stackTraceType; | 10200 element.type = typeProvider.stackTraceType; |
| 14184 } else { | 10201 } else { |
| 14185 // TODO(brianwilkerson) Report the internal error | 10202 // TODO(brianwilkerson) Report the internal error |
| 14186 } | 10203 } |
| 14187 } | 10204 } |
| 14188 return null; | 10205 return null; |
| 14189 } | 10206 } |
| 14190 | 10207 |
| 14191 @override | 10208 @override |
| 14192 Object visitClassDeclaration(ClassDeclaration node) { | 10209 Object visitClassDeclaration(ClassDeclaration node) { |
| 14193 _hasReferenceToSuper = false; | 10210 _hasReferenceToSuper = false; |
| 14194 super.visitClassDeclaration(node); | 10211 super.visitClassDeclaration(node); |
| 14195 ClassElementImpl classElement = _getClassElement(node.name); | 10212 ClassElementImpl classElement = _getClassElement(node.name); |
| 14196 if (classElement != null) { | 10213 if (classElement != null) { |
| 10214 // Clear this flag, as we just invalidated any inferred member types. |
| 10215 classElement.hasBeenInferred = false; |
| 14197 classElement.hasReferenceToSuper = _hasReferenceToSuper; | 10216 classElement.hasReferenceToSuper = _hasReferenceToSuper; |
| 14198 } | 10217 } |
| 14199 return null; | 10218 return null; |
| 14200 } | 10219 } |
| 14201 | 10220 |
| 14202 @override | 10221 @override |
| 14203 void visitClassDeclarationInScope(ClassDeclaration node) { | 10222 void visitClassDeclarationInScope(ClassDeclaration node) { |
| 14204 super.visitClassDeclarationInScope(node); | 10223 super.visitClassDeclarationInScope(node); |
| 14205 ExtendsClause extendsClause = node.extendsClause; | 10224 ExtendsClause extendsClause = node.extendsClause; |
| 14206 WithClause withClause = node.withClause; | 10225 WithClause withClause = node.withClause; |
| 14207 ImplementsClause implementsClause = node.implementsClause; | 10226 ImplementsClause implementsClause = node.implementsClause; |
| 14208 ClassElementImpl classElement = _getClassElement(node.name); | 10227 ClassElementImpl classElement = _getClassElement(node.name); |
| 14209 InterfaceType superclassType = null; | 10228 InterfaceType superclassType = null; |
| 14210 if (extendsClause != null) { | 10229 if (extendsClause != null) { |
| 14211 ErrorCode errorCode = (withClause == null | 10230 ErrorCode errorCode = (withClause == null |
| 14212 ? CompileTimeErrorCode.EXTENDS_NON_CLASS | 10231 ? CompileTimeErrorCode.EXTENDS_NON_CLASS |
| 14213 : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS); | 10232 : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS); |
| 14214 superclassType = _resolveType(extendsClause.superclass, errorCode, | 10233 superclassType = _resolveType(extendsClause.superclass, errorCode, |
| 14215 CompileTimeErrorCode.EXTENDS_ENUM, errorCode); | 10234 CompileTimeErrorCode.EXTENDS_ENUM, errorCode); |
| 14216 if (!identical(superclassType, typeProvider.objectType)) { | |
| 14217 classElement.validMixin = false; | |
| 14218 } | |
| 14219 } | 10235 } |
| 14220 if (classElement != null) { | 10236 if (classElement != null) { |
| 14221 if (superclassType == null) { | 10237 if (superclassType == null) { |
| 14222 InterfaceType objectType = typeProvider.objectType; | 10238 InterfaceType objectType = typeProvider.objectType; |
| 14223 if (!identical(classElement.type, objectType)) { | 10239 if (!identical(classElement.type, objectType)) { |
| 14224 superclassType = objectType; | 10240 superclassType = objectType; |
| 14225 } | 10241 } |
| 14226 } | 10242 } |
| 14227 classElement.supertype = superclassType; | 10243 classElement.supertype = superclassType; |
| 14228 } | 10244 } |
| 14229 _resolve(classElement, withClause, implementsClause); | 10245 _resolve(classElement, withClause, implementsClause); |
| 14230 return null; | 10246 return null; |
| 14231 } | 10247 } |
| 14232 | 10248 |
| 14233 @override | 10249 @override |
| 14234 void visitClassMembersInScope(ClassDeclaration node) { | 10250 void visitClassMembersInScope(ClassDeclaration node) { |
| 10251 node.documentationComment?.accept(this); |
| 10252 node.metadata.accept(this); |
| 14235 // | 10253 // |
| 14236 // Process field declarations before constructors and methods so that the | 10254 // Process field declarations before constructors and methods so that the |
| 14237 // types of field formal parameters can be correctly resolved. | 10255 // types of field formal parameters can be correctly resolved. |
| 14238 // | 10256 // |
| 14239 List<ClassMember> nonFields = new List<ClassMember>(); | 10257 List<ClassMember> nonFields = new List<ClassMember>(); |
| 14240 node.visitChildren( | 10258 NodeList<ClassMember> members = node.members; |
| 14241 new _TypeResolverVisitor_visitClassMembersInScope(this, nonFields)); | 10259 int length = members.length; |
| 10260 for (int i = 0; i < length; i++) { |
| 10261 ClassMember member = members[i]; |
| 10262 if (member is ConstructorDeclaration) { |
| 10263 nonFields.add(member); |
| 10264 } else { |
| 10265 member.accept(this); |
| 10266 } |
| 10267 } |
| 14242 int count = nonFields.length; | 10268 int count = nonFields.length; |
| 14243 for (int i = 0; i < count; i++) { | 10269 for (int i = 0; i < count; i++) { |
| 14244 nonFields[i].accept(this); | 10270 nonFields[i].accept(this); |
| 14245 } | 10271 } |
| 14246 } | 10272 } |
| 14247 | 10273 |
| 14248 @override | 10274 @override |
| 14249 Object visitClassTypeAlias(ClassTypeAlias node) { | 10275 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 14250 super.visitClassTypeAlias(node); | 10276 super.visitClassTypeAlias(node); |
| 14251 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS; | 10277 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS; |
| 14252 InterfaceType superclassType = _resolveType(node.superclass, errorCode, | 10278 InterfaceType superclassType = _resolveType(node.superclass, errorCode, |
| 14253 CompileTimeErrorCode.EXTENDS_ENUM, errorCode); | 10279 CompileTimeErrorCode.EXTENDS_ENUM, errorCode); |
| 14254 if (superclassType == null) { | 10280 if (superclassType == null) { |
| 14255 superclassType = typeProvider.objectType; | 10281 superclassType = typeProvider.objectType; |
| 14256 } | 10282 } |
| 14257 ClassElementImpl classElement = _getClassElement(node.name); | 10283 ClassElementImpl classElement = _getClassElement(node.name); |
| 14258 if (classElement != null) { | 10284 if (classElement != null) { |
| 14259 classElement.supertype = superclassType; | 10285 classElement.supertype = superclassType; |
| 14260 } | 10286 } |
| 14261 _resolve(classElement, node.withClause, node.implementsClause); | 10287 _resolve(classElement, node.withClause, node.implementsClause); |
| 14262 return null; | 10288 return null; |
| 14263 } | 10289 } |
| 14264 | 10290 |
| 14265 @override | 10291 @override |
| 14266 Object visitConstructorDeclaration(ConstructorDeclaration node) { | 10292 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 14267 super.visitConstructorDeclaration(node); | 10293 super.visitConstructorDeclaration(node); |
| 14268 ExecutableElementImpl element = node.element as ExecutableElementImpl; | 10294 if (node.element == null) { |
| 14269 if (element == null) { | |
| 14270 ClassDeclaration classNode = | 10295 ClassDeclaration classNode = |
| 14271 node.getAncestor((node) => node is ClassDeclaration); | 10296 node.getAncestor((node) => node is ClassDeclaration); |
| 14272 StringBuffer buffer = new StringBuffer(); | 10297 StringBuffer buffer = new StringBuffer(); |
| 14273 buffer.write("The element for the constructor "); | 10298 buffer.write("The element for the constructor "); |
| 14274 buffer.write(node.name == null ? "<unnamed>" : node.name.name); | 10299 buffer.write(node.name == null ? "<unnamed>" : node.name.name); |
| 14275 buffer.write(" in "); | 10300 buffer.write(" in "); |
| 14276 if (classNode == null) { | 10301 if (classNode == null) { |
| 14277 buffer.write("<unknown class>"); | 10302 buffer.write("<unknown class>"); |
| 14278 } else { | 10303 } else { |
| 14279 buffer.write(classNode.name.name); | 10304 buffer.write(classNode.name.name); |
| 14280 } | 10305 } |
| 14281 buffer.write(" in "); | 10306 buffer.write(" in "); |
| 14282 buffer.write(source.fullName); | 10307 buffer.write(source.fullName); |
| 14283 buffer.write(" was not set while trying to resolve types."); | 10308 buffer.write(" was not set while trying to resolve types."); |
| 14284 AnalysisEngine.instance.logger.logError(buffer.toString(), | 10309 AnalysisEngine.instance.logger.logError(buffer.toString(), |
| 14285 new CaughtException(new AnalysisException(), null)); | 10310 new CaughtException(new AnalysisException(), null)); |
| 14286 } else { | |
| 14287 ClassElement definingClass = element.enclosingElement as ClassElement; | |
| 14288 element.returnType = definingClass.type; | |
| 14289 FunctionTypeImpl type = new FunctionTypeImpl(element); | |
| 14290 type.typeArguments = definingClass.type.typeArguments; | |
| 14291 element.type = type; | |
| 14292 } | 10311 } |
| 14293 return null; | 10312 return null; |
| 14294 } | 10313 } |
| 14295 | 10314 |
| 14296 @override | 10315 @override |
| 14297 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | 10316 Object visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 14298 super.visitDeclaredIdentifier(node); | 10317 super.visitDeclaredIdentifier(node); |
| 14299 DartType declaredType; | 10318 DartType declaredType; |
| 14300 TypeName typeName = node.type; | 10319 TypeName typeName = node.type; |
| 14301 if (typeName == null) { | 10320 if (typeName == null) { |
| 14302 declaredType = _dynamicType; | 10321 declaredType = _dynamicType; |
| 14303 } else { | 10322 } else { |
| 14304 declaredType = _getType(typeName); | 10323 declaredType = _typeNameResolver._getType(typeName); |
| 14305 } | 10324 } |
| 14306 LocalVariableElementImpl element = node.element as LocalVariableElementImpl; | 10325 LocalVariableElementImpl element = node.element as LocalVariableElementImpl; |
| 14307 element.type = declaredType; | 10326 element.type = declaredType; |
| 14308 return null; | 10327 return null; |
| 14309 } | 10328 } |
| 14310 | 10329 |
| 14311 @override | 10330 @override |
| 14312 Object visitFieldFormalParameter(FieldFormalParameter node) { | 10331 Object visitFieldFormalParameter(FieldFormalParameter node) { |
| 14313 super.visitFieldFormalParameter(node); | 10332 super.visitFieldFormalParameter(node); |
| 14314 Element element = node.identifier.staticElement; | 10333 Element element = node.identifier.staticElement; |
| 14315 if (element is ParameterElementImpl) { | 10334 if (element is ParameterElementImpl) { |
| 14316 ParameterElementImpl parameter = element; | |
| 14317 FormalParameterList parameterList = node.parameters; | 10335 FormalParameterList parameterList = node.parameters; |
| 14318 if (parameterList == null) { | 10336 if (parameterList == null) { |
| 14319 DartType type; | 10337 DartType type; |
| 14320 TypeName typeName = node.type; | 10338 TypeName typeName = node.type; |
| 14321 if (typeName == null) { | 10339 if (typeName == null) { |
| 14322 element.hasImplicitType = true; | 10340 element.hasImplicitType = true; |
| 14323 type = _dynamicType; | 10341 if (element is FieldFormalParameterElement) { |
| 14324 if (parameter is FieldFormalParameterElement) { | |
| 14325 FieldElement fieldElement = | 10342 FieldElement fieldElement = |
| 14326 (parameter as FieldFormalParameterElement).field; | 10343 (element as FieldFormalParameterElement).field; |
| 14327 if (fieldElement != null) { | 10344 type = fieldElement?.type; |
| 14328 type = fieldElement.type; | |
| 14329 } | |
| 14330 } | 10345 } |
| 14331 } else { | 10346 } else { |
| 14332 type = _getType(typeName); | 10347 type = _typeNameResolver._getType(typeName); |
| 14333 } | 10348 } |
| 14334 parameter.type = type; | 10349 element.type = type ?? _dynamicType; |
| 14335 } else { | 10350 } else { |
| 14336 _setFunctionTypedParameterType(parameter, node.type, node.parameters); | 10351 _setFunctionTypedParameterType(element, node.type, node.parameters); |
| 14337 } | 10352 } |
| 14338 } else { | 10353 } else { |
| 14339 // TODO(brianwilkerson) Report this internal error | 10354 // TODO(brianwilkerson) Report this internal error |
| 14340 } | 10355 } |
| 14341 return null; | 10356 return null; |
| 14342 } | 10357 } |
| 14343 | 10358 |
| 14344 @override | 10359 @override |
| 14345 Object visitFunctionDeclaration(FunctionDeclaration node) { | 10360 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 14346 super.visitFunctionDeclaration(node); | 10361 super.visitFunctionDeclaration(node); |
| 14347 ExecutableElementImpl element = node.element as ExecutableElementImpl; | 10362 ExecutableElementImpl element = node.element as ExecutableElementImpl; |
| 14348 if (element == null) { | 10363 if (element == null) { |
| 14349 StringBuffer buffer = new StringBuffer(); | 10364 StringBuffer buffer = new StringBuffer(); |
| 14350 buffer.write("The element for the top-level function "); | 10365 buffer.write("The element for the top-level function "); |
| 14351 buffer.write(node.name); | 10366 buffer.write(node.name); |
| 14352 buffer.write(" in "); | 10367 buffer.write(" in "); |
| 14353 buffer.write(source.fullName); | 10368 buffer.write(source.fullName); |
| 14354 buffer.write(" was not set while trying to resolve types."); | 10369 buffer.write(" was not set while trying to resolve types."); |
| 14355 AnalysisEngine.instance.logger.logError(buffer.toString(), | 10370 AnalysisEngine.instance.logger.logError(buffer.toString(), |
| 14356 new CaughtException(new AnalysisException(), null)); | 10371 new CaughtException(new AnalysisException(), null)); |
| 14357 } | 10372 } |
| 14358 element.returnType = _computeReturnType(node.returnType); | 10373 element.returnType = _computeReturnType(node.returnType); |
| 14359 FunctionTypeImpl type = new FunctionTypeImpl(element); | 10374 element.type = new FunctionTypeImpl(element); |
| 14360 ClassElement definingClass = | 10375 _inferSetterReturnType(element); |
| 14361 element.getAncestor((element) => element is ClassElement); | |
| 14362 if (definingClass != null) { | |
| 14363 type.typeArguments = definingClass.type.typeArguments; | |
| 14364 } | |
| 14365 element.type = type; | |
| 14366 return null; | 10376 return null; |
| 14367 } | 10377 } |
| 14368 | 10378 |
| 14369 @override | 10379 @override |
| 14370 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | 10380 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 14371 FunctionTypeAliasElementImpl element = | 10381 FunctionTypeAliasElementImpl element = |
| 14372 node.element as FunctionTypeAliasElementImpl; | 10382 node.element as FunctionTypeAliasElementImpl; |
| 14373 super.visitFunctionTypeAlias(node); | 10383 super.visitFunctionTypeAlias(node); |
| 14374 element.returnType = _computeReturnType(node.returnType); | 10384 element.returnType = _computeReturnType(node.returnType); |
| 14375 return null; | 10385 return null; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 14403 } else { | 10413 } else { |
| 14404 buffer.write(classNode.name.name); | 10414 buffer.write(classNode.name.name); |
| 14405 } | 10415 } |
| 14406 buffer.write(" in "); | 10416 buffer.write(" in "); |
| 14407 buffer.write(source.fullName); | 10417 buffer.write(source.fullName); |
| 14408 buffer.write(" was not set while trying to resolve types."); | 10418 buffer.write(" was not set while trying to resolve types."); |
| 14409 AnalysisEngine.instance.logger.logError(buffer.toString(), | 10419 AnalysisEngine.instance.logger.logError(buffer.toString(), |
| 14410 new CaughtException(new AnalysisException(), null)); | 10420 new CaughtException(new AnalysisException(), null)); |
| 14411 } | 10421 } |
| 14412 element.returnType = _computeReturnType(node.returnType); | 10422 element.returnType = _computeReturnType(node.returnType); |
| 14413 FunctionTypeImpl type = new FunctionTypeImpl(element); | 10423 element.type = new FunctionTypeImpl(element); |
| 14414 ClassElement definingClass = | 10424 _inferSetterReturnType(element); |
| 14415 element.getAncestor((element) => element is ClassElement); | |
| 14416 if (definingClass != null) { | |
| 14417 type.typeArguments = definingClass.type.typeArguments; | |
| 14418 } | |
| 14419 element.type = type; | |
| 14420 if (element is PropertyAccessorElement) { | 10425 if (element is PropertyAccessorElement) { |
| 14421 PropertyAccessorElement accessor = element as PropertyAccessorElement; | 10426 PropertyAccessorElement accessor = element as PropertyAccessorElement; |
| 14422 PropertyInducingElementImpl variable = | 10427 PropertyInducingElementImpl variable = |
| 14423 accessor.variable as PropertyInducingElementImpl; | 10428 accessor.variable as PropertyInducingElementImpl; |
| 14424 if (accessor.isGetter) { | 10429 if (accessor.isGetter) { |
| 14425 variable.type = type.baseReturnType; | 10430 variable.type = element.returnType; |
| 14426 } else if (variable.type == null) { | 10431 } else if (variable.type == null) { |
| 14427 List<ParameterElement> parameters = type.baseParameters; | 10432 List<ParameterElement> parameters = element.parameters; |
| 14428 if (parameters != null && parameters.length > 0) { | 10433 if (parameters != null && parameters.length > 0) { |
| 14429 variable.type = parameters[0].type; | 10434 variable.type = parameters[0].type; |
| 14430 } | 10435 } |
| 14431 } | 10436 } |
| 14432 } | 10437 } |
| 14433 return null; | 10438 return null; |
| 14434 } | 10439 } |
| 14435 | 10440 |
| 14436 @override | 10441 @override |
| 14437 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | 10442 Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 14438 super.visitSimpleFormalParameter(node); | 10443 super.visitSimpleFormalParameter(node); |
| 14439 DartType declaredType; | 10444 DartType declaredType; |
| 14440 TypeName typeName = node.type; | 10445 TypeName typeName = node.type; |
| 14441 if (typeName == null) { | 10446 if (typeName == null) { |
| 14442 declaredType = _dynamicType; | 10447 declaredType = _dynamicType; |
| 14443 } else { | 10448 } else { |
| 14444 declaredType = _getType(typeName); | 10449 declaredType = _typeNameResolver._getType(typeName); |
| 14445 } | 10450 } |
| 14446 Element element = node.identifier.staticElement; | 10451 Element element = node.identifier.staticElement; |
| 14447 if (element is ParameterElement) { | 10452 if (element is ParameterElementImpl) { |
| 14448 (element as ParameterElementImpl).type = declaredType; | 10453 element.type = declaredType; |
| 14449 } else { | 10454 } else { |
| 14450 // TODO(brianwilkerson) Report the internal error. | 10455 // TODO(brianwilkerson) Report the internal error. |
| 14451 } | 10456 } |
| 14452 return null; | 10457 return null; |
| 14453 } | 10458 } |
| 14454 | 10459 |
| 14455 @override | 10460 @override |
| 14456 Object visitSuperExpression(SuperExpression node) { | 10461 Object visitSuperExpression(SuperExpression node) { |
| 14457 _hasReferenceToSuper = true; | 10462 _hasReferenceToSuper = true; |
| 14458 return super.visitSuperExpression(node); | 10463 return super.visitSuperExpression(node); |
| 14459 } | 10464 } |
| 14460 | 10465 |
| 14461 @override | 10466 @override |
| 14462 Object visitTypeName(TypeName node) { | 10467 Object visitTypeName(TypeName node) { |
| 14463 super.visitTypeName(node); | 10468 super.visitTypeName(node); |
| 14464 Identifier typeName = node.name; | 10469 _typeNameResolver.nameScope = this.nameScope; |
| 14465 TypeArgumentList argumentList = node.typeArguments; | 10470 _typeNameResolver.resolveTypeName(node); |
| 14466 Element element = nameScope.lookup(typeName, definingLibrary); | |
| 14467 if (element == null) { | |
| 14468 // | |
| 14469 // Check to see whether the type name is either 'dynamic' or 'void', | |
| 14470 // neither of which are in the name scope and hence will not be found by | |
| 14471 // normal means. | |
| 14472 // | |
| 14473 if (typeName.name == _dynamicType.name) { | |
| 14474 _setElement(typeName, _dynamicType.element); | |
| 14475 if (argumentList != null) { | |
| 14476 // TODO(brianwilkerson) Report this error | |
| 14477 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU
MENTS, node, dynamicType.getName(), 0, argumentList.getArguments().size()); | |
| 14478 } | |
| 14479 typeName.staticType = _dynamicType; | |
| 14480 node.type = _dynamicType; | |
| 14481 return null; | |
| 14482 } | |
| 14483 VoidTypeImpl voidType = VoidTypeImpl.instance; | |
| 14484 if (typeName.name == voidType.name) { | |
| 14485 // There is no element for 'void'. | |
| 14486 if (argumentList != null) { | |
| 14487 // TODO(brianwilkerson) Report this error | |
| 14488 // reporter.reportError(StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGU
MENTS, node, voidType.getName(), 0, argumentList.getArguments().size()); | |
| 14489 } | |
| 14490 typeName.staticType = voidType; | |
| 14491 node.type = voidType; | |
| 14492 return null; | |
| 14493 } | |
| 14494 // | |
| 14495 // If not, the look to see whether we might have created the wrong AST | |
| 14496 // structure for a constructor name. If so, fix the AST structure and then | |
| 14497 // proceed. | |
| 14498 // | |
| 14499 AstNode parent = node.parent; | |
| 14500 if (typeName is PrefixedIdentifier && | |
| 14501 parent is ConstructorName && | |
| 14502 argumentList == null) { | |
| 14503 ConstructorName name = parent; | |
| 14504 if (name.name == null) { | |
| 14505 PrefixedIdentifier prefixedIdentifier = | |
| 14506 typeName as PrefixedIdentifier; | |
| 14507 SimpleIdentifier prefix = prefixedIdentifier.prefix; | |
| 14508 element = nameScope.lookup(prefix, definingLibrary); | |
| 14509 if (element is PrefixElement) { | |
| 14510 if (parent.parent is InstanceCreationExpression && | |
| 14511 (parent.parent as InstanceCreationExpression).isConst) { | |
| 14512 // If, if this is a const expression, then generate a | |
| 14513 // CompileTimeErrorCode.CONST_WITH_NON_TYPE error. | |
| 14514 reportErrorForNode( | |
| 14515 CompileTimeErrorCode.CONST_WITH_NON_TYPE, | |
| 14516 prefixedIdentifier.identifier, | |
| 14517 [prefixedIdentifier.identifier.name]); | |
| 14518 } else { | |
| 14519 // Else, if this expression is a new expression, report a | |
| 14520 // NEW_WITH_NON_TYPE warning. | |
| 14521 reportErrorForNode( | |
| 14522 StaticWarningCode.NEW_WITH_NON_TYPE, | |
| 14523 prefixedIdentifier.identifier, | |
| 14524 [prefixedIdentifier.identifier.name]); | |
| 14525 } | |
| 14526 _setElement(prefix, element); | |
| 14527 return null; | |
| 14528 } else if (element != null) { | |
| 14529 // | |
| 14530 // Rewrite the constructor name. The parser, when it sees a | |
| 14531 // constructor named "a.b", cannot tell whether "a" is a prefix and | |
| 14532 // "b" is a class name, or whether "a" is a class name and "b" is a | |
| 14533 // constructor name. It arbitrarily chooses the former, but in this | |
| 14534 // case was wrong. | |
| 14535 // | |
| 14536 name.name = prefixedIdentifier.identifier; | |
| 14537 name.period = prefixedIdentifier.period; | |
| 14538 node.name = prefix; | |
| 14539 typeName = prefix; | |
| 14540 } | |
| 14541 } | |
| 14542 } | |
| 14543 } | |
| 14544 // check element | |
| 14545 bool elementValid = element is! MultiplyDefinedElement; | |
| 14546 if (elementValid && | |
| 14547 element is! ClassElement && | |
| 14548 _isTypeNameInInstanceCreationExpression(node)) { | |
| 14549 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName); | |
| 14550 InstanceCreationExpression creation = | |
| 14551 node.parent.parent as InstanceCreationExpression; | |
| 14552 if (creation.isConst) { | |
| 14553 if (element == null) { | |
| 14554 reportErrorForNode( | |
| 14555 CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]); | |
| 14556 } else { | |
| 14557 reportErrorForNode(CompileTimeErrorCode.CONST_WITH_NON_TYPE, | |
| 14558 typeNameSimple, [typeName]); | |
| 14559 } | |
| 14560 elementValid = false; | |
| 14561 } else { | |
| 14562 if (element != null) { | |
| 14563 reportErrorForNode( | |
| 14564 StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]); | |
| 14565 elementValid = false; | |
| 14566 } | |
| 14567 } | |
| 14568 } | |
| 14569 if (elementValid && element == null) { | |
| 14570 // We couldn't resolve the type name. | |
| 14571 // TODO(jwren) Consider moving the check for | |
| 14572 // CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE from the | |
| 14573 // ErrorVerifier, so that we don't have two errors on a built in | |
| 14574 // identifier being used as a class name. | |
| 14575 // See CompileTimeErrorCodeTest.test_builtInIdentifierAsType(). | |
| 14576 SimpleIdentifier typeNameSimple = _getTypeSimpleIdentifier(typeName); | |
| 14577 RedirectingConstructorKind redirectingConstructorKind; | |
| 14578 if (_isBuiltInIdentifier(node) && _isTypeAnnotation(node)) { | |
| 14579 reportErrorForNode(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, | |
| 14580 typeName, [typeName.name]); | |
| 14581 } else if (typeNameSimple.name == "boolean") { | |
| 14582 reportErrorForNode( | |
| 14583 StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []); | |
| 14584 } else if (_isTypeNameInCatchClause(node)) { | |
| 14585 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, | |
| 14586 [typeName.name]); | |
| 14587 } else if (_isTypeNameInAsExpression(node)) { | |
| 14588 reportErrorForNode( | |
| 14589 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]); | |
| 14590 } else if (_isTypeNameInIsExpression(node)) { | |
| 14591 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME, | |
| 14592 typeName, [typeName.name]); | |
| 14593 } else if ((redirectingConstructorKind = | |
| 14594 _getRedirectingConstructorKind(node)) != | |
| 14595 null) { | |
| 14596 ErrorCode errorCode = (redirectingConstructorKind == | |
| 14597 RedirectingConstructorKind.CONST | |
| 14598 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS | |
| 14599 : StaticWarningCode.REDIRECT_TO_NON_CLASS); | |
| 14600 reportErrorForNode(errorCode, typeName, [typeName.name]); | |
| 14601 } else if (_isTypeNameInTypeArgumentList(node)) { | |
| 14602 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, | |
| 14603 typeName, [typeName.name]); | |
| 14604 } else { | |
| 14605 reportErrorForNode( | |
| 14606 StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]); | |
| 14607 } | |
| 14608 elementValid = false; | |
| 14609 } | |
| 14610 if (!elementValid) { | |
| 14611 if (element is MultiplyDefinedElement) { | |
| 14612 _setElement(typeName, element); | |
| 14613 } else { | |
| 14614 _setElement(typeName, _dynamicType.element); | |
| 14615 } | |
| 14616 typeName.staticType = _undefinedType; | |
| 14617 node.type = _undefinedType; | |
| 14618 return null; | |
| 14619 } | |
| 14620 DartType type = null; | |
| 14621 if (element is ClassElement) { | |
| 14622 _setElement(typeName, element); | |
| 14623 type = element.type; | |
| 14624 } else if (element is FunctionTypeAliasElement) { | |
| 14625 _setElement(typeName, element); | |
| 14626 type = element.type; | |
| 14627 } else if (element is TypeParameterElement) { | |
| 14628 _setElement(typeName, element); | |
| 14629 type = element.type; | |
| 14630 if (argumentList != null) { | |
| 14631 // Type parameters cannot have type arguments. | |
| 14632 // TODO(brianwilkerson) Report this error. | |
| 14633 // resolver.reportError(ResolverErrorCode.?, keyType); | |
| 14634 } | |
| 14635 } else if (element is MultiplyDefinedElement) { | |
| 14636 List<Element> elements = element.conflictingElements; | |
| 14637 type = _getTypeWhenMultiplyDefined(elements); | |
| 14638 if (type != null) { | |
| 14639 node.type = type; | |
| 14640 } | |
| 14641 } else { | |
| 14642 // The name does not represent a type. | |
| 14643 RedirectingConstructorKind redirectingConstructorKind; | |
| 14644 if (_isTypeNameInCatchClause(node)) { | |
| 14645 reportErrorForNode(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, | |
| 14646 [typeName.name]); | |
| 14647 } else if (_isTypeNameInAsExpression(node)) { | |
| 14648 reportErrorForNode( | |
| 14649 StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]); | |
| 14650 } else if (_isTypeNameInIsExpression(node)) { | |
| 14651 reportErrorForNode(StaticWarningCode.TYPE_TEST_WITH_NON_TYPE, typeName, | |
| 14652 [typeName.name]); | |
| 14653 } else if ((redirectingConstructorKind = | |
| 14654 _getRedirectingConstructorKind(node)) != | |
| 14655 null) { | |
| 14656 ErrorCode errorCode = (redirectingConstructorKind == | |
| 14657 RedirectingConstructorKind.CONST | |
| 14658 ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS | |
| 14659 : StaticWarningCode.REDIRECT_TO_NON_CLASS); | |
| 14660 reportErrorForNode(errorCode, typeName, [typeName.name]); | |
| 14661 } else if (_isTypeNameInTypeArgumentList(node)) { | |
| 14662 reportErrorForNode(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, | |
| 14663 typeName, [typeName.name]); | |
| 14664 } else { | |
| 14665 AstNode parent = typeName.parent; | |
| 14666 while (parent is TypeName) { | |
| 14667 parent = parent.parent; | |
| 14668 } | |
| 14669 if (parent is ExtendsClause || | |
| 14670 parent is ImplementsClause || | |
| 14671 parent is WithClause || | |
| 14672 parent is ClassTypeAlias) { | |
| 14673 // Ignored. The error will be reported elsewhere. | |
| 14674 } else { | |
| 14675 reportErrorForNode( | |
| 14676 StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]); | |
| 14677 } | |
| 14678 } | |
| 14679 _setElement(typeName, _dynamicType.element); | |
| 14680 typeName.staticType = _dynamicType; | |
| 14681 node.type = _dynamicType; | |
| 14682 return null; | |
| 14683 } | |
| 14684 if (argumentList != null) { | |
| 14685 NodeList<TypeName> arguments = argumentList.arguments; | |
| 14686 int argumentCount = arguments.length; | |
| 14687 List<DartType> parameters = _getTypeArguments(type); | |
| 14688 int parameterCount = parameters.length; | |
| 14689 List<DartType> typeArguments = new List<DartType>(parameterCount); | |
| 14690 if (argumentCount == parameterCount) { | |
| 14691 for (int i = 0; i < parameterCount; i++) { | |
| 14692 TypeName argumentTypeName = arguments[i]; | |
| 14693 DartType argumentType = _getType(argumentTypeName); | |
| 14694 if (argumentType == null) { | |
| 14695 argumentType = _dynamicType; | |
| 14696 } | |
| 14697 typeArguments[i] = argumentType; | |
| 14698 } | |
| 14699 } else { | |
| 14700 reportErrorForNode(_getInvalidTypeParametersErrorCode(node), node, | |
| 14701 [typeName.name, parameterCount, argumentCount]); | |
| 14702 for (int i = 0; i < parameterCount; i++) { | |
| 14703 typeArguments[i] = _dynamicType; | |
| 14704 } | |
| 14705 } | |
| 14706 if (type is InterfaceTypeImpl) { | |
| 14707 InterfaceTypeImpl interfaceType = type as InterfaceTypeImpl; | |
| 14708 type = interfaceType.substitute4(typeArguments); | |
| 14709 } else if (type is FunctionTypeImpl) { | |
| 14710 FunctionTypeImpl functionType = type as FunctionTypeImpl; | |
| 14711 type = functionType.substitute3(typeArguments); | |
| 14712 } else { | |
| 14713 // TODO(brianwilkerson) Report this internal error. | |
| 14714 } | |
| 14715 } else { | |
| 14716 // | |
| 14717 // Check for the case where there are no type arguments given for a | |
| 14718 // parameterized type. | |
| 14719 // | |
| 14720 List<DartType> parameters = _getTypeArguments(type); | |
| 14721 int parameterCount = parameters.length; | |
| 14722 if (parameterCount > 0) { | |
| 14723 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance; | |
| 14724 List<DartType> arguments = new List<DartType>(parameterCount); | |
| 14725 for (int i = 0; i < parameterCount; i++) { | |
| 14726 arguments[i] = dynamicType; | |
| 14727 } | |
| 14728 type = type.substitute2(arguments, parameters); | |
| 14729 } | |
| 14730 } | |
| 14731 typeName.staticType = type; | |
| 14732 node.type = type; | |
| 14733 return null; | 10471 return null; |
| 14734 } | 10472 } |
| 14735 | 10473 |
| 14736 @override | 10474 @override |
| 14737 Object visitTypeParameter(TypeParameter node) { | 10475 Object visitTypeParameter(TypeParameter node) { |
| 14738 super.visitTypeParameter(node); | 10476 super.visitTypeParameter(node); |
| 14739 TypeName bound = node.bound; | 10477 AstNode parent2 = node.parent?.parent; |
| 14740 if (bound != null) { | 10478 if (parent2 is ClassDeclaration || |
| 14741 TypeParameterElementImpl typeParameter = | 10479 parent2 is ClassTypeAlias || |
| 14742 node.name.staticElement as TypeParameterElementImpl; | 10480 parent2 is FunctionTypeAlias) { |
| 14743 if (typeParameter != null) { | 10481 // Bounds of parameters of classes and function type aliases are |
| 14744 typeParameter.bound = bound.type; | 10482 // already resolved. |
| 10483 } else { |
| 10484 TypeName bound = node.bound; |
| 10485 if (bound != null) { |
| 10486 TypeParameterElementImpl typeParameter = |
| 10487 node.name.staticElement as TypeParameterElementImpl; |
| 10488 if (typeParameter != null) { |
| 10489 typeParameter.bound = bound.type; |
| 10490 } |
| 14745 } | 10491 } |
| 14746 } | 10492 } |
| 14747 return null; | 10493 return null; |
| 14748 } | 10494 } |
| 14749 | 10495 |
| 14750 @override | 10496 @override |
| 14751 Object visitVariableDeclaration(VariableDeclaration node) { | 10497 Object visitVariableDeclaration(VariableDeclaration node) { |
| 14752 super.visitVariableDeclaration(node); | 10498 super.visitVariableDeclaration(node); |
| 14753 DartType declaredType; | 10499 DartType declaredType; |
| 14754 TypeName typeName = (node.parent as VariableDeclarationList).type; | 10500 TypeName typeName = (node.parent as VariableDeclarationList).type; |
| 14755 if (typeName == null) { | 10501 if (typeName == null) { |
| 14756 declaredType = _dynamicType; | 10502 declaredType = _dynamicType; |
| 14757 } else { | 10503 } else { |
| 14758 declaredType = _getType(typeName); | 10504 declaredType = _typeNameResolver._getType(typeName); |
| 14759 } | 10505 } |
| 14760 Element element = node.name.staticElement; | 10506 Element element = node.name.staticElement; |
| 14761 if (element is VariableElement) { | 10507 if (element is VariableElementImpl) { |
| 14762 (element as VariableElementImpl).type = declaredType; | 10508 element.type = declaredType; |
| 14763 if (element is PropertyInducingElement) { | |
| 14764 PropertyInducingElement variableElement = element; | |
| 14765 PropertyAccessorElementImpl getter = | |
| 14766 variableElement.getter as PropertyAccessorElementImpl; | |
| 14767 getter.returnType = declaredType; | |
| 14768 FunctionTypeImpl getterType = new FunctionTypeImpl(getter); | |
| 14769 ClassElement definingClass = | |
| 14770 element.getAncestor((element) => element is ClassElement); | |
| 14771 if (definingClass != null) { | |
| 14772 getterType.typeArguments = definingClass.type.typeArguments; | |
| 14773 } | |
| 14774 getter.type = getterType; | |
| 14775 PropertyAccessorElementImpl setter = | |
| 14776 variableElement.setter as PropertyAccessorElementImpl; | |
| 14777 if (setter != null) { | |
| 14778 List<ParameterElement> parameters = setter.parameters; | |
| 14779 if (parameters.length > 0) { | |
| 14780 (parameters[0] as ParameterElementImpl).type = declaredType; | |
| 14781 } | |
| 14782 setter.returnType = VoidTypeImpl.instance; | |
| 14783 FunctionTypeImpl setterType = new FunctionTypeImpl(setter); | |
| 14784 if (definingClass != null) { | |
| 14785 setterType.typeArguments = definingClass.type.typeArguments; | |
| 14786 } | |
| 14787 setter.type = setterType; | |
| 14788 } | |
| 14789 } | |
| 14790 } else { | |
| 14791 // TODO(brianwilkerson) Report the internal error. | |
| 14792 } | 10509 } |
| 14793 return null; | 10510 return null; |
| 14794 } | 10511 } |
| 14795 | 10512 |
| 14796 /** | 10513 /** |
| 14797 * Given a type name representing the return type of a function, compute the r
eturn type of the | 10514 * Given a type name representing the return type of a function, compute the r
eturn type of the |
| 14798 * function. | 10515 * function. |
| 14799 * | 10516 * |
| 14800 * @param returnType the type name representing the return type of the functio
n | 10517 * @param returnType the type name representing the return type of the functio
n |
| 14801 * @return the return type that was computed | 10518 * @return the return type that was computed |
| (...skipping 15 matching lines...) Expand all Loading... |
| 14817 ClassElementImpl _getClassElement(SimpleIdentifier identifier) { | 10534 ClassElementImpl _getClassElement(SimpleIdentifier identifier) { |
| 14818 // TODO(brianwilkerson) Seems like we should be using | 10535 // TODO(brianwilkerson) Seems like we should be using |
| 14819 // ClassDeclaration.getElement(). | 10536 // ClassDeclaration.getElement(). |
| 14820 if (identifier == null) { | 10537 if (identifier == null) { |
| 14821 // TODO(brianwilkerson) Report this | 10538 // TODO(brianwilkerson) Report this |
| 14822 // Internal error: We should never build a class declaration without a | 10539 // Internal error: We should never build a class declaration without a |
| 14823 // name. | 10540 // name. |
| 14824 return null; | 10541 return null; |
| 14825 } | 10542 } |
| 14826 Element element = identifier.staticElement; | 10543 Element element = identifier.staticElement; |
| 14827 if (element is! ClassElementImpl) { | 10544 if (element is ClassElementImpl) { |
| 14828 // TODO(brianwilkerson) Report this | 10545 return element; |
| 14829 // Internal error: Failed to create an element for a class declaration. | 10546 } |
| 14830 return null; | 10547 // TODO(brianwilkerson) Report this |
| 14831 } | 10548 // Internal error: Failed to create an element for a class declaration. |
| 14832 return element as ClassElementImpl; | 10549 return null; |
| 14833 } | 10550 } |
| 14834 | 10551 |
| 14835 /** | 10552 /** |
| 14836 * Return an array containing all of the elements associated with the paramete
rs in the given | 10553 * Return an array containing all of the elements associated with the paramete
rs in the given |
| 14837 * list. | 10554 * list. |
| 14838 * | 10555 * |
| 14839 * @param parameterList the list of parameters whose elements are to be return
ed | 10556 * @param parameterList the list of parameters whose elements are to be return
ed |
| 14840 * @return the elements associated with the parameters | 10557 * @return the elements associated with the parameters |
| 14841 */ | 10558 */ |
| 14842 List<ParameterElement> _getElements(FormalParameterList parameterList) { | 10559 List<ParameterElement> _getElements(FormalParameterList parameterList) { |
| 14843 List<ParameterElement> elements = new List<ParameterElement>(); | 10560 List<ParameterElement> elements = new List<ParameterElement>(); |
| 14844 for (FormalParameter parameter in parameterList.parameters) { | 10561 for (FormalParameter parameter in parameterList.parameters) { |
| 14845 ParameterElement element = | 10562 ParameterElement element = |
| 14846 parameter.identifier.staticElement as ParameterElement; | 10563 parameter.identifier.staticElement as ParameterElement; |
| 14847 // TODO(brianwilkerson) Understand why the element would be null. | 10564 // TODO(brianwilkerson) Understand why the element would be null. |
| 14848 if (element != null) { | 10565 if (element != null) { |
| 14849 elements.add(element); | 10566 elements.add(element); |
| 14850 } | 10567 } |
| 14851 } | 10568 } |
| 14852 return elements; | 10569 return elements; |
| 14853 } | 10570 } |
| 14854 | 10571 |
| 14855 /** | 10572 /** |
| 14856 * The number of type arguments in the given type name does not match the numb
er of parameters in | 10573 * In strong mode we infer "void" as the setter return type (as void is the |
| 14857 * the corresponding class element. Return the error code that should be used
to report this | 10574 * only legal return type for a setter). This allows us to give better |
| 14858 * error. | 10575 * errors later if an invalid type is returned. |
| 14859 * | 10576 */ |
| 14860 * @param node the type name with the wrong number of type arguments | 10577 void _inferSetterReturnType(ExecutableElementImpl element) { |
| 14861 * @return the error code that should be used to report that the wrong number
of type arguments | 10578 if (_strongMode && |
| 14862 * were provided | 10579 element is PropertyAccessorElementImpl && |
| 14863 */ | 10580 element.isSetter && |
| 14864 ErrorCode _getInvalidTypeParametersErrorCode(TypeName node) { | 10581 element.hasImplicitReturnType) { |
| 14865 AstNode parent = node.parent; | 10582 element.returnType = VoidTypeImpl.instance; |
| 14866 if (parent is ConstructorName) { | 10583 } |
| 14867 parent = parent.parent; | 10584 } |
| 14868 if (parent is InstanceCreationExpression) { | |
| 14869 if (parent.isConst) { | |
| 14870 return CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS; | |
| 14871 } else { | |
| 14872 return StaticWarningCode.NEW_WITH_INVALID_TYPE_PARAMETERS; | |
| 14873 } | |
| 14874 } | |
| 14875 } | |
| 14876 return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS; | |
| 14877 } | |
| 14878 | |
| 14879 /** | |
| 14880 * Checks if the given type name is the target in a redirected constructor. | |
| 14881 * | |
| 14882 * @param typeName the type name to analyze | |
| 14883 * @return some [RedirectingConstructorKind] if the given type name is used as
the type in a | |
| 14884 * redirected constructor, or `null` otherwise | |
| 14885 */ | |
| 14886 RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) { | |
| 14887 AstNode parent = typeName.parent; | |
| 14888 if (parent is ConstructorName) { | |
| 14889 ConstructorName constructorName = parent as ConstructorName; | |
| 14890 parent = constructorName.parent; | |
| 14891 if (parent is ConstructorDeclaration) { | |
| 14892 if (identical(parent.redirectedConstructor, constructorName)) { | |
| 14893 if (parent.constKeyword != null) { | |
| 14894 return RedirectingConstructorKind.CONST; | |
| 14895 } | |
| 14896 return RedirectingConstructorKind.NORMAL; | |
| 14897 } | |
| 14898 } | |
| 14899 } | |
| 14900 return null; | |
| 14901 } | |
| 14902 | |
| 14903 /** | |
| 14904 * Return the type represented by the given type name. | |
| 14905 * | |
| 14906 * @param typeName the type name representing the type to be returned | |
| 14907 * @return the type represented by the type name | |
| 14908 */ | |
| 14909 DartType _getType(TypeName typeName) { | |
| 14910 DartType type = typeName.type; | |
| 14911 if (type == null) { | |
| 14912 return _undefinedType; | |
| 14913 } | |
| 14914 return type; | |
| 14915 } | |
| 14916 | |
| 14917 /** | |
| 14918 * Return the type arguments associated with the given type. | |
| 14919 * | |
| 14920 * @param type the type whole type arguments are to be returned | |
| 14921 * @return the type arguments associated with the given type | |
| 14922 */ | |
| 14923 List<DartType> _getTypeArguments(DartType type) { | |
| 14924 if (type is InterfaceType) { | |
| 14925 return type.typeArguments; | |
| 14926 } else if (type is FunctionType) { | |
| 14927 return type.typeArguments; | |
| 14928 } | |
| 14929 return DartType.EMPTY_LIST; | |
| 14930 } | |
| 14931 | |
| 14932 /** | |
| 14933 * Returns the simple identifier of the given (may be qualified) type name. | |
| 14934 * | |
| 14935 * @param typeName the (may be qualified) qualified type name | |
| 14936 * @return the simple identifier of the given (may be qualified) type name. | |
| 14937 */ | |
| 14938 SimpleIdentifier _getTypeSimpleIdentifier(Identifier typeName) { | |
| 14939 if (typeName is SimpleIdentifier) { | |
| 14940 return typeName; | |
| 14941 } else { | |
| 14942 return (typeName as PrefixedIdentifier).identifier; | |
| 14943 } | |
| 14944 } | |
| 14945 | |
| 14946 /** | |
| 14947 * Given the multiple elements to which a single name could potentially be res
olved, return the | |
| 14948 * single interface type that should be used, or `null` if there is no clear c
hoice. | |
| 14949 * | |
| 14950 * @param elements the elements to which a single name could potentially be re
solved | |
| 14951 * @return the single interface type that should be used for the type name | |
| 14952 */ | |
| 14953 InterfaceType _getTypeWhenMultiplyDefined(List<Element> elements) { | |
| 14954 InterfaceType type = null; | |
| 14955 for (Element element in elements) { | |
| 14956 if (element is ClassElement) { | |
| 14957 if (type != null) { | |
| 14958 return null; | |
| 14959 } | |
| 14960 type = element.type; | |
| 14961 } | |
| 14962 } | |
| 14963 return type; | |
| 14964 } | |
| 14965 | |
| 14966 /** | |
| 14967 * Checks if the given type name is used as the type in an as expression. | |
| 14968 * | |
| 14969 * @param typeName the type name to analyzer | |
| 14970 * @return `true` if the given type name is used as the type in an as expressi
on | |
| 14971 */ | |
| 14972 bool _isTypeNameInAsExpression(TypeName typeName) { | |
| 14973 AstNode parent = typeName.parent; | |
| 14974 if (parent is AsExpression) { | |
| 14975 AsExpression asExpression = parent; | |
| 14976 return identical(asExpression.type, typeName); | |
| 14977 } | |
| 14978 return false; | |
| 14979 } | |
| 14980 | |
| 14981 /** | |
| 14982 * Checks if the given type name is used as the exception type in a catch clau
se. | |
| 14983 * | |
| 14984 * @param typeName the type name to analyzer | |
| 14985 * @return `true` if the given type name is used as the exception type in a ca
tch clause | |
| 14986 */ | |
| 14987 bool _isTypeNameInCatchClause(TypeName typeName) { | |
| 14988 AstNode parent = typeName.parent; | |
| 14989 if (parent is CatchClause) { | |
| 14990 CatchClause catchClause = parent; | |
| 14991 return identical(catchClause.exceptionType, typeName); | |
| 14992 } | |
| 14993 return false; | |
| 14994 } | |
| 14995 | |
| 14996 /** | |
| 14997 * Checks if the given type name is used as the type in an instance creation e
xpression. | |
| 14998 * | |
| 14999 * @param typeName the type name to analyzer | |
| 15000 * @return `true` if the given type name is used as the type in an instance cr
eation | |
| 15001 * expression | |
| 15002 */ | |
| 15003 bool _isTypeNameInInstanceCreationExpression(TypeName typeName) { | |
| 15004 AstNode parent = typeName.parent; | |
| 15005 if (parent is ConstructorName && | |
| 15006 parent.parent is InstanceCreationExpression) { | |
| 15007 ConstructorName constructorName = parent; | |
| 15008 return constructorName != null && | |
| 15009 identical(constructorName.type, typeName); | |
| 15010 } | |
| 15011 return false; | |
| 15012 } | |
| 15013 | |
| 15014 /** | |
| 15015 * Checks if the given type name is used as the type in an is expression. | |
| 15016 * | |
| 15017 * @param typeName the type name to analyzer | |
| 15018 * @return `true` if the given type name is used as the type in an is expressi
on | |
| 15019 */ | |
| 15020 bool _isTypeNameInIsExpression(TypeName typeName) { | |
| 15021 AstNode parent = typeName.parent; | |
| 15022 if (parent is IsExpression) { | |
| 15023 IsExpression isExpression = parent; | |
| 15024 return identical(isExpression.type, typeName); | |
| 15025 } | |
| 15026 return false; | |
| 15027 } | |
| 15028 | |
| 15029 /** | |
| 15030 * Checks if the given type name used in a type argument list. | |
| 15031 * | |
| 15032 * @param typeName the type name to analyzer | |
| 15033 * @return `true` if the given type name is in a type argument list | |
| 15034 */ | |
| 15035 bool _isTypeNameInTypeArgumentList(TypeName typeName) => | |
| 15036 typeName.parent is TypeArgumentList; | |
| 15037 | 10585 |
| 15038 /** | 10586 /** |
| 15039 * Record that the static type of the given node is the given type. | 10587 * Record that the static type of the given node is the given type. |
| 15040 * | 10588 * |
| 15041 * @param expression the node whose type is to be recorded | 10589 * @param expression the node whose type is to be recorded |
| 15042 * @param type the static type of the node | 10590 * @param type the static type of the node |
| 15043 */ | 10591 */ |
| 15044 Object _recordType(Expression expression, DartType type) { | 10592 Object _recordType(Expression expression, DartType type) { |
| 15045 if (type == null) { | 10593 if (type == null) { |
| 15046 expression.staticType = _dynamicType; | 10594 expression.staticType = _dynamicType; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 15062 void _resolve(ClassElementImpl classElement, WithClause withClause, | 10610 void _resolve(ClassElementImpl classElement, WithClause withClause, |
| 15063 ImplementsClause implementsClause) { | 10611 ImplementsClause implementsClause) { |
| 15064 if (withClause != null) { | 10612 if (withClause != null) { |
| 15065 List<InterfaceType> mixinTypes = _resolveTypes( | 10613 List<InterfaceType> mixinTypes = _resolveTypes( |
| 15066 withClause.mixinTypes, | 10614 withClause.mixinTypes, |
| 15067 CompileTimeErrorCode.MIXIN_OF_NON_CLASS, | 10615 CompileTimeErrorCode.MIXIN_OF_NON_CLASS, |
| 15068 CompileTimeErrorCode.MIXIN_OF_ENUM, | 10616 CompileTimeErrorCode.MIXIN_OF_ENUM, |
| 15069 CompileTimeErrorCode.MIXIN_OF_NON_CLASS); | 10617 CompileTimeErrorCode.MIXIN_OF_NON_CLASS); |
| 15070 if (classElement != null) { | 10618 if (classElement != null) { |
| 15071 classElement.mixins = mixinTypes; | 10619 classElement.mixins = mixinTypes; |
| 15072 classElement.withClauseRange = | |
| 15073 new SourceRange(withClause.offset, withClause.length); | |
| 15074 } | 10620 } |
| 15075 } | 10621 } |
| 15076 if (implementsClause != null) { | 10622 if (implementsClause != null) { |
| 15077 NodeList<TypeName> interfaces = implementsClause.interfaces; | 10623 NodeList<TypeName> interfaces = implementsClause.interfaces; |
| 15078 List<InterfaceType> interfaceTypes = _resolveTypes( | 10624 List<InterfaceType> interfaceTypes = _resolveTypes( |
| 15079 interfaces, | 10625 interfaces, |
| 15080 CompileTimeErrorCode.IMPLEMENTS_NON_CLASS, | 10626 CompileTimeErrorCode.IMPLEMENTS_NON_CLASS, |
| 15081 CompileTimeErrorCode.IMPLEMENTS_ENUM, | 10627 CompileTimeErrorCode.IMPLEMENTS_ENUM, |
| 15082 CompileTimeErrorCode.IMPLEMENTS_DYNAMIC); | 10628 CompileTimeErrorCode.IMPLEMENTS_DYNAMIC); |
| 15083 if (classElement != null) { | 10629 if (classElement != null) { |
| 15084 classElement.interfaces = interfaceTypes; | 10630 classElement.interfaces = interfaceTypes; |
| 15085 } | 10631 } |
| 15086 // TODO(brianwilkerson) Move the following checks to ErrorVerifier. | 10632 // TODO(brianwilkerson) Move the following checks to ErrorVerifier. |
| 15087 int count = interfaces.length; | 10633 int count = interfaces.length; |
| 15088 List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false); | 10634 List<bool> detectedRepeatOnIndex = new List<bool>.filled(count, false); |
| 15089 for (int i = 0; i < detectedRepeatOnIndex.length; i++) { | 10635 for (int i = 0; i < detectedRepeatOnIndex.length; i++) { |
| 15090 detectedRepeatOnIndex[i] = false; | 10636 detectedRepeatOnIndex[i] = false; |
| 15091 } | 10637 } |
| 15092 for (int i = 0; i < count; i++) { | 10638 for (int i = 0; i < count; i++) { |
| 15093 TypeName typeName = interfaces[i]; | 10639 TypeName typeName = interfaces[i]; |
| 15094 if (!detectedRepeatOnIndex[i]) { | 10640 if (!detectedRepeatOnIndex[i]) { |
| 15095 Element element = typeName.name.staticElement; | 10641 Element element = typeName.name.staticElement; |
| 15096 for (int j = i + 1; j < count; j++) { | 10642 for (int j = i + 1; j < count; j++) { |
| 15097 TypeName typeName2 = interfaces[j]; | 10643 TypeName typeName2 = interfaces[j]; |
| 15098 Identifier identifier2 = typeName2.name; | 10644 Identifier identifier2 = typeName2.name; |
| 15099 String name2 = identifier2.name; | 10645 String name2 = identifier2.name; |
| 15100 Element element2 = identifier2.staticElement; | 10646 Element element2 = identifier2.staticElement; |
| 15101 if (element != null && element == element2) { | 10647 if (element != null && element == element2) { |
| 15102 detectedRepeatOnIndex[j] = true; | 10648 detectedRepeatOnIndex[j] = true; |
| 15103 reportErrorForNode( | 10649 errorReporter.reportErrorForNode( |
| 15104 CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]); | 10650 CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]); |
| 15105 } | 10651 } |
| 15106 } | 10652 } |
| 15107 } | 10653 } |
| 15108 } | 10654 } |
| 15109 } | 10655 } |
| 15110 } | 10656 } |
| 15111 | 10657 |
| 15112 /** | 10658 /** |
| 15113 * Return the type specified by the given name. | 10659 * Return the type specified by the given name. |
| 15114 * | 10660 * |
| 15115 * @param typeName the type name specifying the type to be returned | 10661 * @param typeName the type name specifying the type to be returned |
| 15116 * @param nonTypeError the error to produce if the type name is defined to be
something other than | 10662 * @param nonTypeError the error to produce if the type name is defined to be
something other than |
| 15117 * a type | 10663 * a type |
| 15118 * @param enumTypeError the error to produce if the type name is defined to be
an enum | 10664 * @param enumTypeError the error to produce if the type name is defined to be
an enum |
| 15119 * @param dynamicTypeError the error to produce if the type name is "dynamic" | 10665 * @param dynamicTypeError the error to produce if the type name is "dynamic" |
| 15120 * @return the type specified by the type name | 10666 * @return the type specified by the type name |
| 15121 */ | 10667 */ |
| 15122 InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError, | 10668 InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError, |
| 15123 ErrorCode enumTypeError, ErrorCode dynamicTypeError) { | 10669 ErrorCode enumTypeError, ErrorCode dynamicTypeError) { |
| 15124 DartType type = typeName.type; | 10670 DartType type = typeName.type; |
| 15125 if (type is InterfaceType) { | 10671 if (type is InterfaceType) { |
| 15126 ClassElement element = type.element; | 10672 ClassElement element = type.element; |
| 15127 if (element != null && element.isEnum) { | 10673 if (element != null && element.isEnum) { |
| 15128 reportErrorForNode(enumTypeError, typeName); | 10674 errorReporter.reportErrorForNode(enumTypeError, typeName); |
| 15129 return null; | 10675 return null; |
| 15130 } | 10676 } |
| 15131 return type; | 10677 return type; |
| 15132 } | 10678 } |
| 15133 // If the type is not an InterfaceType, then visitTypeName() sets the type | 10679 // If the type is not an InterfaceType, then visitTypeName() sets the type |
| 15134 // to be a DynamicTypeImpl | 10680 // to be a DynamicTypeImpl |
| 15135 Identifier name = typeName.name; | 10681 Identifier name = typeName.name; |
| 15136 if (name.name == sc.Keyword.DYNAMIC.syntax) { | 10682 if (name.name == Keyword.DYNAMIC.syntax) { |
| 15137 reportErrorForNode(dynamicTypeError, name, [name.name]); | 10683 errorReporter.reportErrorForNode(dynamicTypeError, name, [name.name]); |
| 15138 } else { | 10684 } else if (!nameScope.shouldIgnoreUndefined(name)) { |
| 15139 reportErrorForNode(nonTypeError, name, [name.name]); | 10685 errorReporter.reportErrorForNode(nonTypeError, name, [name.name]); |
| 15140 } | 10686 } |
| 15141 return null; | 10687 return null; |
| 15142 } | 10688 } |
| 15143 | 10689 |
| 15144 /** | 10690 /** |
| 15145 * Resolve the types in the given list of type names. | 10691 * Resolve the types in the given list of type names. |
| 15146 * | 10692 * |
| 15147 * @param typeNames the type names to be resolved | 10693 * @param typeNames the type names to be resolved |
| 15148 * @param nonTypeError the error to produce if the type name is defined to be
something other than | 10694 * @param nonTypeError the error to produce if the type name is defined to be
something other than |
| 15149 * a type | 10695 * a type |
| (...skipping 10 matching lines...) Expand all Loading... |
| 15160 for (TypeName typeName in typeNames) { | 10706 for (TypeName typeName in typeNames) { |
| 15161 InterfaceType type = | 10707 InterfaceType type = |
| 15162 _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError); | 10708 _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError); |
| 15163 if (type != null) { | 10709 if (type != null) { |
| 15164 types.add(type); | 10710 types.add(type); |
| 15165 } | 10711 } |
| 15166 } | 10712 } |
| 15167 return types; | 10713 return types; |
| 15168 } | 10714 } |
| 15169 | 10715 |
| 15170 void _setElement(Identifier typeName, Element element) { | |
| 15171 if (element != null) { | |
| 15172 if (typeName is SimpleIdentifier) { | |
| 15173 typeName.staticElement = element; | |
| 15174 } else if (typeName is PrefixedIdentifier) { | |
| 15175 PrefixedIdentifier identifier = typeName; | |
| 15176 identifier.identifier.staticElement = element; | |
| 15177 SimpleIdentifier prefix = identifier.prefix; | |
| 15178 Element prefixElement = nameScope.lookup(prefix, definingLibrary); | |
| 15179 if (prefixElement != null) { | |
| 15180 prefix.staticElement = prefixElement; | |
| 15181 } | |
| 15182 } | |
| 15183 } | |
| 15184 } | |
| 15185 | |
| 15186 /** | 10716 /** |
| 15187 * Given a parameter element, create a function type based on the given return
type and parameter | 10717 * Given a parameter element, create a function type based on the given return
type and parameter |
| 15188 * list and associate the created type with the element. | 10718 * list and associate the created type with the element. |
| 15189 * | 10719 * |
| 15190 * @param element the parameter element whose type is to be set | 10720 * @param element the parameter element whose type is to be set |
| 15191 * @param returnType the (possibly `null`) return type of the function | 10721 * @param returnType the (possibly `null`) return type of the function |
| 15192 * @param parameterList the list of parameters to the function | 10722 * @param parameterList the list of parameters to the function |
| 15193 */ | 10723 */ |
| 15194 void _setFunctionTypedParameterType(ParameterElementImpl element, | 10724 void _setFunctionTypedParameterType(ParameterElementImpl element, |
| 15195 TypeName returnType, FormalParameterList parameterList) { | 10725 TypeName returnType, FormalParameterList parameterList) { |
| 15196 List<ParameterElement> parameters = _getElements(parameterList); | 10726 List<ParameterElement> parameters = _getElements(parameterList); |
| 15197 FunctionTypeAliasElementImpl aliasElement = | 10727 FunctionElementImpl functionElement = new FunctionElementImpl.forNode(null); |
| 15198 new FunctionTypeAliasElementImpl.forNode(null); | 10728 functionElement.synthetic = true; |
| 15199 aliasElement.synthetic = true; | 10729 functionElement.shareParameters(parameters); |
| 15200 aliasElement.shareParameters(parameters); | 10730 functionElement.returnType = _computeReturnType(returnType); |
| 15201 aliasElement.returnType = _computeReturnType(returnType); | 10731 functionElement.enclosingElement = element; |
| 15202 // FunctionTypeAliasElementImpl assumes the enclosing element is a | 10732 functionElement.shareTypeParameters(element.typeParameters); |
| 15203 // CompilationUnitElement (because non-synthetic function types can only be | 10733 element.type = new FunctionTypeImpl(functionElement); |
| 15204 // declared at top level), so to avoid breaking things, go find the | 10734 functionElement.type = element.type; |
| 15205 // compilation unit element. | |
| 15206 aliasElement.enclosingElement = | |
| 15207 element.getAncestor((element) => element is CompilationUnitElement); | |
| 15208 FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(aliasElement); | |
| 15209 ClassElement definingClass = | |
| 15210 element.getAncestor((element) => element is ClassElement); | |
| 15211 if (definingClass != null) { | |
| 15212 aliasElement.shareTypeParameters(definingClass.typeParameters); | |
| 15213 type.typeArguments = definingClass.type.typeArguments; | |
| 15214 } else { | |
| 15215 FunctionTypeAliasElement alias = | |
| 15216 element.getAncestor((element) => element is FunctionTypeAliasElement); | |
| 15217 while (alias != null && alias.isSynthetic) { | |
| 15218 alias = | |
| 15219 alias.getAncestor((element) => element is FunctionTypeAliasElement); | |
| 15220 } | |
| 15221 if (alias != null) { | |
| 15222 aliasElement.typeParameters = alias.typeParameters; | |
| 15223 type.typeArguments = alias.type.typeArguments; | |
| 15224 } else { | |
| 15225 type.typeArguments = DartType.EMPTY_LIST; | |
| 15226 } | |
| 15227 } | |
| 15228 element.type = type; | |
| 15229 } | |
| 15230 | |
| 15231 /** | |
| 15232 * @return `true` if the name of the given [TypeName] is an built-in identifie
r. | |
| 15233 */ | |
| 15234 static bool _isBuiltInIdentifier(TypeName node) { | |
| 15235 sc.Token token = node.name.beginToken; | |
| 15236 return token.type == sc.TokenType.KEYWORD; | |
| 15237 } | |
| 15238 | |
| 15239 /** | |
| 15240 * @return `true` if given [TypeName] is used as a type annotation. | |
| 15241 */ | |
| 15242 static bool _isTypeAnnotation(TypeName node) { | |
| 15243 AstNode parent = node.parent; | |
| 15244 if (parent is VariableDeclarationList) { | |
| 15245 return identical(parent.type, node); | |
| 15246 } | |
| 15247 if (parent is FieldFormalParameter) { | |
| 15248 return identical(parent.type, node); | |
| 15249 } | |
| 15250 if (parent is SimpleFormalParameter) { | |
| 15251 return identical(parent.type, node); | |
| 15252 } | |
| 15253 return false; | |
| 15254 } | 10735 } |
| 15255 } | 10736 } |
| 15256 | 10737 |
| 15257 /** | |
| 15258 * The interface `TypeSystem` defines the behavior of an object representing | |
| 15259 * the type system. This provides a common location to put methods that act on | |
| 15260 * types but may need access to more global data structures, and it paves the | |
| 15261 * way for a possible future where we may wish to make the type system | |
| 15262 * pluggable. | |
| 15263 */ | |
| 15264 abstract class TypeSystem { | |
| 15265 /** | |
| 15266 * Compute the least upper bound of two types. | |
| 15267 */ | |
| 15268 DartType getLeastUpperBound( | |
| 15269 TypeProvider typeProvider, DartType type1, DartType type2); | |
| 15270 | |
| 15271 /** | |
| 15272 * Return `true` if the [leftType] is assignable to the [rightType] (that is, | |
| 15273 * if leftType <==> rightType). | |
| 15274 */ | |
| 15275 bool isAssignableTo(DartType leftType, DartType rightType); | |
| 15276 | |
| 15277 /** | |
| 15278 * Return `true` if the [leftType] is a subtype of the [rightType] (that is, | |
| 15279 * if leftType <: rightType). | |
| 15280 */ | |
| 15281 bool isSubtypeOf(DartType leftType, DartType rightType); | |
| 15282 | |
| 15283 /** | |
| 15284 * Create either a strong mode or regular type system based on context. | |
| 15285 */ | |
| 15286 static TypeSystem create(AnalysisContext context) { | |
| 15287 return (context.analysisOptions.strongMode) | |
| 15288 ? new StrongTypeSystemImpl() | |
| 15289 : new TypeSystemImpl(); | |
| 15290 } | |
| 15291 } | |
| 15292 | |
| 15293 /** | |
| 15294 * Implementation of [TypeSystem] using the rules in the Dart specification. | |
| 15295 */ | |
| 15296 class TypeSystemImpl implements TypeSystem { | |
| 15297 TypeSystemImpl(); | |
| 15298 | |
| 15299 @override | |
| 15300 DartType getLeastUpperBound( | |
| 15301 TypeProvider typeProvider, DartType type1, DartType type2) { | |
| 15302 // The least upper bound relation is reflexive. | |
| 15303 if (identical(type1, type2)) { | |
| 15304 return type1; | |
| 15305 } | |
| 15306 // The least upper bound of dynamic and any type T is dynamic. | |
| 15307 if (type1.isDynamic) { | |
| 15308 return type1; | |
| 15309 } | |
| 15310 if (type2.isDynamic) { | |
| 15311 return type2; | |
| 15312 } | |
| 15313 // The least upper bound of void and any type T != dynamic is void. | |
| 15314 if (type1.isVoid) { | |
| 15315 return type1; | |
| 15316 } | |
| 15317 if (type2.isVoid) { | |
| 15318 return type2; | |
| 15319 } | |
| 15320 // The least upper bound of bottom and any type T is T. | |
| 15321 if (type1.isBottom) { | |
| 15322 return type2; | |
| 15323 } | |
| 15324 if (type2.isBottom) { | |
| 15325 return type1; | |
| 15326 } | |
| 15327 // Let U be a type variable with upper bound B. The least upper bound of U | |
| 15328 // and a type T is the least upper bound of B and T. | |
| 15329 while (type1 is TypeParameterType) { | |
| 15330 // TODO(paulberry): is this correct in the complex of F-bounded | |
| 15331 // polymorphism? | |
| 15332 DartType bound = (type1 as TypeParameterType).element.bound; | |
| 15333 if (bound == null) { | |
| 15334 bound = typeProvider.objectType; | |
| 15335 } | |
| 15336 type1 = bound; | |
| 15337 } | |
| 15338 while (type2 is TypeParameterType) { | |
| 15339 // TODO(paulberry): is this correct in the context of F-bounded | |
| 15340 // polymorphism? | |
| 15341 DartType bound = (type2 as TypeParameterType).element.bound; | |
| 15342 if (bound == null) { | |
| 15343 bound = typeProvider.objectType; | |
| 15344 } | |
| 15345 type2 = bound; | |
| 15346 } | |
| 15347 // The least upper bound of a function type and an interface type T is the | |
| 15348 // least upper bound of Function and T. | |
| 15349 if (type1 is FunctionType && type2 is InterfaceType) { | |
| 15350 type1 = typeProvider.functionType; | |
| 15351 } | |
| 15352 if (type2 is FunctionType && type1 is InterfaceType) { | |
| 15353 type2 = typeProvider.functionType; | |
| 15354 } | |
| 15355 | |
| 15356 // At this point type1 and type2 should both either be interface types or | |
| 15357 // function types. | |
| 15358 if (type1 is InterfaceType && type2 is InterfaceType) { | |
| 15359 InterfaceType result = | |
| 15360 InterfaceTypeImpl.computeLeastUpperBound(type1, type2); | |
| 15361 if (result == null) { | |
| 15362 return typeProvider.dynamicType; | |
| 15363 } | |
| 15364 return result; | |
| 15365 } else if (type1 is FunctionType && type2 is FunctionType) { | |
| 15366 FunctionType result = | |
| 15367 FunctionTypeImpl.computeLeastUpperBound(type1, type2); | |
| 15368 if (result == null) { | |
| 15369 return typeProvider.functionType; | |
| 15370 } | |
| 15371 return result; | |
| 15372 } else { | |
| 15373 // Should never happen. As a defensive measure, return the dynamic type. | |
| 15374 assert(false); | |
| 15375 return typeProvider.dynamicType; | |
| 15376 } | |
| 15377 } | |
| 15378 | |
| 15379 @override | |
| 15380 bool isAssignableTo(DartType leftType, DartType rightType) { | |
| 15381 return leftType.isAssignableTo(rightType); | |
| 15382 } | |
| 15383 | |
| 15384 @override | |
| 15385 bool isSubtypeOf(DartType leftType, DartType rightType) { | |
| 15386 return leftType.isSubtypeOf(rightType); | |
| 15387 } | |
| 15388 } | |
| 15389 | |
| 15390 /** | 10738 /** |
| 15391 * Instances of the class [UnusedLocalElementsVerifier] traverse an element | 10739 * Instances of the class [UnusedLocalElementsVerifier] traverse an element |
| 15392 * structure looking for cases of [HintCode.UNUSED_ELEMENT], | 10740 * structure looking for cases of [HintCode.UNUSED_ELEMENT], |
| 15393 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc. | 10741 * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc. |
| 15394 */ | 10742 */ |
| 15395 class UnusedLocalElementsVerifier extends RecursiveElementVisitor { | 10743 class UnusedLocalElementsVerifier extends RecursiveElementVisitor { |
| 15396 /** | 10744 /** |
| 15397 * The error listener to which errors will be reported. | 10745 * The error listener to which errors will be reported. |
| 15398 */ | 10746 */ |
| 15399 final AnalysisErrorListener _errorListener; | 10747 final AnalysisErrorListener _errorListener; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 15537 } | 10885 } |
| 15538 } | 10886 } |
| 15539 } | 10887 } |
| 15540 | 10888 |
| 15541 /** | 10889 /** |
| 15542 * A container with information about used imports prefixes and used imported | 10890 * A container with information about used imports prefixes and used imported |
| 15543 * elements. | 10891 * elements. |
| 15544 */ | 10892 */ |
| 15545 class UsedImportedElements { | 10893 class UsedImportedElements { |
| 15546 /** | 10894 /** |
| 15547 * The set of referenced [PrefixElement]s. | 10895 * The map of referenced [PrefixElement]s and the [Element]s that they prefix. |
| 15548 */ | 10896 */ |
| 15549 final Set<PrefixElement> prefixes = new HashSet<PrefixElement>(); | 10897 final Map<PrefixElement, List<Element>> prefixMap = |
| 10898 new HashMap<PrefixElement, List<Element>>(); |
| 15550 | 10899 |
| 15551 /** | 10900 /** |
| 15552 * The set of referenced top-level [Element]s. | 10901 * The set of referenced top-level [Element]s. |
| 15553 */ | 10902 */ |
| 15554 final Set<Element> elements = new HashSet<Element>(); | 10903 final Set<Element> elements = new HashSet<Element>(); |
| 15555 } | 10904 } |
| 15556 | 10905 |
| 15557 /** | 10906 /** |
| 15558 * A container with sets of used [Element]s. | 10907 * A container with sets of used [Element]s. |
| 15559 * All these elements are defined in a single compilation unit or a library. | 10908 * All these elements are defined in a single compilation unit or a library. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 15586 /** | 10935 /** |
| 15587 * Names of resolved or unresolved class members that are read in the | 10936 * Names of resolved or unresolved class members that are read in the |
| 15588 * library. | 10937 * library. |
| 15589 */ | 10938 */ |
| 15590 final HashSet<String> readMembers = new HashSet<String>(); | 10939 final HashSet<String> readMembers = new HashSet<String>(); |
| 15591 | 10940 |
| 15592 UsedLocalElements(); | 10941 UsedLocalElements(); |
| 15593 | 10942 |
| 15594 factory UsedLocalElements.merge(List<UsedLocalElements> parts) { | 10943 factory UsedLocalElements.merge(List<UsedLocalElements> parts) { |
| 15595 UsedLocalElements result = new UsedLocalElements(); | 10944 UsedLocalElements result = new UsedLocalElements(); |
| 15596 for (UsedLocalElements part in parts) { | 10945 int length = parts.length; |
| 10946 for (int i = 0; i < length; i++) { |
| 10947 UsedLocalElements part = parts[i]; |
| 15597 result.elements.addAll(part.elements); | 10948 result.elements.addAll(part.elements); |
| 15598 result.catchExceptionElements.addAll(part.catchExceptionElements); | 10949 result.catchExceptionElements.addAll(part.catchExceptionElements); |
| 15599 result.catchStackTraceElements.addAll(part.catchStackTraceElements); | 10950 result.catchStackTraceElements.addAll(part.catchStackTraceElements); |
| 15600 result.members.addAll(part.members); | 10951 result.members.addAll(part.members); |
| 15601 result.readMembers.addAll(part.readMembers); | 10952 result.readMembers.addAll(part.readMembers); |
| 15602 } | 10953 } |
| 15603 return result; | 10954 return result; |
| 15604 } | 10955 } |
| 15605 | 10956 |
| 15606 void addCatchException(LocalVariableElement element) { | 10957 void addCatchException(LocalVariableElement element) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 15635 * [SimpleIdentifier]s to local variables and formal parameters. | 10986 * [SimpleIdentifier]s to local variables and formal parameters. |
| 15636 */ | 10987 */ |
| 15637 class VariableResolverVisitor extends ScopedVisitor { | 10988 class VariableResolverVisitor extends ScopedVisitor { |
| 15638 /** | 10989 /** |
| 15639 * The method or function that we are currently visiting, or `null` if we are
not inside a | 10990 * The method or function that we are currently visiting, or `null` if we are
not inside a |
| 15640 * method or function. | 10991 * method or function. |
| 15641 */ | 10992 */ |
| 15642 ExecutableElement _enclosingFunction; | 10993 ExecutableElement _enclosingFunction; |
| 15643 | 10994 |
| 15644 /** | 10995 /** |
| 10996 * Information about local variables in the enclosing function or method. |
| 10997 */ |
| 10998 LocalVariableInfo _localVariableInfo; |
| 10999 |
| 11000 /** |
| 15645 * Initialize a newly created visitor to resolve the nodes in an AST node. | 11001 * Initialize a newly created visitor to resolve the nodes in an AST node. |
| 15646 * | 11002 * |
| 15647 * [definingLibrary] is the element for the library containing the node being | 11003 * [definingLibrary] is the element for the library containing the node being |
| 15648 * visited. | 11004 * visited. |
| 15649 * [source] is the source representing the compilation unit containing the | 11005 * [source] is the source representing the compilation unit containing the |
| 15650 * node being visited | 11006 * node being visited |
| 15651 * [typeProvider] is the object used to access the types from the core | 11007 * [typeProvider] is the object used to access the types from the core |
| 15652 * library. | 11008 * library. |
| 15653 * [errorListener] is the error listener that will be informed of any errors | 11009 * [errorListener] is the error listener that will be informed of any errors |
| 15654 * that are found during resolution. | 11010 * that are found during resolution. |
| 15655 * [nameScope] is the scope used to resolve identifiers in the node that will | 11011 * [nameScope] is the scope used to resolve identifiers in the node that will |
| 15656 * first be visited. If `null` or unspecified, a new [LibraryScope] will be | 11012 * first be visited. If `null` or unspecified, a new [LibraryScope] will be |
| 15657 * created based on [definingLibrary] and [typeProvider]. | 11013 * created based on [definingLibrary] and [typeProvider]. |
| 15658 */ | 11014 */ |
| 15659 VariableResolverVisitor(LibraryElement definingLibrary, Source source, | 11015 VariableResolverVisitor(LibraryElement definingLibrary, Source source, |
| 15660 TypeProvider typeProvider, AnalysisErrorListener errorListener, | 11016 TypeProvider typeProvider, AnalysisErrorListener errorListener, |
| 15661 {Scope nameScope}) | 11017 {Scope nameScope}) |
| 15662 : super(definingLibrary, source, typeProvider, errorListener, | 11018 : super(definingLibrary, source, typeProvider, errorListener, |
| 15663 nameScope: nameScope); | 11019 nameScope: nameScope); |
| 15664 | 11020 |
| 15665 /** | 11021 @override |
| 15666 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | 11022 Object visitBlockFunctionBody(BlockFunctionBody node) { |
| 15667 * | 11023 assert(_localVariableInfo != null); |
| 15668 * @param library the library containing the compilation unit being resolved | 11024 return super.visitBlockFunctionBody(node); |
| 15669 * @param source the source representing the compilation unit being visited | 11025 } |
| 15670 * @param typeProvider the object used to access the types from the core libra
ry | 11026 |
| 15671 * | 11027 @override |
| 15672 * Deprecated. Please use unnamed constructor instead. | 11028 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 15673 */ | 11029 ExecutableElement outerFunction = _enclosingFunction; |
| 15674 @deprecated | 11030 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo; |
| 15675 VariableResolverVisitor.con1( | 11031 try { |
| 15676 Library library, Source source, TypeProvider typeProvider) | 11032 _localVariableInfo ??= new LocalVariableInfo(); |
| 15677 : this( | 11033 (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo; |
| 15678 library.libraryElement, source, typeProvider, library.errorListener, | 11034 _enclosingFunction = node.element; |
| 15679 nameScope: library.libraryScope); | 11035 return super.visitConstructorDeclaration(node); |
| 11036 } finally { |
| 11037 _localVariableInfo = outerLocalVariableInfo; |
| 11038 _enclosingFunction = outerFunction; |
| 11039 } |
| 11040 } |
| 15680 | 11041 |
| 15681 @override | 11042 @override |
| 15682 Object visitExportDirective(ExportDirective node) => null; | 11043 Object visitExportDirective(ExportDirective node) => null; |
| 15683 | 11044 |
| 15684 @override | 11045 @override |
| 11046 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 11047 assert(_localVariableInfo != null); |
| 11048 return super.visitExpressionFunctionBody(node); |
| 11049 } |
| 11050 |
| 11051 @override |
| 15685 Object visitFunctionDeclaration(FunctionDeclaration node) { | 11052 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 15686 ExecutableElement outerFunction = _enclosingFunction; | 11053 ExecutableElement outerFunction = _enclosingFunction; |
| 11054 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo; |
| 15687 try { | 11055 try { |
| 11056 _localVariableInfo ??= new LocalVariableInfo(); |
| 11057 (node.functionExpression.body as FunctionBodyImpl).localVariableInfo = |
| 11058 _localVariableInfo; |
| 15688 _enclosingFunction = node.element; | 11059 _enclosingFunction = node.element; |
| 15689 return super.visitFunctionDeclaration(node); | 11060 return super.visitFunctionDeclaration(node); |
| 15690 } finally { | 11061 } finally { |
| 11062 _localVariableInfo = outerLocalVariableInfo; |
| 15691 _enclosingFunction = outerFunction; | 11063 _enclosingFunction = outerFunction; |
| 15692 } | 11064 } |
| 15693 } | 11065 } |
| 15694 | 11066 |
| 15695 @override | 11067 @override |
| 15696 Object visitFunctionExpression(FunctionExpression node) { | 11068 Object visitFunctionExpression(FunctionExpression node) { |
| 15697 if (node.parent is! FunctionDeclaration) { | 11069 if (node.parent is! FunctionDeclaration) { |
| 15698 ExecutableElement outerFunction = _enclosingFunction; | 11070 ExecutableElement outerFunction = _enclosingFunction; |
| 11071 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo; |
| 15699 try { | 11072 try { |
| 11073 _localVariableInfo ??= new LocalVariableInfo(); |
| 11074 (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo; |
| 15700 _enclosingFunction = node.element; | 11075 _enclosingFunction = node.element; |
| 15701 return super.visitFunctionExpression(node); | 11076 return super.visitFunctionExpression(node); |
| 15702 } finally { | 11077 } finally { |
| 11078 _localVariableInfo = outerLocalVariableInfo; |
| 15703 _enclosingFunction = outerFunction; | 11079 _enclosingFunction = outerFunction; |
| 15704 } | 11080 } |
| 15705 } else { | 11081 } else { |
| 15706 return super.visitFunctionExpression(node); | 11082 return super.visitFunctionExpression(node); |
| 15707 } | 11083 } |
| 15708 } | 11084 } |
| 15709 | 11085 |
| 15710 @override | 11086 @override |
| 15711 Object visitImportDirective(ImportDirective node) => null; | 11087 Object visitImportDirective(ImportDirective node) => null; |
| 15712 | 11088 |
| 15713 @override | 11089 @override |
| 15714 Object visitMethodDeclaration(MethodDeclaration node) { | 11090 Object visitMethodDeclaration(MethodDeclaration node) { |
| 15715 ExecutableElement outerFunction = _enclosingFunction; | 11091 ExecutableElement outerFunction = _enclosingFunction; |
| 11092 LocalVariableInfo outerLocalVariableInfo = _localVariableInfo; |
| 15716 try { | 11093 try { |
| 11094 _localVariableInfo ??= new LocalVariableInfo(); |
| 11095 (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo; |
| 15717 _enclosingFunction = node.element; | 11096 _enclosingFunction = node.element; |
| 15718 return super.visitMethodDeclaration(node); | 11097 return super.visitMethodDeclaration(node); |
| 15719 } finally { | 11098 } finally { |
| 11099 _localVariableInfo = outerLocalVariableInfo; |
| 15720 _enclosingFunction = outerFunction; | 11100 _enclosingFunction = outerFunction; |
| 15721 } | 11101 } |
| 15722 } | 11102 } |
| 15723 | 11103 |
| 15724 @override | 11104 @override |
| 15725 Object visitSimpleIdentifier(SimpleIdentifier node) { | 11105 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 15726 // Ignore if already resolved - declaration or type. | 11106 // Ignore if already resolved - declaration or type. |
| 15727 if (node.inDeclarationContext()) { | 11107 if (node.inDeclarationContext()) { |
| 15728 return null; | 11108 return null; |
| 15729 } | 11109 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 15755 if (parent is Label) { | 11135 if (parent is Label) { |
| 15756 return null; | 11136 return null; |
| 15757 } | 11137 } |
| 15758 // Prepare VariableElement. | 11138 // Prepare VariableElement. |
| 15759 Element element = nameScope.lookup(node, definingLibrary); | 11139 Element element = nameScope.lookup(node, definingLibrary); |
| 15760 if (element is! VariableElement) { | 11140 if (element is! VariableElement) { |
| 15761 return null; | 11141 return null; |
| 15762 } | 11142 } |
| 15763 // Must be local or parameter. | 11143 // Must be local or parameter. |
| 15764 ElementKind kind = element.kind; | 11144 ElementKind kind = element.kind; |
| 15765 if (kind == ElementKind.LOCAL_VARIABLE) { | 11145 if (kind == ElementKind.LOCAL_VARIABLE || kind == ElementKind.PARAMETER) { |
| 15766 node.staticElement = element; | |
| 15767 LocalVariableElementImpl variableImpl = | |
| 15768 element as LocalVariableElementImpl; | |
| 15769 if (node.inSetterContext()) { | |
| 15770 variableImpl.markPotentiallyMutatedInScope(); | |
| 15771 if (element.enclosingElement != _enclosingFunction) { | |
| 15772 variableImpl.markPotentiallyMutatedInClosure(); | |
| 15773 } | |
| 15774 } | |
| 15775 } else if (kind == ElementKind.PARAMETER) { | |
| 15776 node.staticElement = element; | 11146 node.staticElement = element; |
| 15777 if (node.inSetterContext()) { | 11147 if (node.inSetterContext()) { |
| 15778 ParameterElementImpl parameterImpl = element as ParameterElementImpl; | 11148 _localVariableInfo.potentiallyMutatedInScope.add(element); |
| 15779 parameterImpl.markPotentiallyMutatedInScope(); | 11149 if (element.enclosingElement != _enclosingFunction) { |
| 15780 // If we are in some closure, check if it is not the same as where | 11150 _localVariableInfo.potentiallyMutatedInClosure.add(element); |
| 15781 // variable is declared. | |
| 15782 if (_enclosingFunction != null && | |
| 15783 (element.enclosingElement != _enclosingFunction)) { | |
| 15784 parameterImpl.markPotentiallyMutatedInClosure(); | |
| 15785 } | 11151 } |
| 15786 } | 11152 } |
| 15787 } | 11153 } |
| 15788 return null; | 11154 return null; |
| 15789 } | 11155 } |
| 15790 | 11156 |
| 15791 @override | 11157 @override |
| 15792 Object visitTypeName(TypeName node) { | 11158 Object visitTypeName(TypeName node) { |
| 15793 return null; | 11159 return null; |
| 15794 } | 11160 } |
| 15795 } | 11161 } |
| 15796 | 11162 |
| 15797 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor { | 11163 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor { |
| 15798 final ConstantVerifier verifier; | 11164 final ConstantVerifier verifier; |
| 15799 | 11165 |
| 15800 List<ParameterElement> parameterElements; | 11166 List<ParameterElement> parameterElements; |
| 15801 | 11167 |
| 15802 TypeSystem _typeSystem; | 11168 TypeSystem _typeSystem; |
| 15803 | 11169 |
| 15804 _ConstantVerifier_validateInitializerExpression( | 11170 _ConstantVerifier_validateInitializerExpression( |
| 15805 TypeProvider typeProvider, | 11171 TypeProvider typeProvider, |
| 15806 ErrorReporter errorReporter, | 11172 ErrorReporter errorReporter, |
| 15807 this.verifier, | 11173 this.verifier, |
| 15808 this.parameterElements, | 11174 this.parameterElements, |
| 15809 DeclaredVariables declaredVariables, | 11175 DeclaredVariables declaredVariables, |
| 15810 {TypeSystem typeSystem}) | 11176 {TypeSystem typeSystem}) |
| 15811 : _typeSystem = (typeSystem != null) ? typeSystem : new TypeSystemImpl(), | 11177 : _typeSystem = typeSystem ?? new TypeSystemImpl(), |
| 15812 super( | 11178 super( |
| 15813 new ConstantEvaluationEngine(typeProvider, declaredVariables, | 11179 new ConstantEvaluationEngine(typeProvider, declaredVariables, |
| 15814 typeSystem: typeSystem), | 11180 typeSystem: typeSystem), |
| 15815 errorReporter); | 11181 errorReporter); |
| 15816 | 11182 |
| 15817 @override | 11183 @override |
| 15818 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) { | 11184 DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) { |
| 15819 Element element = node.staticElement; | 11185 Element element = node.staticElement; |
| 15820 for (ParameterElement parameterElement in parameterElements) { | 11186 int length = parameterElements.length; |
| 11187 for (int i = 0; i < length; i++) { |
| 11188 ParameterElement parameterElement = parameterElements[i]; |
| 15821 if (identical(parameterElement, element) && parameterElement != null) { | 11189 if (identical(parameterElement, element) && parameterElement != null) { |
| 15822 DartType type = parameterElement.type; | 11190 DartType type = parameterElement.type; |
| 15823 if (type != null) { | 11191 if (type != null) { |
| 15824 if (type.isDynamic) { | 11192 if (type.isDynamic) { |
| 15825 return new DartObjectImpl( | 11193 return new DartObjectImpl( |
| 15826 verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE); | 11194 verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE); |
| 15827 } else if (_typeSystem.isSubtypeOf(type, verifier._boolType)) { | 11195 } else if (_typeSystem.isSubtypeOf(type, verifier._boolType)) { |
| 15828 return new DartObjectImpl( | 11196 return new DartObjectImpl( |
| 15829 verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE); | 11197 verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE); |
| 15830 } else if (_typeSystem.isSubtypeOf( | 11198 } else if (_typeSystem.isSubtypeOf( |
| (...skipping 20 matching lines...) Expand all Loading... |
| 15851 } | 11219 } |
| 15852 return new DartObjectImpl( | 11220 return new DartObjectImpl( |
| 15853 type is InterfaceType ? type : verifier._typeProvider.objectType, | 11221 type is InterfaceType ? type : verifier._typeProvider.objectType, |
| 15854 GenericState.UNKNOWN_VALUE); | 11222 GenericState.UNKNOWN_VALUE); |
| 15855 } | 11223 } |
| 15856 } | 11224 } |
| 15857 return super.visitSimpleIdentifier(node); | 11225 return super.visitSimpleIdentifier(node); |
| 15858 } | 11226 } |
| 15859 } | 11227 } |
| 15860 | 11228 |
| 15861 class _ElementBuilder_visitClassDeclaration extends UnifyingAstVisitor<Object> { | |
| 15862 final ElementBuilder builder; | |
| 15863 | |
| 15864 List<ClassMember> nonFields; | |
| 15865 | |
| 15866 _ElementBuilder_visitClassDeclaration(this.builder, this.nonFields) : super(); | |
| 15867 | |
| 15868 @override | |
| 15869 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 15870 nonFields.add(node); | |
| 15871 return null; | |
| 15872 } | |
| 15873 | |
| 15874 @override | |
| 15875 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 15876 nonFields.add(node); | |
| 15877 return null; | |
| 15878 } | |
| 15879 | |
| 15880 @override | |
| 15881 Object visitNode(AstNode node) => node.accept(builder); | |
| 15882 } | |
| 15883 | |
| 15884 class _ResolverVisitor_isVariableAccessedInClosure | 11229 class _ResolverVisitor_isVariableAccessedInClosure |
| 15885 extends RecursiveAstVisitor<Object> { | 11230 extends RecursiveAstVisitor<Object> { |
| 15886 final Element variable; | 11231 final Element variable; |
| 15887 | 11232 |
| 15888 bool result = false; | 11233 bool result = false; |
| 15889 | 11234 |
| 15890 bool _inClosure = false; | 11235 bool _inClosure = false; |
| 15891 | 11236 |
| 15892 _ResolverVisitor_isVariableAccessedInClosure(this.variable); | 11237 _ResolverVisitor_isVariableAccessedInClosure(this.variable); |
| 15893 | 11238 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 15928 return null; | 11273 return null; |
| 15929 } | 11274 } |
| 15930 if (identical(node.staticElement, variable)) { | 11275 if (identical(node.staticElement, variable)) { |
| 15931 if (node.inSetterContext()) { | 11276 if (node.inSetterContext()) { |
| 15932 result = true; | 11277 result = true; |
| 15933 } | 11278 } |
| 15934 } | 11279 } |
| 15935 return null; | 11280 return null; |
| 15936 } | 11281 } |
| 15937 } | 11282 } |
| 15938 | |
| 15939 class _TypeResolverVisitor_visitClassMembersInScope | |
| 15940 extends UnifyingAstVisitor<Object> { | |
| 15941 final TypeResolverVisitor TypeResolverVisitor_this; | |
| 15942 | |
| 15943 List<ClassMember> nonFields; | |
| 15944 | |
| 15945 _TypeResolverVisitor_visitClassMembersInScope( | |
| 15946 this.TypeResolverVisitor_this, this.nonFields) | |
| 15947 : super(); | |
| 15948 | |
| 15949 @override | |
| 15950 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 15951 nonFields.add(node); | |
| 15952 return null; | |
| 15953 } | |
| 15954 | |
| 15955 @override | |
| 15956 Object visitExtendsClause(ExtendsClause node) => null; | |
| 15957 | |
| 15958 @override | |
| 15959 Object visitImplementsClause(ImplementsClause node) => null; | |
| 15960 | |
| 15961 @override | |
| 15962 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 15963 nonFields.add(node); | |
| 15964 return null; | |
| 15965 } | |
| 15966 | |
| 15967 @override | |
| 15968 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); | |
| 15969 | |
| 15970 @override | |
| 15971 Object visitWithClause(WithClause node) => null; | |
| 15972 } | |
| OLD | NEW |