| OLD | NEW |
| (Empty) |
| 1 // This code was auto-generated, is not intended to be edited, and is subject to | |
| 2 // significant change. Please see the README file for more information. | |
| 3 library engine.resolver; | |
| 4 import 'dart:collection'; | |
| 5 import 'java_core.dart'; | |
| 6 import 'java_engine.dart'; | |
| 7 import 'instrumentation.dart'; | |
| 8 import 'source.dart'; | |
| 9 import 'error.dart'; | |
| 10 import 'scanner.dart' as sc; | |
| 11 import 'utilities_dart.dart'; | |
| 12 import 'utilities_general.dart'; | |
| 13 import 'ast.dart'; | |
| 14 import 'parser.dart' show Parser, ParserErrorCode; | |
| 15 import 'sdk.dart' show DartSdk, SdkLibrary; | |
| 16 import 'element.dart'; | |
| 17 import 'html.dart' as ht; | |
| 18 import 'engine.dart'; | |
| 19 import 'constant.dart'; | |
| 20 /** | |
| 21 * Instances of the class `CompilationUnitBuilder` build an element model for a
single | |
| 22 * compilation unit. | |
| 23 * | |
| 24 * @coverage dart.engine.resolver | |
| 25 */ | |
| 26 class CompilationUnitBuilder { | |
| 27 | |
| 28 /** | |
| 29 * Build the compilation unit element for the given source. | |
| 30 * | |
| 31 * @param source the source describing the compilation unit | |
| 32 * @param unit the AST structure representing the compilation unit | |
| 33 * @return the compilation unit element that was built | |
| 34 * @throws AnalysisException if the analysis could not be performed | |
| 35 */ | |
| 36 CompilationUnitElementImpl buildCompilationUnit(Source source, CompilationUnit
unit) { | |
| 37 TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.resolve.st
art(); | |
| 38 try { | |
| 39 if (unit == null) { | |
| 40 return null; | |
| 41 } | |
| 42 ElementHolder holder = new ElementHolder(); | |
| 43 ElementBuilder builder = new ElementBuilder(holder); | |
| 44 unit.accept(builder); | |
| 45 CompilationUnitElementImpl element = new CompilationUnitElementImpl(source
.shortName); | |
| 46 element.accessors = holder.accessors; | |
| 47 element.functions = holder.functions; | |
| 48 element.source = source; | |
| 49 element.typeAliases = holder.typeAliases; | |
| 50 element.types = holder.types; | |
| 51 element.topLevelVariables = holder.topLevelVariables; | |
| 52 unit.element = element; | |
| 53 return element; | |
| 54 } finally { | |
| 55 timeCounter.stop(); | |
| 56 } | |
| 57 } | |
| 58 } | |
| 59 /** | |
| 60 * Instances of the class `ElementBuilder` traverse an AST structure and build t
he element | |
| 61 * model representing the AST structure. | |
| 62 * | |
| 63 * @coverage dart.engine.resolver | |
| 64 */ | |
| 65 class ElementBuilder extends RecursiveASTVisitor<Object> { | |
| 66 | |
| 67 /** | |
| 68 * The element holder associated with the element that is currently being buil
t. | |
| 69 */ | |
| 70 ElementHolder _currentHolder; | |
| 71 | |
| 72 /** | |
| 73 * A flag indicating whether a variable declaration is in the context of a fie
ld declaration. | |
| 74 */ | |
| 75 bool _inFieldContext = false; | |
| 76 | |
| 77 /** | |
| 78 * A flag indicating whether a variable declaration is within the body of a me
thod or function. | |
| 79 */ | |
| 80 bool _inFunction = false; | |
| 81 | |
| 82 /** | |
| 83 * A flag indicating whether the class currently being visited can be used as
a mixin. | |
| 84 */ | |
| 85 bool _isValidMixin = false; | |
| 86 | |
| 87 /** | |
| 88 * A collection holding the function types defined in a class that need to hav
e their type | |
| 89 * arguments set to the types of the type parameters for the class, or `null`
if we are not | |
| 90 * currently processing nodes within a class. | |
| 91 */ | |
| 92 List<FunctionTypeImpl> _functionTypesToFix = null; | |
| 93 | |
| 94 /** | |
| 95 * Initialize a newly created element builder to build the elements for a comp
ilation unit. | |
| 96 * | |
| 97 * @param initialHolder the element holder associated with the compilation uni
t being built | |
| 98 */ | |
| 99 ElementBuilder(ElementHolder initialHolder) { | |
| 100 _currentHolder = initialHolder; | |
| 101 } | |
| 102 Object visitBlock(Block node) { | |
| 103 bool wasInField = _inFieldContext; | |
| 104 _inFieldContext = false; | |
| 105 try { | |
| 106 node.visitChildren(this); | |
| 107 } finally { | |
| 108 _inFieldContext = wasInField; | |
| 109 } | |
| 110 return null; | |
| 111 } | |
| 112 Object visitCatchClause(CatchClause node) { | |
| 113 SimpleIdentifier exceptionParameter = node.exceptionParameter; | |
| 114 if (exceptionParameter != null) { | |
| 115 LocalVariableElementImpl exception = new LocalVariableElementImpl(exceptio
nParameter); | |
| 116 _currentHolder.addLocalVariable(exception); | |
| 117 exceptionParameter.staticElement = exception; | |
| 118 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; | |
| 119 if (stackTraceParameter != null) { | |
| 120 LocalVariableElementImpl stackTrace = new LocalVariableElementImpl(stack
TraceParameter); | |
| 121 _currentHolder.addLocalVariable(stackTrace); | |
| 122 stackTraceParameter.staticElement = stackTrace; | |
| 123 } | |
| 124 } | |
| 125 return super.visitCatchClause(node); | |
| 126 } | |
| 127 Object visitClassDeclaration(ClassDeclaration node) { | |
| 128 ElementHolder holder = new ElementHolder(); | |
| 129 _isValidMixin = true; | |
| 130 _functionTypesToFix = new List<FunctionTypeImpl>(); | |
| 131 visitChildren(holder, node); | |
| 132 SimpleIdentifier className = node.name; | |
| 133 ClassElementImpl element = new ClassElementImpl(className); | |
| 134 List<TypeParameterElement> typeParameters = holder.typeParameters; | |
| 135 List<Type2> typeArguments = createTypeParameterTypes(typeParameters); | |
| 136 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl.con1(element); | |
| 137 interfaceType.typeArguments = typeArguments; | |
| 138 element.type = interfaceType; | |
| 139 List<ConstructorElement> constructors = holder.constructors; | |
| 140 if (constructors.length == 0) { | |
| 141 constructors = createDefaultConstructors(interfaceType); | |
| 142 } | |
| 143 element.abstract = node.abstractKeyword != null; | |
| 144 element.accessors = holder.accessors; | |
| 145 element.constructors = constructors; | |
| 146 element.fields = holder.fields; | |
| 147 element.methods = holder.methods; | |
| 148 element.typeParameters = typeParameters; | |
| 149 element.validMixin = _isValidMixin; | |
| 150 for (FunctionTypeImpl functionType in _functionTypesToFix) { | |
| 151 functionType.typeArguments = typeArguments; | |
| 152 } | |
| 153 _functionTypesToFix = null; | |
| 154 _currentHolder.addType(element); | |
| 155 className.staticElement = element; | |
| 156 holder.validate(); | |
| 157 return null; | |
| 158 } | |
| 159 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 160 ElementHolder holder = new ElementHolder(); | |
| 161 _functionTypesToFix = new List<FunctionTypeImpl>(); | |
| 162 visitChildren(holder, node); | |
| 163 SimpleIdentifier className = node.name; | |
| 164 ClassElementImpl element = new ClassElementImpl(className); | |
| 165 element.abstract = node.abstractKeyword != null; | |
| 166 element.typedef = true; | |
| 167 List<TypeParameterElement> typeParameters = holder.typeParameters; | |
| 168 element.typeParameters = typeParameters; | |
| 169 List<Type2> typeArguments = createTypeParameterTypes(typeParameters); | |
| 170 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl.con1(element); | |
| 171 interfaceType.typeArguments = typeArguments; | |
| 172 element.type = interfaceType; | |
| 173 element.constructors = createDefaultConstructors(interfaceType); | |
| 174 for (FunctionTypeImpl functionType in _functionTypesToFix) { | |
| 175 functionType.typeArguments = typeArguments; | |
| 176 } | |
| 177 _functionTypesToFix = null; | |
| 178 _currentHolder.addType(element); | |
| 179 className.staticElement = element; | |
| 180 holder.validate(); | |
| 181 return null; | |
| 182 } | |
| 183 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 184 _isValidMixin = false; | |
| 185 ElementHolder holder = new ElementHolder(); | |
| 186 bool wasInFunction = _inFunction; | |
| 187 _inFunction = true; | |
| 188 try { | |
| 189 visitChildren(holder, node); | |
| 190 } finally { | |
| 191 _inFunction = wasInFunction; | |
| 192 } | |
| 193 SimpleIdentifier constructorName = node.name; | |
| 194 ConstructorElementImpl element = new ConstructorElementImpl(constructorName)
; | |
| 195 if (node.factoryKeyword != null) { | |
| 196 element.factory = true; | |
| 197 } | |
| 198 element.functions = holder.functions; | |
| 199 element.labels = holder.labels; | |
| 200 element.localVariables = holder.localVariables; | |
| 201 element.parameters = holder.parameters; | |
| 202 element.const2 = node.constKeyword != null; | |
| 203 _currentHolder.addConstructor(element); | |
| 204 node.element = element; | |
| 205 if (constructorName == null) { | |
| 206 Identifier returnType = node.returnType; | |
| 207 if (returnType != null) { | |
| 208 element.nameOffset = returnType.offset; | |
| 209 } | |
| 210 } else { | |
| 211 constructorName.staticElement = element; | |
| 212 } | |
| 213 holder.validate(); | |
| 214 return null; | |
| 215 } | |
| 216 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 217 SimpleIdentifier variableName = node.identifier; | |
| 218 sc.Token keyword = node.keyword; | |
| 219 LocalVariableElementImpl element = new LocalVariableElementImpl(variableName
); | |
| 220 ForEachStatement statement = node.parent as ForEachStatement; | |
| 221 int declarationEnd = node.offset + node.length; | |
| 222 int statementEnd = statement.offset + statement.length; | |
| 223 element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1); | |
| 224 element.const3 = matches(keyword, sc.Keyword.CONST); | |
| 225 element.final2 = matches(keyword, sc.Keyword.FINAL); | |
| 226 _currentHolder.addLocalVariable(element); | |
| 227 variableName.staticElement = element; | |
| 228 return super.visitDeclaredIdentifier(node); | |
| 229 } | |
| 230 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 231 ElementHolder holder = new ElementHolder(); | |
| 232 visit(holder, node.defaultValue); | |
| 233 FunctionElementImpl initializer = new FunctionElementImpl(); | |
| 234 initializer.functions = holder.functions; | |
| 235 initializer.labels = holder.labels; | |
| 236 initializer.localVariables = holder.localVariables; | |
| 237 initializer.parameters = holder.parameters; | |
| 238 SimpleIdentifier parameterName = node.parameter.identifier; | |
| 239 ParameterElementImpl parameter; | |
| 240 if (node.parameter is FieldFormalParameter) { | |
| 241 parameter = new DefaultFieldFormalParameterElementImpl(parameterName); | |
| 242 } else { | |
| 243 parameter = new DefaultParameterElementImpl(parameterName); | |
| 244 } | |
| 245 parameter.const3 = node.isConst; | |
| 246 parameter.final2 = node.isFinal; | |
| 247 parameter.initializer = initializer; | |
| 248 parameter.parameterKind = node.kind; | |
| 249 Expression defaultValue = node.defaultValue; | |
| 250 if (defaultValue != null) { | |
| 251 parameter.setDefaultValueRange(defaultValue.offset, defaultValue.length); | |
| 252 } | |
| 253 setParameterVisibleRange(node, parameter); | |
| 254 _currentHolder.addParameter(parameter); | |
| 255 parameterName.staticElement = parameter; | |
| 256 node.parameter.accept(this); | |
| 257 holder.validate(); | |
| 258 return null; | |
| 259 } | |
| 260 Object visitFieldDeclaration(FieldDeclaration node) { | |
| 261 bool wasInField = _inFieldContext; | |
| 262 _inFieldContext = true; | |
| 263 try { | |
| 264 node.visitChildren(this); | |
| 265 } finally { | |
| 266 _inFieldContext = wasInField; | |
| 267 } | |
| 268 return null; | |
| 269 } | |
| 270 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 271 if (node.parent is! DefaultFormalParameter) { | |
| 272 SimpleIdentifier parameterName = node.identifier; | |
| 273 FieldFormalParameterElementImpl parameter = new FieldFormalParameterElemen
tImpl(parameterName); | |
| 274 parameter.const3 = node.isConst; | |
| 275 parameter.final2 = node.isFinal; | |
| 276 parameter.parameterKind = node.kind; | |
| 277 _currentHolder.addParameter(parameter); | |
| 278 parameterName.staticElement = parameter; | |
| 279 } | |
| 280 ElementHolder holder = new ElementHolder(); | |
| 281 visitChildren(holder, node); | |
| 282 ((node.element as ParameterElementImpl)).parameters = holder.parameters; | |
| 283 holder.validate(); | |
| 284 return null; | |
| 285 } | |
| 286 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 287 FunctionExpression expression = node.functionExpression; | |
| 288 if (expression != null) { | |
| 289 ElementHolder holder = new ElementHolder(); | |
| 290 bool wasInFunction = _inFunction; | |
| 291 _inFunction = true; | |
| 292 try { | |
| 293 visitChildren(holder, expression); | |
| 294 } finally { | |
| 295 _inFunction = wasInFunction; | |
| 296 } | |
| 297 sc.Token property = node.propertyKeyword; | |
| 298 if (property == null) { | |
| 299 SimpleIdentifier functionName = node.name; | |
| 300 FunctionElementImpl element = new FunctionElementImpl.con1(functionName)
; | |
| 301 element.functions = holder.functions; | |
| 302 element.labels = holder.labels; | |
| 303 element.localVariables = holder.localVariables; | |
| 304 element.parameters = holder.parameters; | |
| 305 if (_inFunction) { | |
| 306 Block enclosingBlock = node.getAncestor(Block); | |
| 307 if (enclosingBlock != null) { | |
| 308 int functionEnd = node.offset + node.length; | |
| 309 int blockEnd = enclosingBlock.offset + enclosingBlock.length; | |
| 310 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1); | |
| 311 } | |
| 312 } | |
| 313 _currentHolder.addFunction(element); | |
| 314 expression.element = element; | |
| 315 functionName.staticElement = element; | |
| 316 } else { | |
| 317 SimpleIdentifier propertyNameNode = node.name; | |
| 318 if (propertyNameNode == null) { | |
| 319 return null; | |
| 320 } | |
| 321 String propertyName = propertyNameNode.name; | |
| 322 TopLevelVariableElementImpl variable = _currentHolder.getTopLevelVariabl
e(propertyName) as TopLevelVariableElementImpl; | |
| 323 if (variable == null) { | |
| 324 variable = new TopLevelVariableElementImpl.con2(node.name.name); | |
| 325 variable.final2 = true; | |
| 326 variable.synthetic = true; | |
| 327 _currentHolder.addTopLevelVariable(variable); | |
| 328 } | |
| 329 if (matches(property, sc.Keyword.GET)) { | |
| 330 PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.c
on1(propertyNameNode); | |
| 331 getter.functions = holder.functions; | |
| 332 getter.labels = holder.labels; | |
| 333 getter.localVariables = holder.localVariables; | |
| 334 getter.variable = variable; | |
| 335 getter.getter = true; | |
| 336 getter.static = true; | |
| 337 variable.getter = getter; | |
| 338 _currentHolder.addAccessor(getter); | |
| 339 expression.element = getter; | |
| 340 propertyNameNode.staticElement = getter; | |
| 341 } else { | |
| 342 PropertyAccessorElementImpl setter = new PropertyAccessorElementImpl.c
on1(propertyNameNode); | |
| 343 setter.functions = holder.functions; | |
| 344 setter.labels = holder.labels; | |
| 345 setter.localVariables = holder.localVariables; | |
| 346 setter.parameters = holder.parameters; | |
| 347 setter.variable = variable; | |
| 348 setter.setter = true; | |
| 349 setter.static = true; | |
| 350 variable.setter = setter; | |
| 351 variable.final2 = false; | |
| 352 _currentHolder.addAccessor(setter); | |
| 353 expression.element = setter; | |
| 354 propertyNameNode.staticElement = setter; | |
| 355 } | |
| 356 } | |
| 357 holder.validate(); | |
| 358 } | |
| 359 return null; | |
| 360 } | |
| 361 Object visitFunctionExpression(FunctionExpression node) { | |
| 362 ElementHolder holder = new ElementHolder(); | |
| 363 bool wasInFunction = _inFunction; | |
| 364 _inFunction = true; | |
| 365 try { | |
| 366 visitChildren(holder, node); | |
| 367 } finally { | |
| 368 _inFunction = wasInFunction; | |
| 369 } | |
| 370 FunctionElementImpl element = new FunctionElementImpl.con2(node.beginToken.o
ffset); | |
| 371 element.functions = holder.functions; | |
| 372 element.labels = holder.labels; | |
| 373 element.localVariables = holder.localVariables; | |
| 374 element.parameters = holder.parameters; | |
| 375 if (_inFunction) { | |
| 376 Block enclosingBlock = node.getAncestor(Block); | |
| 377 if (enclosingBlock != null) { | |
| 378 int functionEnd = node.offset + node.length; | |
| 379 int blockEnd = enclosingBlock.offset + enclosingBlock.length; | |
| 380 element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1); | |
| 381 } | |
| 382 } | |
| 383 FunctionTypeImpl type = new FunctionTypeImpl.con1(element); | |
| 384 if (_functionTypesToFix != null) { | |
| 385 _functionTypesToFix.add(type); | |
| 386 } | |
| 387 element.type = type; | |
| 388 _currentHolder.addFunction(element); | |
| 389 node.element = element; | |
| 390 holder.validate(); | |
| 391 return null; | |
| 392 } | |
| 393 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 394 ElementHolder holder = new ElementHolder(); | |
| 395 visitChildren(holder, node); | |
| 396 SimpleIdentifier aliasName = node.name; | |
| 397 List<ParameterElement> parameters = holder.parameters; | |
| 398 List<TypeParameterElement> typeParameters = holder.typeParameters; | |
| 399 FunctionTypeAliasElementImpl element = new FunctionTypeAliasElementImpl(alia
sName); | |
| 400 element.parameters = parameters; | |
| 401 element.typeParameters = typeParameters; | |
| 402 FunctionTypeImpl type = new FunctionTypeImpl.con2(element); | |
| 403 type.typeArguments = createTypeParameterTypes(typeParameters); | |
| 404 element.type = type; | |
| 405 _currentHolder.addTypeAlias(element); | |
| 406 aliasName.staticElement = element; | |
| 407 holder.validate(); | |
| 408 return null; | |
| 409 } | |
| 410 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 411 if (node.parent is! DefaultFormalParameter) { | |
| 412 SimpleIdentifier parameterName = node.identifier; | |
| 413 ParameterElementImpl parameter = new ParameterElementImpl.con1(parameterNa
me); | |
| 414 parameter.parameterKind = node.kind; | |
| 415 setParameterVisibleRange(node, parameter); | |
| 416 _currentHolder.addParameter(parameter); | |
| 417 parameterName.staticElement = parameter; | |
| 418 } | |
| 419 ElementHolder holder = new ElementHolder(); | |
| 420 visitChildren(holder, node); | |
| 421 ((node.element as ParameterElementImpl)).parameters = holder.parameters; | |
| 422 holder.validate(); | |
| 423 return null; | |
| 424 } | |
| 425 Object visitLabeledStatement(LabeledStatement node) { | |
| 426 bool onSwitchStatement = node.statement is SwitchStatement; | |
| 427 for (Label label in node.labels) { | |
| 428 SimpleIdentifier labelName = label.label; | |
| 429 LabelElementImpl element = new LabelElementImpl(labelName, onSwitchStateme
nt, false); | |
| 430 _currentHolder.addLabel(element); | |
| 431 labelName.staticElement = element; | |
| 432 } | |
| 433 return super.visitLabeledStatement(node); | |
| 434 } | |
| 435 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 436 ElementHolder holder = new ElementHolder(); | |
| 437 bool wasInFunction = _inFunction; | |
| 438 _inFunction = true; | |
| 439 try { | |
| 440 visitChildren(holder, node); | |
| 441 } finally { | |
| 442 _inFunction = wasInFunction; | |
| 443 } | |
| 444 bool isStatic = node.isStatic; | |
| 445 sc.Token property = node.propertyKeyword; | |
| 446 if (property == null) { | |
| 447 SimpleIdentifier methodName = node.name; | |
| 448 String nameOfMethod = methodName.name; | |
| 449 if (nameOfMethod == sc.TokenType.MINUS.lexeme && node.parameters.parameter
s.length == 0) { | |
| 450 nameOfMethod = "unary-"; | |
| 451 } | |
| 452 MethodElementImpl element = new MethodElementImpl.con2(nameOfMethod, metho
dName.offset); | |
| 453 element.abstract = node.isAbstract; | |
| 454 element.functions = holder.functions; | |
| 455 element.labels = holder.labels; | |
| 456 element.localVariables = holder.localVariables; | |
| 457 element.parameters = holder.parameters; | |
| 458 element.static = isStatic; | |
| 459 _currentHolder.addMethod(element); | |
| 460 methodName.staticElement = element; | |
| 461 } else { | |
| 462 SimpleIdentifier propertyNameNode = node.name; | |
| 463 String propertyName = propertyNameNode.name; | |
| 464 FieldElementImpl field = _currentHolder.getField(propertyName) as FieldEle
mentImpl; | |
| 465 if (field == null) { | |
| 466 field = new FieldElementImpl.con2(node.name.name); | |
| 467 field.final2 = true; | |
| 468 field.static = isStatic; | |
| 469 field.synthetic = true; | |
| 470 _currentHolder.addField(field); | |
| 471 } | |
| 472 if (matches(property, sc.Keyword.GET)) { | |
| 473 PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.con
1(propertyNameNode); | |
| 474 getter.functions = holder.functions; | |
| 475 getter.labels = holder.labels; | |
| 476 getter.localVariables = holder.localVariables; | |
| 477 getter.variable = field; | |
| 478 getter.abstract = node.body is EmptyFunctionBody && node.externalKeyword
== null; | |
| 479 getter.getter = true; | |
| 480 getter.static = isStatic; | |
| 481 field.getter = getter; | |
| 482 _currentHolder.addAccessor(getter); | |
| 483 propertyNameNode.staticElement = getter; | |
| 484 } else { | |
| 485 PropertyAccessorElementImpl setter = new PropertyAccessorElementImpl.con
1(propertyNameNode); | |
| 486 setter.functions = holder.functions; | |
| 487 setter.labels = holder.labels; | |
| 488 setter.localVariables = holder.localVariables; | |
| 489 setter.parameters = holder.parameters; | |
| 490 setter.variable = field; | |
| 491 setter.abstract = node.body is EmptyFunctionBody && !matches(node.extern
alKeyword, sc.Keyword.EXTERNAL); | |
| 492 setter.setter = true; | |
| 493 setter.static = isStatic; | |
| 494 field.setter = setter; | |
| 495 field.final2 = false; | |
| 496 _currentHolder.addAccessor(setter); | |
| 497 propertyNameNode.staticElement = setter; | |
| 498 } | |
| 499 } | |
| 500 holder.validate(); | |
| 501 return null; | |
| 502 } | |
| 503 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 504 if (node.parent is! DefaultFormalParameter) { | |
| 505 SimpleIdentifier parameterName = node.identifier; | |
| 506 ParameterElementImpl parameter = new ParameterElementImpl.con1(parameterNa
me); | |
| 507 parameter.const3 = node.isConst; | |
| 508 parameter.final2 = node.isFinal; | |
| 509 parameter.parameterKind = node.kind; | |
| 510 setParameterVisibleRange(node, parameter); | |
| 511 _currentHolder.addParameter(parameter); | |
| 512 parameterName.staticElement = parameter; | |
| 513 } | |
| 514 return super.visitSimpleFormalParameter(node); | |
| 515 } | |
| 516 Object visitSuperExpression(SuperExpression node) { | |
| 517 _isValidMixin = false; | |
| 518 return super.visitSuperExpression(node); | |
| 519 } | |
| 520 Object visitSwitchCase(SwitchCase node) { | |
| 521 for (Label label in node.labels) { | |
| 522 SimpleIdentifier labelName = label.label; | |
| 523 LabelElementImpl element = new LabelElementImpl(labelName, false, true); | |
| 524 _currentHolder.addLabel(element); | |
| 525 labelName.staticElement = element; | |
| 526 } | |
| 527 return super.visitSwitchCase(node); | |
| 528 } | |
| 529 Object visitSwitchDefault(SwitchDefault node) { | |
| 530 for (Label label in node.labels) { | |
| 531 SimpleIdentifier labelName = label.label; | |
| 532 LabelElementImpl element = new LabelElementImpl(labelName, false, true); | |
| 533 _currentHolder.addLabel(element); | |
| 534 labelName.staticElement = element; | |
| 535 } | |
| 536 return super.visitSwitchDefault(node); | |
| 537 } | |
| 538 Object visitTypeParameter(TypeParameter node) { | |
| 539 SimpleIdentifier parameterName = node.name; | |
| 540 TypeParameterElementImpl typeParameter = new TypeParameterElementImpl(parame
terName); | |
| 541 TypeParameterTypeImpl typeParameterType = new TypeParameterTypeImpl(typePara
meter); | |
| 542 typeParameter.type = typeParameterType; | |
| 543 _currentHolder.addTypeParameter(typeParameter); | |
| 544 parameterName.staticElement = typeParameter; | |
| 545 return super.visitTypeParameter(node); | |
| 546 } | |
| 547 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 548 sc.Token keyword = ((node.parent as VariableDeclarationList)).keyword; | |
| 549 bool isConst = matches(keyword, sc.Keyword.CONST); | |
| 550 bool isFinal = matches(keyword, sc.Keyword.FINAL); | |
| 551 bool hasInitializer = node.initializer != null; | |
| 552 VariableElementImpl element; | |
| 553 if (_inFieldContext) { | |
| 554 SimpleIdentifier fieldName = node.name; | |
| 555 FieldElementImpl field; | |
| 556 if (isConst && hasInitializer) { | |
| 557 field = new ConstFieldElementImpl(fieldName); | |
| 558 } else { | |
| 559 field = new FieldElementImpl.con1(fieldName); | |
| 560 } | |
| 561 element = field; | |
| 562 _currentHolder.addField(field); | |
| 563 fieldName.staticElement = field; | |
| 564 } else if (_inFunction) { | |
| 565 SimpleIdentifier variableName = node.name; | |
| 566 LocalVariableElementImpl variable; | |
| 567 if (isConst && hasInitializer) { | |
| 568 variable = new ConstLocalVariableElementImpl(variableName); | |
| 569 } else { | |
| 570 variable = new LocalVariableElementImpl(variableName); | |
| 571 } | |
| 572 element = variable; | |
| 573 Block enclosingBlock = node.getAncestor(Block); | |
| 574 int functionEnd = node.offset + node.length; | |
| 575 int blockEnd = enclosingBlock.offset + enclosingBlock.length; | |
| 576 variable.setVisibleRange(functionEnd, blockEnd - functionEnd - 1); | |
| 577 _currentHolder.addLocalVariable(variable); | |
| 578 variableName.staticElement = element; | |
| 579 } else { | |
| 580 SimpleIdentifier variableName = node.name; | |
| 581 TopLevelVariableElementImpl variable; | |
| 582 if (isConst && hasInitializer) { | |
| 583 variable = new ConstTopLevelVariableElementImpl(variableName); | |
| 584 } else { | |
| 585 variable = new TopLevelVariableElementImpl.con1(variableName); | |
| 586 } | |
| 587 element = variable; | |
| 588 _currentHolder.addTopLevelVariable(variable); | |
| 589 variableName.staticElement = element; | |
| 590 } | |
| 591 element.const3 = isConst; | |
| 592 element.final2 = isFinal; | |
| 593 if (hasInitializer) { | |
| 594 ElementHolder holder = new ElementHolder(); | |
| 595 bool wasInFieldContext = _inFieldContext; | |
| 596 _inFieldContext = false; | |
| 597 try { | |
| 598 visit(holder, node.initializer); | |
| 599 } finally { | |
| 600 _inFieldContext = wasInFieldContext; | |
| 601 } | |
| 602 FunctionElementImpl initializer = new FunctionElementImpl(); | |
| 603 initializer.functions = holder.functions; | |
| 604 initializer.labels = holder.labels; | |
| 605 initializer.localVariables = holder.localVariables; | |
| 606 initializer.synthetic = true; | |
| 607 element.initializer = initializer; | |
| 608 holder.validate(); | |
| 609 } | |
| 610 if (element is PropertyInducingElementImpl) { | |
| 611 PropertyInducingElementImpl variable = element as PropertyInducingElementI
mpl; | |
| 612 if (_inFieldContext) { | |
| 613 ((variable as FieldElementImpl)).static = matches(((node.parent.parent a
s FieldDeclaration)).staticKeyword, sc.Keyword.STATIC); | |
| 614 } | |
| 615 PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.con2(
variable); | |
| 616 getter.getter = true; | |
| 617 getter.static = variable.isStatic; | |
| 618 _currentHolder.addAccessor(getter); | |
| 619 variable.getter = getter; | |
| 620 if (!isFinal) { | |
| 621 PropertyAccessorElementImpl setter = new PropertyAccessorElementImpl.con
2(variable); | |
| 622 setter.setter = true; | |
| 623 setter.static = variable.isStatic; | |
| 624 ParameterElementImpl parameter = new ParameterElementImpl.con2("_${varia
ble.name}", variable.nameOffset); | |
| 625 parameter.synthetic = true; | |
| 626 parameter.parameterKind = ParameterKind.REQUIRED; | |
| 627 setter.parameters = <ParameterElement> [parameter]; | |
| 628 _currentHolder.addAccessor(setter); | |
| 629 variable.setter = setter; | |
| 630 } | |
| 631 } | |
| 632 return null; | |
| 633 } | |
| 634 | |
| 635 /** | |
| 636 * Creates the [ConstructorElement]s array with the single default constructor
element. | |
| 637 * | |
| 638 * @param interfaceType the interface type for which to create a default const
ructor | |
| 639 * @return the [ConstructorElement]s array with the single default constructor
element | |
| 640 */ | |
| 641 List<ConstructorElement> createDefaultConstructors(InterfaceTypeImpl interface
Type) { | |
| 642 ConstructorElementImpl constructor = new ConstructorElementImpl(null); | |
| 643 constructor.synthetic = true; | |
| 644 constructor.returnType = interfaceType; | |
| 645 FunctionTypeImpl type = new FunctionTypeImpl.con1(constructor); | |
| 646 _functionTypesToFix.add(type); | |
| 647 constructor.type = type; | |
| 648 return <ConstructorElement> [constructor]; | |
| 649 } | |
| 650 | |
| 651 /** | |
| 652 * Create the types associated with the given type parameters, setting the typ
e of each type | |
| 653 * parameter, and return an array of types corresponding to the given paramete
rs. | |
| 654 * | |
| 655 * @param typeParameters the type parameters for which types are to be created | |
| 656 * @return an array of types corresponding to the given parameters | |
| 657 */ | |
| 658 List<Type2> createTypeParameterTypes(List<TypeParameterElement> typeParameters
) { | |
| 659 int typeParameterCount = typeParameters.length; | |
| 660 List<Type2> typeArguments = new List<Type2>(typeParameterCount); | |
| 661 for (int i = 0; i < typeParameterCount; i++) { | |
| 662 TypeParameterElementImpl typeParameter = typeParameters[i] as TypeParamete
rElementImpl; | |
| 663 TypeParameterTypeImpl typeParameterType = new TypeParameterTypeImpl(typePa
rameter); | |
| 664 typeParameter.type = typeParameterType; | |
| 665 typeArguments[i] = typeParameterType; | |
| 666 } | |
| 667 return typeArguments; | |
| 668 } | |
| 669 | |
| 670 /** | |
| 671 * Return the body of the function that contains the given parameter, or `null
` if no | |
| 672 * function body could be found. | |
| 673 * | |
| 674 * @param node the parameter contained in the function whose body is to be ret
urned | |
| 675 * @return the body of the function that contains the given parameter | |
| 676 */ | |
| 677 FunctionBody getFunctionBody(FormalParameter node) { | |
| 678 ASTNode parent = node.parent; | |
| 679 while (parent != null) { | |
| 680 if (parent is ConstructorDeclaration) { | |
| 681 return ((parent as ConstructorDeclaration)).body; | |
| 682 } else if (parent is FunctionExpression) { | |
| 683 return ((parent as FunctionExpression)).body; | |
| 684 } else if (parent is MethodDeclaration) { | |
| 685 return ((parent as MethodDeclaration)).body; | |
| 686 } | |
| 687 parent = parent.parent; | |
| 688 } | |
| 689 return null; | |
| 690 } | |
| 691 | |
| 692 /** | |
| 693 * Return `true` if the given token is a token for the given keyword. | |
| 694 * | |
| 695 * @param token the token being tested | |
| 696 * @param keyword the keyword being tested for | |
| 697 * @return `true` if the given token is a token for the given keyword | |
| 698 */ | |
| 699 bool matches(sc.Token token, sc.Keyword keyword) => token != null && identical
(token.type, sc.TokenType.KEYWORD) && identical(((token as sc.KeywordToken)).key
word, keyword); | |
| 700 | |
| 701 /** | |
| 702 * Sets the visible source range for formal parameter. | |
| 703 */ | |
| 704 void setParameterVisibleRange(FormalParameter node, ParameterElementImpl eleme
nt) { | |
| 705 FunctionBody body = getFunctionBody(node); | |
| 706 if (body != null) { | |
| 707 element.setVisibleRange(body.offset, body.length); | |
| 708 } | |
| 709 } | |
| 710 | |
| 711 /** | |
| 712 * Make the given holder be the current holder while visiting the given node. | |
| 713 * | |
| 714 * @param holder the holder that will gather elements that are built while vis
iting the children | |
| 715 * @param node the node to be visited | |
| 716 */ | |
| 717 void visit(ElementHolder holder, ASTNode node) { | |
| 718 if (node != null) { | |
| 719 ElementHolder previousHolder = _currentHolder; | |
| 720 _currentHolder = holder; | |
| 721 try { | |
| 722 node.accept(this); | |
| 723 } finally { | |
| 724 _currentHolder = previousHolder; | |
| 725 } | |
| 726 } | |
| 727 } | |
| 728 | |
| 729 /** | |
| 730 * Make the given holder be the current holder while visiting the children of
the given node. | |
| 731 * | |
| 732 * @param holder the holder that will gather elements that are built while vis
iting the children | |
| 733 * @param node the node whose children are to be visited | |
| 734 */ | |
| 735 void visitChildren(ElementHolder holder, ASTNode node) { | |
| 736 if (node != null) { | |
| 737 ElementHolder previousHolder = _currentHolder; | |
| 738 _currentHolder = holder; | |
| 739 try { | |
| 740 node.visitChildren(this); | |
| 741 } finally { | |
| 742 _currentHolder = previousHolder; | |
| 743 } | |
| 744 } | |
| 745 } | |
| 746 } | |
| 747 /** | |
| 748 * Instances of the class `ElementHolder` hold on to elements created while trav
ersing an AST | |
| 749 * structure so that they can be accessed when creating their enclosing element. | |
| 750 * | |
| 751 * @coverage dart.engine.resolver | |
| 752 */ | |
| 753 class ElementHolder { | |
| 754 List<PropertyAccessorElement> _accessors; | |
| 755 List<ConstructorElement> _constructors; | |
| 756 List<FieldElement> _fields; | |
| 757 List<FunctionElement> _functions; | |
| 758 List<LabelElement> _labels; | |
| 759 List<VariableElement> _localVariables; | |
| 760 List<MethodElement> _methods; | |
| 761 List<ParameterElement> _parameters; | |
| 762 List<TopLevelVariableElement> _topLevelVariables; | |
| 763 List<ClassElement> _types; | |
| 764 List<FunctionTypeAliasElement> _typeAliases; | |
| 765 List<TypeParameterElement> _typeParameters; | |
| 766 void addAccessor(PropertyAccessorElement element) { | |
| 767 if (_accessors == null) { | |
| 768 _accessors = new List<PropertyAccessorElement>(); | |
| 769 } | |
| 770 _accessors.add(element); | |
| 771 } | |
| 772 void addConstructor(ConstructorElement element) { | |
| 773 if (_constructors == null) { | |
| 774 _constructors = new List<ConstructorElement>(); | |
| 775 } | |
| 776 _constructors.add(element); | |
| 777 } | |
| 778 void addField(FieldElement element) { | |
| 779 if (_fields == null) { | |
| 780 _fields = new List<FieldElement>(); | |
| 781 } | |
| 782 _fields.add(element); | |
| 783 } | |
| 784 void addFunction(FunctionElement element) { | |
| 785 if (_functions == null) { | |
| 786 _functions = new List<FunctionElement>(); | |
| 787 } | |
| 788 _functions.add(element); | |
| 789 } | |
| 790 void addLabel(LabelElement element) { | |
| 791 if (_labels == null) { | |
| 792 _labels = new List<LabelElement>(); | |
| 793 } | |
| 794 _labels.add(element); | |
| 795 } | |
| 796 void addLocalVariable(LocalVariableElement element) { | |
| 797 if (_localVariables == null) { | |
| 798 _localVariables = new List<VariableElement>(); | |
| 799 } | |
| 800 _localVariables.add(element); | |
| 801 } | |
| 802 void addMethod(MethodElement element) { | |
| 803 if (_methods == null) { | |
| 804 _methods = new List<MethodElement>(); | |
| 805 } | |
| 806 _methods.add(element); | |
| 807 } | |
| 808 void addParameter(ParameterElement element) { | |
| 809 if (_parameters == null) { | |
| 810 _parameters = new List<ParameterElement>(); | |
| 811 } | |
| 812 _parameters.add(element); | |
| 813 } | |
| 814 void addTopLevelVariable(TopLevelVariableElement element) { | |
| 815 if (_topLevelVariables == null) { | |
| 816 _topLevelVariables = new List<TopLevelVariableElement>(); | |
| 817 } | |
| 818 _topLevelVariables.add(element); | |
| 819 } | |
| 820 void addType(ClassElement element) { | |
| 821 if (_types == null) { | |
| 822 _types = new List<ClassElement>(); | |
| 823 } | |
| 824 _types.add(element); | |
| 825 } | |
| 826 void addTypeAlias(FunctionTypeAliasElement element) { | |
| 827 if (_typeAliases == null) { | |
| 828 _typeAliases = new List<FunctionTypeAliasElement>(); | |
| 829 } | |
| 830 _typeAliases.add(element); | |
| 831 } | |
| 832 void addTypeParameter(TypeParameterElement element) { | |
| 833 if (_typeParameters == null) { | |
| 834 _typeParameters = new List<TypeParameterElement>(); | |
| 835 } | |
| 836 _typeParameters.add(element); | |
| 837 } | |
| 838 List<PropertyAccessorElement> get accessors { | |
| 839 if (_accessors == null) { | |
| 840 return PropertyAccessorElementImpl.EMPTY_ARRAY; | |
| 841 } | |
| 842 List<PropertyAccessorElement> result = new List.from(_accessors); | |
| 843 _accessors = null; | |
| 844 return result; | |
| 845 } | |
| 846 List<ConstructorElement> get constructors { | |
| 847 if (_constructors == null) { | |
| 848 return ConstructorElementImpl.EMPTY_ARRAY; | |
| 849 } | |
| 850 List<ConstructorElement> result = new List.from(_constructors); | |
| 851 _constructors = null; | |
| 852 return result; | |
| 853 } | |
| 854 FieldElement getField(String fieldName) { | |
| 855 if (_fields == null) { | |
| 856 return null; | |
| 857 } | |
| 858 for (FieldElement field in _fields) { | |
| 859 if (field.name == fieldName) { | |
| 860 return field; | |
| 861 } | |
| 862 } | |
| 863 return null; | |
| 864 } | |
| 865 List<FieldElement> get fields { | |
| 866 if (_fields == null) { | |
| 867 return FieldElementImpl.EMPTY_ARRAY; | |
| 868 } | |
| 869 List<FieldElement> result = new List.from(_fields); | |
| 870 _fields = null; | |
| 871 return result; | |
| 872 } | |
| 873 List<FunctionElement> get functions { | |
| 874 if (_functions == null) { | |
| 875 return FunctionElementImpl.EMPTY_ARRAY; | |
| 876 } | |
| 877 List<FunctionElement> result = new List.from(_functions); | |
| 878 _functions = null; | |
| 879 return result; | |
| 880 } | |
| 881 List<LabelElement> get labels { | |
| 882 if (_labels == null) { | |
| 883 return LabelElementImpl.EMPTY_ARRAY; | |
| 884 } | |
| 885 List<LabelElement> result = new List.from(_labels); | |
| 886 _labels = null; | |
| 887 return result; | |
| 888 } | |
| 889 List<LocalVariableElement> get localVariables { | |
| 890 if (_localVariables == null) { | |
| 891 return LocalVariableElementImpl.EMPTY_ARRAY; | |
| 892 } | |
| 893 List<LocalVariableElement> result = new List.from(_localVariables); | |
| 894 _localVariables = null; | |
| 895 return result; | |
| 896 } | |
| 897 List<MethodElement> get methods { | |
| 898 if (_methods == null) { | |
| 899 return MethodElementImpl.EMPTY_ARRAY; | |
| 900 } | |
| 901 List<MethodElement> result = new List.from(_methods); | |
| 902 _methods = null; | |
| 903 return result; | |
| 904 } | |
| 905 List<ParameterElement> get parameters { | |
| 906 if (_parameters == null) { | |
| 907 return ParameterElementImpl.EMPTY_ARRAY; | |
| 908 } | |
| 909 List<ParameterElement> result = new List.from(_parameters); | |
| 910 _parameters = null; | |
| 911 return result; | |
| 912 } | |
| 913 TopLevelVariableElement getTopLevelVariable(String variableName) { | |
| 914 if (_topLevelVariables == null) { | |
| 915 return null; | |
| 916 } | |
| 917 for (TopLevelVariableElement variable in _topLevelVariables) { | |
| 918 if (variable.name == variableName) { | |
| 919 return variable; | |
| 920 } | |
| 921 } | |
| 922 return null; | |
| 923 } | |
| 924 List<TopLevelVariableElement> get topLevelVariables { | |
| 925 if (_topLevelVariables == null) { | |
| 926 return TopLevelVariableElementImpl.EMPTY_ARRAY; | |
| 927 } | |
| 928 List<TopLevelVariableElement> result = new List.from(_topLevelVariables); | |
| 929 _topLevelVariables = null; | |
| 930 return result; | |
| 931 } | |
| 932 List<FunctionTypeAliasElement> get typeAliases { | |
| 933 if (_typeAliases == null) { | |
| 934 return FunctionTypeAliasElementImpl.EMPTY_ARRAY; | |
| 935 } | |
| 936 List<FunctionTypeAliasElement> result = new List.from(_typeAliases); | |
| 937 _typeAliases = null; | |
| 938 return result; | |
| 939 } | |
| 940 List<TypeParameterElement> get typeParameters { | |
| 941 if (_typeParameters == null) { | |
| 942 return TypeParameterElementImpl.EMPTY_ARRAY; | |
| 943 } | |
| 944 List<TypeParameterElement> result = new List.from(_typeParameters); | |
| 945 _typeParameters = null; | |
| 946 return result; | |
| 947 } | |
| 948 List<ClassElement> get types { | |
| 949 if (_types == null) { | |
| 950 return ClassElementImpl.EMPTY_ARRAY; | |
| 951 } | |
| 952 List<ClassElement> result = new List.from(_types); | |
| 953 _types = null; | |
| 954 return result; | |
| 955 } | |
| 956 void validate() { | |
| 957 JavaStringBuilder builder = new JavaStringBuilder(); | |
| 958 if (_accessors != null) { | |
| 959 builder.append(_accessors.length); | |
| 960 builder.append(" accessors"); | |
| 961 } | |
| 962 if (_constructors != null) { | |
| 963 if (builder.length > 0) { | |
| 964 builder.append("; "); | |
| 965 } | |
| 966 builder.append(_constructors.length); | |
| 967 builder.append(" constructors"); | |
| 968 } | |
| 969 if (_fields != null) { | |
| 970 if (builder.length > 0) { | |
| 971 builder.append("; "); | |
| 972 } | |
| 973 builder.append(_fields.length); | |
| 974 builder.append(" fields"); | |
| 975 } | |
| 976 if (_functions != null) { | |
| 977 if (builder.length > 0) { | |
| 978 builder.append("; "); | |
| 979 } | |
| 980 builder.append(_functions.length); | |
| 981 builder.append(" functions"); | |
| 982 } | |
| 983 if (_labels != null) { | |
| 984 if (builder.length > 0) { | |
| 985 builder.append("; "); | |
| 986 } | |
| 987 builder.append(_labels.length); | |
| 988 builder.append(" labels"); | |
| 989 } | |
| 990 if (_localVariables != null) { | |
| 991 if (builder.length > 0) { | |
| 992 builder.append("; "); | |
| 993 } | |
| 994 builder.append(_localVariables.length); | |
| 995 builder.append(" local variables"); | |
| 996 } | |
| 997 if (_methods != null) { | |
| 998 if (builder.length > 0) { | |
| 999 builder.append("; "); | |
| 1000 } | |
| 1001 builder.append(_methods.length); | |
| 1002 builder.append(" methods"); | |
| 1003 } | |
| 1004 if (_parameters != null) { | |
| 1005 if (builder.length > 0) { | |
| 1006 builder.append("; "); | |
| 1007 } | |
| 1008 builder.append(_parameters.length); | |
| 1009 builder.append(" parameters"); | |
| 1010 } | |
| 1011 if (_topLevelVariables != null) { | |
| 1012 if (builder.length > 0) { | |
| 1013 builder.append("; "); | |
| 1014 } | |
| 1015 builder.append(_topLevelVariables.length); | |
| 1016 builder.append(" top-level variables"); | |
| 1017 } | |
| 1018 if (_types != null) { | |
| 1019 if (builder.length > 0) { | |
| 1020 builder.append("; "); | |
| 1021 } | |
| 1022 builder.append(_types.length); | |
| 1023 builder.append(" types"); | |
| 1024 } | |
| 1025 if (_typeAliases != null) { | |
| 1026 if (builder.length > 0) { | |
| 1027 builder.append("; "); | |
| 1028 } | |
| 1029 builder.append(_typeAliases.length); | |
| 1030 builder.append(" type aliases"); | |
| 1031 } | |
| 1032 if (_typeParameters != null) { | |
| 1033 if (builder.length > 0) { | |
| 1034 builder.append("; "); | |
| 1035 } | |
| 1036 builder.append(_typeParameters.length); | |
| 1037 builder.append(" type parameters"); | |
| 1038 } | |
| 1039 if (builder.length > 0) { | |
| 1040 AnalysisEngine.instance.logger.logError("Failed to capture elements: ${bui
lder.toString()}"); | |
| 1041 } | |
| 1042 } | |
| 1043 } | |
| 1044 /** | |
| 1045 * Instances of the class `HtmlUnitBuilder` build an element model for a single
HTML unit. | |
| 1046 */ | |
| 1047 class HtmlUnitBuilder implements ht.XmlVisitor<Object> { | |
| 1048 static String _APPLICATION_DART_IN_DOUBLE_QUOTES = "\"application/dart\""; | |
| 1049 static String _APPLICATION_DART_IN_SINGLE_QUOTES = "'application/dart'"; | |
| 1050 static String _SCRIPT = "script"; | |
| 1051 static String _SRC = "src"; | |
| 1052 static String _TYPE = "type"; | |
| 1053 | |
| 1054 /** | |
| 1055 * The analysis context in which the element model will be built. | |
| 1056 */ | |
| 1057 InternalAnalysisContext _context; | |
| 1058 | |
| 1059 /** | |
| 1060 * The error listener to which errors will be reported. | |
| 1061 */ | |
| 1062 RecordingErrorListener errorListener; | |
| 1063 | |
| 1064 /** | |
| 1065 * The modification time of the source for which an element is being built. | |
| 1066 */ | |
| 1067 int _modificationStamp = 0; | |
| 1068 | |
| 1069 /** | |
| 1070 * The line information associated with the source for which an element is bei
ng built, or | |
| 1071 * `null` if we are not building an element. | |
| 1072 */ | |
| 1073 LineInfo _lineInfo; | |
| 1074 | |
| 1075 /** | |
| 1076 * The HTML element being built. | |
| 1077 */ | |
| 1078 HtmlElementImpl _htmlElement; | |
| 1079 | |
| 1080 /** | |
| 1081 * The elements in the path from the HTML unit to the current tag node. | |
| 1082 */ | |
| 1083 List<ht.XmlTagNode> _parentNodes; | |
| 1084 | |
| 1085 /** | |
| 1086 * The script elements being built. | |
| 1087 */ | |
| 1088 List<HtmlScriptElement> _scripts; | |
| 1089 | |
| 1090 /** | |
| 1091 * A set of the libraries that were resolved while resolving the HTML unit. | |
| 1092 */ | |
| 1093 final Set<Library> resolvedLibraries = new Set<Library>(); | |
| 1094 | |
| 1095 /** | |
| 1096 * Initialize a newly created HTML unit builder. | |
| 1097 * | |
| 1098 * @param context the analysis context in which the element model will be buil
t | |
| 1099 */ | |
| 1100 HtmlUnitBuilder(InternalAnalysisContext context) { | |
| 1101 this._context = context; | |
| 1102 this.errorListener = new RecordingErrorListener(); | |
| 1103 } | |
| 1104 | |
| 1105 /** | |
| 1106 * Build the HTML element for the given source. | |
| 1107 * | |
| 1108 * @param source the source describing the compilation unit | |
| 1109 * @return the HTML element that was built | |
| 1110 * @throws AnalysisException if the analysis could not be performed | |
| 1111 */ | |
| 1112 HtmlElementImpl buildHtmlElement(Source source) => buildHtmlElement2(source, s
ource.modificationStamp, _context.parseHtmlUnit(source)); | |
| 1113 | |
| 1114 /** | |
| 1115 * Build the HTML element for the given source. | |
| 1116 * | |
| 1117 * @param source the source describing the compilation unit | |
| 1118 * @param modificationStamp the modification time of the source for which an e
lement is being | |
| 1119 * built | |
| 1120 * @param unit the AST structure representing the HTML | |
| 1121 * @throws AnalysisException if the analysis could not be performed | |
| 1122 */ | |
| 1123 HtmlElementImpl buildHtmlElement2(Source source, int modificationStamp, ht.Htm
lUnit unit) { | |
| 1124 this._modificationStamp = modificationStamp; | |
| 1125 _lineInfo = _context.computeLineInfo(source); | |
| 1126 HtmlElementImpl result = new HtmlElementImpl(_context, source.shortName); | |
| 1127 result.source = source; | |
| 1128 _htmlElement = result; | |
| 1129 unit.accept(this); | |
| 1130 _htmlElement = null; | |
| 1131 unit.element = result; | |
| 1132 return result; | |
| 1133 } | |
| 1134 Object visitHtmlUnit(ht.HtmlUnit node) { | |
| 1135 _parentNodes = new List<ht.XmlTagNode>(); | |
| 1136 _scripts = new List<HtmlScriptElement>(); | |
| 1137 try { | |
| 1138 node.visitChildren(this); | |
| 1139 _htmlElement.scripts = new List.from(_scripts); | |
| 1140 } finally { | |
| 1141 _scripts = null; | |
| 1142 _parentNodes = null; | |
| 1143 } | |
| 1144 return null; | |
| 1145 } | |
| 1146 Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null; | |
| 1147 Object visitXmlTagNode(ht.XmlTagNode node) { | |
| 1148 if (_parentNodes.contains(node)) { | |
| 1149 JavaStringBuilder builder = new JavaStringBuilder(); | |
| 1150 builder.append("Found circularity in XML nodes: "); | |
| 1151 bool first = true; | |
| 1152 for (ht.XmlTagNode pathNode in _parentNodes) { | |
| 1153 if (first) { | |
| 1154 first = false; | |
| 1155 } else { | |
| 1156 builder.append(", "); | |
| 1157 } | |
| 1158 String tagName = pathNode.tag.lexeme; | |
| 1159 if (identical(pathNode, node)) { | |
| 1160 builder.append("*"); | |
| 1161 builder.append(tagName); | |
| 1162 builder.append("*"); | |
| 1163 } else { | |
| 1164 builder.append(tagName); | |
| 1165 } | |
| 1166 } | |
| 1167 AnalysisEngine.instance.logger.logError(builder.toString()); | |
| 1168 return null; | |
| 1169 } | |
| 1170 _parentNodes.add(node); | |
| 1171 try { | |
| 1172 if (isScriptNode(node)) { | |
| 1173 Source htmlSource = _htmlElement.source; | |
| 1174 ht.XmlAttributeNode scriptAttribute = getScriptSourcePath(node); | |
| 1175 String scriptSourcePath = scriptAttribute == null ? null : scriptAttribu
te.text; | |
| 1176 if (identical(node.attributeEnd.type, ht.TokenType.GT) && scriptSourcePa
th == null) { | |
| 1177 EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementIm
pl(node); | |
| 1178 String contents = node.content; | |
| 1179 int attributeEnd = node.attributeEnd.end; | |
| 1180 LineInfo_Location location = _lineInfo.getLocation(attributeEnd); | |
| 1181 sc.Scanner scanner = new sc.Scanner(htmlSource, new sc.SubSequenceRead
er(new CharSequence(contents), attributeEnd), errorListener); | |
| 1182 scanner.setSourceStart(location.lineNumber, location.columnNumber); | |
| 1183 sc.Token firstToken = scanner.tokenize(); | |
| 1184 List<int> lineStarts = scanner.lineStarts; | |
| 1185 Parser parser = new Parser(htmlSource, errorListener); | |
| 1186 CompilationUnit unit = parser.parseCompilationUnit(firstToken); | |
| 1187 try { | |
| 1188 LibraryResolver resolver = new LibraryResolver(_context); | |
| 1189 LibraryElementImpl library = resolver.resolveEmbeddedLibrary(htmlSou
rce, _modificationStamp, unit, true) as LibraryElementImpl; | |
| 1190 script.scriptLibrary = library; | |
| 1191 resolvedLibraries.addAll(resolver.resolvedLibraries); | |
| 1192 errorListener.addAll(resolver.errorListener); | |
| 1193 } on AnalysisException catch (exception) { | |
| 1194 AnalysisEngine.instance.logger.logError3(exception); | |
| 1195 } | |
| 1196 _scripts.add(script); | |
| 1197 } else { | |
| 1198 ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementIm
pl(node); | |
| 1199 if (scriptSourcePath != null) { | |
| 1200 try { | |
| 1201 scriptSourcePath = Uri.encodeFull(scriptSourcePath); | |
| 1202 parseUriWithException(scriptSourcePath); | |
| 1203 Source scriptSource = _context.sourceFactory.resolveUri(htmlSource
, scriptSourcePath); | |
| 1204 script.scriptSource = scriptSource; | |
| 1205 if (scriptSource == null || !scriptSource.exists()) { | |
| 1206 reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttri
bute, [scriptSourcePath]); | |
| 1207 } | |
| 1208 } on URISyntaxException catch (exception) { | |
| 1209 reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, [sc
riptSourcePath]); | |
| 1210 } | |
| 1211 } | |
| 1212 _scripts.add(script); | |
| 1213 } | |
| 1214 } else { | |
| 1215 node.visitChildren(this); | |
| 1216 } | |
| 1217 } finally { | |
| 1218 _parentNodes.remove(node); | |
| 1219 } | |
| 1220 return null; | |
| 1221 } | |
| 1222 | |
| 1223 /** | |
| 1224 * Return the first source attribute for the given tag node, or `null` if it d
oes not exist. | |
| 1225 * | |
| 1226 * @param node the node containing attributes | |
| 1227 * @return the source attribute contained in the given tag | |
| 1228 */ | |
| 1229 ht.XmlAttributeNode getScriptSourcePath(ht.XmlTagNode node) { | |
| 1230 for (ht.XmlAttributeNode attribute in node.attributes) { | |
| 1231 if (attribute.name.lexeme == _SRC) { | |
| 1232 return attribute; | |
| 1233 } | |
| 1234 } | |
| 1235 return null; | |
| 1236 } | |
| 1237 | |
| 1238 /** | |
| 1239 * Determine if the specified node is a Dart script. | |
| 1240 * | |
| 1241 * @param node the node to be tested (not `null`) | |
| 1242 * @return `true` if the node is a Dart script | |
| 1243 */ | |
| 1244 bool isScriptNode(ht.XmlTagNode node) { | |
| 1245 if (node.tagNodes.length != 0 || node.tag.lexeme != _SCRIPT) { | |
| 1246 return false; | |
| 1247 } | |
| 1248 for (ht.XmlAttributeNode attribute in node.attributes) { | |
| 1249 if (attribute.name.lexeme == _TYPE) { | |
| 1250 ht.Token valueToken = attribute.value; | |
| 1251 if (valueToken != null) { | |
| 1252 String value = valueToken.lexeme; | |
| 1253 if (value == _APPLICATION_DART_IN_DOUBLE_QUOTES || value == _APPLICATI
ON_DART_IN_SINGLE_QUOTES) { | |
| 1254 return true; | |
| 1255 } | |
| 1256 } | |
| 1257 } | |
| 1258 } | |
| 1259 return false; | |
| 1260 } | |
| 1261 | |
| 1262 /** | |
| 1263 * Report an error with the given error code at the given location. Use the gi
ven arguments to | |
| 1264 * compose the error message. | |
| 1265 * | |
| 1266 * @param errorCode the error code of the error to be reported | |
| 1267 * @param offset the offset of the first character to be highlighted | |
| 1268 * @param length the number of characters to be highlighted | |
| 1269 * @param arguments the arguments used to compose the error message | |
| 1270 */ | |
| 1271 void reportError(ErrorCode errorCode, int offset, int length, List<Object> arg
uments) { | |
| 1272 errorListener.onError(new AnalysisError.con2(_htmlElement.source, offset, le
ngth, errorCode, arguments)); | |
| 1273 } | |
| 1274 | |
| 1275 /** | |
| 1276 * Report an error with the given error code at the location of the value of t
he given attribute. | |
| 1277 * Use the given arguments to compose the error message. | |
| 1278 * | |
| 1279 * @param errorCode the error code of the error to be reported | |
| 1280 * @param offset the offset of the first character to be highlighted | |
| 1281 * @param length the number of characters to be highlighted | |
| 1282 * @param arguments the arguments used to compose the error message | |
| 1283 */ | |
| 1284 void reportValueError(ErrorCode errorCode, ht.XmlAttributeNode attribute, List
<Object> arguments) { | |
| 1285 int offset = attribute.value.offset + 1; | |
| 1286 int length = attribute.value.length - 2; | |
| 1287 reportError(errorCode, offset, length, arguments); | |
| 1288 } | |
| 1289 } | |
| 1290 /** | |
| 1291 * Instances of the class `BestPracticesVerifier` traverse an AST structure look
ing for | |
| 1292 * violations of Dart best practices. | |
| 1293 * | |
| 1294 * @coverage dart.engine.resolver | |
| 1295 */ | |
| 1296 class BestPracticesVerifier extends RecursiveASTVisitor<Object> { | |
| 1297 static String _GETTER = "getter"; | |
| 1298 static String _HASHCODE_GETTER_NAME = "hashCode"; | |
| 1299 static String _METHOD = "method"; | |
| 1300 static String _NULL_TYPE_NAME = "Null"; | |
| 1301 static String _SETTER = "setter"; | |
| 1302 static String _TO_INT_METHOD_NAME = "toInt"; | |
| 1303 | |
| 1304 /** | |
| 1305 * Given a parenthesized expression, this returns the parent (or recursively g
rand-parent) of the | |
| 1306 * expression that is a parenthesized expression, but whose parent is not a pa
renthesized | |
| 1307 * expression. | |
| 1308 * | |
| 1309 * For example given the code `(((e)))`: `(e) -> (((e)))`. | |
| 1310 * | |
| 1311 * @param parenthesizedExpression some expression whose parent is a parenthesi
zed expression | |
| 1312 * @return the first parent or grand-parent that is a parenthesized expression
, that does not have | |
| 1313 * a parenthesized expression parent | |
| 1314 */ | |
| 1315 static ParenthesizedExpression wrapParenthesizedExpression(ParenthesizedExpres
sion parenthesizedExpression) { | |
| 1316 if (parenthesizedExpression.parent is ParenthesizedExpression) { | |
| 1317 return wrapParenthesizedExpression(parenthesizedExpression.parent as Paren
thesizedExpression); | |
| 1318 } | |
| 1319 return parenthesizedExpression; | |
| 1320 } | |
| 1321 | |
| 1322 /** | |
| 1323 * The class containing the AST nodes being visited, or `null` if we are not i
n the scope of | |
| 1324 * a class. | |
| 1325 */ | |
| 1326 ClassElement _enclosingClass; | |
| 1327 | |
| 1328 /** | |
| 1329 * The error reporter by which errors will be reported. | |
| 1330 */ | |
| 1331 ErrorReporter _errorReporter; | |
| 1332 | |
| 1333 /** | |
| 1334 * Create a new instance of the [BestPracticesVerifier]. | |
| 1335 * | |
| 1336 * @param errorReporter the error reporter | |
| 1337 */ | |
| 1338 BestPracticesVerifier(ErrorReporter errorReporter) { | |
| 1339 this._errorReporter = errorReporter; | |
| 1340 } | |
| 1341 Object visitAsExpression(AsExpression node) { | |
| 1342 checkForUnnecessaryCast(node); | |
| 1343 return super.visitAsExpression(node); | |
| 1344 } | |
| 1345 Object visitBinaryExpression(BinaryExpression node) { | |
| 1346 checkForDivisionOptimizationHint(node); | |
| 1347 return super.visitBinaryExpression(node); | |
| 1348 } | |
| 1349 Object visitClassDeclaration(ClassDeclaration node) { | |
| 1350 ClassElement outerClass = _enclosingClass; | |
| 1351 try { | |
| 1352 _enclosingClass = node.element; | |
| 1353 return super.visitClassDeclaration(node); | |
| 1354 } finally { | |
| 1355 _enclosingClass = outerClass; | |
| 1356 } | |
| 1357 } | |
| 1358 Object visitIsExpression(IsExpression node) { | |
| 1359 checkAllTypeChecks(node); | |
| 1360 return super.visitIsExpression(node); | |
| 1361 } | |
| 1362 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 1363 checkForOverridingPrivateMember(node); | |
| 1364 return super.visitMethodDeclaration(node); | |
| 1365 } | |
| 1366 | |
| 1367 /** | |
| 1368 * Check for the passed is expression for the unnecessary type check hint code
s as well as null | |
| 1369 * checks expressed using an is expression. | |
| 1370 * | |
| 1371 * @param node the is expression to check | |
| 1372 * @return `true` if and only if a hint code is generated on the passed node | |
| 1373 * @see HintCode#TYPE_CHECK_IS_NOT_NULL | |
| 1374 * @see HintCode#TYPE_CHECK_IS_NULL | |
| 1375 * @see HintCode#UNNECESSARY_TYPE_CHECK_TRUE | |
| 1376 * @see HintCode#UNNECESSARY_TYPE_CHECK_FALSE | |
| 1377 */ | |
| 1378 bool checkAllTypeChecks(IsExpression node) { | |
| 1379 Expression expression = node.expression; | |
| 1380 TypeName typeName = node.type; | |
| 1381 Type2 lhsType = expression.staticType; | |
| 1382 Type2 rhsType = typeName.type; | |
| 1383 if (lhsType == null || rhsType == null) { | |
| 1384 return false; | |
| 1385 } | |
| 1386 String rhsNameStr = typeName.name.name; | |
| 1387 if (rhsType.isDynamic && rhsNameStr == sc.Keyword.DYNAMIC.syntax) { | |
| 1388 if (node.notOperator == null) { | |
| 1389 _errorReporter.reportError2(HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node,
[]); | |
| 1390 } else { | |
| 1391 _errorReporter.reportError2(HintCode.UNNECESSARY_TYPE_CHECK_FALSE, node,
[]); | |
| 1392 } | |
| 1393 return true; | |
| 1394 } | |
| 1395 Element rhsElement = rhsType.element; | |
| 1396 LibraryElement libraryElement = rhsElement != null ? rhsElement.library : nu
ll; | |
| 1397 if (libraryElement != null && libraryElement.isDartCore) { | |
| 1398 if (rhsType.isObject || (expression is NullLiteral && rhsNameStr == _NULL_
TYPE_NAME)) { | |
| 1399 if (node.notOperator == null) { | |
| 1400 _errorReporter.reportError2(HintCode.UNNECESSARY_TYPE_CHECK_TRUE, node
, []); | |
| 1401 } else { | |
| 1402 _errorReporter.reportError2(HintCode.UNNECESSARY_TYPE_CHECK_FALSE, nod
e, []); | |
| 1403 } | |
| 1404 return true; | |
| 1405 } else if (rhsNameStr == _NULL_TYPE_NAME) { | |
| 1406 if (node.notOperator == null) { | |
| 1407 _errorReporter.reportError2(HintCode.TYPE_CHECK_IS_NULL, node, []); | |
| 1408 } else { | |
| 1409 _errorReporter.reportError2(HintCode.TYPE_CHECK_IS_NOT_NULL, node, [])
; | |
| 1410 } | |
| 1411 return true; | |
| 1412 } | |
| 1413 } | |
| 1414 return false; | |
| 1415 } | |
| 1416 | |
| 1417 /** | |
| 1418 * Check for the passed binary expression for the [HintCode#DIVISION_OPTIMIZAT
ION]. | |
| 1419 * | |
| 1420 * @param node the binary expression to check | |
| 1421 * @return `true` if and only if a hint code is generated on the passed node | |
| 1422 * @see HintCode#DIVISION_OPTIMIZATION | |
| 1423 */ | |
| 1424 bool checkForDivisionOptimizationHint(BinaryExpression node) { | |
| 1425 if (node.operator.type != sc.TokenType.SLASH) { | |
| 1426 return false; | |
| 1427 } | |
| 1428 MethodElement methodElement = node.bestElement; | |
| 1429 if (methodElement == null) { | |
| 1430 return false; | |
| 1431 } | |
| 1432 LibraryElement libraryElement = methodElement.library; | |
| 1433 if (libraryElement != null && !libraryElement.isDartCore) { | |
| 1434 return false; | |
| 1435 } | |
| 1436 if (node.parent is ParenthesizedExpression) { | |
| 1437 ParenthesizedExpression parenthesizedExpression = wrapParenthesizedExpress
ion(node.parent as ParenthesizedExpression); | |
| 1438 if (parenthesizedExpression.parent is MethodInvocation) { | |
| 1439 MethodInvocation methodInvocation = parenthesizedExpression.parent as Me
thodInvocation; | |
| 1440 if (_TO_INT_METHOD_NAME == methodInvocation.methodName.name && methodInv
ocation.argumentList.arguments.isEmpty) { | |
| 1441 _errorReporter.reportError2(HintCode.DIVISION_OPTIMIZATION, methodInvo
cation, []); | |
| 1442 return true; | |
| 1443 } | |
| 1444 } | |
| 1445 } | |
| 1446 return false; | |
| 1447 } | |
| 1448 | |
| 1449 /** | |
| 1450 * Check for the passed class declaration for the | |
| 1451 * [HintCode#OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. | |
| 1452 * | |
| 1453 * @param node the class declaration to check | |
| 1454 * @return `true` if and only if a hint code is generated on the passed node | |
| 1455 * @see HintCode#OVERRIDE_EQUALS_BUT_NOT_HASH_CODE | |
| 1456 */ | |
| 1457 bool checkForOverrideEqualsButNotHashCode(ClassDeclaration node) { | |
| 1458 ClassElement classElement = node.element; | |
| 1459 if (classElement == null) { | |
| 1460 return false; | |
| 1461 } | |
| 1462 MethodElement equalsOperatorMethodElement = classElement.getMethod(sc.TokenT
ype.EQ_EQ.lexeme); | |
| 1463 if (equalsOperatorMethodElement != null) { | |
| 1464 PropertyAccessorElement hashCodeElement = classElement.getGetter(_HASHCODE
_GETTER_NAME); | |
| 1465 if (hashCodeElement == null) { | |
| 1466 _errorReporter.reportError2(HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
node.name, [classElement.displayName]); | |
| 1467 return true; | |
| 1468 } | |
| 1469 } | |
| 1470 return false; | |
| 1471 } | |
| 1472 | |
| 1473 /** | |
| 1474 * Check for the passed class declaration for the | |
| 1475 * [HintCode#OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code. | |
| 1476 * | |
| 1477 * @param node the class declaration to check | |
| 1478 * @return `true` if and only if a hint code is generated on the passed node | |
| 1479 * @see HintCode#OVERRIDDING_PRIVATE_MEMBER | |
| 1480 */ | |
| 1481 bool checkForOverridingPrivateMember(MethodDeclaration node) { | |
| 1482 if (_enclosingClass == null) { | |
| 1483 return false; | |
| 1484 } | |
| 1485 if (!Identifier.isPrivateName(node.name.name)) { | |
| 1486 return false; | |
| 1487 } | |
| 1488 ExecutableElement executableElement = node.element; | |
| 1489 if (executableElement == null) { | |
| 1490 return false; | |
| 1491 } | |
| 1492 String elementName = executableElement.name; | |
| 1493 bool isGetterOrSetter = executableElement is PropertyAccessorElement; | |
| 1494 InterfaceType superType = _enclosingClass.supertype; | |
| 1495 if (superType == null) { | |
| 1496 return false; | |
| 1497 } | |
| 1498 ClassElement classElement = superType.element; | |
| 1499 while (classElement != null) { | |
| 1500 if (_enclosingClass.library != classElement.library) { | |
| 1501 if (isGetterOrSetter) { | |
| 1502 PropertyAccessorElement overriddenAccessor = null; | |
| 1503 List<PropertyAccessorElement> accessors = classElement.accessors; | |
| 1504 for (PropertyAccessorElement propertyAccessorElement in accessors) { | |
| 1505 if (elementName == propertyAccessorElement.name) { | |
| 1506 overriddenAccessor = propertyAccessorElement; | |
| 1507 break; | |
| 1508 } | |
| 1509 } | |
| 1510 if (overriddenAccessor != null) { | |
| 1511 String memberType = ((executableElement as PropertyAccessorElement))
.isGetter ? _GETTER : _SETTER; | |
| 1512 _errorReporter.reportError2(HintCode.OVERRIDDING_PRIVATE_MEMBER, nod
e.name, [ | |
| 1513 memberType, | |
| 1514 executableElement.displayName, | |
| 1515 classElement.displayName]); | |
| 1516 return true; | |
| 1517 } | |
| 1518 } else { | |
| 1519 MethodElement overriddenMethod = classElement.getMethod(elementName); | |
| 1520 if (overriddenMethod != null) { | |
| 1521 _errorReporter.reportError2(HintCode.OVERRIDDING_PRIVATE_MEMBER, nod
e.name, [ | |
| 1522 _METHOD, | |
| 1523 executableElement.displayName, | |
| 1524 classElement.displayName]); | |
| 1525 return true; | |
| 1526 } | |
| 1527 } | |
| 1528 } | |
| 1529 superType = classElement.supertype; | |
| 1530 classElement = superType != null ? superType.element : null; | |
| 1531 } | |
| 1532 return false; | |
| 1533 } | |
| 1534 | |
| 1535 /** | |
| 1536 * Check for the passed as expression for the [HintCode#UNNECESSARY_CAST] hint
code. | |
| 1537 * | |
| 1538 * @param node the as expression to check | |
| 1539 * @return `true` if and only if a hint code is generated on the passed node | |
| 1540 * @see HintCode#UNNECESSARY_CAST | |
| 1541 */ | |
| 1542 bool checkForUnnecessaryCast(AsExpression node) { | |
| 1543 Expression expression = node.expression; | |
| 1544 TypeName typeName = node.type; | |
| 1545 Type2 lhsType = expression.staticType; | |
| 1546 Type2 rhsType = typeName.type; | |
| 1547 if (lhsType != null && rhsType != null && !lhsType.isDynamic && !rhsType.isD
ynamic && lhsType is! TypeParameterType && rhsType is! TypeParameterType && lhsT
ype.isSubtypeOf(rhsType)) { | |
| 1548 _errorReporter.reportError2(HintCode.UNNECESSARY_CAST, node, []); | |
| 1549 return true; | |
| 1550 } | |
| 1551 return false; | |
| 1552 } | |
| 1553 } | |
| 1554 /** | |
| 1555 * Instances of the class `Dart2JSVerifier` traverse an AST structure looking fo
r hints for | |
| 1556 * code that will be compiled to JS, such as [HintCode#IS_DOUBLE]. | |
| 1557 * | |
| 1558 * @coverage dart.engine.resolver | |
| 1559 */ | |
| 1560 class Dart2JSVerifier extends RecursiveASTVisitor<Object> { | |
| 1561 | |
| 1562 /** | |
| 1563 * The error reporter by which errors will be reported. | |
| 1564 */ | |
| 1565 ErrorReporter _errorReporter; | |
| 1566 | |
| 1567 /** | |
| 1568 * The name of the `double` type. | |
| 1569 */ | |
| 1570 static String _DOUBLE_TYPE_NAME = "double"; | |
| 1571 | |
| 1572 /** | |
| 1573 * Create a new instance of the [Dart2JSVerifier]. | |
| 1574 * | |
| 1575 * @param errorReporter the error reporter | |
| 1576 */ | |
| 1577 Dart2JSVerifier(ErrorReporter errorReporter) { | |
| 1578 this._errorReporter = errorReporter; | |
| 1579 } | |
| 1580 Object visitIsExpression(IsExpression node) { | |
| 1581 checkForIsDoubleHints(node); | |
| 1582 return super.visitIsExpression(node); | |
| 1583 } | |
| 1584 | |
| 1585 /** | |
| 1586 * Check for instances of `x is double`, `x is int`, `x is! double` and | |
| 1587 * `x is! int`. | |
| 1588 * | |
| 1589 * @param node the is expression to check | |
| 1590 * @return `true` if and only if a hint code is generated on the passed node | |
| 1591 * @see HintCode#IS_DOUBLE | |
| 1592 * @see HintCode#IS_INT | |
| 1593 * @see HintCode#IS_NOT_DOUBLE | |
| 1594 * @see HintCode#IS_NOT_INT | |
| 1595 */ | |
| 1596 bool checkForIsDoubleHints(IsExpression node) { | |
| 1597 TypeName typeName = node.type; | |
| 1598 Type2 type = typeName.type; | |
| 1599 if (type != null && type.element != null) { | |
| 1600 Element element = type.element; | |
| 1601 String typeNameStr = element.name; | |
| 1602 LibraryElement libraryElement = element.library; | |
| 1603 if (typeNameStr == _DOUBLE_TYPE_NAME && libraryElement != null && libraryE
lement.isDartCore) { | |
| 1604 if (node.notOperator == null) { | |
| 1605 _errorReporter.reportError2(HintCode.IS_DOUBLE, node, []); | |
| 1606 } else { | |
| 1607 _errorReporter.reportError2(HintCode.IS_NOT_DOUBLE, node, []); | |
| 1608 } | |
| 1609 return true; | |
| 1610 } | |
| 1611 } | |
| 1612 return false; | |
| 1613 } | |
| 1614 } | |
| 1615 /** | |
| 1616 * Instances of the class `DeadCodeVerifier` traverse an AST structure looking f
or cases of | |
| 1617 * [HintCode#DEAD_CODE]. | |
| 1618 * | |
| 1619 * @coverage dart.engine.resolver | |
| 1620 */ | |
| 1621 class DeadCodeVerifier extends RecursiveASTVisitor<Object> { | |
| 1622 | |
| 1623 /** | |
| 1624 * The error reporter by which errors will be reported. | |
| 1625 */ | |
| 1626 ErrorReporter _errorReporter; | |
| 1627 | |
| 1628 /** | |
| 1629 * Create a new instance of the [DeadCodeVerifier]. | |
| 1630 * | |
| 1631 * @param errorReporter the error reporter | |
| 1632 */ | |
| 1633 DeadCodeVerifier(ErrorReporter errorReporter) { | |
| 1634 this._errorReporter = errorReporter; | |
| 1635 } | |
| 1636 Object visitBinaryExpression(BinaryExpression node) { | |
| 1637 sc.Token operator = node.operator; | |
| 1638 bool isAmpAmp = identical(operator.type, sc.TokenType.AMPERSAND_AMPERSAND); | |
| 1639 bool isBarBar = identical(operator.type, sc.TokenType.BAR_BAR); | |
| 1640 if (isAmpAmp || isBarBar) { | |
| 1641 Expression lhsCondition = node.leftOperand; | |
| 1642 if (!isDebugConstant(lhsCondition)) { | |
| 1643 ValidResult lhsResult = getConstantBooleanValue(lhsCondition); | |
| 1644 if (lhsResult != null) { | |
| 1645 if (identical(lhsResult, ValidResult.RESULT_TRUE) && isBarBar) { | |
| 1646 _errorReporter.reportError2(HintCode.DEAD_CODE, node.rightOperand, [
]); | |
| 1647 safelyVisit(lhsCondition); | |
| 1648 return null; | |
| 1649 } else if (identical(lhsResult, ValidResult.RESULT_FALSE) && isAmpAmp)
{ | |
| 1650 _errorReporter.reportError2(HintCode.DEAD_CODE, node.rightOperand, [
]); | |
| 1651 safelyVisit(lhsCondition); | |
| 1652 return null; | |
| 1653 } | |
| 1654 } | |
| 1655 } | |
| 1656 } | |
| 1657 return super.visitBinaryExpression(node); | |
| 1658 } | |
| 1659 | |
| 1660 /** | |
| 1661 * For each [Block], this method reports and error on all statements between t
he end of the | |
| 1662 * block and the first return statement (assuming there it is not at the end o
f the block.) | |
| 1663 * | |
| 1664 * @param node the block to evaluate | |
| 1665 */ | |
| 1666 Object visitBlock(Block node) { | |
| 1667 NodeList<Statement> statements = node.statements; | |
| 1668 int size = statements.length; | |
| 1669 for (int i = 0; i < size; i++) { | |
| 1670 Statement currentStatement = statements[i]; | |
| 1671 safelyVisit(currentStatement); | |
| 1672 if (currentStatement is ReturnStatement && i != size - 1) { | |
| 1673 Statement nextStatement = statements[i + 1]; | |
| 1674 Statement lastStatement = statements[size - 1]; | |
| 1675 int offset = nextStatement.offset; | |
| 1676 int length = lastStatement.end - offset; | |
| 1677 _errorReporter.reportError3(HintCode.DEAD_CODE, offset, length, []); | |
| 1678 return null; | |
| 1679 } | |
| 1680 } | |
| 1681 return null; | |
| 1682 } | |
| 1683 Object visitConditionalExpression(ConditionalExpression node) { | |
| 1684 Expression conditionExpression = node.condition; | |
| 1685 safelyVisit(conditionExpression); | |
| 1686 if (!isDebugConstant(conditionExpression)) { | |
| 1687 ValidResult result = getConstantBooleanValue(conditionExpression); | |
| 1688 if (result != null) { | |
| 1689 if (identical(result, ValidResult.RESULT_TRUE)) { | |
| 1690 _errorReporter.reportError2(HintCode.DEAD_CODE, node.elseExpression, [
]); | |
| 1691 safelyVisit(node.thenExpression); | |
| 1692 return null; | |
| 1693 } else { | |
| 1694 _errorReporter.reportError2(HintCode.DEAD_CODE, node.thenExpression, [
]); | |
| 1695 safelyVisit(node.elseExpression); | |
| 1696 return null; | |
| 1697 } | |
| 1698 } | |
| 1699 } | |
| 1700 return super.visitConditionalExpression(node); | |
| 1701 } | |
| 1702 Object visitIfStatement(IfStatement node) { | |
| 1703 Expression conditionExpression = node.condition; | |
| 1704 safelyVisit(conditionExpression); | |
| 1705 if (!isDebugConstant(conditionExpression)) { | |
| 1706 ValidResult result = getConstantBooleanValue(conditionExpression); | |
| 1707 if (result != null) { | |
| 1708 if (identical(result, ValidResult.RESULT_TRUE)) { | |
| 1709 Statement elseStatement = node.elseStatement; | |
| 1710 if (elseStatement != null) { | |
| 1711 _errorReporter.reportError2(HintCode.DEAD_CODE, elseStatement, []); | |
| 1712 safelyVisit(node.thenStatement); | |
| 1713 return null; | |
| 1714 } | |
| 1715 } else { | |
| 1716 _errorReporter.reportError2(HintCode.DEAD_CODE, node.thenStatement, []
); | |
| 1717 safelyVisit(node.elseStatement); | |
| 1718 return null; | |
| 1719 } | |
| 1720 } | |
| 1721 } | |
| 1722 return super.visitIfStatement(node); | |
| 1723 } | |
| 1724 Object visitTryStatement(TryStatement node) { | |
| 1725 safelyVisit(node.body); | |
| 1726 safelyVisit(node.finallyBlock); | |
| 1727 NodeList<CatchClause> catchClauses = node.catchClauses; | |
| 1728 int numOfCatchClauses = catchClauses.length; | |
| 1729 List<Type2> visitedTypes = new List<Type2>(); | |
| 1730 for (int i = 0; i < numOfCatchClauses; i++) { | |
| 1731 CatchClause catchClause = catchClauses[i]; | |
| 1732 if (catchClause.onKeyword != null) { | |
| 1733 TypeName typeName = catchClause.exceptionType; | |
| 1734 if (typeName != null && typeName.type != null) { | |
| 1735 Type2 currentType = typeName.type; | |
| 1736 if (currentType.isObject) { | |
| 1737 safelyVisit(catchClause); | |
| 1738 if (i + 1 != numOfCatchClauses) { | |
| 1739 CatchClause nextCatchClause = catchClauses[i + 1]; | |
| 1740 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; | |
| 1741 int offset = nextCatchClause.offset; | |
| 1742 int length = lastCatchClause.end - offset; | |
| 1743 _errorReporter.reportError3(HintCode.DEAD_CODE_CATCH_FOLLOWING_CAT
CH, offset, length, []); | |
| 1744 return null; | |
| 1745 } | |
| 1746 } | |
| 1747 for (Type2 type in visitedTypes) { | |
| 1748 if (currentType.isSubtypeOf(type)) { | |
| 1749 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; | |
| 1750 int offset = catchClause.offset; | |
| 1751 int length = lastCatchClause.end - offset; | |
| 1752 _errorReporter.reportError3(HintCode.DEAD_CODE_ON_CATCH_SUBTYPE, o
ffset, length, [currentType.displayName, type.displayName]); | |
| 1753 return null; | |
| 1754 } | |
| 1755 } | |
| 1756 visitedTypes.add(currentType); | |
| 1757 } | |
| 1758 safelyVisit(catchClause); | |
| 1759 } else { | |
| 1760 safelyVisit(catchClause); | |
| 1761 if (i + 1 != numOfCatchClauses) { | |
| 1762 CatchClause nextCatchClause = catchClauses[i + 1]; | |
| 1763 CatchClause lastCatchClause = catchClauses[numOfCatchClauses - 1]; | |
| 1764 int offset = nextCatchClause.offset; | |
| 1765 int length = lastCatchClause.end - offset; | |
| 1766 _errorReporter.reportError3(HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
offset, length, []); | |
| 1767 return null; | |
| 1768 } | |
| 1769 } | |
| 1770 } | |
| 1771 return null; | |
| 1772 } | |
| 1773 Object visitWhileStatement(WhileStatement node) { | |
| 1774 Expression conditionExpression = node.condition; | |
| 1775 safelyVisit(conditionExpression); | |
| 1776 if (!isDebugConstant(conditionExpression)) { | |
| 1777 ValidResult result = getConstantBooleanValue(conditionExpression); | |
| 1778 if (result != null) { | |
| 1779 if (identical(result, ValidResult.RESULT_FALSE)) { | |
| 1780 _errorReporter.reportError2(HintCode.DEAD_CODE, node.body, []); | |
| 1781 return null; | |
| 1782 } | |
| 1783 } | |
| 1784 } | |
| 1785 safelyVisit(node.body); | |
| 1786 return null; | |
| 1787 } | |
| 1788 | |
| 1789 /** | |
| 1790 * Given some [Expression], this method returns [ValidResult#RESULT_TRUE] if i
t is | |
| 1791 * `true`, [ValidResult#RESULT_FALSE] if it is `false`, or `null` if the | |
| 1792 * expression is not a constant boolean value. | |
| 1793 * | |
| 1794 * @param expression the expression to evaluate | |
| 1795 * @return [ValidResult#RESULT_TRUE] if it is `true`, [ValidResult#RESULT_FALS
E] | |
| 1796 * if it is `false`, or `null` if the expression is not a constant boo
lean | |
| 1797 * value | |
| 1798 */ | |
| 1799 ValidResult getConstantBooleanValue(Expression expression) { | |
| 1800 if (expression is BooleanLiteral) { | |
| 1801 if (((expression as BooleanLiteral)).value) { | |
| 1802 return ValidResult.RESULT_TRUE; | |
| 1803 } else { | |
| 1804 return ValidResult.RESULT_FALSE; | |
| 1805 } | |
| 1806 } | |
| 1807 return null; | |
| 1808 } | |
| 1809 | |
| 1810 /** | |
| 1811 * Return `true` if and only if the passed expression is resolved to a constan
t variable. | |
| 1812 * | |
| 1813 * @param expression some conditional expression | |
| 1814 * @return `true` if and only if the passed expression is resolved to a consta
nt variable | |
| 1815 */ | |
| 1816 bool isDebugConstant(Expression expression) { | |
| 1817 Element element = null; | |
| 1818 if (expression is Identifier) { | |
| 1819 Identifier identifier = expression as Identifier; | |
| 1820 element = identifier.staticElement; | |
| 1821 } else if (expression is PropertyAccess) { | |
| 1822 PropertyAccess propertyAccess = expression as PropertyAccess; | |
| 1823 element = propertyAccess.propertyName.staticElement; | |
| 1824 } | |
| 1825 if (element is PropertyAccessorElement) { | |
| 1826 PropertyAccessorElement pae = element as PropertyAccessorElement; | |
| 1827 PropertyInducingElement variable = pae.variable; | |
| 1828 return variable != null && variable.isConst; | |
| 1829 } | |
| 1830 return false; | |
| 1831 } | |
| 1832 | |
| 1833 /** | |
| 1834 * If the given node is not `null`, visit this instance of the dead code verif
ier. | |
| 1835 * | |
| 1836 * @param node the node to be visited | |
| 1837 */ | |
| 1838 void safelyVisit(ASTNode node) { | |
| 1839 if (node != null) { | |
| 1840 node.accept(this); | |
| 1841 } | |
| 1842 } | |
| 1843 } | |
| 1844 /** | |
| 1845 * Instances of the class `HintGenerator` traverse a library's worth of dart cod
e at a time to | |
| 1846 * generate hints over the set of sources. | |
| 1847 * | |
| 1848 * @see HintCode | |
| 1849 * @coverage dart.engine.resolver | |
| 1850 */ | |
| 1851 class HintGenerator { | |
| 1852 List<CompilationUnit> _compilationUnits; | |
| 1853 AnalysisContext _context; | |
| 1854 AnalysisErrorListener _errorListener; | |
| 1855 ImportsVerifier _importsVerifier; | |
| 1856 bool _enableDart2JSHints = false; | |
| 1857 HintGenerator(List<CompilationUnit> compilationUnits, AnalysisContext context,
AnalysisErrorListener errorListener) { | |
| 1858 this._compilationUnits = compilationUnits; | |
| 1859 this._context = context; | |
| 1860 this._errorListener = errorListener; | |
| 1861 LibraryElement library = compilationUnits[0].element.library; | |
| 1862 _importsVerifier = new ImportsVerifier(library); | |
| 1863 _enableDart2JSHints = context.analysisOptions.dart2jsHint; | |
| 1864 } | |
| 1865 void generateForLibrary() { | |
| 1866 TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.hints.star
t(); | |
| 1867 try { | |
| 1868 for (int i = 0; i < _compilationUnits.length; i++) { | |
| 1869 CompilationUnitElement element = _compilationUnits[i].element; | |
| 1870 if (element != null) { | |
| 1871 if (i == 0) { | |
| 1872 _importsVerifier.inDefiningCompilationUnit = true; | |
| 1873 generateForCompilationUnit(_compilationUnits[i], element.source); | |
| 1874 _importsVerifier.inDefiningCompilationUnit = false; | |
| 1875 } else { | |
| 1876 generateForCompilationUnit(_compilationUnits[i], element.source); | |
| 1877 } | |
| 1878 } | |
| 1879 } | |
| 1880 ErrorReporter definingCompilationUnitErrorReporter = new ErrorReporter(_er
rorListener, _compilationUnits[0].element.source); | |
| 1881 _importsVerifier.generateDuplicateImportHints(definingCompilationUnitError
Reporter); | |
| 1882 _importsVerifier.generateUnusedImportHints(definingCompilationUnitErrorRep
orter); | |
| 1883 } finally { | |
| 1884 timeCounter.stop(); | |
| 1885 } | |
| 1886 } | |
| 1887 void generateForCompilationUnit(CompilationUnit unit, Source source) { | |
| 1888 ErrorReporter errorReporter = new ErrorReporter(_errorListener, source); | |
| 1889 _importsVerifier.visitCompilationUnit(unit); | |
| 1890 new DeadCodeVerifier(errorReporter).visitCompilationUnit(unit); | |
| 1891 if (_enableDart2JSHints) { | |
| 1892 new Dart2JSVerifier(errorReporter).visitCompilationUnit(unit); | |
| 1893 } | |
| 1894 new BestPracticesVerifier(errorReporter).visitCompilationUnit(unit); | |
| 1895 } | |
| 1896 } | |
| 1897 /** | |
| 1898 * Instances of the class `ImportsVerifier` visit all of the referenced librarie
s in the | |
| 1899 * source code verifying that all of the imports are used, otherwise a | |
| 1900 * [HintCode#UNUSED_IMPORT] is generated with | |
| 1901 * [generateUnusedImportHints]. | |
| 1902 * | |
| 1903 * While this class does not yet have support for an "Organize Imports" action,
this logic built up | |
| 1904 * in this class could be used for such an action in the future. | |
| 1905 * | |
| 1906 * @coverage dart.engine.resolver | |
| 1907 */ | |
| 1908 class ImportsVerifier extends RecursiveASTVisitor<Object> { | |
| 1909 | |
| 1910 /** | |
| 1911 * This is set to `true` if the current compilation unit which is being visite
d is the | |
| 1912 * defining compilation unit for the library, its value can be set with | |
| 1913 * [setInDefiningCompilationUnit]. | |
| 1914 */ | |
| 1915 bool _inDefiningCompilationUnit = false; | |
| 1916 | |
| 1917 /** | |
| 1918 * The current library. | |
| 1919 */ | |
| 1920 LibraryElement _currentLibrary; | |
| 1921 | |
| 1922 /** | |
| 1923 * A list of [ImportDirective]s that the current library imports, as identifie
rs are visited | |
| 1924 * by this visitor and an import has been identified as being used by the libr
ary, the | |
| 1925 * [ImportDirective] is removed from this list. After all the sources in the l
ibrary have | |
| 1926 * been evaluated, this list represents the set of unused imports. | |
| 1927 * | |
| 1928 * @see ImportsVerifier#generateUnusedImportErrors(ErrorReporter) | |
| 1929 */ | |
| 1930 List<ImportDirective> _unusedImports; | |
| 1931 | |
| 1932 /** | |
| 1933 * After the list of [unusedImports] has been computed, this list is a proper
subset of the | |
| 1934 * unused imports that are listed more than once. | |
| 1935 */ | |
| 1936 List<ImportDirective> _duplicateImports; | |
| 1937 | |
| 1938 /** | |
| 1939 * This is a map between the set of [LibraryElement]s that the current library
imports, and | |
| 1940 * a list of [ImportDirective]s that imports the library. In cases where the c
urrent library | |
| 1941 * imports a library with a single directive (such as `import lib1.dart;`), th
e library | |
| 1942 * element will map to a list of one [ImportDirective], which will then be rem
oved from the | |
| 1943 * [unusedImports] list. In cases where the current library imports a library
with multiple | |
| 1944 * directives (such as `import lib1.dart; import lib1.dart show C;`), the | |
| 1945 * [LibraryElement] will be mapped to a list of the import directives, and the
namespace | |
| 1946 * will need to be used to compute the correct [ImportDirective] being used, s
ee | |
| 1947 * [namespaceMap]. | |
| 1948 */ | |
| 1949 Map<LibraryElement, List<ImportDirective>> _libraryMap; | |
| 1950 | |
| 1951 /** | |
| 1952 * In cases where there is more than one import directive per library element,
this mapping is | |
| 1953 * used to determine which of the multiple import directives are used by gener
ating a | |
| 1954 * [Namespace] for each of the imports to do lookups in the same way that they
are done from | |
| 1955 * the [ElementResolver]. | |
| 1956 */ | |
| 1957 Map<ImportDirective, Namespace> _namespaceMap; | |
| 1958 | |
| 1959 /** | |
| 1960 * This is a map between prefix elements and the import directive from which t
hey are derived. In | |
| 1961 * cases where a type is referenced via a prefix element, the import directive
can be marked as | |
| 1962 * used (removed from the unusedImports) by looking at the resolved `lib` in `
lib.X`, | |
| 1963 * instead of looking at which library the `lib.X` resolves. | |
| 1964 */ | |
| 1965 Map<PrefixElement, ImportDirective> _prefixElementMap; | |
| 1966 | |
| 1967 /** | |
| 1968 * Create a new instance of the [ImportsVerifier]. | |
| 1969 * | |
| 1970 * @param errorReporter the error reporter | |
| 1971 */ | |
| 1972 ImportsVerifier(LibraryElement library) { | |
| 1973 this._currentLibrary = library; | |
| 1974 this._unusedImports = new List<ImportDirective>(); | |
| 1975 this._duplicateImports = new List<ImportDirective>(); | |
| 1976 this._libraryMap = new Map<LibraryElement, List<ImportDirective>>(); | |
| 1977 this._namespaceMap = new Map<ImportDirective, Namespace>(); | |
| 1978 this._prefixElementMap = new Map<PrefixElement, ImportDirective>(); | |
| 1979 } | |
| 1980 | |
| 1981 /** | |
| 1982 * Any time after the defining compilation unit has been visited by this visit
or, this method can | |
| 1983 * be called to report an [HintCode#DUPLICATE_IMPORT] hint for each of the imp
ort directives | |
| 1984 * in the [duplicateImports] list. | |
| 1985 * | |
| 1986 * @param errorReporter the error reporter to report the set of [HintCode#DUPL
ICATE_IMPORT] | |
| 1987 * hints to | |
| 1988 */ | |
| 1989 void generateDuplicateImportHints(ErrorReporter errorReporter) { | |
| 1990 for (ImportDirective duplicateImport in _duplicateImports) { | |
| 1991 errorReporter.reportError2(HintCode.DUPLICATE_IMPORT, duplicateImport.uri,
[]); | |
| 1992 } | |
| 1993 } | |
| 1994 | |
| 1995 /** | |
| 1996 * After all of the compilation units have been visited by this visitor, this
method can be called | |
| 1997 * to report an [HintCode#UNUSED_IMPORT] hint for each of the import directive
s in the | |
| 1998 * [unusedImports] list. | |
| 1999 * | |
| 2000 * @param errorReporter the error reporter to report the set of [HintCode#UNUS
ED_IMPORT] | |
| 2001 * hints to | |
| 2002 */ | |
| 2003 void generateUnusedImportHints(ErrorReporter errorReporter) { | |
| 2004 for (ImportDirective unusedImport in _unusedImports) { | |
| 2005 ImportElement importElement = unusedImport.element; | |
| 2006 if (importElement != null) { | |
| 2007 LibraryElement libraryElement = importElement.importedLibrary; | |
| 2008 if (libraryElement != null && libraryElement.isDartCore) { | |
| 2009 continue; | |
| 2010 } | |
| 2011 } | |
| 2012 errorReporter.reportError2(HintCode.UNUSED_IMPORT, unusedImport.uri, []); | |
| 2013 } | |
| 2014 } | |
| 2015 Object visitCompilationUnit(CompilationUnit node) { | |
| 2016 if (_inDefiningCompilationUnit) { | |
| 2017 NodeList<Directive> directives = node.directives; | |
| 2018 for (Directive directive in directives) { | |
| 2019 if (directive is ImportDirective) { | |
| 2020 ImportDirective importDirective = directive as ImportDirective; | |
| 2021 LibraryElement libraryElement = importDirective.uriElement; | |
| 2022 if (libraryElement != null) { | |
| 2023 _unusedImports.add(importDirective); | |
| 2024 if (importDirective.asToken != null) { | |
| 2025 SimpleIdentifier prefixIdentifier = importDirective.prefix; | |
| 2026 if (prefixIdentifier != null) { | |
| 2027 Element element = prefixIdentifier.staticElement; | |
| 2028 if (element is PrefixElement) { | |
| 2029 PrefixElement prefixElementKey = element as PrefixElement; | |
| 2030 _prefixElementMap[prefixElementKey] = importDirective; | |
| 2031 } | |
| 2032 } | |
| 2033 } | |
| 2034 putIntoLibraryMap(libraryElement, importDirective); | |
| 2035 addAdditionalLibrariesForExports(libraryElement, importDirective, ne
w List<LibraryElement>()); | |
| 2036 } | |
| 2037 } | |
| 2038 } | |
| 2039 } | |
| 2040 if (_unusedImports.isEmpty) { | |
| 2041 return null; | |
| 2042 } | |
| 2043 if (_unusedImports.length > 1) { | |
| 2044 List<ImportDirective> importDirectiveArray = new List.from(_unusedImports)
; | |
| 2045 importDirectiveArray.sort(ImportDirective.COMPARATOR); | |
| 2046 ImportDirective currentDirective = importDirectiveArray[0]; | |
| 2047 for (int i = 1; i < importDirectiveArray.length; i++) { | |
| 2048 ImportDirective nextDirective = importDirectiveArray[i]; | |
| 2049 if (ImportDirective.COMPARATOR(currentDirective, nextDirective) == 0) { | |
| 2050 if (currentDirective.offset < nextDirective.offset) { | |
| 2051 _duplicateImports.add(nextDirective); | |
| 2052 } else { | |
| 2053 _duplicateImports.add(currentDirective); | |
| 2054 } | |
| 2055 } | |
| 2056 currentDirective = nextDirective; | |
| 2057 } | |
| 2058 } | |
| 2059 return super.visitCompilationUnit(node); | |
| 2060 } | |
| 2061 Object visitExportDirective(ExportDirective node) { | |
| 2062 visitMetadata(node.metadata); | |
| 2063 return null; | |
| 2064 } | |
| 2065 Object visitImportDirective(ImportDirective node) { | |
| 2066 visitMetadata(node.metadata); | |
| 2067 return null; | |
| 2068 } | |
| 2069 Object visitLibraryDirective(LibraryDirective node) { | |
| 2070 visitMetadata(node.metadata); | |
| 2071 return null; | |
| 2072 } | |
| 2073 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 2074 SimpleIdentifier prefixIdentifier = node.prefix; | |
| 2075 Element element = prefixIdentifier.staticElement; | |
| 2076 if (element is PrefixElement) { | |
| 2077 _unusedImports.remove(_prefixElementMap[element]); | |
| 2078 return null; | |
| 2079 } | |
| 2080 return visitIdentifier(element, prefixIdentifier.name); | |
| 2081 } | |
| 2082 Object visitSimpleIdentifier(SimpleIdentifier node) => visitIdentifier(node.st
aticElement, node.name); | |
| 2083 void set inDefiningCompilationUnit(bool inDefiningCompilationUnit) { | |
| 2084 this._inDefiningCompilationUnit = inDefiningCompilationUnit; | |
| 2085 } | |
| 2086 | |
| 2087 /** | |
| 2088 * Recursively add any exported library elements into the [libraryMap]. | |
| 2089 */ | |
| 2090 void addAdditionalLibrariesForExports(LibraryElement library, ImportDirective
importDirective, List<LibraryElement> exportPath) { | |
| 2091 if (exportPath.contains(library)) { | |
| 2092 return; | |
| 2093 } | |
| 2094 exportPath.add(library); | |
| 2095 for (LibraryElement exportedLibraryElt in library.exportedLibraries) { | |
| 2096 putIntoLibraryMap(exportedLibraryElt, importDirective); | |
| 2097 addAdditionalLibrariesForExports(exportedLibraryElt, importDirective, expo
rtPath); | |
| 2098 } | |
| 2099 } | |
| 2100 | |
| 2101 /** | |
| 2102 * Lookup and return the [Namespace] from the [namespaceMap], if the map does
not | |
| 2103 * have the computed namespace, compute it and cache it in the map. If the imp
ort directive is not | |
| 2104 * resolved or is not resolvable, `null` is returned. | |
| 2105 * | |
| 2106 * @param importDirective the import directive used to compute the returned na
mespace | |
| 2107 * @return the computed or looked up [Namespace] | |
| 2108 */ | |
| 2109 Namespace computeNamespace(ImportDirective importDirective) { | |
| 2110 Namespace namespace = _namespaceMap[importDirective]; | |
| 2111 if (namespace == null) { | |
| 2112 ImportElement importElement = importDirective.element; | |
| 2113 if (importElement != null) { | |
| 2114 NamespaceBuilder builder = new NamespaceBuilder(); | |
| 2115 namespace = builder.createImportNamespace(importElement); | |
| 2116 _namespaceMap[importDirective] = namespace; | |
| 2117 } | |
| 2118 } | |
| 2119 return namespace; | |
| 2120 } | |
| 2121 | |
| 2122 /** | |
| 2123 * The [libraryMap] is a mapping between a library elements and a list of impo
rt | |
| 2124 * directives, but when adding these mappings into the [libraryMap], this meth
od can be | |
| 2125 * used to simply add the mapping between the library element an an import dir
ective without | |
| 2126 * needing to check to see if a list needs to be created. | |
| 2127 */ | |
| 2128 void putIntoLibraryMap(LibraryElement libraryElement, ImportDirective importDi
rective) { | |
| 2129 List<ImportDirective> importList = _libraryMap[libraryElement]; | |
| 2130 if (importList == null) { | |
| 2131 importList = new List<ImportDirective>(); | |
| 2132 _libraryMap[libraryElement] = importList; | |
| 2133 } | |
| 2134 importList.add(importDirective); | |
| 2135 } | |
| 2136 Object visitIdentifier(Element element, String name) { | |
| 2137 if (element == null) { | |
| 2138 return null; | |
| 2139 } | |
| 2140 if (element is MultiplyDefinedElement) { | |
| 2141 MultiplyDefinedElement multiplyDefinedElement = element as MultiplyDefined
Element; | |
| 2142 for (Element elt in multiplyDefinedElement.conflictingElements) { | |
| 2143 visitIdentifier(elt, name); | |
| 2144 } | |
| 2145 return null; | |
| 2146 } else if (element is PrefixElement) { | |
| 2147 _unusedImports.remove(_prefixElementMap[element]); | |
| 2148 return null; | |
| 2149 } | |
| 2150 LibraryElement containingLibrary = element.library; | |
| 2151 if (containingLibrary == null) { | |
| 2152 return null; | |
| 2153 } | |
| 2154 if (_currentLibrary == containingLibrary) { | |
| 2155 return null; | |
| 2156 } | |
| 2157 List<ImportDirective> importsFromSameLibrary = _libraryMap[containingLibrary
]; | |
| 2158 if (importsFromSameLibrary == null) { | |
| 2159 return null; | |
| 2160 } | |
| 2161 if (importsFromSameLibrary.length == 1) { | |
| 2162 ImportDirective usedImportDirective = importsFromSameLibrary[0]; | |
| 2163 _unusedImports.remove(usedImportDirective); | |
| 2164 } else { | |
| 2165 for (ImportDirective importDirective in importsFromSameLibrary) { | |
| 2166 Namespace namespace = computeNamespace(importDirective); | |
| 2167 if (namespace != null && namespace.get(name) != null) { | |
| 2168 _unusedImports.remove(importDirective); | |
| 2169 } | |
| 2170 } | |
| 2171 } | |
| 2172 return null; | |
| 2173 } | |
| 2174 | |
| 2175 /** | |
| 2176 * Given some [NodeList] of [Annotation]s, ensure that the identifiers are vis
ited by | |
| 2177 * this visitor. Specifically, this covers the cases where AST nodes don't hav
e their identifiers | |
| 2178 * visited by this visitor, but still need their annotations visited. | |
| 2179 * | |
| 2180 * @param annotations the list of annotations to visit | |
| 2181 */ | |
| 2182 void visitMetadata(NodeList<Annotation> annotations) { | |
| 2183 for (Annotation annotation in annotations) { | |
| 2184 Identifier name = annotation.name; | |
| 2185 visitIdentifier(name.staticElement, name.name); | |
| 2186 } | |
| 2187 } | |
| 2188 } | |
| 2189 /** | |
| 2190 * Instances of the class `PubVerifier` traverse an AST structure looking for de
viations from | |
| 2191 * pub best practices. | |
| 2192 */ | |
| 2193 class PubVerifier extends RecursiveASTVisitor<Object> { | |
| 2194 static String _PUBSPEC_YAML = "pubspec.yaml"; | |
| 2195 | |
| 2196 /** | |
| 2197 * The analysis context containing the sources to be analyzed | |
| 2198 */ | |
| 2199 AnalysisContext _context; | |
| 2200 | |
| 2201 /** | |
| 2202 * The error reporter by which errors will be reported. | |
| 2203 */ | |
| 2204 ErrorReporter _errorReporter; | |
| 2205 PubVerifier(AnalysisContext context, ErrorReporter errorReporter) { | |
| 2206 this._context = context; | |
| 2207 this._errorReporter = errorReporter; | |
| 2208 } | |
| 2209 Object visitImportDirective(ImportDirective directive) { | |
| 2210 return null; | |
| 2211 } | |
| 2212 | |
| 2213 /** | |
| 2214 * This verifies that the passed file import directive is not contained in a s
ource inside a | |
| 2215 * package "lib" directory hierarchy referencing a source outside that package
"lib" directory | |
| 2216 * hierarchy. | |
| 2217 * | |
| 2218 * @param uriLiteral the import URL (not `null`) | |
| 2219 * @param path the file path being verified (not `null`) | |
| 2220 * @return `true` if and only if an error code is generated on the passed node | |
| 2221 * @see PubSuggestionCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE | |
| 2222 */ | |
| 2223 bool checkForFileImportInsideLibReferencesFileOutside(StringLiteral uriLiteral
, String path) { | |
| 2224 Source source = getSource(uriLiteral); | |
| 2225 String fullName = getSourceFullName(source); | |
| 2226 if (fullName != null) { | |
| 2227 int pathIndex = 0; | |
| 2228 int fullNameIndex = fullName.length; | |
| 2229 while (pathIndex < path.length && JavaString.startsWithBefore(path, "../",
pathIndex)) { | |
| 2230 fullNameIndex = JavaString.lastIndexOf(fullName, '/', fullNameIndex); | |
| 2231 if (fullNameIndex < 4) { | |
| 2232 return false; | |
| 2233 } | |
| 2234 if (JavaString.startsWithBefore(fullName, "/lib", fullNameIndex - 4)) { | |
| 2235 String relativePubspecPath = path.substring(0, pathIndex + 3) + _PUBSP
EC_YAML; | |
| 2236 Source pubspecSource = _context.sourceFactory.resolveUri(source, relat
ivePubspecPath); | |
| 2237 if (pubspecSource != null && pubspecSource.exists()) { | |
| 2238 _errorReporter.reportError2(PubSuggestionCode.FILE_IMPORT_INSIDE_LIB
_REFERENCES_FILE_OUTSIDE, uriLiteral, []); | |
| 2239 } | |
| 2240 return true; | |
| 2241 } | |
| 2242 pathIndex += 3; | |
| 2243 } | |
| 2244 } | |
| 2245 return false; | |
| 2246 } | |
| 2247 | |
| 2248 /** | |
| 2249 * This verifies that the passed file import directive is not contained in a s
ource outside a | |
| 2250 * package "lib" directory hierarchy referencing a source inside that package
"lib" directory | |
| 2251 * hierarchy. | |
| 2252 * | |
| 2253 * @param uriLiteral the import URL (not `null`) | |
| 2254 * @param path the file path being verified (not `null`) | |
| 2255 * @return `true` if and only if an error code is generated on the passed node | |
| 2256 * @see PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE | |
| 2257 */ | |
| 2258 bool checkForFileImportOutsideLibReferencesFileInside(StringLiteral uriLiteral
, String path) { | |
| 2259 if (path.startsWith("lib/")) { | |
| 2260 if (checkForFileImportOutsideLibReferencesFileInside2(uriLiteral, path, 0)
) { | |
| 2261 return true; | |
| 2262 } | |
| 2263 } | |
| 2264 int pathIndex = path.indexOf("/lib/"); | |
| 2265 while (pathIndex != -1) { | |
| 2266 if (checkForFileImportOutsideLibReferencesFileInside2(uriLiteral, path, pa
thIndex + 1)) { | |
| 2267 return true; | |
| 2268 } | |
| 2269 pathIndex = JavaString.indexOf(path, "/lib/", pathIndex + 4); | |
| 2270 } | |
| 2271 return false; | |
| 2272 } | |
| 2273 bool checkForFileImportOutsideLibReferencesFileInside2(StringLiteral uriLitera
l, String path, int pathIndex) { | |
| 2274 Source source = getSource(uriLiteral); | |
| 2275 String relativePubspecPath = path.substring(0, pathIndex) + _PUBSPEC_YAML; | |
| 2276 Source pubspecSource = _context.sourceFactory.resolveUri(source, relativePub
specPath); | |
| 2277 if (pubspecSource == null || !pubspecSource.exists()) { | |
| 2278 return false; | |
| 2279 } | |
| 2280 String fullName = getSourceFullName(source); | |
| 2281 if (fullName != null) { | |
| 2282 if (!fullName.contains("/lib/")) { | |
| 2283 _errorReporter.reportError2(PubSuggestionCode.FILE_IMPORT_OUTSIDE_LIB_RE
FERENCES_FILE_INSIDE, uriLiteral, []); | |
| 2284 return true; | |
| 2285 } | |
| 2286 } | |
| 2287 return false; | |
| 2288 } | |
| 2289 | |
| 2290 /** | |
| 2291 * This verifies that the passed package import directive does not contain "..
" | |
| 2292 * | |
| 2293 * @param uriLiteral the import URL (not `null`) | |
| 2294 * @param path the path to be validated (not `null`) | |
| 2295 * @return `true` if and only if an error code is generated on the passed node | |
| 2296 * @see PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT | |
| 2297 */ | |
| 2298 bool checkForPackageImportContainsDotDot(StringLiteral uriLiteral, String path
) { | |
| 2299 if (path.startsWith("../") || path.contains("/../")) { | |
| 2300 _errorReporter.reportError2(PubSuggestionCode.PACKAGE_IMPORT_CONTAINS_DOT_
DOT, uriLiteral, []); | |
| 2301 return true; | |
| 2302 } | |
| 2303 return false; | |
| 2304 } | |
| 2305 | |
| 2306 /** | |
| 2307 * Answer the source associated with the compilation unit containing the given
AST node. | |
| 2308 * | |
| 2309 * @param node the node (not `null`) | |
| 2310 * @return the source or `null` if it could not be determined | |
| 2311 */ | |
| 2312 Source getSource(ASTNode node) { | |
| 2313 Source source = null; | |
| 2314 CompilationUnit unit = node.getAncestor(CompilationUnit); | |
| 2315 if (unit != null) { | |
| 2316 CompilationUnitElement element = unit.element; | |
| 2317 if (element != null) { | |
| 2318 source = element.source; | |
| 2319 } | |
| 2320 } | |
| 2321 return source; | |
| 2322 } | |
| 2323 | |
| 2324 /** | |
| 2325 * Answer the full name of the given source. The returned value will have all | |
| 2326 * [File#separatorChar] replace by '/'. | |
| 2327 * | |
| 2328 * @param source the source | |
| 2329 * @return the full name or `null` if it could not be determined | |
| 2330 */ | |
| 2331 String getSourceFullName(Source source) { | |
| 2332 if (source != null) { | |
| 2333 String fullName = source.fullName; | |
| 2334 if (fullName != null) { | |
| 2335 return fullName.replaceAll(r'\', '/'); | |
| 2336 } | |
| 2337 } | |
| 2338 return null; | |
| 2339 } | |
| 2340 } | |
| 2341 /** | |
| 2342 * Instances of the class `DeclarationResolver` are used to resolve declarations
in an AST | |
| 2343 * structure to already built elements. | |
| 2344 */ | |
| 2345 class DeclarationResolver extends RecursiveASTVisitor<Object> { | |
| 2346 | |
| 2347 /** | |
| 2348 * The compilation unit containing the AST nodes being visited. | |
| 2349 */ | |
| 2350 CompilationUnitElement _enclosingUnit; | |
| 2351 | |
| 2352 /** | |
| 2353 * The function type alias containing the AST nodes being visited, or `null` i
f we are not | |
| 2354 * in the scope of a function type alias. | |
| 2355 */ | |
| 2356 FunctionTypeAliasElement _enclosingAlias; | |
| 2357 | |
| 2358 /** | |
| 2359 * The class containing the AST nodes being visited, or `null` if we are not i
n the scope of | |
| 2360 * a class. | |
| 2361 */ | |
| 2362 ClassElement _enclosingClass; | |
| 2363 | |
| 2364 /** | |
| 2365 * The method or function containing the AST nodes being visited, or `null` if
we are not in | |
| 2366 * the scope of a method or function. | |
| 2367 */ | |
| 2368 ExecutableElement _enclosingExecutable; | |
| 2369 | |
| 2370 /** | |
| 2371 * The parameter containing the AST nodes being visited, or `null` if we are n
ot in the | |
| 2372 * scope of a parameter. | |
| 2373 */ | |
| 2374 ParameterElement _enclosingParameter; | |
| 2375 | |
| 2376 /** | |
| 2377 * Resolve the declarations within the given compilation unit to the elements
rooted at the given | |
| 2378 * element. | |
| 2379 * | |
| 2380 * @param unit the compilation unit to be resolved | |
| 2381 * @param element the root of the element model used to resolve the AST nodes | |
| 2382 */ | |
| 2383 void resolve(CompilationUnit unit, CompilationUnitElement element) { | |
| 2384 _enclosingUnit = element; | |
| 2385 unit.element = element; | |
| 2386 unit.accept(this); | |
| 2387 } | |
| 2388 Object visitCatchClause(CatchClause node) { | |
| 2389 SimpleIdentifier exceptionParameter = node.exceptionParameter; | |
| 2390 if (exceptionParameter != null) { | |
| 2391 List<LocalVariableElement> localVariables = _enclosingExecutable.localVari
ables; | |
| 2392 find3(localVariables, exceptionParameter); | |
| 2393 SimpleIdentifier stackTraceParameter = node.stackTraceParameter; | |
| 2394 if (stackTraceParameter != null) { | |
| 2395 find3(localVariables, stackTraceParameter); | |
| 2396 } | |
| 2397 } | |
| 2398 return super.visitCatchClause(node); | |
| 2399 } | |
| 2400 Object visitClassDeclaration(ClassDeclaration node) { | |
| 2401 ClassElement outerClass = _enclosingClass; | |
| 2402 try { | |
| 2403 SimpleIdentifier className = node.name; | |
| 2404 _enclosingClass = find3(_enclosingUnit.types, className); | |
| 2405 return super.visitClassDeclaration(node); | |
| 2406 } finally { | |
| 2407 _enclosingClass = outerClass; | |
| 2408 } | |
| 2409 } | |
| 2410 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 2411 ClassElement outerClass = _enclosingClass; | |
| 2412 try { | |
| 2413 SimpleIdentifier className = node.name; | |
| 2414 _enclosingClass = find3(_enclosingUnit.types, className); | |
| 2415 return super.visitClassTypeAlias(node); | |
| 2416 } finally { | |
| 2417 _enclosingClass = outerClass; | |
| 2418 } | |
| 2419 } | |
| 2420 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 2421 ExecutableElement outerExecutable = _enclosingExecutable; | |
| 2422 try { | |
| 2423 SimpleIdentifier constructorName = node.name; | |
| 2424 if (constructorName == null) { | |
| 2425 _enclosingExecutable = _enclosingClass.unnamedConstructor; | |
| 2426 } else { | |
| 2427 _enclosingExecutable = _enclosingClass.getNamedConstructor(constructorNa
me.name); | |
| 2428 constructorName.staticElement = _enclosingExecutable; | |
| 2429 } | |
| 2430 node.element = _enclosingExecutable as ConstructorElement; | |
| 2431 return super.visitConstructorDeclaration(node); | |
| 2432 } finally { | |
| 2433 _enclosingExecutable = outerExecutable; | |
| 2434 } | |
| 2435 } | |
| 2436 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 2437 SimpleIdentifier variableName = node.identifier; | |
| 2438 find3(_enclosingExecutable.localVariables, variableName); | |
| 2439 return super.visitDeclaredIdentifier(node); | |
| 2440 } | |
| 2441 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 2442 SimpleIdentifier parameterName = node.parameter.identifier; | |
| 2443 ParameterElement element = getElementForParameter(node, parameterName); | |
| 2444 Expression defaultValue = node.defaultValue; | |
| 2445 if (defaultValue != null) { | |
| 2446 ExecutableElement outerExecutable = _enclosingExecutable; | |
| 2447 try { | |
| 2448 if (element == null) { | |
| 2449 } else { | |
| 2450 _enclosingExecutable = element.initializer; | |
| 2451 } | |
| 2452 defaultValue.accept(this); | |
| 2453 } finally { | |
| 2454 _enclosingExecutable = outerExecutable; | |
| 2455 } | |
| 2456 } | |
| 2457 ParameterElement outerParameter = _enclosingParameter; | |
| 2458 try { | |
| 2459 _enclosingParameter = element; | |
| 2460 return super.visitDefaultFormalParameter(node); | |
| 2461 } finally { | |
| 2462 _enclosingParameter = outerParameter; | |
| 2463 } | |
| 2464 } | |
| 2465 Object visitExportDirective(ExportDirective node) { | |
| 2466 String uri = getStringValue(node.uri); | |
| 2467 if (uri != null) { | |
| 2468 LibraryElement library = _enclosingUnit.library; | |
| 2469 ExportElement exportElement = find5(library.exports, _enclosingUnit.contex
t.sourceFactory.resolveUri(_enclosingUnit.source, uri)); | |
| 2470 node.element = exportElement; | |
| 2471 } | |
| 2472 return super.visitExportDirective(node); | |
| 2473 } | |
| 2474 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 2475 if (node.parent is! DefaultFormalParameter) { | |
| 2476 SimpleIdentifier parameterName = node.identifier; | |
| 2477 ParameterElement element = getElementForParameter(node, parameterName); | |
| 2478 ParameterElement outerParameter = _enclosingParameter; | |
| 2479 try { | |
| 2480 _enclosingParameter = element; | |
| 2481 return super.visitFieldFormalParameter(node); | |
| 2482 } finally { | |
| 2483 _enclosingParameter = outerParameter; | |
| 2484 } | |
| 2485 } else { | |
| 2486 return super.visitFieldFormalParameter(node); | |
| 2487 } | |
| 2488 } | |
| 2489 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 2490 ExecutableElement outerExecutable = _enclosingExecutable; | |
| 2491 try { | |
| 2492 SimpleIdentifier functionName = node.name; | |
| 2493 sc.Token property = node.propertyKeyword; | |
| 2494 if (property == null) { | |
| 2495 if (_enclosingExecutable != null) { | |
| 2496 _enclosingExecutable = find3(_enclosingExecutable.functions, functionN
ame); | |
| 2497 } else { | |
| 2498 _enclosingExecutable = find3(_enclosingUnit.functions, functionName); | |
| 2499 } | |
| 2500 } else { | |
| 2501 PropertyAccessorElement accessor = find3(_enclosingUnit.accessors, funct
ionName); | |
| 2502 if (identical(((property as sc.KeywordToken)).keyword, sc.Keyword.SET))
{ | |
| 2503 accessor = accessor.variable.setter; | |
| 2504 functionName.staticElement = accessor; | |
| 2505 } | |
| 2506 _enclosingExecutable = accessor; | |
| 2507 } | |
| 2508 node.functionExpression.element = _enclosingExecutable; | |
| 2509 return super.visitFunctionDeclaration(node); | |
| 2510 } finally { | |
| 2511 _enclosingExecutable = outerExecutable; | |
| 2512 } | |
| 2513 } | |
| 2514 Object visitFunctionExpression(FunctionExpression node) { | |
| 2515 if (node.parent is! FunctionDeclaration) { | |
| 2516 FunctionElement element = find2(_enclosingExecutable.functions, node.begin
Token.offset); | |
| 2517 node.element = element; | |
| 2518 } | |
| 2519 ExecutableElement outerExecutable = _enclosingExecutable; | |
| 2520 try { | |
| 2521 _enclosingExecutable = node.element; | |
| 2522 return super.visitFunctionExpression(node); | |
| 2523 } finally { | |
| 2524 _enclosingExecutable = outerExecutable; | |
| 2525 } | |
| 2526 } | |
| 2527 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 2528 FunctionTypeAliasElement outerAlias = _enclosingAlias; | |
| 2529 try { | |
| 2530 SimpleIdentifier aliasName = node.name; | |
| 2531 _enclosingAlias = find3(_enclosingUnit.functionTypeAliases, aliasName); | |
| 2532 return super.visitFunctionTypeAlias(node); | |
| 2533 } finally { | |
| 2534 _enclosingAlias = outerAlias; | |
| 2535 } | |
| 2536 } | |
| 2537 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 2538 if (node.parent is! DefaultFormalParameter) { | |
| 2539 SimpleIdentifier parameterName = node.identifier; | |
| 2540 ParameterElement element = getElementForParameter(node, parameterName); | |
| 2541 ParameterElement outerParameter = _enclosingParameter; | |
| 2542 try { | |
| 2543 _enclosingParameter = element; | |
| 2544 return super.visitFunctionTypedFormalParameter(node); | |
| 2545 } finally { | |
| 2546 _enclosingParameter = outerParameter; | |
| 2547 } | |
| 2548 } else { | |
| 2549 return super.visitFunctionTypedFormalParameter(node); | |
| 2550 } | |
| 2551 } | |
| 2552 Object visitImportDirective(ImportDirective node) { | |
| 2553 String uri = getStringValue(node.uri); | |
| 2554 if (uri != null) { | |
| 2555 LibraryElement library = _enclosingUnit.library; | |
| 2556 ImportElement importElement = find6(library.imports, _enclosingUnit.contex
t.sourceFactory.resolveUri(_enclosingUnit.source, uri), node.prefix); | |
| 2557 node.element = importElement; | |
| 2558 } | |
| 2559 return super.visitImportDirective(node); | |
| 2560 } | |
| 2561 Object visitLabeledStatement(LabeledStatement node) { | |
| 2562 for (Label label in node.labels) { | |
| 2563 SimpleIdentifier labelName = label.label; | |
| 2564 find3(_enclosingExecutable.labels, labelName); | |
| 2565 } | |
| 2566 return super.visitLabeledStatement(node); | |
| 2567 } | |
| 2568 Object visitLibraryDirective(LibraryDirective node) { | |
| 2569 node.element = _enclosingUnit.library; | |
| 2570 return super.visitLibraryDirective(node); | |
| 2571 } | |
| 2572 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 2573 ExecutableElement outerExecutable = _enclosingExecutable; | |
| 2574 try { | |
| 2575 sc.Token property = node.propertyKeyword; | |
| 2576 SimpleIdentifier methodName = node.name; | |
| 2577 String nameOfMethod = methodName.name; | |
| 2578 if (nameOfMethod == sc.TokenType.MINUS.lexeme && node.parameters.parameter
s.length == 0) { | |
| 2579 nameOfMethod = "unary-"; | |
| 2580 } | |
| 2581 if (property == null) { | |
| 2582 _enclosingExecutable = find4(_enclosingClass.methods, nameOfMethod, meth
odName.offset); | |
| 2583 methodName.staticElement = _enclosingExecutable; | |
| 2584 } else { | |
| 2585 PropertyAccessorElement accessor = find3(_enclosingClass.accessors, meth
odName); | |
| 2586 if (identical(((property as sc.KeywordToken)).keyword, sc.Keyword.SET))
{ | |
| 2587 accessor = accessor.variable.setter; | |
| 2588 methodName.staticElement = accessor; | |
| 2589 } | |
| 2590 _enclosingExecutable = accessor; | |
| 2591 } | |
| 2592 return super.visitMethodDeclaration(node); | |
| 2593 } finally { | |
| 2594 _enclosingExecutable = outerExecutable; | |
| 2595 } | |
| 2596 } | |
| 2597 Object visitPartDirective(PartDirective node) { | |
| 2598 String uri = getStringValue(node.uri); | |
| 2599 if (uri != null) { | |
| 2600 Source partSource = _enclosingUnit.context.sourceFactory.resolveUri(_enclo
singUnit.source, uri); | |
| 2601 node.element = find(_enclosingUnit.library.parts, partSource); | |
| 2602 } | |
| 2603 return super.visitPartDirective(node); | |
| 2604 } | |
| 2605 Object visitPartOfDirective(PartOfDirective node) { | |
| 2606 node.element = _enclosingUnit.library; | |
| 2607 return super.visitPartOfDirective(node); | |
| 2608 } | |
| 2609 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 2610 if (node.parent is! DefaultFormalParameter) { | |
| 2611 SimpleIdentifier parameterName = node.identifier; | |
| 2612 ParameterElement element = getElementForParameter(node, parameterName); | |
| 2613 ParameterElement outerParameter = _enclosingParameter; | |
| 2614 try { | |
| 2615 _enclosingParameter = element; | |
| 2616 return super.visitSimpleFormalParameter(node); | |
| 2617 } finally { | |
| 2618 _enclosingParameter = outerParameter; | |
| 2619 } | |
| 2620 } else { | |
| 2621 } | |
| 2622 return super.visitSimpleFormalParameter(node); | |
| 2623 } | |
| 2624 Object visitSwitchCase(SwitchCase node) { | |
| 2625 for (Label label in node.labels) { | |
| 2626 SimpleIdentifier labelName = label.label; | |
| 2627 find3(_enclosingExecutable.labels, labelName); | |
| 2628 } | |
| 2629 return super.visitSwitchCase(node); | |
| 2630 } | |
| 2631 Object visitSwitchDefault(SwitchDefault node) { | |
| 2632 for (Label label in node.labels) { | |
| 2633 SimpleIdentifier labelName = label.label; | |
| 2634 find3(_enclosingExecutable.labels, labelName); | |
| 2635 } | |
| 2636 return super.visitSwitchDefault(node); | |
| 2637 } | |
| 2638 Object visitTypeParameter(TypeParameter node) { | |
| 2639 SimpleIdentifier parameterName = node.name; | |
| 2640 if (_enclosingClass != null) { | |
| 2641 find3(_enclosingClass.typeParameters, parameterName); | |
| 2642 } else if (_enclosingAlias != null) { | |
| 2643 find3(_enclosingAlias.typeParameters, parameterName); | |
| 2644 } | |
| 2645 return super.visitTypeParameter(node); | |
| 2646 } | |
| 2647 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 2648 VariableElement element = null; | |
| 2649 SimpleIdentifier variableName = node.name; | |
| 2650 if (_enclosingExecutable != null) { | |
| 2651 element = find3(_enclosingExecutable.localVariables, variableName); | |
| 2652 } | |
| 2653 if (element == null && _enclosingClass != null) { | |
| 2654 element = find3(_enclosingClass.fields, variableName); | |
| 2655 } | |
| 2656 if (element == null && _enclosingUnit != null) { | |
| 2657 element = find3(_enclosingUnit.topLevelVariables, variableName); | |
| 2658 } | |
| 2659 Expression initializer = node.initializer; | |
| 2660 if (initializer != null) { | |
| 2661 ExecutableElement outerExecutable = _enclosingExecutable; | |
| 2662 try { | |
| 2663 if (element == null) { | |
| 2664 } else { | |
| 2665 _enclosingExecutable = element.initializer; | |
| 2666 } | |
| 2667 return super.visitVariableDeclaration(node); | |
| 2668 } finally { | |
| 2669 _enclosingExecutable = outerExecutable; | |
| 2670 } | |
| 2671 } | |
| 2672 return super.visitVariableDeclaration(node); | |
| 2673 } | |
| 2674 | |
| 2675 /** | |
| 2676 * Return the element for the part with the given source, or `null` if there i
s no element | |
| 2677 * for the given source. | |
| 2678 * | |
| 2679 * @param parts the elements for the parts | |
| 2680 * @param partSource the source for the part whose element is to be returned | |
| 2681 * @return the element for the part with the given source | |
| 2682 */ | |
| 2683 CompilationUnitElement find(List<CompilationUnitElement> parts, Source partSou
rce) { | |
| 2684 for (CompilationUnitElement part in parts) { | |
| 2685 if (part.source == partSource) { | |
| 2686 return part; | |
| 2687 } | |
| 2688 } | |
| 2689 return null; | |
| 2690 } | |
| 2691 | |
| 2692 /** | |
| 2693 * Return the element in the given array of elements that was created for the
declaration at the | |
| 2694 * given offset. This method should only be used when there is no name | |
| 2695 * | |
| 2696 * @param elements the elements of the appropriate kind that exist in the curr
ent context | |
| 2697 * @param offset the offset of the name of the element to be returned | |
| 2698 * @return the element at the given offset | |
| 2699 */ | |
| 2700 Element find2(List<Element> elements, int offset) => find4(elements, "", offse
t); | |
| 2701 | |
| 2702 /** | |
| 2703 * Return the element in the given array of elements that was created for the
declaration with the | |
| 2704 * given name. | |
| 2705 * | |
| 2706 * @param elements the elements of the appropriate kind that exist in the curr
ent context | |
| 2707 * @param identifier the name node in the declaration of the element to be ret
urned | |
| 2708 * @return the element created for the declaration with the given name | |
| 2709 */ | |
| 2710 Element find3(List<Element> elements, SimpleIdentifier identifier) { | |
| 2711 Element element = find4(elements, identifier.name, identifier.offset); | |
| 2712 identifier.staticElement = element; | |
| 2713 return element; | |
| 2714 } | |
| 2715 | |
| 2716 /** | |
| 2717 * Return the element in the given array of elements that was created for the
declaration with the | |
| 2718 * given name at the given offset. | |
| 2719 * | |
| 2720 * @param elements the elements of the appropriate kind that exist in the curr
ent context | |
| 2721 * @param name the name of the element to be returned | |
| 2722 * @param offset the offset of the name of the element to be returned | |
| 2723 * @return the element with the given name and offset | |
| 2724 */ | |
| 2725 Element find4(List<Element> elements, String name, int offset) { | |
| 2726 for (Element element in elements) { | |
| 2727 if (element.displayName == name && element.nameOffset == offset) { | |
| 2728 return element; | |
| 2729 } | |
| 2730 } | |
| 2731 return null; | |
| 2732 } | |
| 2733 | |
| 2734 /** | |
| 2735 * Return the export element from the given array whose library has the given
source, or | |
| 2736 * `null` if there is no such export. | |
| 2737 * | |
| 2738 * @param exports the export elements being searched | |
| 2739 * @param source the source of the library associated with the export element
to being searched | |
| 2740 * for | |
| 2741 * @return the export element whose library has the given source | |
| 2742 */ | |
| 2743 ExportElement find5(List<ExportElement> exports, Source source) { | |
| 2744 for (ExportElement export in exports) { | |
| 2745 if (export.exportedLibrary.source == source) { | |
| 2746 return export; | |
| 2747 } | |
| 2748 } | |
| 2749 return null; | |
| 2750 } | |
| 2751 | |
| 2752 /** | |
| 2753 * Return the import element from the given array whose library has the given
source and that has | |
| 2754 * the given prefix, or `null` if there is no such import. | |
| 2755 * | |
| 2756 * @param imports the import elements being searched | |
| 2757 * @param source the source of the library associated with the import element
to being searched | |
| 2758 * for | |
| 2759 * @param prefix the prefix with which the library was imported | |
| 2760 * @return the import element whose library has the given source and prefix | |
| 2761 */ | |
| 2762 ImportElement find6(List<ImportElement> imports, Source source, SimpleIdentifi
er prefix) { | |
| 2763 for (ImportElement element in imports) { | |
| 2764 if (element.importedLibrary.source == source) { | |
| 2765 PrefixElement prefixElement = element.prefix; | |
| 2766 if (prefix == null) { | |
| 2767 if (prefixElement == null) { | |
| 2768 return element; | |
| 2769 } | |
| 2770 } else { | |
| 2771 if (prefixElement != null && prefix.name == prefixElement.displayName)
{ | |
| 2772 return element; | |
| 2773 } | |
| 2774 } | |
| 2775 } | |
| 2776 } | |
| 2777 return null; | |
| 2778 } | |
| 2779 | |
| 2780 /** | |
| 2781 * Search the most closely enclosing list of parameters for a parameter with t
he given name. | |
| 2782 * | |
| 2783 * @param node the node defining the parameter with the given name | |
| 2784 * @param parameterName the name of the parameter being searched for | |
| 2785 * @return the element representing the parameter with that name | |
| 2786 */ | |
| 2787 ParameterElement getElementForParameter(FormalParameter node, SimpleIdentifier
parameterName) { | |
| 2788 List<ParameterElement> parameters = null; | |
| 2789 if (_enclosingParameter != null) { | |
| 2790 parameters = _enclosingParameter.parameters; | |
| 2791 } | |
| 2792 if (parameters == null && _enclosingExecutable != null) { | |
| 2793 parameters = _enclosingExecutable.parameters; | |
| 2794 } | |
| 2795 if (parameters == null && _enclosingAlias != null) { | |
| 2796 parameters = _enclosingAlias.parameters; | |
| 2797 } | |
| 2798 ParameterElement element = parameters == null ? null : find3(parameters, par
ameterName); | |
| 2799 if (element == null) { | |
| 2800 PrintStringWriter writer = new PrintStringWriter(); | |
| 2801 writer.println("Invalid state found in the Analysis Engine:"); | |
| 2802 writer.println("DeclarationResolver.getElementForParameter() is visiting a
parameter that does not appear to be in a method or function."); | |
| 2803 writer.println("Ancestors:"); | |
| 2804 ASTNode parent = node.parent; | |
| 2805 while (parent != null) { | |
| 2806 writer.println(parent.runtimeType.toString()); | |
| 2807 writer.println("---------"); | |
| 2808 parent = parent.parent; | |
| 2809 } | |
| 2810 AnalysisEngine.instance.logger.logError2(writer.toString(), new AnalysisEx
ception()); | |
| 2811 } | |
| 2812 return element; | |
| 2813 } | |
| 2814 | |
| 2815 /** | |
| 2816 * Return the value of the given string literal, or `null` if the string is no
t a constant | |
| 2817 * string without any string interpolation. | |
| 2818 * | |
| 2819 * @param literal the string literal whose value is to be returned | |
| 2820 * @return the value of the given string literal | |
| 2821 */ | |
| 2822 String getStringValue(StringLiteral literal) { | |
| 2823 if (literal is StringInterpolation) { | |
| 2824 return null; | |
| 2825 } | |
| 2826 return literal.stringValue; | |
| 2827 } | |
| 2828 } | |
| 2829 /** | |
| 2830 * Instances of the class `ElementResolver` are used by instances of [ResolverVi
sitor] | |
| 2831 * to resolve references within the AST structure to the elements being referenc
ed. The requirements | |
| 2832 * for the element resolver are: | |
| 2833 * <ol> | |
| 2834 * * Every [SimpleIdentifier] should be resolved to the element to which it refe
rs. | |
| 2835 * Specifically: | |
| 2836 * | |
| 2837 * * An identifier within the declaration of that name should resolve to the ele
ment being | |
| 2838 * declared. | |
| 2839 * * An identifier denoting a prefix should resolve to the element representing
the import that | |
| 2840 * defines the prefix (an [ImportElement]). | |
| 2841 * * An identifier denoting a variable should resolve to the element representin
g the variable (a | |
| 2842 * [VariableElement]). | |
| 2843 * * An identifier denoting a parameter should resolve to the element representi
ng the parameter | |
| 2844 * (a [ParameterElement]). | |
| 2845 * * An identifier denoting a field should resolve to the element representing t
he getter or | |
| 2846 * setter being invoked (a [PropertyAccessorElement]). | |
| 2847 * * An identifier denoting the name of a method or function being invoked shoul
d resolve to the | |
| 2848 * element representing the method or function (a [ExecutableElement]). | |
| 2849 * * An identifier denoting a label should resolve to the element representing t
he label (a | |
| 2850 * [LabelElement]). | |
| 2851 * | |
| 2852 * The identifiers within directives are exceptions to this rule and are covered
below. | |
| 2853 * * Every node containing a token representing an operator that can be overridd
en ( | |
| 2854 * [BinaryExpression], [PrefixExpression], [PostfixExpression]) should resolve t
o | |
| 2855 * the element representing the method invoked by that operator (a [MethodElemen
t]). | |
| 2856 * * Every [FunctionExpressionInvocation] should resolve to the element represen
ting the | |
| 2857 * function being invoked (a [FunctionElement]). This will be the same element a
s that to | |
| 2858 * which the name is resolved if the function has a name, but is provided for th
ose cases where an | |
| 2859 * unnamed function is being invoked. | |
| 2860 * * Every [LibraryDirective] and [PartOfDirective] should resolve to the elemen
t | |
| 2861 * representing the library being specified by the directive (a [LibraryElement]
) unless, in | |
| 2862 * the case of a part-of directive, the specified library does not exist. | |
| 2863 * * Every [ImportDirective] and [ExportDirective] should resolve to the element | |
| 2864 * representing the library being specified by the directive unless the specifie
d library does not | |
| 2865 * exist (an [ImportElement] or [ExportElement]). | |
| 2866 * * The identifier representing the prefix in an [ImportDirective] should resol
ve to the | |
| 2867 * element representing the prefix (a [PrefixElement]). | |
| 2868 * * The identifiers in the hide and show combinators in [ImportDirective]s and | |
| 2869 * [ExportDirective]s should resolve to the elements that are being hidden or sh
own, | |
| 2870 * respectively, unless those names are not defined in the specified library (or
the specified | |
| 2871 * library does not exist). | |
| 2872 * * Every [PartDirective] should resolve to the element representing the compil
ation unit | |
| 2873 * being specified by the string unless the specified compilation unit does not
exist (a | |
| 2874 * [CompilationUnitElement]). | |
| 2875 * </ol> | |
| 2876 * Note that AST nodes that would represent elements that are not defined are no
t resolved to | |
| 2877 * anything. This includes such things as references to undeclared variables (wh
ich is an error) and | |
| 2878 * names in hide and show combinators that are not defined in the imported libra
ry (which is not an | |
| 2879 * error). | |
| 2880 * | |
| 2881 * @coverage dart.engine.resolver | |
| 2882 */ | |
| 2883 class ElementResolver extends SimpleASTVisitor<Object> { | |
| 2884 | |
| 2885 /** | |
| 2886 * @return `true` if the given identifier is the return type of a constructor
declaration. | |
| 2887 */ | |
| 2888 static bool isConstructorReturnType(SimpleIdentifier node) { | |
| 2889 ASTNode parent = node.parent; | |
| 2890 if (parent is ConstructorDeclaration) { | |
| 2891 ConstructorDeclaration constructor = parent as ConstructorDeclaration; | |
| 2892 return identical(constructor.returnType, node); | |
| 2893 } | |
| 2894 return false; | |
| 2895 } | |
| 2896 | |
| 2897 /** | |
| 2898 * @return `true` if the given identifier is the return type of a factory cons
tructor | |
| 2899 * declaration. | |
| 2900 */ | |
| 2901 static bool isFactoryConstructorReturnType(SimpleIdentifier node) { | |
| 2902 ASTNode parent = node.parent; | |
| 2903 if (parent is ConstructorDeclaration) { | |
| 2904 ConstructorDeclaration constructor = parent as ConstructorDeclaration; | |
| 2905 return identical(constructor.returnType, node) && constructor.factoryKeywo
rd != null; | |
| 2906 } | |
| 2907 return false; | |
| 2908 } | |
| 2909 | |
| 2910 /** | |
| 2911 * Checks if the given 'super' expression is used in the valid context. | |
| 2912 * | |
| 2913 * @param node the 'super' expression to analyze | |
| 2914 * @return `true` if the given 'super' expression is in the valid context | |
| 2915 */ | |
| 2916 static bool isSuperInValidContext(SuperExpression node) { | |
| 2917 for (ASTNode n = node; n != null; n = n.parent) { | |
| 2918 if (n is CompilationUnit) { | |
| 2919 return false; | |
| 2920 } | |
| 2921 if (n is ConstructorDeclaration) { | |
| 2922 ConstructorDeclaration constructor = n as ConstructorDeclaration; | |
| 2923 return constructor.factoryKeyword == null; | |
| 2924 } | |
| 2925 if (n is ConstructorFieldInitializer) { | |
| 2926 return false; | |
| 2927 } | |
| 2928 if (n is MethodDeclaration) { | |
| 2929 MethodDeclaration method = n as MethodDeclaration; | |
| 2930 return !method.isStatic; | |
| 2931 } | |
| 2932 } | |
| 2933 return false; | |
| 2934 } | |
| 2935 | |
| 2936 /** | |
| 2937 * The resolver driving this participant. | |
| 2938 */ | |
| 2939 ResolverVisitor _resolver; | |
| 2940 | |
| 2941 /** | |
| 2942 * A flag indicating whether we are running in strict mode. In strict mode, er
ror reporting is | |
| 2943 * based exclusively on the static type information. | |
| 2944 */ | |
| 2945 bool _strictMode = false; | |
| 2946 | |
| 2947 /** | |
| 2948 * A flag indicating whether we should generate hints. | |
| 2949 */ | |
| 2950 bool _enableHints = false; | |
| 2951 | |
| 2952 /** | |
| 2953 * The type representing the type 'dynamic'. | |
| 2954 */ | |
| 2955 Type2 _dynamicType; | |
| 2956 | |
| 2957 /** | |
| 2958 * The type representing the type 'type'. | |
| 2959 */ | |
| 2960 Type2 _typeType; | |
| 2961 | |
| 2962 /** | |
| 2963 * A utility class for the resolver to answer the question of "what are my sub
types?". | |
| 2964 */ | |
| 2965 SubtypeManager _subtypeManager; | |
| 2966 | |
| 2967 /** | |
| 2968 * The object keeping track of which elements have had their types promoted. | |
| 2969 */ | |
| 2970 TypePromotionManager _promoteManager; | |
| 2971 | |
| 2972 /** | |
| 2973 * The name of the method that can be implemented by a class to allow its inst
ances to be invoked | |
| 2974 * as if they were a function. | |
| 2975 */ | |
| 2976 static String CALL_METHOD_NAME = "call"; | |
| 2977 | |
| 2978 /** | |
| 2979 * The name of the method that will be invoked if an attempt is made to invoke
an undefined method | |
| 2980 * on an object. | |
| 2981 */ | |
| 2982 static String NO_SUCH_METHOD_METHOD_NAME = "noSuchMethod"; | |
| 2983 | |
| 2984 /** | |
| 2985 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 2986 * | |
| 2987 * @param resolver the resolver driving this participant | |
| 2988 */ | |
| 2989 ElementResolver(ResolverVisitor resolver) { | |
| 2990 this._resolver = resolver; | |
| 2991 AnalysisOptions options = resolver.definingLibrary.context.analysisOptions; | |
| 2992 _strictMode = options.strictMode; | |
| 2993 _enableHints = options.hint; | |
| 2994 _dynamicType = resolver.typeProvider.dynamicType; | |
| 2995 _typeType = resolver.typeProvider.typeType; | |
| 2996 _subtypeManager = new SubtypeManager(); | |
| 2997 _promoteManager = resolver.promoteManager; | |
| 2998 } | |
| 2999 Object visitAssignmentExpression(AssignmentExpression node) { | |
| 3000 sc.Token operator = node.operator; | |
| 3001 sc.TokenType operatorType = operator.type; | |
| 3002 if (operatorType != sc.TokenType.EQ) { | |
| 3003 operatorType = operatorFromCompoundAssignment(operatorType); | |
| 3004 Expression leftHandSide = node.leftHandSide; | |
| 3005 if (leftHandSide != null) { | |
| 3006 String methodName = operatorType.lexeme; | |
| 3007 Type2 staticType = getStaticType(leftHandSide); | |
| 3008 MethodElement staticMethod = lookUpMethod(leftHandSide, staticType, meth
odName); | |
| 3009 node.staticElement = staticMethod; | |
| 3010 Type2 propagatedType = getPropagatedType(leftHandSide); | |
| 3011 MethodElement propagatedMethod = lookUpMethod(leftHandSide, propagatedTy
pe, methodName); | |
| 3012 node.propagatedElement = propagatedMethod; | |
| 3013 bool shouldReportMissingMember_static = shouldReportMissingMember(static
Type, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType,
propagatedMethod)); | |
| 3014 bool shouldReportMissingMember_propagated = !shouldReportMissingMember_s
tatic && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMeth
od) : false; | |
| 3015 if (shouldReportMissingMember_propagated) { | |
| 3016 if (memberFoundInSubclass(propagatedType.element, methodName, true, fa
lse)) { | |
| 3017 shouldReportMissingMember_propagated = false; | |
| 3018 } | |
| 3019 } | |
| 3020 if (shouldReportMissingMember_static || shouldReportMissingMember_propag
ated) { | |
| 3021 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWa
rningCode.UNDEFINED_METHOD : HintCode.UNDEFINED_METHOD) as ErrorCode; | |
| 3022 _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissin
gMember_static ? staticType.element : propagatedType.element, errorCode, operato
r, [ | |
| 3023 methodName, | |
| 3024 shouldReportMissingMember_static ? staticType.displayName : propag
atedType.displayName]); | |
| 3025 } | |
| 3026 } | |
| 3027 } | |
| 3028 return null; | |
| 3029 } | |
| 3030 Object visitBinaryExpression(BinaryExpression node) { | |
| 3031 sc.Token operator = node.operator; | |
| 3032 if (operator.isUserDefinableOperator) { | |
| 3033 Expression leftOperand = node.leftOperand; | |
| 3034 if (leftOperand != null) { | |
| 3035 String methodName = operator.lexeme; | |
| 3036 Type2 staticType = getStaticType(leftOperand); | |
| 3037 MethodElement staticMethod = lookUpMethod(leftOperand, staticType, metho
dName); | |
| 3038 node.staticElement = staticMethod; | |
| 3039 Type2 propagatedType = getPropagatedType(leftOperand); | |
| 3040 MethodElement propagatedMethod = lookUpMethod(leftOperand, propagatedTyp
e, methodName); | |
| 3041 node.propagatedElement = propagatedMethod; | |
| 3042 bool shouldReportMissingMember_static = shouldReportMissingMember(static
Type, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType,
propagatedMethod)); | |
| 3043 bool shouldReportMissingMember_propagated = !shouldReportMissingMember_s
tatic && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMeth
od) : false; | |
| 3044 if (shouldReportMissingMember_propagated) { | |
| 3045 if (memberFoundInSubclass(propagatedType.element, methodName, true, fa
lse)) { | |
| 3046 shouldReportMissingMember_propagated = false; | |
| 3047 } | |
| 3048 } | |
| 3049 if (shouldReportMissingMember_static || shouldReportMissingMember_propag
ated) { | |
| 3050 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWa
rningCode.UNDEFINED_OPERATOR : HintCode.UNDEFINED_OPERATOR) as ErrorCode; | |
| 3051 _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissin
gMember_static ? staticType.element : propagatedType.element, errorCode, operato
r, [ | |
| 3052 methodName, | |
| 3053 shouldReportMissingMember_static ? staticType.displayName : propag
atedType.displayName]); | |
| 3054 } | |
| 3055 } | |
| 3056 } | |
| 3057 return null; | |
| 3058 } | |
| 3059 Object visitBreakStatement(BreakStatement node) { | |
| 3060 SimpleIdentifier labelNode = node.label; | |
| 3061 LabelElementImpl labelElement = lookupLabel(node, labelNode); | |
| 3062 if (labelElement != null && labelElement.isOnSwitchMember) { | |
| 3063 _resolver.reportError5(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, lab
elNode, []); | |
| 3064 } | |
| 3065 return null; | |
| 3066 } | |
| 3067 Object visitClassDeclaration(ClassDeclaration node) { | |
| 3068 setMetadata(node.element, node); | |
| 3069 return null; | |
| 3070 } | |
| 3071 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 3072 setMetadata(node.element, node); | |
| 3073 return null; | |
| 3074 } | |
| 3075 Object visitCommentReference(CommentReference node) { | |
| 3076 Identifier identifier = node.identifier; | |
| 3077 if (identifier is SimpleIdentifier) { | |
| 3078 SimpleIdentifier simpleIdentifier = identifier as SimpleIdentifier; | |
| 3079 Element element = resolveSimpleIdentifier(simpleIdentifier); | |
| 3080 if (element == null) { | |
| 3081 element = findImportWithoutPrefix(simpleIdentifier); | |
| 3082 if (element is MultiplyDefinedElement) { | |
| 3083 element = null; | |
| 3084 } | |
| 3085 } | |
| 3086 if (element == null) { | |
| 3087 } else { | |
| 3088 if (element.library == null || element.library != _resolver.definingLibr
ary) { | |
| 3089 } | |
| 3090 simpleIdentifier.staticElement = element; | |
| 3091 if (node.newKeyword != null) { | |
| 3092 if (element is ClassElement) { | |
| 3093 ConstructorElement constructor = ((element as ClassElement)).unnamed
Constructor; | |
| 3094 if (constructor == null) { | |
| 3095 } else { | |
| 3096 simpleIdentifier.staticElement = constructor; | |
| 3097 } | |
| 3098 } else { | |
| 3099 } | |
| 3100 } | |
| 3101 } | |
| 3102 } else if (identifier is PrefixedIdentifier) { | |
| 3103 PrefixedIdentifier prefixedIdentifier = identifier as PrefixedIdentifier; | |
| 3104 SimpleIdentifier prefix = prefixedIdentifier.prefix; | |
| 3105 SimpleIdentifier name = prefixedIdentifier.identifier; | |
| 3106 Element element = resolveSimpleIdentifier(prefix); | |
| 3107 if (element == null) { | |
| 3108 } else { | |
| 3109 if (element is PrefixElement) { | |
| 3110 prefix.staticElement = element; | |
| 3111 element = _resolver.nameScope.lookup(identifier, _resolver.definingLib
rary); | |
| 3112 name.staticElement = element; | |
| 3113 return null; | |
| 3114 } | |
| 3115 LibraryElement library = element.library; | |
| 3116 if (library == null) { | |
| 3117 AnalysisEngine.instance.logger.logError("Found element with null libra
ry: ${element.name}"); | |
| 3118 } else if (library != _resolver.definingLibrary) { | |
| 3119 } | |
| 3120 name.staticElement = element; | |
| 3121 if (node.newKeyword == null) { | |
| 3122 if (element is ClassElement) { | |
| 3123 Element memberElement = lookupGetterOrMethod(((element as ClassEleme
nt)).type, name.name); | |
| 3124 if (memberElement == null) { | |
| 3125 memberElement = ((element as ClassElement)).getNamedConstructor(na
me.name); | |
| 3126 if (memberElement == null) { | |
| 3127 memberElement = lookUpSetter(prefix, ((element as ClassElement))
.type, name.name); | |
| 3128 } | |
| 3129 } | |
| 3130 if (memberElement == null) { | |
| 3131 } else { | |
| 3132 name.staticElement = memberElement; | |
| 3133 } | |
| 3134 } else { | |
| 3135 } | |
| 3136 } else { | |
| 3137 if (element is ClassElement) { | |
| 3138 ConstructorElement constructor = ((element as ClassElement)).getName
dConstructor(name.name); | |
| 3139 if (constructor == null) { | |
| 3140 } else { | |
| 3141 name.staticElement = constructor; | |
| 3142 } | |
| 3143 } else { | |
| 3144 } | |
| 3145 } | |
| 3146 } | |
| 3147 } | |
| 3148 return null; | |
| 3149 } | |
| 3150 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 3151 super.visitConstructorDeclaration(node); | |
| 3152 ConstructorElement element = node.element; | |
| 3153 if (element is ConstructorElementImpl) { | |
| 3154 ConstructorElementImpl constructorElement = element as ConstructorElementI
mpl; | |
| 3155 ConstructorName redirectedNode = node.redirectedConstructor; | |
| 3156 if (redirectedNode != null) { | |
| 3157 ConstructorElement redirectedElement = redirectedNode.staticElement; | |
| 3158 constructorElement.redirectedConstructor = redirectedElement; | |
| 3159 } | |
| 3160 for (ConstructorInitializer initializer in node.initializers) { | |
| 3161 if (initializer is RedirectingConstructorInvocation) { | |
| 3162 ConstructorElement redirectedElement = ((initializer as RedirectingCon
structorInvocation)).staticElement; | |
| 3163 constructorElement.redirectedConstructor = redirectedElement; | |
| 3164 } | |
| 3165 } | |
| 3166 setMetadata(constructorElement, node); | |
| 3167 } | |
| 3168 return null; | |
| 3169 } | |
| 3170 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 3171 SimpleIdentifier fieldName = node.fieldName; | |
| 3172 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 3173 FieldElement fieldElement = ((enclosingClass as ClassElementImpl)).getField(
fieldName.name); | |
| 3174 fieldName.staticElement = fieldElement; | |
| 3175 if (fieldElement == null || fieldElement.isSynthetic) { | |
| 3176 _resolver.reportError5(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_F
IELD, node, [fieldName]); | |
| 3177 } else if (fieldElement.isStatic) { | |
| 3178 _resolver.reportError5(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD,
node, [fieldName]); | |
| 3179 } | |
| 3180 return null; | |
| 3181 } | |
| 3182 Object visitConstructorName(ConstructorName node) { | |
| 3183 Type2 type = node.type.type; | |
| 3184 if (type != null && type.isDynamic) { | |
| 3185 return null; | |
| 3186 } else if (type is! InterfaceType) { | |
| 3187 ASTNode parent = node.parent; | |
| 3188 if (parent is InstanceCreationExpression) { | |
| 3189 if (((parent as InstanceCreationExpression)).isConst) { | |
| 3190 } else { | |
| 3191 } | |
| 3192 } else { | |
| 3193 } | |
| 3194 return null; | |
| 3195 } | |
| 3196 ConstructorElement constructor; | |
| 3197 SimpleIdentifier name = node.name; | |
| 3198 InterfaceType interfaceType = type as InterfaceType; | |
| 3199 LibraryElement definingLibrary = _resolver.definingLibrary; | |
| 3200 if (name == null) { | |
| 3201 constructor = interfaceType.lookUpConstructor(null, definingLibrary); | |
| 3202 } else { | |
| 3203 constructor = interfaceType.lookUpConstructor(name.name, definingLibrary); | |
| 3204 name.staticElement = constructor; | |
| 3205 } | |
| 3206 node.staticElement = constructor; | |
| 3207 return null; | |
| 3208 } | |
| 3209 Object visitContinueStatement(ContinueStatement node) { | |
| 3210 SimpleIdentifier labelNode = node.label; | |
| 3211 LabelElementImpl labelElement = lookupLabel(node, labelNode); | |
| 3212 if (labelElement != null && labelElement.isOnSwitchStatement) { | |
| 3213 _resolver.reportError5(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNo
de, []); | |
| 3214 } | |
| 3215 return null; | |
| 3216 } | |
| 3217 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 3218 setMetadata(node.element, node); | |
| 3219 return null; | |
| 3220 } | |
| 3221 Object visitExportDirective(ExportDirective node) { | |
| 3222 Element element = node.element; | |
| 3223 if (element is ExportElement) { | |
| 3224 resolveCombinators(((element as ExportElement)).exportedLibrary, node.comb
inators); | |
| 3225 setMetadata(element, node); | |
| 3226 } | |
| 3227 return null; | |
| 3228 } | |
| 3229 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 3230 String fieldName = node.identifier.name; | |
| 3231 ClassElement classElement = _resolver.enclosingClass; | |
| 3232 if (classElement != null) { | |
| 3233 FieldElement fieldElement = ((classElement as ClassElementImpl)).getField(
fieldName); | |
| 3234 if (fieldElement == null) { | |
| 3235 _resolver.reportError5(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_
EXISTANT_FIELD, node, [fieldName]); | |
| 3236 } else { | |
| 3237 ParameterElement parameterElement = node.element; | |
| 3238 if (parameterElement is FieldFormalParameterElementImpl) { | |
| 3239 FieldFormalParameterElementImpl fieldFormal = parameterElement as Fiel
dFormalParameterElementImpl; | |
| 3240 fieldFormal.field = fieldElement; | |
| 3241 Type2 declaredType = fieldFormal.type; | |
| 3242 Type2 fieldType = fieldElement.type; | |
| 3243 if (node.type == null) { | |
| 3244 fieldFormal.type = fieldType; | |
| 3245 } | |
| 3246 if (fieldElement.isSynthetic) { | |
| 3247 _resolver.reportError5(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_
NON_EXISTANT_FIELD, node, [fieldName]); | |
| 3248 } else if (fieldElement.isStatic) { | |
| 3249 _resolver.reportError5(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_
STATIC_FIELD, node, [fieldName]); | |
| 3250 } else if (declaredType != null && fieldType != null && !declaredType.
isAssignableTo(fieldType)) { | |
| 3251 _resolver.reportError5(StaticWarningCode.FIELD_INITIALIZING_FORMAL_N
OT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]); | |
| 3252 } | |
| 3253 } else { | |
| 3254 if (fieldElement.isSynthetic) { | |
| 3255 _resolver.reportError5(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_
NON_EXISTANT_FIELD, node, [fieldName]); | |
| 3256 } else if (fieldElement.isStatic) { | |
| 3257 _resolver.reportError5(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_
STATIC_FIELD, node, [fieldName]); | |
| 3258 } | |
| 3259 } | |
| 3260 } | |
| 3261 } | |
| 3262 return super.visitFieldFormalParameter(node); | |
| 3263 } | |
| 3264 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 3265 setMetadata(node.element, node); | |
| 3266 return null; | |
| 3267 } | |
| 3268 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) =>
null; | |
| 3269 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 3270 setMetadata(node.element, node); | |
| 3271 return null; | |
| 3272 } | |
| 3273 Object visitImportDirective(ImportDirective node) { | |
| 3274 SimpleIdentifier prefixNode = node.prefix; | |
| 3275 if (prefixNode != null) { | |
| 3276 String prefixName = prefixNode.name; | |
| 3277 for (PrefixElement prefixElement in _resolver.definingLibrary.prefixes) { | |
| 3278 if (prefixElement.displayName == prefixName) { | |
| 3279 prefixNode.staticElement = prefixElement; | |
| 3280 break; | |
| 3281 } | |
| 3282 } | |
| 3283 } | |
| 3284 ImportElement importElement = node.element; | |
| 3285 if (importElement != null) { | |
| 3286 LibraryElement library = importElement.importedLibrary; | |
| 3287 if (library != null) { | |
| 3288 resolveCombinators(library, node.combinators); | |
| 3289 } | |
| 3290 setMetadata(importElement, node); | |
| 3291 } | |
| 3292 return null; | |
| 3293 } | |
| 3294 Object visitIndexExpression(IndexExpression node) { | |
| 3295 Expression target = node.realTarget; | |
| 3296 Type2 staticType = getStaticType(target); | |
| 3297 Type2 propagatedType = getPropagatedType(target); | |
| 3298 String getterMethodName = sc.TokenType.INDEX.lexeme; | |
| 3299 String setterMethodName = sc.TokenType.INDEX_EQ.lexeme; | |
| 3300 bool isInGetterContext = node.inGetterContext(); | |
| 3301 bool isInSetterContext = node.inSetterContext(); | |
| 3302 if (isInGetterContext && isInSetterContext) { | |
| 3303 MethodElement setterStaticMethod = lookUpMethod(target, staticType, setter
MethodName); | |
| 3304 MethodElement setterPropagatedMethod = lookUpMethod(target, propagatedType
, setterMethodName); | |
| 3305 node.staticElement = setterStaticMethod; | |
| 3306 node.propagatedElement = setterPropagatedMethod; | |
| 3307 checkForUndefinedIndexOperator(node, target, getterMethodName, setterStati
cMethod, setterPropagatedMethod, staticType, propagatedType); | |
| 3308 MethodElement getterStaticMethod = lookUpMethod(target, staticType, getter
MethodName); | |
| 3309 MethodElement getterPropagatedMethod = lookUpMethod(target, propagatedType
, getterMethodName); | |
| 3310 AuxiliaryElements auxiliaryElements = new AuxiliaryElements(getterStaticMe
thod, getterPropagatedMethod); | |
| 3311 node.auxiliaryElements = auxiliaryElements; | |
| 3312 checkForUndefinedIndexOperator(node, target, getterMethodName, getterStati
cMethod, getterPropagatedMethod, staticType, propagatedType); | |
| 3313 } else if (isInGetterContext) { | |
| 3314 MethodElement staticMethod = lookUpMethod(target, staticType, getterMethod
Name); | |
| 3315 MethodElement propagatedMethod = lookUpMethod(target, propagatedType, gett
erMethodName); | |
| 3316 node.staticElement = staticMethod; | |
| 3317 node.propagatedElement = propagatedMethod; | |
| 3318 checkForUndefinedIndexOperator(node, target, getterMethodName, staticMetho
d, propagatedMethod, staticType, propagatedType); | |
| 3319 } else if (isInSetterContext) { | |
| 3320 MethodElement staticMethod = lookUpMethod(target, staticType, setterMethod
Name); | |
| 3321 MethodElement propagatedMethod = lookUpMethod(target, propagatedType, sett
erMethodName); | |
| 3322 node.staticElement = staticMethod; | |
| 3323 node.propagatedElement = propagatedMethod; | |
| 3324 checkForUndefinedIndexOperator(node, target, setterMethodName, staticMetho
d, propagatedMethod, staticType, propagatedType); | |
| 3325 } | |
| 3326 return null; | |
| 3327 } | |
| 3328 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 3329 ConstructorElement invokedConstructor = node.constructorName.staticElement; | |
| 3330 node.staticElement = invokedConstructor; | |
| 3331 ArgumentList argumentList = node.argumentList; | |
| 3332 List<ParameterElement> parameters = resolveArgumentsToParameters(node.isCons
t, argumentList, invokedConstructor); | |
| 3333 if (parameters != null) { | |
| 3334 argumentList.correspondingStaticParameters = parameters; | |
| 3335 } | |
| 3336 return null; | |
| 3337 } | |
| 3338 Object visitLibraryDirective(LibraryDirective node) { | |
| 3339 setMetadata(node.element, node); | |
| 3340 return null; | |
| 3341 } | |
| 3342 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 3343 setMetadata(node.element, node); | |
| 3344 return null; | |
| 3345 } | |
| 3346 Object visitMethodInvocation(MethodInvocation node) { | |
| 3347 SimpleIdentifier methodName = node.methodName; | |
| 3348 Expression target = node.realTarget; | |
| 3349 if (target is SuperExpression && !isSuperInValidContext(target as SuperExpre
ssion)) { | |
| 3350 return null; | |
| 3351 } | |
| 3352 Element staticElement; | |
| 3353 Element propagatedElement; | |
| 3354 if (target == null) { | |
| 3355 staticElement = resolveInvokedElement2(methodName); | |
| 3356 propagatedElement = null; | |
| 3357 } else { | |
| 3358 Type2 staticType = getStaticType(target); | |
| 3359 staticElement = resolveInvokedElement(target, staticType, methodName); | |
| 3360 propagatedElement = resolveInvokedElement(target, getPropagatedType(target
), methodName); | |
| 3361 } | |
| 3362 staticElement = convertSetterToGetter(staticElement); | |
| 3363 propagatedElement = convertSetterToGetter(propagatedElement); | |
| 3364 methodName.staticElement = staticElement; | |
| 3365 methodName.propagatedElement = propagatedElement; | |
| 3366 ArgumentList argumentList = node.argumentList; | |
| 3367 if (staticElement != null) { | |
| 3368 List<ParameterElement> parameters = computeCorrespondingParameters(argumen
tList, staticElement); | |
| 3369 if (parameters != null) { | |
| 3370 argumentList.correspondingStaticParameters = parameters; | |
| 3371 } | |
| 3372 } | |
| 3373 if (propagatedElement != null) { | |
| 3374 List<ParameterElement> parameters = computeCorrespondingParameters(argumen
tList, propagatedElement); | |
| 3375 if (parameters != null) { | |
| 3376 argumentList.correspondingPropagatedParameters = parameters; | |
| 3377 } | |
| 3378 } | |
| 3379 ErrorCode errorCode = checkForInvocationError(target, true, staticElement); | |
| 3380 bool generatedWithTypePropagation = false; | |
| 3381 if (_enableHints && errorCode == null && staticElement == null) { | |
| 3382 errorCode = checkForInvocationError(target, false, propagatedElement); | |
| 3383 if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) { | |
| 3384 ClassElement classElementContext = null; | |
| 3385 if (target == null) { | |
| 3386 classElementContext = _resolver.enclosingClass; | |
| 3387 } else { | |
| 3388 Type2 type = target.bestType; | |
| 3389 if (type != null) { | |
| 3390 if (type.element is ClassElement) { | |
| 3391 classElementContext = type.element as ClassElement; | |
| 3392 } | |
| 3393 } | |
| 3394 } | |
| 3395 if (classElementContext != null) { | |
| 3396 _subtypeManager.ensureLibraryVisited(_resolver.definingLibrary); | |
| 3397 Set<ClassElement> subtypeElements = _subtypeManager.computeAllSubtypes
(classElementContext); | |
| 3398 for (ClassElement subtypeElement in subtypeElements) { | |
| 3399 if (subtypeElement.getMethod(methodName.name) != null) { | |
| 3400 errorCode = null; | |
| 3401 } | |
| 3402 } | |
| 3403 } | |
| 3404 } | |
| 3405 generatedWithTypePropagation = true; | |
| 3406 } | |
| 3407 if (errorCode == null) { | |
| 3408 return null; | |
| 3409 } | |
| 3410 if (identical(errorCode, StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION))
{ | |
| 3411 _resolver.reportError5(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, m
ethodName, [methodName.name]); | |
| 3412 } else if (identical(errorCode, CompileTimeErrorCode.UNDEFINED_FUNCTION)) { | |
| 3413 _resolver.reportError5(CompileTimeErrorCode.UNDEFINED_FUNCTION, methodName
, [methodName.name]); | |
| 3414 } else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) { | |
| 3415 String targetTypeName; | |
| 3416 if (target == null) { | |
| 3417 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 3418 targetTypeName = enclosingClass.displayName; | |
| 3419 ErrorCode proxyErrorCode = (generatedWithTypePropagation ? HintCode.UNDE
FINED_METHOD : StaticTypeWarningCode.UNDEFINED_METHOD) as ErrorCode; | |
| 3420 _resolver.reportErrorProxyConditionalAnalysisError(_resolver.enclosingCl
ass, proxyErrorCode, methodName, [methodName.name, targetTypeName]); | |
| 3421 } else { | |
| 3422 Type2 targetType = null; | |
| 3423 if (!generatedWithTypePropagation) { | |
| 3424 targetType = getStaticType(target); | |
| 3425 } else { | |
| 3426 targetType = getPropagatedType(target); | |
| 3427 if (targetType == null) { | |
| 3428 targetType = getStaticType(target); | |
| 3429 } | |
| 3430 } | |
| 3431 if (targetType != null && targetType.isDartCoreFunction && methodName.na
me == CALL_METHOD_NAME) { | |
| 3432 return null; | |
| 3433 } | |
| 3434 targetTypeName = targetType == null ? null : targetType.displayName; | |
| 3435 ErrorCode proxyErrorCode = (generatedWithTypePropagation ? HintCode.UNDE
FINED_METHOD : StaticTypeWarningCode.UNDEFINED_METHOD) as ErrorCode; | |
| 3436 _resolver.reportErrorProxyConditionalAnalysisError(targetType.element, p
roxyErrorCode, methodName, [methodName.name, targetTypeName]); | |
| 3437 } | |
| 3438 } else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_SUPER_METHOD
)) { | |
| 3439 Type2 targetType = getStaticType(target); | |
| 3440 String targetTypeName = targetType == null ? null : targetType.name; | |
| 3441 _resolver.reportError5(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, metho
dName, [methodName.name, targetTypeName]); | |
| 3442 } | |
| 3443 return null; | |
| 3444 } | |
| 3445 Object visitPartDirective(PartDirective node) { | |
| 3446 setMetadata(node.element, node); | |
| 3447 return null; | |
| 3448 } | |
| 3449 Object visitPartOfDirective(PartOfDirective node) { | |
| 3450 setMetadata(node.element, node); | |
| 3451 return null; | |
| 3452 } | |
| 3453 Object visitPostfixExpression(PostfixExpression node) { | |
| 3454 Expression operand = node.operand; | |
| 3455 String methodName = getPostfixOperator(node); | |
| 3456 Type2 staticType = getStaticType(operand); | |
| 3457 MethodElement staticMethod = lookUpMethod(operand, staticType, methodName); | |
| 3458 node.staticElement = staticMethod; | |
| 3459 Type2 propagatedType = getPropagatedType(operand); | |
| 3460 MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, metho
dName); | |
| 3461 node.propagatedElement = propagatedMethod; | |
| 3462 bool shouldReportMissingMember_static = shouldReportMissingMember(staticType
, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, pro
pagatedMethod)); | |
| 3463 bool shouldReportMissingMember_propagated = !shouldReportMissingMember_stati
c && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod)
: false; | |
| 3464 if (shouldReportMissingMember_propagated) { | |
| 3465 if (memberFoundInSubclass(propagatedType.element, methodName, true, false)
) { | |
| 3466 shouldReportMissingMember_propagated = false; | |
| 3467 } | |
| 3468 } | |
| 3469 if (shouldReportMissingMember_static || shouldReportMissingMember_propagated
) { | |
| 3470 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarnin
gCode.UNDEFINED_OPERATOR : HintCode.UNDEFINED_OPERATOR) as ErrorCode; | |
| 3471 _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissingMem
ber_static ? staticType.element : propagatedType.element, errorCode, node.operat
or, [ | |
| 3472 methodName, | |
| 3473 shouldReportMissingMember_static ? staticType.displayName : propagated
Type.displayName]); | |
| 3474 } | |
| 3475 return null; | |
| 3476 } | |
| 3477 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 3478 SimpleIdentifier prefix = node.prefix; | |
| 3479 SimpleIdentifier identifier = node.identifier; | |
| 3480 Element prefixElement = prefix.staticElement; | |
| 3481 if (prefixElement is PrefixElement) { | |
| 3482 Element element = _resolver.nameScope.lookup(node, _resolver.definingLibra
ry); | |
| 3483 if (element == null && identifier.inSetterContext()) { | |
| 3484 element = _resolver.nameScope.lookup(new ElementResolver_SyntheticIdenti
fier("${node.name}="), _resolver.definingLibrary); | |
| 3485 } | |
| 3486 if (element == null) { | |
| 3487 if (identifier.inSetterContext()) { | |
| 3488 _resolver.reportError5(StaticWarningCode.UNDEFINED_SETTER, identifier,
[identifier.name, prefixElement.name]); | |
| 3489 } else { | |
| 3490 _resolver.reportError5(StaticWarningCode.UNDEFINED_GETTER, identifier,
[identifier.name, prefixElement.name]); | |
| 3491 } | |
| 3492 return null; | |
| 3493 } | |
| 3494 if (element is PropertyAccessorElement && identifier.inSetterContext()) { | |
| 3495 PropertyInducingElement variable = ((element as PropertyAccessorElement)
).variable; | |
| 3496 if (variable != null) { | |
| 3497 PropertyAccessorElement setter = variable.setter; | |
| 3498 if (setter != null) { | |
| 3499 element = setter; | |
| 3500 } | |
| 3501 } | |
| 3502 } | |
| 3503 identifier.staticElement = element; | |
| 3504 if (node.parent is Annotation) { | |
| 3505 Annotation annotation = node.parent as Annotation; | |
| 3506 resolveAnnotationElement(annotation, element, null); | |
| 3507 return null; | |
| 3508 } | |
| 3509 return null; | |
| 3510 } | |
| 3511 if (node.parent is Annotation) { | |
| 3512 Annotation annotation = node.parent as Annotation; | |
| 3513 resolveAnnotationElement(annotation, prefixElement, identifier); | |
| 3514 } | |
| 3515 resolvePropertyAccess(prefix, identifier); | |
| 3516 return null; | |
| 3517 } | |
| 3518 Object visitPrefixExpression(PrefixExpression node) { | |
| 3519 sc.Token operator = node.operator; | |
| 3520 sc.TokenType operatorType = operator.type; | |
| 3521 if (operatorType.isUserDefinableOperator || identical(operatorType, sc.Token
Type.PLUS_PLUS) || identical(operatorType, sc.TokenType.MINUS_MINUS)) { | |
| 3522 Expression operand = node.operand; | |
| 3523 String methodName = getPrefixOperator(node); | |
| 3524 Type2 staticType = getStaticType(operand); | |
| 3525 MethodElement staticMethod = lookUpMethod(operand, staticType, methodName)
; | |
| 3526 node.staticElement = staticMethod; | |
| 3527 Type2 propagatedType = getPropagatedType(operand); | |
| 3528 MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, met
hodName); | |
| 3529 node.propagatedElement = propagatedMethod; | |
| 3530 bool shouldReportMissingMember_static = shouldReportMissingMember(staticTy
pe, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, p
ropagatedMethod)); | |
| 3531 bool shouldReportMissingMember_propagated = !shouldReportMissingMember_sta
tic && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod
) : false; | |
| 3532 if (shouldReportMissingMember_propagated) { | |
| 3533 if (memberFoundInSubclass(propagatedType.element, methodName, true, fals
e)) { | |
| 3534 shouldReportMissingMember_propagated = false; | |
| 3535 } | |
| 3536 } | |
| 3537 if (shouldReportMissingMember_static || shouldReportMissingMember_propagat
ed) { | |
| 3538 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarn
ingCode.UNDEFINED_OPERATOR : HintCode.UNDEFINED_OPERATOR) as ErrorCode; | |
| 3539 _resolver.reportErrorProxyConditionalAnalysisError3(shouldReportMissingM
ember_static ? staticType.element : propagatedType.element, errorCode, operator,
[ | |
| 3540 methodName, | |
| 3541 shouldReportMissingMember_static ? staticType.displayName : propagat
edType.displayName]); | |
| 3542 } | |
| 3543 } | |
| 3544 return null; | |
| 3545 } | |
| 3546 Object visitPropertyAccess(PropertyAccess node) { | |
| 3547 Expression target = node.realTarget; | |
| 3548 if (target is SuperExpression && !isSuperInValidContext(target as SuperExpre
ssion)) { | |
| 3549 return null; | |
| 3550 } | |
| 3551 SimpleIdentifier propertyName = node.propertyName; | |
| 3552 resolvePropertyAccess(target, propertyName); | |
| 3553 return null; | |
| 3554 } | |
| 3555 Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation
node) { | |
| 3556 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 3557 if (enclosingClass == null) { | |
| 3558 return null; | |
| 3559 } | |
| 3560 SimpleIdentifier name = node.constructorName; | |
| 3561 ConstructorElement element; | |
| 3562 if (name == null) { | |
| 3563 element = enclosingClass.unnamedConstructor; | |
| 3564 } else { | |
| 3565 element = enclosingClass.getNamedConstructor(name.name); | |
| 3566 } | |
| 3567 if (element == null) { | |
| 3568 return null; | |
| 3569 } | |
| 3570 if (name != null) { | |
| 3571 name.staticElement = element; | |
| 3572 } | |
| 3573 node.staticElement = element; | |
| 3574 ArgumentList argumentList = node.argumentList; | |
| 3575 List<ParameterElement> parameters = resolveArgumentsToParameters(false, argu
mentList, element); | |
| 3576 if (parameters != null) { | |
| 3577 argumentList.correspondingStaticParameters = parameters; | |
| 3578 } | |
| 3579 return null; | |
| 3580 } | |
| 3581 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 3582 if (node.staticElement != null) { | |
| 3583 return null; | |
| 3584 } | |
| 3585 if (node.name == _dynamicType.name) { | |
| 3586 node.staticElement = _dynamicType.element; | |
| 3587 node.staticType = _typeType; | |
| 3588 return null; | |
| 3589 } | |
| 3590 Element element = resolveSimpleIdentifier(node); | |
| 3591 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 3592 if (isFactoryConstructorReturnType(node) && element != enclosingClass) { | |
| 3593 _resolver.reportError5(CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLA
SS, node, []); | |
| 3594 } else if (isConstructorReturnType(node) && element != enclosingClass) { | |
| 3595 _resolver.reportError5(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node
, []); | |
| 3596 element = null; | |
| 3597 } else if (element == null || (element is PrefixElement && !isValidAsPrefix(
node))) { | |
| 3598 if (isConstructorReturnType(node)) { | |
| 3599 _resolver.reportError5(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, no
de, []); | |
| 3600 } else { | |
| 3601 _resolver.reportErrorProxyConditionalAnalysisError(_resolver.enclosingCl
ass, StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]); | |
| 3602 } | |
| 3603 } | |
| 3604 node.staticElement = element; | |
| 3605 if (node.inSetterContext() && node.inGetterContext() && enclosingClass != nu
ll) { | |
| 3606 InterfaceType enclosingType = enclosingClass.type; | |
| 3607 AuxiliaryElements auxiliaryElements = new AuxiliaryElements(lookUpGetter(n
ull, enclosingType, node.name), null); | |
| 3608 node.auxiliaryElements = auxiliaryElements; | |
| 3609 } | |
| 3610 if (node.parent is Annotation) { | |
| 3611 Annotation annotation = node.parent as Annotation; | |
| 3612 resolveAnnotationElement(annotation, element, null); | |
| 3613 } | |
| 3614 return null; | |
| 3615 } | |
| 3616 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 3617 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 3618 if (enclosingClass == null) { | |
| 3619 return null; | |
| 3620 } | |
| 3621 InterfaceType superType = enclosingClass.supertype; | |
| 3622 if (superType == null) { | |
| 3623 return null; | |
| 3624 } | |
| 3625 SimpleIdentifier name = node.constructorName; | |
| 3626 String superName = name != null ? name.name : null; | |
| 3627 ConstructorElement element = superType.lookUpConstructor(superName, _resolve
r.definingLibrary); | |
| 3628 if (element == null) { | |
| 3629 if (name != null) { | |
| 3630 _resolver.reportError5(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INI
TIALIZER, node, [superType.displayName, name]); | |
| 3631 } else { | |
| 3632 _resolver.reportError5(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INI
TIALIZER_DEFAULT, node, [superType.displayName]); | |
| 3633 } | |
| 3634 return null; | |
| 3635 } else { | |
| 3636 if (element.isFactory) { | |
| 3637 _resolver.reportError5(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR,
node, [element]); | |
| 3638 } | |
| 3639 } | |
| 3640 if (name != null) { | |
| 3641 name.staticElement = element; | |
| 3642 } | |
| 3643 node.staticElement = element; | |
| 3644 ArgumentList argumentList = node.argumentList; | |
| 3645 List<ParameterElement> parameters = resolveArgumentsToParameters(isInConstCo
nstructor, argumentList, element); | |
| 3646 if (parameters != null) { | |
| 3647 argumentList.correspondingStaticParameters = parameters; | |
| 3648 } | |
| 3649 return null; | |
| 3650 } | |
| 3651 Object visitSuperExpression(SuperExpression node) { | |
| 3652 if (!isSuperInValidContext(node)) { | |
| 3653 _resolver.reportError5(CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node
, []); | |
| 3654 } | |
| 3655 return super.visitSuperExpression(node); | |
| 3656 } | |
| 3657 Object visitTypeParameter(TypeParameter node) { | |
| 3658 TypeName bound = node.bound; | |
| 3659 if (bound != null) { | |
| 3660 TypeParameterElementImpl typeParameter = node.name.staticElement as TypePa
rameterElementImpl; | |
| 3661 if (typeParameter != null) { | |
| 3662 typeParameter.bound = bound.type; | |
| 3663 } | |
| 3664 } | |
| 3665 setMetadata(node.element, node); | |
| 3666 return null; | |
| 3667 } | |
| 3668 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 3669 setMetadata(node.element, node); | |
| 3670 return null; | |
| 3671 } | |
| 3672 | |
| 3673 /** | |
| 3674 * Generate annotation elements for each of the annotations in the given node
list and add them to | |
| 3675 * the given list of elements. | |
| 3676 * | |
| 3677 * @param annotationList the list of elements to which new elements are to be
added | |
| 3678 * @param annotations the AST nodes used to generate new elements | |
| 3679 */ | |
| 3680 void addAnnotations(List<ElementAnnotationImpl> annotationList, NodeList<Annot
ation> annotations) { | |
| 3681 for (Annotation annotationNode in annotations) { | |
| 3682 Element resolvedElement = annotationNode.element; | |
| 3683 if (resolvedElement != null) { | |
| 3684 annotationList.add(new ElementAnnotationImpl(resolvedElement)); | |
| 3685 } | |
| 3686 } | |
| 3687 } | |
| 3688 | |
| 3689 /** | |
| 3690 * Given that we have found code to invoke the given element, return the error
code that should be | |
| 3691 * reported, or `null` if no error should be reported. | |
| 3692 * | |
| 3693 * @param target the target of the invocation, or `null` if there was no targe
t | |
| 3694 * @param useStaticContext | |
| 3695 * @param element the element to be invoked | |
| 3696 * @return the error code that should be reported | |
| 3697 */ | |
| 3698 ErrorCode checkForInvocationError(Expression target, bool useStaticContext, El
ement element) { | |
| 3699 if (element is PrefixElement) { | |
| 3700 element = null; | |
| 3701 } | |
| 3702 if (element is PropertyAccessorElement) { | |
| 3703 FunctionType getterType = ((element as PropertyAccessorElement)).type; | |
| 3704 if (getterType != null) { | |
| 3705 Type2 returnType = getterType.returnType; | |
| 3706 if (!isExecutableType(returnType)) { | |
| 3707 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 3708 } | |
| 3709 } | |
| 3710 } else if (element is ExecutableElement) { | |
| 3711 return null; | |
| 3712 } else if (element == null && target is SuperExpression) { | |
| 3713 return StaticTypeWarningCode.UNDEFINED_SUPER_METHOD; | |
| 3714 } else { | |
| 3715 if (element is PropertyInducingElement) { | |
| 3716 PropertyAccessorElement getter = ((element as PropertyInducingElement)).
getter; | |
| 3717 FunctionType getterType = getter.type; | |
| 3718 if (getterType != null) { | |
| 3719 Type2 returnType = getterType.returnType; | |
| 3720 if (!isExecutableType(returnType)) { | |
| 3721 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 3722 } | |
| 3723 } | |
| 3724 } else if (element is VariableElement) { | |
| 3725 Type2 variableType = ((element as VariableElement)).type; | |
| 3726 if (!isExecutableType(variableType)) { | |
| 3727 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 3728 } | |
| 3729 } else { | |
| 3730 if (target == null) { | |
| 3731 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 3732 if (enclosingClass == null) { | |
| 3733 return CompileTimeErrorCode.UNDEFINED_FUNCTION; | |
| 3734 } else if (element == null) { | |
| 3735 return StaticTypeWarningCode.UNDEFINED_METHOD; | |
| 3736 } else { | |
| 3737 return StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION; | |
| 3738 } | |
| 3739 } else { | |
| 3740 Type2 targetType; | |
| 3741 if (useStaticContext) { | |
| 3742 targetType = getStaticType(target); | |
| 3743 } else { | |
| 3744 targetType = target.bestType; | |
| 3745 } | |
| 3746 if (targetType == null) { | |
| 3747 return CompileTimeErrorCode.UNDEFINED_FUNCTION; | |
| 3748 } else if (!targetType.isDynamic && !targetType.isBottom) { | |
| 3749 return StaticTypeWarningCode.UNDEFINED_METHOD; | |
| 3750 } | |
| 3751 } | |
| 3752 } | |
| 3753 } | |
| 3754 return null; | |
| 3755 } | |
| 3756 | |
| 3757 /** | |
| 3758 * Check that the for some index expression that the method element was resolv
ed, otherwise a | |
| 3759 * [StaticWarningCode#UNDEFINED_OPERATOR] is generated. | |
| 3760 * | |
| 3761 * @param node the index expression to resolve | |
| 3762 * @param target the target of the expression | |
| 3763 * @param methodName the name of the operator associated with the context of u
sing of the given | |
| 3764 * index expression | |
| 3765 * @return `true` if and only if an error code is generated on the passed node | |
| 3766 */ | |
| 3767 bool checkForUndefinedIndexOperator(IndexExpression node, Expression target, S
tring methodName, MethodElement staticMethod, MethodElement propagatedMethod, Ty
pe2 staticType, Type2 propagatedType) { | |
| 3768 bool shouldReportMissingMember_static = shouldReportMissingMember(staticType
, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, pro
pagatedMethod)); | |
| 3769 bool shouldReportMissingMember_propagated = !shouldReportMissingMember_stati
c && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod)
: false; | |
| 3770 if (shouldReportMissingMember_propagated) { | |
| 3771 if (memberFoundInSubclass(propagatedType.element, methodName, true, false)
) { | |
| 3772 shouldReportMissingMember_propagated = false; | |
| 3773 } | |
| 3774 } | |
| 3775 if (shouldReportMissingMember_static || shouldReportMissingMember_propagated
) { | |
| 3776 sc.Token leftBracket = node.leftBracket; | |
| 3777 sc.Token rightBracket = node.rightBracket; | |
| 3778 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarnin
gCode.UNDEFINED_OPERATOR : HintCode.UNDEFINED_OPERATOR) as ErrorCode; | |
| 3779 if (leftBracket == null || rightBracket == null) { | |
| 3780 _resolver.reportErrorProxyConditionalAnalysisError(shouldReportMissingMe
mber_static ? staticType.element : propagatedType.element, errorCode, node, [ | |
| 3781 methodName, | |
| 3782 shouldReportMissingMember_static ? staticType.displayName : propagat
edType.displayName]); | |
| 3783 } else { | |
| 3784 int offset = leftBracket.offset; | |
| 3785 int length = rightBracket.offset - offset + 1; | |
| 3786 _resolver.reportErrorProxyConditionalAnalysisError2(shouldReportMissingM
ember_static ? staticType.element : propagatedType.element, errorCode, offset, l
ength, [ | |
| 3787 methodName, | |
| 3788 shouldReportMissingMember_static ? staticType.displayName : propagat
edType.displayName]); | |
| 3789 } | |
| 3790 return true; | |
| 3791 } | |
| 3792 return false; | |
| 3793 } | |
| 3794 | |
| 3795 /** | |
| 3796 * Given a list of arguments and the element that will be invoked using those
argument, compute | |
| 3797 * the list of parameters that correspond to the list of arguments. Return the
parameters that | |
| 3798 * correspond to the arguments, or `null` if no correspondence could be comput
ed. | |
| 3799 * | |
| 3800 * @param argumentList the list of arguments being passed to the element | |
| 3801 * @param executableElement the element that will be invoked with the argument
s | |
| 3802 * @return the parameters that correspond to the arguments | |
| 3803 */ | |
| 3804 List<ParameterElement> computeCorrespondingParameters(ArgumentList argumentLis
t, Element element) { | |
| 3805 if (element is PropertyAccessorElement) { | |
| 3806 FunctionType getterType = ((element as PropertyAccessorElement)).type; | |
| 3807 if (getterType != null) { | |
| 3808 Type2 getterReturnType = getterType.returnType; | |
| 3809 if (getterReturnType is InterfaceType) { | |
| 3810 MethodElement callMethod = ((getterReturnType as InterfaceType)).lookU
pMethod(CALL_METHOD_NAME, _resolver.definingLibrary); | |
| 3811 if (callMethod != null) { | |
| 3812 return resolveArgumentsToParameters(false, argumentList, callMethod)
; | |
| 3813 } | |
| 3814 } else if (getterReturnType is FunctionType) { | |
| 3815 Element functionElement = ((getterReturnType as FunctionType)).element
; | |
| 3816 if (functionElement is ExecutableElement) { | |
| 3817 return resolveArgumentsToParameters(false, argumentList, functionEle
ment as ExecutableElement); | |
| 3818 } | |
| 3819 } | |
| 3820 } | |
| 3821 } else if (element is ExecutableElement) { | |
| 3822 return resolveArgumentsToParameters(false, argumentList, element as Execut
ableElement); | |
| 3823 } else if (element is VariableElement) { | |
| 3824 VariableElement variable = element as VariableElement; | |
| 3825 Type2 type = _promoteManager.getStaticType(variable); | |
| 3826 if (type is FunctionType) { | |
| 3827 FunctionType functionType = type as FunctionType; | |
| 3828 List<ParameterElement> parameters = functionType.parameters; | |
| 3829 return resolveArgumentsToParameters2(false, argumentList, parameters); | |
| 3830 } else if (type is InterfaceType) { | |
| 3831 MethodElement callMethod = ((type as InterfaceType)).lookUpMethod(CALL_M
ETHOD_NAME, _resolver.definingLibrary); | |
| 3832 if (callMethod != null) { | |
| 3833 List<ParameterElement> parameters = callMethod.parameters; | |
| 3834 return resolveArgumentsToParameters2(false, argumentList, parameters); | |
| 3835 } | |
| 3836 } | |
| 3837 } | |
| 3838 return null; | |
| 3839 } | |
| 3840 | |
| 3841 /** | |
| 3842 * If the given element is a setter, return the getter associated with it. Oth
erwise, return the | |
| 3843 * element unchanged. | |
| 3844 * | |
| 3845 * @param element the element to be normalized | |
| 3846 * @return a non-setter element derived from the given element | |
| 3847 */ | |
| 3848 Element convertSetterToGetter(Element element) { | |
| 3849 if (element is PropertyAccessorElement) { | |
| 3850 return ((element as PropertyAccessorElement)).variable.getter; | |
| 3851 } | |
| 3852 return element; | |
| 3853 } | |
| 3854 | |
| 3855 /** | |
| 3856 * Look for any declarations of the given identifier that are imported using a
prefix. Return the | |
| 3857 * element that was found, or `null` if the name is not imported using a prefi
x. | |
| 3858 * | |
| 3859 * @param identifier the identifier that might have been imported using a pref
ix | |
| 3860 * @return the element that was found | |
| 3861 */ | |
| 3862 Element findImportWithoutPrefix(SimpleIdentifier identifier) { | |
| 3863 Element element = null; | |
| 3864 Scope nameScope = _resolver.nameScope; | |
| 3865 LibraryElement definingLibrary = _resolver.definingLibrary; | |
| 3866 for (ImportElement importElement in definingLibrary.imports) { | |
| 3867 PrefixElement prefixElement = importElement.prefix; | |
| 3868 if (prefixElement != null) { | |
| 3869 Identifier prefixedIdentifier = new ElementResolver_SyntheticIdentifier(
"${prefixElement.name}.${identifier.name}"); | |
| 3870 Element importedElement = nameScope.lookup(prefixedIdentifier, definingL
ibrary); | |
| 3871 if (importedElement != null) { | |
| 3872 if (element == null) { | |
| 3873 element = importedElement; | |
| 3874 } else { | |
| 3875 element = MultiplyDefinedElementImpl.fromElements(definingLibrary.co
ntext, element, importedElement); | |
| 3876 } | |
| 3877 } | |
| 3878 } | |
| 3879 } | |
| 3880 return element; | |
| 3881 } | |
| 3882 | |
| 3883 /** | |
| 3884 * Return the name of the method invoked by the given postfix expression. | |
| 3885 * | |
| 3886 * @param node the postfix expression being invoked | |
| 3887 * @return the name of the method invoked by the expression | |
| 3888 */ | |
| 3889 String getPostfixOperator(PostfixExpression node) => (identical(node.operator.
type, sc.TokenType.PLUS_PLUS)) ? sc.TokenType.PLUS.lexeme : sc.TokenType.MINUS.l
exeme; | |
| 3890 | |
| 3891 /** | |
| 3892 * Return the name of the method invoked by the given postfix expression. | |
| 3893 * | |
| 3894 * @param node the postfix expression being invoked | |
| 3895 * @return the name of the method invoked by the expression | |
| 3896 */ | |
| 3897 String getPrefixOperator(PrefixExpression node) { | |
| 3898 sc.Token operator = node.operator; | |
| 3899 sc.TokenType operatorType = operator.type; | |
| 3900 if (identical(operatorType, sc.TokenType.PLUS_PLUS)) { | |
| 3901 return sc.TokenType.PLUS.lexeme; | |
| 3902 } else if (identical(operatorType, sc.TokenType.MINUS_MINUS)) { | |
| 3903 return sc.TokenType.MINUS.lexeme; | |
| 3904 } else if (identical(operatorType, sc.TokenType.MINUS)) { | |
| 3905 return "unary-"; | |
| 3906 } else { | |
| 3907 return operator.lexeme; | |
| 3908 } | |
| 3909 } | |
| 3910 | |
| 3911 /** | |
| 3912 * Return the propagated type of the given expression that is to be used for t
ype analysis. | |
| 3913 * | |
| 3914 * @param expression the expression whose type is to be returned | |
| 3915 * @return the type of the given expression | |
| 3916 */ | |
| 3917 Type2 getPropagatedType(Expression expression) { | |
| 3918 Type2 propagatedType = resolveTypeParameter(expression.propagatedType); | |
| 3919 if (propagatedType is FunctionType) { | |
| 3920 propagatedType = _resolver.typeProvider.functionType; | |
| 3921 } | |
| 3922 return propagatedType; | |
| 3923 } | |
| 3924 | |
| 3925 /** | |
| 3926 * Return the static type of the given expression that is to be used for type
analysis. | |
| 3927 * | |
| 3928 * @param expression the expression whose type is to be returned | |
| 3929 * @return the type of the given expression | |
| 3930 */ | |
| 3931 Type2 getStaticType(Expression expression) { | |
| 3932 if (expression is NullLiteral) { | |
| 3933 return _resolver.typeProvider.bottomType; | |
| 3934 } | |
| 3935 Type2 staticType = resolveTypeParameter(expression.staticType); | |
| 3936 if (staticType is FunctionType) { | |
| 3937 staticType = _resolver.typeProvider.functionType; | |
| 3938 } | |
| 3939 return staticType; | |
| 3940 } | |
| 3941 | |
| 3942 /** | |
| 3943 * Return `true` if the given type represents an object that could be invoked
using the call | |
| 3944 * operator '()'. | |
| 3945 * | |
| 3946 * @param type the type being tested | |
| 3947 * @return `true` if the given type represents an object that could be invoked | |
| 3948 */ | |
| 3949 bool isExecutableType(Type2 type) { | |
| 3950 if (type.isDynamic || (type is FunctionType) || type.isDartCoreFunction || t
ype.isObject) { | |
| 3951 return true; | |
| 3952 } else if (type is InterfaceType) { | |
| 3953 ClassElement classElement = ((type as InterfaceType)).element; | |
| 3954 MethodElement methodElement = classElement.lookUpMethod(CALL_METHOD_NAME,
_resolver.definingLibrary); | |
| 3955 return methodElement != null; | |
| 3956 } | |
| 3957 return false; | |
| 3958 } | |
| 3959 | |
| 3960 /** | |
| 3961 * @return `true` iff current enclosing function is constant constructor decla
ration. | |
| 3962 */ | |
| 3963 bool get isInConstConstructor { | |
| 3964 ExecutableElement function = _resolver.enclosingFunction; | |
| 3965 if (function is ConstructorElement) { | |
| 3966 return ((function as ConstructorElement)).isConst; | |
| 3967 } | |
| 3968 return false; | |
| 3969 } | |
| 3970 | |
| 3971 /** | |
| 3972 * Return `true` if the given element is a static element. | |
| 3973 * | |
| 3974 * @param element the element being tested | |
| 3975 * @return `true` if the given element is a static element | |
| 3976 */ | |
| 3977 bool isStatic(Element element) { | |
| 3978 if (element is ExecutableElement) { | |
| 3979 return ((element as ExecutableElement)).isStatic; | |
| 3980 } else if (element is PropertyInducingElement) { | |
| 3981 return ((element as PropertyInducingElement)).isStatic; | |
| 3982 } | |
| 3983 return false; | |
| 3984 } | |
| 3985 | |
| 3986 /** | |
| 3987 * Return `true` if the given node can validly be resolved to a prefix: | |
| 3988 * | |
| 3989 * * it is the prefix in an import directive, or | |
| 3990 * * it is the prefix in a prefixed identifier. | |
| 3991 * | |
| 3992 * | |
| 3993 * @param node the node being tested | |
| 3994 * @return `true` if the given node is the prefix in an import directive | |
| 3995 */ | |
| 3996 bool isValidAsPrefix(SimpleIdentifier node) { | |
| 3997 ASTNode parent = node.parent; | |
| 3998 if (parent is ImportDirective) { | |
| 3999 return identical(((parent as ImportDirective)).prefix, node); | |
| 4000 } else if (parent is PrefixedIdentifier) { | |
| 4001 return true; | |
| 4002 } else if (parent is MethodInvocation) { | |
| 4003 return identical(((parent as MethodInvocation)).target, node); | |
| 4004 } | |
| 4005 return false; | |
| 4006 } | |
| 4007 | |
| 4008 /** | |
| 4009 * Look up the getter with the given name in the given type. Return the elemen
t representing the | |
| 4010 * getter that was found, or `null` if there is no getter with the given name. | |
| 4011 * | |
| 4012 * @param target the target of the invocation, or `null` if there is no target | |
| 4013 * @param type the type in which the getter is defined | |
| 4014 * @param getterName the name of the getter being looked up | |
| 4015 * @return the element representing the getter that was found | |
| 4016 */ | |
| 4017 PropertyAccessorElement lookUpGetter(Expression target, Type2 type, String get
terName) { | |
| 4018 type = resolveTypeParameter(type); | |
| 4019 if (type is InterfaceType) { | |
| 4020 InterfaceType interfaceType = type as InterfaceType; | |
| 4021 PropertyAccessorElement accessor; | |
| 4022 if (target is SuperExpression) { | |
| 4023 accessor = interfaceType.lookUpGetterInSuperclass(getterName, _resolver.
definingLibrary); | |
| 4024 } else { | |
| 4025 accessor = interfaceType.lookUpGetter(getterName, _resolver.definingLibr
ary); | |
| 4026 } | |
| 4027 if (accessor != null) { | |
| 4028 return accessor; | |
| 4029 } | |
| 4030 return lookUpGetterInInterfaces(interfaceType, false, getterName, new Set<
ClassElement>()); | |
| 4031 } | |
| 4032 return null; | |
| 4033 } | |
| 4034 | |
| 4035 /** | |
| 4036 * Look up the getter with the given name in the interfaces implemented by the
given type, either | |
| 4037 * directly or indirectly. Return the element representing the getter that was
found, or | |
| 4038 * `null` if there is no getter with the given name. | |
| 4039 * | |
| 4040 * @param targetType the type in which the getter might be defined | |
| 4041 * @param includeTargetType `true` if the search should include the target typ
e | |
| 4042 * @param getterName the name of the getter being looked up | |
| 4043 * @param visitedInterfaces a set containing all of the interfaces that have b
een examined, used | |
| 4044 * to prevent infinite recursion and to optimize the search | |
| 4045 * @return the element representing the getter that was found | |
| 4046 */ | |
| 4047 PropertyAccessorElement lookUpGetterInInterfaces(InterfaceType targetType, boo
l includeTargetType, String getterName, Set<ClassElement> visitedInterfaces) { | |
| 4048 ClassElement targetClass = targetType.element; | |
| 4049 if (visitedInterfaces.contains(targetClass)) { | |
| 4050 return null; | |
| 4051 } | |
| 4052 javaSetAdd(visitedInterfaces, targetClass); | |
| 4053 if (includeTargetType) { | |
| 4054 PropertyAccessorElement getter = targetType.getGetter(getterName); | |
| 4055 if (getter != null && getter.isAccessibleIn(_resolver.definingLibrary)) { | |
| 4056 return getter; | |
| 4057 } | |
| 4058 } | |
| 4059 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 4060 PropertyAccessorElement getter = lookUpGetterInInterfaces(interfaceType, t
rue, getterName, visitedInterfaces); | |
| 4061 if (getter != null) { | |
| 4062 return getter; | |
| 4063 } | |
| 4064 } | |
| 4065 for (InterfaceType mixinType in targetType.mixins) { | |
| 4066 PropertyAccessorElement getter = lookUpGetterInInterfaces(mixinType, true,
getterName, visitedInterfaces); | |
| 4067 if (getter != null) { | |
| 4068 return getter; | |
| 4069 } | |
| 4070 } | |
| 4071 InterfaceType superclass = targetType.superclass; | |
| 4072 if (superclass == null) { | |
| 4073 return null; | |
| 4074 } | |
| 4075 return lookUpGetterInInterfaces(superclass, true, getterName, visitedInterfa
ces); | |
| 4076 } | |
| 4077 | |
| 4078 /** | |
| 4079 * Look up the method or getter with the given name in the given type. Return
the element | |
| 4080 * representing the method or getter that was found, or `null` if there is no
method or | |
| 4081 * getter with the given name. | |
| 4082 * | |
| 4083 * @param type the type in which the method or getter is defined | |
| 4084 * @param memberName the name of the method or getter being looked up | |
| 4085 * @return the element representing the method or getter that was found | |
| 4086 */ | |
| 4087 ExecutableElement lookupGetterOrMethod(Type2 type, String memberName) { | |
| 4088 type = resolveTypeParameter(type); | |
| 4089 if (type is InterfaceType) { | |
| 4090 InterfaceType interfaceType = type as InterfaceType; | |
| 4091 ExecutableElement member = interfaceType.lookUpMethod(memberName, _resolve
r.definingLibrary); | |
| 4092 if (member != null) { | |
| 4093 return member; | |
| 4094 } | |
| 4095 member = interfaceType.lookUpGetter(memberName, _resolver.definingLibrary)
; | |
| 4096 if (member != null) { | |
| 4097 return member; | |
| 4098 } | |
| 4099 return lookUpGetterOrMethodInInterfaces(interfaceType, false, memberName,
new Set<ClassElement>()); | |
| 4100 } | |
| 4101 return null; | |
| 4102 } | |
| 4103 | |
| 4104 /** | |
| 4105 * Look up the method or getter with the given name in the interfaces implemen
ted by the given | |
| 4106 * type, either directly or indirectly. Return the element representing the me
thod or getter that | |
| 4107 * was found, or `null` if there is no method or getter with the given name. | |
| 4108 * | |
| 4109 * @param targetType the type in which the method or getter might be defined | |
| 4110 * @param includeTargetType `true` if the search should include the target typ
e | |
| 4111 * @param memberName the name of the method or getter being looked up | |
| 4112 * @param visitedInterfaces a set containing all of the interfaces that have b
een examined, used | |
| 4113 * to prevent infinite recursion and to optimize the search | |
| 4114 * @return the element representing the method or getter that was found | |
| 4115 */ | |
| 4116 ExecutableElement lookUpGetterOrMethodInInterfaces(InterfaceType targetType, b
ool includeTargetType, String memberName, Set<ClassElement> visitedInterfaces) { | |
| 4117 ClassElement targetClass = targetType.element; | |
| 4118 if (visitedInterfaces.contains(targetClass)) { | |
| 4119 return null; | |
| 4120 } | |
| 4121 javaSetAdd(visitedInterfaces, targetClass); | |
| 4122 if (includeTargetType) { | |
| 4123 ExecutableElement member = targetType.getMethod(memberName); | |
| 4124 if (member != null) { | |
| 4125 return member; | |
| 4126 } | |
| 4127 member = targetType.getGetter(memberName); | |
| 4128 if (member != null) { | |
| 4129 return member; | |
| 4130 } | |
| 4131 } | |
| 4132 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 4133 ExecutableElement member = lookUpGetterOrMethodInInterfaces(interfaceType,
true, memberName, visitedInterfaces); | |
| 4134 if (member != null) { | |
| 4135 return member; | |
| 4136 } | |
| 4137 } | |
| 4138 for (InterfaceType mixinType in targetType.mixins) { | |
| 4139 ExecutableElement member = lookUpGetterOrMethodInInterfaces(mixinType, tru
e, memberName, visitedInterfaces); | |
| 4140 if (member != null) { | |
| 4141 return member; | |
| 4142 } | |
| 4143 } | |
| 4144 InterfaceType superclass = targetType.superclass; | |
| 4145 if (superclass == null) { | |
| 4146 return null; | |
| 4147 } | |
| 4148 return lookUpGetterOrMethodInInterfaces(superclass, true, memberName, visite
dInterfaces); | |
| 4149 } | |
| 4150 | |
| 4151 /** | |
| 4152 * Find the element corresponding to the given label node in the current label
scope. | |
| 4153 * | |
| 4154 * @param parentNode the node containing the given label | |
| 4155 * @param labelNode the node representing the label being looked up | |
| 4156 * @return the element corresponding to the given label node in the current sc
ope | |
| 4157 */ | |
| 4158 LabelElementImpl lookupLabel(ASTNode parentNode, SimpleIdentifier labelNode) { | |
| 4159 LabelScope labelScope = _resolver.labelScope; | |
| 4160 LabelElementImpl labelElement = null; | |
| 4161 if (labelNode == null) { | |
| 4162 if (labelScope == null) { | |
| 4163 } else { | |
| 4164 labelElement = labelScope.lookup2(LabelScope.EMPTY_LABEL) as LabelElemen
tImpl; | |
| 4165 if (labelElement == null) { | |
| 4166 } | |
| 4167 labelElement = null; | |
| 4168 } | |
| 4169 } else { | |
| 4170 if (labelScope == null) { | |
| 4171 _resolver.reportError5(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode,
[labelNode.name]); | |
| 4172 } else { | |
| 4173 labelElement = labelScope.lookup(labelNode) as LabelElementImpl; | |
| 4174 if (labelElement == null) { | |
| 4175 _resolver.reportError5(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode
, [labelNode.name]); | |
| 4176 } else { | |
| 4177 labelNode.staticElement = labelElement; | |
| 4178 } | |
| 4179 } | |
| 4180 } | |
| 4181 if (labelElement != null) { | |
| 4182 ExecutableElement labelContainer = labelElement.getAncestor(ExecutableElem
ent); | |
| 4183 if (labelContainer != _resolver.enclosingFunction) { | |
| 4184 _resolver.reportError5(CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE, labelN
ode, [labelNode.name]); | |
| 4185 labelElement = null; | |
| 4186 } | |
| 4187 } | |
| 4188 return labelElement; | |
| 4189 } | |
| 4190 | |
| 4191 /** | |
| 4192 * Look up the method with the given name in the given type. Return the elemen
t representing the | |
| 4193 * method that was found, or `null` if there is no method with the given name. | |
| 4194 * | |
| 4195 * @param target the target of the invocation, or `null` if there is no target | |
| 4196 * @param type the type in which the method is defined | |
| 4197 * @param methodName the name of the method being looked up | |
| 4198 * @return the element representing the method that was found | |
| 4199 */ | |
| 4200 MethodElement lookUpMethod(Expression target, Type2 type, String methodName) { | |
| 4201 type = resolveTypeParameter(type); | |
| 4202 if (type is InterfaceType) { | |
| 4203 InterfaceType interfaceType = type as InterfaceType; | |
| 4204 MethodElement method; | |
| 4205 if (target is SuperExpression) { | |
| 4206 method = interfaceType.lookUpMethodInSuperclass(methodName, _resolver.de
finingLibrary); | |
| 4207 } else { | |
| 4208 method = interfaceType.lookUpMethod(methodName, _resolver.definingLibrar
y); | |
| 4209 } | |
| 4210 if (method != null) { | |
| 4211 return method; | |
| 4212 } | |
| 4213 return lookUpMethodInInterfaces(interfaceType, false, methodName, new Set<
ClassElement>()); | |
| 4214 } | |
| 4215 return null; | |
| 4216 } | |
| 4217 | |
| 4218 /** | |
| 4219 * Look up the method with the given name in the interfaces implemented by the
given type, either | |
| 4220 * directly or indirectly. Return the element representing the method that was
found, or | |
| 4221 * `null` if there is no method with the given name. | |
| 4222 * | |
| 4223 * @param targetType the type in which the member might be defined | |
| 4224 * @param includeTargetType `true` if the search should include the target typ
e | |
| 4225 * @param methodName the name of the method being looked up | |
| 4226 * @param visitedInterfaces a set containing all of the interfaces that have b
een examined, used | |
| 4227 * to prevent infinite recursion and to optimize the search | |
| 4228 * @return the element representing the method that was found | |
| 4229 */ | |
| 4230 MethodElement lookUpMethodInInterfaces(InterfaceType targetType, bool includeT
argetType, String methodName, Set<ClassElement> visitedInterfaces) { | |
| 4231 ClassElement targetClass = targetType.element; | |
| 4232 if (visitedInterfaces.contains(targetClass)) { | |
| 4233 return null; | |
| 4234 } | |
| 4235 javaSetAdd(visitedInterfaces, targetClass); | |
| 4236 if (includeTargetType) { | |
| 4237 MethodElement method = targetType.getMethod(methodName); | |
| 4238 if (method != null && method.isAccessibleIn(_resolver.definingLibrary)) { | |
| 4239 return method; | |
| 4240 } | |
| 4241 } | |
| 4242 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 4243 MethodElement method = lookUpMethodInInterfaces(interfaceType, true, metho
dName, visitedInterfaces); | |
| 4244 if (method != null) { | |
| 4245 return method; | |
| 4246 } | |
| 4247 } | |
| 4248 for (InterfaceType mixinType in targetType.mixins) { | |
| 4249 MethodElement method = lookUpMethodInInterfaces(mixinType, true, methodNam
e, visitedInterfaces); | |
| 4250 if (method != null) { | |
| 4251 return method; | |
| 4252 } | |
| 4253 } | |
| 4254 InterfaceType superclass = targetType.superclass; | |
| 4255 if (superclass == null) { | |
| 4256 return null; | |
| 4257 } | |
| 4258 return lookUpMethodInInterfaces(superclass, true, methodName, visitedInterfa
ces); | |
| 4259 } | |
| 4260 | |
| 4261 /** | |
| 4262 * Look up the setter with the given name in the given type. Return the elemen
t representing the | |
| 4263 * setter that was found, or `null` if there is no setter with the given name. | |
| 4264 * | |
| 4265 * @param target the target of the invocation, or `null` if there is no target | |
| 4266 * @param type the type in which the setter is defined | |
| 4267 * @param setterName the name of the setter being looked up | |
| 4268 * @return the element representing the setter that was found | |
| 4269 */ | |
| 4270 PropertyAccessorElement lookUpSetter(Expression target, Type2 type, String set
terName) { | |
| 4271 type = resolveTypeParameter(type); | |
| 4272 if (type is InterfaceType) { | |
| 4273 InterfaceType interfaceType = type as InterfaceType; | |
| 4274 PropertyAccessorElement accessor; | |
| 4275 if (target is SuperExpression) { | |
| 4276 accessor = interfaceType.lookUpSetterInSuperclass(setterName, _resolver.
definingLibrary); | |
| 4277 } else { | |
| 4278 accessor = interfaceType.lookUpSetter(setterName, _resolver.definingLibr
ary); | |
| 4279 } | |
| 4280 if (accessor != null) { | |
| 4281 return accessor; | |
| 4282 } | |
| 4283 return lookUpSetterInInterfaces(interfaceType, false, setterName, new Set<
ClassElement>()); | |
| 4284 } | |
| 4285 return null; | |
| 4286 } | |
| 4287 | |
| 4288 /** | |
| 4289 * Look up the setter with the given name in the interfaces implemented by the
given type, either | |
| 4290 * directly or indirectly. Return the element representing the setter that was
found, or | |
| 4291 * `null` if there is no setter with the given name. | |
| 4292 * | |
| 4293 * @param targetType the type in which the setter might be defined | |
| 4294 * @param includeTargetType `true` if the search should include the target typ
e | |
| 4295 * @param setterName the name of the setter being looked up | |
| 4296 * @param visitedInterfaces a set containing all of the interfaces that have b
een examined, used | |
| 4297 * to prevent infinite recursion and to optimize the search | |
| 4298 * @return the element representing the setter that was found | |
| 4299 */ | |
| 4300 PropertyAccessorElement lookUpSetterInInterfaces(InterfaceType targetType, boo
l includeTargetType, String setterName, Set<ClassElement> visitedInterfaces) { | |
| 4301 ClassElement targetClass = targetType.element; | |
| 4302 if (visitedInterfaces.contains(targetClass)) { | |
| 4303 return null; | |
| 4304 } | |
| 4305 javaSetAdd(visitedInterfaces, targetClass); | |
| 4306 if (includeTargetType) { | |
| 4307 PropertyAccessorElement setter = targetType.getSetter(setterName); | |
| 4308 if (setter != null && setter.isAccessibleIn(_resolver.definingLibrary)) { | |
| 4309 return setter; | |
| 4310 } | |
| 4311 } | |
| 4312 for (InterfaceType interfaceType in targetType.interfaces) { | |
| 4313 PropertyAccessorElement setter = lookUpSetterInInterfaces(interfaceType, t
rue, setterName, visitedInterfaces); | |
| 4314 if (setter != null) { | |
| 4315 return setter; | |
| 4316 } | |
| 4317 } | |
| 4318 for (InterfaceType mixinType in targetType.mixins) { | |
| 4319 PropertyAccessorElement setter = lookUpSetterInInterfaces(mixinType, true,
setterName, visitedInterfaces); | |
| 4320 if (setter != null) { | |
| 4321 return setter; | |
| 4322 } | |
| 4323 } | |
| 4324 InterfaceType superclass = targetType.superclass; | |
| 4325 if (superclass == null) { | |
| 4326 return null; | |
| 4327 } | |
| 4328 return lookUpSetterInInterfaces(superclass, true, setterName, visitedInterfa
ces); | |
| 4329 } | |
| 4330 | |
| 4331 /** | |
| 4332 * Given some class element, this method uses [subtypeManager] to find the set
of all | |
| 4333 * subtypes; the subtypes are then searched for a member (method, getter, or s
etter), that matches | |
| 4334 * a passed | |
| 4335 * | |
| 4336 * @param element the class element to search the subtypes of, if a non-ClassE
lement element is | |
| 4337 * passed, then `false` is returned | |
| 4338 * @param memberName the member name to search for | |
| 4339 * @param asMethod `true` if the methods should be searched for in the subtype
s | |
| 4340 * @param asAccessor `true` if the accessors (getters and setters) should be s
earched for in | |
| 4341 * the subtypes | |
| 4342 * @return `true` if and only if the passed memberName was found in a subtype | |
| 4343 */ | |
| 4344 bool memberFoundInSubclass(Element element, String memberName, bool asMethod,
bool asAccessor) { | |
| 4345 if (element is ClassElement) { | |
| 4346 _subtypeManager.ensureLibraryVisited(_resolver.definingLibrary); | |
| 4347 Set<ClassElement> subtypeElements = _subtypeManager.computeAllSubtypes(ele
ment as ClassElement); | |
| 4348 for (ClassElement subtypeElement in subtypeElements) { | |
| 4349 if (asMethod && subtypeElement.getMethod(memberName) != null) { | |
| 4350 return true; | |
| 4351 } else if (asAccessor && (subtypeElement.getGetter(memberName) != null |
| subtypeElement.getSetter(memberName) != null)) { | |
| 4352 return true; | |
| 4353 } | |
| 4354 } | |
| 4355 } | |
| 4356 return false; | |
| 4357 } | |
| 4358 | |
| 4359 /** | |
| 4360 * Return the binary operator that is invoked by the given compound assignment
operator. | |
| 4361 * | |
| 4362 * @param operator the assignment operator being mapped | |
| 4363 * @return the binary operator that invoked by the given assignment operator | |
| 4364 */ | |
| 4365 sc.TokenType operatorFromCompoundAssignment(sc.TokenType operator) { | |
| 4366 while (true) { | |
| 4367 if (operator == sc.TokenType.AMPERSAND_EQ) { | |
| 4368 return sc.TokenType.AMPERSAND; | |
| 4369 } else if (operator == sc.TokenType.BAR_EQ) { | |
| 4370 return sc.TokenType.BAR; | |
| 4371 } else if (operator == sc.TokenType.CARET_EQ) { | |
| 4372 return sc.TokenType.CARET; | |
| 4373 } else if (operator == sc.TokenType.GT_GT_EQ) { | |
| 4374 return sc.TokenType.GT_GT; | |
| 4375 } else if (operator == sc.TokenType.LT_LT_EQ) { | |
| 4376 return sc.TokenType.LT_LT; | |
| 4377 } else if (operator == sc.TokenType.MINUS_EQ) { | |
| 4378 return sc.TokenType.MINUS; | |
| 4379 } else if (operator == sc.TokenType.PERCENT_EQ) { | |
| 4380 return sc.TokenType.PERCENT; | |
| 4381 } else if (operator == sc.TokenType.PLUS_EQ) { | |
| 4382 return sc.TokenType.PLUS; | |
| 4383 } else if (operator == sc.TokenType.SLASH_EQ) { | |
| 4384 return sc.TokenType.SLASH; | |
| 4385 } else if (operator == sc.TokenType.STAR_EQ) { | |
| 4386 return sc.TokenType.STAR; | |
| 4387 } else if (operator == sc.TokenType.TILDE_SLASH_EQ) { | |
| 4388 return sc.TokenType.TILDE_SLASH; | |
| 4389 } | |
| 4390 break; | |
| 4391 } | |
| 4392 AnalysisEngine.instance.logger.logError("Failed to map ${operator.lexeme} to
it's corresponding operator"); | |
| 4393 return operator; | |
| 4394 } | |
| 4395 void resolveAnnotationConstructorInvocationArguments(Annotation annotation, Co
nstructorElement constructor) { | |
| 4396 ArgumentList argumentList = annotation.arguments; | |
| 4397 if (argumentList == null) { | |
| 4398 return; | |
| 4399 } | |
| 4400 List<ParameterElement> parameters = resolveArgumentsToParameters(true, argum
entList, constructor); | |
| 4401 if (parameters != null) { | |
| 4402 argumentList.correspondingStaticParameters = parameters; | |
| 4403 } | |
| 4404 } | |
| 4405 | |
| 4406 /** | |
| 4407 * Validates that the given [Element] is the constant variable; or resolves it
as a | |
| 4408 * constructor invocation. | |
| 4409 * | |
| 4410 * @param annotation the [Annotation] to resolve | |
| 4411 * @param element the current known [Element] of the annotation, or [ClassElem
ent] | |
| 4412 * @param nameNode the name of the invoked constructor, may be `null` if unnam
ed constructor | |
| 4413 * or not a constructor invocation | |
| 4414 */ | |
| 4415 void resolveAnnotationElement(Annotation annotation, Element element, SimpleId
entifier nameNode) { | |
| 4416 if (element is PropertyAccessorElement) { | |
| 4417 PropertyAccessorElement accessorElement = element as PropertyAccessorEleme
nt; | |
| 4418 if (!accessorElement.isSynthetic) { | |
| 4419 _resolver.reportError5(CompileTimeErrorCode.INVALID_ANNOTATION, annotati
on, []); | |
| 4420 return; | |
| 4421 } | |
| 4422 VariableElement variableElement = accessorElement.variable; | |
| 4423 if (!variableElement.isConst) { | |
| 4424 _resolver.reportError5(CompileTimeErrorCode.INVALID_ANNOTATION, annotati
on, []); | |
| 4425 } | |
| 4426 return; | |
| 4427 } | |
| 4428 if (element is ClassElement) { | |
| 4429 if (nameNode == null) { | |
| 4430 nameNode = annotation.constructorName; | |
| 4431 } | |
| 4432 String name = nameNode != null ? nameNode.name : null; | |
| 4433 ConstructorElement constructor; | |
| 4434 { | |
| 4435 InterfaceType interfaceType = new InterfaceTypeImpl.con1(element as Clas
sElement); | |
| 4436 LibraryElement definingLibrary = _resolver.definingLibrary; | |
| 4437 constructor = interfaceType.lookUpConstructor(name, definingLibrary); | |
| 4438 } | |
| 4439 if (constructor == null) { | |
| 4440 _resolver.reportError5(CompileTimeErrorCode.INVALID_ANNOTATION, annotati
on, []); | |
| 4441 return; | |
| 4442 } | |
| 4443 annotation.element = constructor; | |
| 4444 if (nameNode != null) { | |
| 4445 nameNode.staticElement = constructor; | |
| 4446 } | |
| 4447 resolveAnnotationConstructorInvocationArguments(annotation, constructor); | |
| 4448 return; | |
| 4449 } | |
| 4450 if (element != null) { | |
| 4451 _resolver.reportError5(CompileTimeErrorCode.INVALID_ANNOTATION, annotation
, []); | |
| 4452 } | |
| 4453 } | |
| 4454 | |
| 4455 /** | |
| 4456 * Given a list of arguments and the element that will be invoked using those
argument, compute | |
| 4457 * the list of parameters that correspond to the list of arguments. Return the
parameters that | |
| 4458 * correspond to the arguments, or `null` if no correspondence could be comput
ed. | |
| 4459 * | |
| 4460 * @param reportError if `true` then compile-time error should be reported; if
`false` | |
| 4461 * then compile-time warning | |
| 4462 * @param argumentList the list of arguments being passed to the element | |
| 4463 * @param executableElement the element that will be invoked with the argument
s | |
| 4464 * @return the parameters that correspond to the arguments | |
| 4465 */ | |
| 4466 List<ParameterElement> resolveArgumentsToParameters(bool reportError, Argument
List argumentList, ExecutableElement executableElement) { | |
| 4467 if (executableElement == null) { | |
| 4468 return null; | |
| 4469 } | |
| 4470 List<ParameterElement> parameters = executableElement.parameters; | |
| 4471 return resolveArgumentsToParameters2(reportError, argumentList, parameters); | |
| 4472 } | |
| 4473 | |
| 4474 /** | |
| 4475 * Given a list of arguments and the parameters related to the element that wi
ll be invoked using | |
| 4476 * those argument, compute the list of parameters that correspond to the list
of arguments. Return | |
| 4477 * the parameters that correspond to the arguments. | |
| 4478 * | |
| 4479 * @param reportError if `true` then compile-time error should be reported; if
`false` | |
| 4480 * then compile-time warning | |
| 4481 * @param argumentList the list of arguments being passed to the element | |
| 4482 * @param parameters the of the function that will be invoked with the argumen
ts | |
| 4483 * @return the parameters that correspond to the arguments | |
| 4484 */ | |
| 4485 List<ParameterElement> resolveArgumentsToParameters2(bool reportError, Argumen
tList argumentList, List<ParameterElement> parameters) { | |
| 4486 List<ParameterElement> requiredParameters = new List<ParameterElement>(); | |
| 4487 List<ParameterElement> positionalParameters = new List<ParameterElement>(); | |
| 4488 Map<String, ParameterElement> namedParameters = new Map<String, ParameterEle
ment>(); | |
| 4489 for (ParameterElement parameter in parameters) { | |
| 4490 ParameterKind kind = parameter.parameterKind; | |
| 4491 if (identical(kind, ParameterKind.REQUIRED)) { | |
| 4492 requiredParameters.add(parameter); | |
| 4493 } else if (identical(kind, ParameterKind.POSITIONAL)) { | |
| 4494 positionalParameters.add(parameter); | |
| 4495 } else { | |
| 4496 namedParameters[parameter.name] = parameter; | |
| 4497 } | |
| 4498 } | |
| 4499 List<ParameterElement> unnamedParameters = new List<ParameterElement>.from(r
equiredParameters); | |
| 4500 unnamedParameters.addAll(positionalParameters); | |
| 4501 int unnamedParameterCount = unnamedParameters.length; | |
| 4502 int unnamedIndex = 0; | |
| 4503 NodeList<Expression> arguments = argumentList.arguments; | |
| 4504 int argumentCount = arguments.length; | |
| 4505 List<ParameterElement> resolvedParameters = new List<ParameterElement>(argum
entCount); | |
| 4506 int positionalArgumentCount = 0; | |
| 4507 Set<String> usedNames = new Set<String>(); | |
| 4508 for (int i = 0; i < argumentCount; i++) { | |
| 4509 Expression argument = arguments[i]; | |
| 4510 if (argument is NamedExpression) { | |
| 4511 SimpleIdentifier nameNode = ((argument as NamedExpression)).name.label; | |
| 4512 String name = nameNode.name; | |
| 4513 ParameterElement element = namedParameters[name]; | |
| 4514 if (element == null) { | |
| 4515 ErrorCode errorCode = (reportError ? CompileTimeErrorCode.UNDEFINED_NA
MED_PARAMETER : StaticWarningCode.UNDEFINED_NAMED_PARAMETER) as ErrorCode; | |
| 4516 _resolver.reportError5(errorCode, nameNode, [name]); | |
| 4517 } else { | |
| 4518 resolvedParameters[i] = element; | |
| 4519 nameNode.staticElement = element; | |
| 4520 } | |
| 4521 if (!javaSetAdd(usedNames, name)) { | |
| 4522 _resolver.reportError5(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT,
nameNode, [name]); | |
| 4523 } | |
| 4524 } else { | |
| 4525 positionalArgumentCount++; | |
| 4526 if (unnamedIndex < unnamedParameterCount) { | |
| 4527 resolvedParameters[i] = unnamedParameters[unnamedIndex++]; | |
| 4528 } | |
| 4529 } | |
| 4530 } | |
| 4531 if (positionalArgumentCount < requiredParameters.length) { | |
| 4532 ErrorCode errorCode = (reportError ? CompileTimeErrorCode.NOT_ENOUGH_REQUI
RED_ARGUMENTS : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS) as ErrorCode; | |
| 4533 _resolver.reportError5(errorCode, argumentList, [requiredParameters.length
, positionalArgumentCount]); | |
| 4534 } else if (positionalArgumentCount > unnamedParameterCount) { | |
| 4535 ErrorCode errorCode = (reportError ? CompileTimeErrorCode.EXTRA_POSITIONAL
_ARGUMENTS : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) as ErrorCode; | |
| 4536 _resolver.reportError5(errorCode, argumentList, [unnamedParameterCount, po
sitionalArgumentCount]); | |
| 4537 } | |
| 4538 return resolvedParameters; | |
| 4539 } | |
| 4540 | |
| 4541 /** | |
| 4542 * Resolve the names in the given combinators in the scope of the given librar
y. | |
| 4543 * | |
| 4544 * @param library the library that defines the names | |
| 4545 * @param combinators the combinators containing the names to be resolved | |
| 4546 */ | |
| 4547 void resolveCombinators(LibraryElement library, NodeList<Combinator> combinato
rs) { | |
| 4548 if (library == null) { | |
| 4549 return; | |
| 4550 } | |
| 4551 Namespace namespace = new NamespaceBuilder().createExportNamespace2(library)
; | |
| 4552 for (Combinator combinator in combinators) { | |
| 4553 NodeList<SimpleIdentifier> names; | |
| 4554 if (combinator is HideCombinator) { | |
| 4555 names = ((combinator as HideCombinator)).hiddenNames; | |
| 4556 } else { | |
| 4557 names = ((combinator as ShowCombinator)).shownNames; | |
| 4558 } | |
| 4559 for (SimpleIdentifier name in names) { | |
| 4560 Element element = namespace.get(name.name); | |
| 4561 if (element != null) { | |
| 4562 name.staticElement = element; | |
| 4563 } | |
| 4564 } | |
| 4565 } | |
| 4566 } | |
| 4567 | |
| 4568 /** | |
| 4569 * Given an invocation of the form 'e.m(a1, ..., an)', resolve 'e.m' to the el
ement being invoked. | |
| 4570 * If the returned element is a method, then the method will be invoked. If th
e returned element | |
| 4571 * is a getter, the getter will be invoked without arguments and the result of
that invocation | |
| 4572 * will then be invoked with the arguments. | |
| 4573 * | |
| 4574 * @param target the target of the invocation ('e') | |
| 4575 * @param targetType the type of the target | |
| 4576 * @param methodName the name of the method being invoked ('m') | |
| 4577 * @return the element being invoked | |
| 4578 */ | |
| 4579 Element resolveInvokedElement(Expression target, Type2 targetType, SimpleIdent
ifier methodName) { | |
| 4580 if (targetType is InterfaceType) { | |
| 4581 InterfaceType classType = targetType as InterfaceType; | |
| 4582 Element element = lookUpMethod(target, classType, methodName.name); | |
| 4583 if (element == null) { | |
| 4584 element = lookUpGetter(target, classType, methodName.name); | |
| 4585 } | |
| 4586 return element; | |
| 4587 } else if (target is SimpleIdentifier) { | |
| 4588 Element targetElement = ((target as SimpleIdentifier)).staticElement; | |
| 4589 if (targetElement is PrefixElement) { | |
| 4590 String name = "${((target as SimpleIdentifier)).name}.${methodName}"; | |
| 4591 Identifier functionName = new ElementResolver_SyntheticIdentifier(name); | |
| 4592 Element element = _resolver.nameScope.lookup(functionName, _resolver.def
iningLibrary); | |
| 4593 if (element != null) { | |
| 4594 return element; | |
| 4595 } | |
| 4596 } | |
| 4597 } | |
| 4598 return null; | |
| 4599 } | |
| 4600 | |
| 4601 /** | |
| 4602 * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the elemen
t being invoked. If | |
| 4603 * the returned element is a method, then the method will be invoked. If the r
eturned element is a | |
| 4604 * getter, the getter will be invoked without arguments and the result of that
invocation will | |
| 4605 * then be invoked with the arguments. | |
| 4606 * | |
| 4607 * @param methodName the name of the method being invoked ('m') | |
| 4608 * @return the element being invoked | |
| 4609 */ | |
| 4610 Element resolveInvokedElement2(SimpleIdentifier methodName) { | |
| 4611 Element element = _resolver.nameScope.lookup(methodName, _resolver.definingL
ibrary); | |
| 4612 if (element == null) { | |
| 4613 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 4614 if (enclosingClass != null) { | |
| 4615 InterfaceType enclosingType = enclosingClass.type; | |
| 4616 element = lookUpMethod(null, enclosingType, methodName.name); | |
| 4617 if (element == null) { | |
| 4618 element = lookUpGetter(null, enclosingType, methodName.name); | |
| 4619 } | |
| 4620 } | |
| 4621 } | |
| 4622 return element; | |
| 4623 } | |
| 4624 | |
| 4625 /** | |
| 4626 * Given that we are accessing a property of the given type with the given nam
e, return the | |
| 4627 * element that represents the property. | |
| 4628 * | |
| 4629 * @param target the target of the invocation ('e') | |
| 4630 * @param targetType the type in which the search for the property should begi
n | |
| 4631 * @param propertyName the name of the property being accessed | |
| 4632 * @return the element that represents the property | |
| 4633 */ | |
| 4634 ExecutableElement resolveProperty(Expression target, Type2 targetType, SimpleI
dentifier propertyName) { | |
| 4635 ExecutableElement memberElement = null; | |
| 4636 if (propertyName.inSetterContext()) { | |
| 4637 memberElement = lookUpSetter(target, targetType, propertyName.name); | |
| 4638 } | |
| 4639 if (memberElement == null) { | |
| 4640 memberElement = lookUpGetter(target, targetType, propertyName.name); | |
| 4641 } | |
| 4642 if (memberElement == null) { | |
| 4643 memberElement = lookUpMethod(target, targetType, propertyName.name); | |
| 4644 } | |
| 4645 return memberElement; | |
| 4646 } | |
| 4647 void resolvePropertyAccess(Expression target, SimpleIdentifier propertyName) { | |
| 4648 Type2 staticType = getStaticType(target); | |
| 4649 ExecutableElement staticElement = resolveProperty(target, staticType, proper
tyName); | |
| 4650 if (target.parent.parent is Annotation) { | |
| 4651 if (staticElement != null) { | |
| 4652 propertyName.staticElement = staticElement; | |
| 4653 } | |
| 4654 return; | |
| 4655 } | |
| 4656 propertyName.staticElement = staticElement; | |
| 4657 Type2 propagatedType = getPropagatedType(target); | |
| 4658 ExecutableElement propagatedElement = resolveProperty(target, propagatedType
, propertyName); | |
| 4659 propertyName.propagatedElement = propagatedElement; | |
| 4660 bool shouldReportMissingMember_static = shouldReportMissingMember(staticType
, staticElement) && (_strictMode || shouldReportMissingMember(propagatedType, pr
opagatedElement)); | |
| 4661 bool shouldReportMissingMember_propagated = !shouldReportMissingMember_stati
c && _enableHints ? shouldReportMissingMember(propagatedType, propagatedElement)
: false; | |
| 4662 if (shouldReportMissingMember_propagated) { | |
| 4663 if (memberFoundInSubclass(propagatedType.element, propertyName.name, false
, true)) { | |
| 4664 shouldReportMissingMember_propagated = false; | |
| 4665 } | |
| 4666 } | |
| 4667 if (shouldReportMissingMember_static || shouldReportMissingMember_propagated
) { | |
| 4668 Element staticOrPropagatedEnclosingElt = shouldReportMissingMember_static
? staticType.element : propagatedType.element; | |
| 4669 bool isStaticProperty = isStatic(staticOrPropagatedEnclosingElt); | |
| 4670 if (propertyName.inSetterContext()) { | |
| 4671 if (isStaticProperty) { | |
| 4672 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticWarnin
gCode.UNDEFINED_SETTER : HintCode.UNDEFINED_SETTER) as ErrorCode; | |
| 4673 _resolver.reportErrorProxyConditionalAnalysisError(staticOrPropagatedE
nclosingElt, errorCode, propertyName, [ | |
| 4674 propertyName.name, | |
| 4675 staticOrPropagatedEnclosingElt.displayName]); | |
| 4676 } else { | |
| 4677 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWa
rningCode.UNDEFINED_SETTER : HintCode.UNDEFINED_SETTER) as ErrorCode; | |
| 4678 _resolver.reportErrorProxyConditionalAnalysisError(staticOrPropagatedE
nclosingElt, errorCode, propertyName, [ | |
| 4679 propertyName.name, | |
| 4680 staticOrPropagatedEnclosingElt.displayName]); | |
| 4681 } | |
| 4682 } else if (propertyName.inGetterContext()) { | |
| 4683 if (isStaticProperty) { | |
| 4684 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticWarnin
gCode.UNDEFINED_GETTER : HintCode.UNDEFINED_GETTER) as ErrorCode; | |
| 4685 _resolver.reportErrorProxyConditionalAnalysisError(staticOrPropagatedE
nclosingElt, errorCode, propertyName, [ | |
| 4686 propertyName.name, | |
| 4687 staticOrPropagatedEnclosingElt.displayName]); | |
| 4688 } else { | |
| 4689 ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWa
rningCode.UNDEFINED_GETTER : HintCode.UNDEFINED_GETTER) as ErrorCode; | |
| 4690 _resolver.reportErrorProxyConditionalAnalysisError(staticOrPropagatedE
nclosingElt, errorCode, propertyName, [ | |
| 4691 propertyName.name, | |
| 4692 staticOrPropagatedEnclosingElt.displayName]); | |
| 4693 } | |
| 4694 } else { | |
| 4695 _resolver.reportErrorProxyConditionalAnalysisError(staticOrPropagatedEnc
losingElt, StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName, [propertyName.n
ame]); | |
| 4696 } | |
| 4697 } | |
| 4698 } | |
| 4699 | |
| 4700 /** | |
| 4701 * Resolve the given simple identifier if possible. Return the element to whic
h it could be | |
| 4702 * resolved, or `null` if it could not be resolved. This does not record the r
esults of the | |
| 4703 * resolution. | |
| 4704 * | |
| 4705 * @param node the identifier to be resolved | |
| 4706 * @return the element to which the identifier could be resolved | |
| 4707 */ | |
| 4708 Element resolveSimpleIdentifier(SimpleIdentifier node) { | |
| 4709 Element element = _resolver.nameScope.lookup(node, _resolver.definingLibrary
); | |
| 4710 if (element is PropertyAccessorElement && node.inSetterContext()) { | |
| 4711 PropertyInducingElement variable = ((element as PropertyAccessorElement)).
variable; | |
| 4712 if (variable != null) { | |
| 4713 PropertyAccessorElement setter = variable.setter; | |
| 4714 if (setter == null) { | |
| 4715 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 4716 if (enclosingClass != null) { | |
| 4717 setter = lookUpSetter(null, enclosingClass.type, node.name); | |
| 4718 } | |
| 4719 } | |
| 4720 if (setter != null) { | |
| 4721 element = setter; | |
| 4722 } | |
| 4723 } | |
| 4724 } else if (element == null && node.inSetterContext()) { | |
| 4725 element = _resolver.nameScope.lookup(new ElementResolver_SyntheticIdentifi
er("${node.name}="), _resolver.definingLibrary); | |
| 4726 } | |
| 4727 ClassElement enclosingClass = _resolver.enclosingClass; | |
| 4728 if (element == null && enclosingClass != null) { | |
| 4729 InterfaceType enclosingType = enclosingClass.type; | |
| 4730 if (element == null && node.inSetterContext()) { | |
| 4731 element = lookUpSetter(null, enclosingType, node.name); | |
| 4732 } | |
| 4733 if (element == null && node.inGetterContext()) { | |
| 4734 element = lookUpGetter(null, enclosingType, node.name); | |
| 4735 } | |
| 4736 if (element == null) { | |
| 4737 element = lookUpMethod(null, enclosingType, node.name); | |
| 4738 } | |
| 4739 } | |
| 4740 return element; | |
| 4741 } | |
| 4742 | |
| 4743 /** | |
| 4744 * If the given type is a type parameter, resolve it to the type that should b
e used when looking | |
| 4745 * up members. Otherwise, return the original type. | |
| 4746 * | |
| 4747 * @param type the type that is to be resolved if it is a type parameter | |
| 4748 * @return the type that should be used in place of the argument if it is a ty
pe parameter, or the | |
| 4749 * original argument if it isn't a type parameter | |
| 4750 */ | |
| 4751 Type2 resolveTypeParameter(Type2 type) { | |
| 4752 if (type is TypeParameterType) { | |
| 4753 Type2 bound = ((type as TypeParameterType)).element.bound; | |
| 4754 if (bound == null) { | |
| 4755 return _resolver.typeProvider.objectType; | |
| 4756 } | |
| 4757 return bound; | |
| 4758 } | |
| 4759 return type; | |
| 4760 } | |
| 4761 | |
| 4762 /** | |
| 4763 * Return the propagated element if it is not `null`, or the static element if
it is. | |
| 4764 * | |
| 4765 * @param staticElement the element computed using static type information | |
| 4766 * @param propagatedElement the element computed using propagated type informa
tion | |
| 4767 * @return the more specific of the two elements | |
| 4768 */ | |
| 4769 ExecutableElement select(ExecutableElement staticElement, ExecutableElement pr
opagatedElement) => propagatedElement != null ? propagatedElement : staticElemen
t; | |
| 4770 | |
| 4771 /** | |
| 4772 * Given a node that can have annotations associated with it and the element t
o which that node | |
| 4773 * has been resolved, create the annotations in the element model representing
the annotations on | |
| 4774 * the node. | |
| 4775 * | |
| 4776 * @param element the element to which the node has been resolved | |
| 4777 * @param node the node that can have annotations associated with it | |
| 4778 */ | |
| 4779 void setMetadata(Element element, AnnotatedNode node) { | |
| 4780 if (element is! ElementImpl) { | |
| 4781 return; | |
| 4782 } | |
| 4783 List<ElementAnnotationImpl> annotationList = new List<ElementAnnotationImpl>
(); | |
| 4784 addAnnotations(annotationList, node.metadata); | |
| 4785 if (node is VariableDeclaration && node.parent is VariableDeclarationList) { | |
| 4786 VariableDeclarationList list = node.parent as VariableDeclarationList; | |
| 4787 addAnnotations(annotationList, list.metadata); | |
| 4788 if (list.parent is FieldDeclaration) { | |
| 4789 FieldDeclaration fieldDeclaration = list.parent as FieldDeclaration; | |
| 4790 addAnnotations(annotationList, fieldDeclaration.metadata); | |
| 4791 } else if (list.parent is TopLevelVariableDeclaration) { | |
| 4792 TopLevelVariableDeclaration variableDeclaration = list.parent as TopLeve
lVariableDeclaration; | |
| 4793 addAnnotations(annotationList, variableDeclaration.metadata); | |
| 4794 } | |
| 4795 } | |
| 4796 if (!annotationList.isEmpty) { | |
| 4797 ((element as ElementImpl)).metadata = new List.from(annotationList); | |
| 4798 } | |
| 4799 } | |
| 4800 | |
| 4801 /** | |
| 4802 * Return `true` if we should report an error as a result of looking up a memb
er in the | |
| 4803 * given type and not finding any member. | |
| 4804 * | |
| 4805 * @param type the type in which we attempted to perform the look-up | |
| 4806 * @param member the result of the look-up | |
| 4807 * @return `true` if we should report an error | |
| 4808 */ | |
| 4809 bool shouldReportMissingMember(Type2 type, ExecutableElement member) { | |
| 4810 if (member != null || type == null || type.isDynamic || type.isBottom) { | |
| 4811 return false; | |
| 4812 } | |
| 4813 return true; | |
| 4814 } | |
| 4815 } | |
| 4816 /** | |
| 4817 * Instances of the class `SyntheticIdentifier` implement an identifier that can
be used to | |
| 4818 * look up names in the lexical scope when there is no identifier in the AST str
ucture. There is | |
| 4819 * no identifier in the AST when the parser could not distinguish between a meth
od invocation and | |
| 4820 * an invocation of a top-level function imported with a prefix. | |
| 4821 */ | |
| 4822 class ElementResolver_SyntheticIdentifier extends Identifier { | |
| 4823 | |
| 4824 /** | |
| 4825 * The name of the synthetic identifier. | |
| 4826 */ | |
| 4827 String _name; | |
| 4828 | |
| 4829 /** | |
| 4830 * Initialize a newly created synthetic identifier to have the given name. | |
| 4831 * | |
| 4832 * @param name the name of the synthetic identifier | |
| 4833 */ | |
| 4834 ElementResolver_SyntheticIdentifier(String name) { | |
| 4835 this._name = name; | |
| 4836 } | |
| 4837 accept(ASTVisitor visitor) => null; | |
| 4838 sc.Token get beginToken => null; | |
| 4839 Element get bestElement => null; | |
| 4840 sc.Token get endToken => null; | |
| 4841 String get name => _name; | |
| 4842 Element get propagatedElement => null; | |
| 4843 Element get staticElement => null; | |
| 4844 void visitChildren(ASTVisitor visitor) { | |
| 4845 } | |
| 4846 } | |
| 4847 /** | |
| 4848 * Instances of the class `InheritanceManager` manage the knowledge of where cla
ss members | |
| 4849 * (methods, getters & setters) are inherited from. | |
| 4850 * | |
| 4851 * @coverage dart.engine.resolver | |
| 4852 */ | |
| 4853 class InheritanceManager { | |
| 4854 | |
| 4855 /** | |
| 4856 * The [LibraryElement] that is managed by this manager. | |
| 4857 */ | |
| 4858 LibraryElement _library; | |
| 4859 | |
| 4860 /** | |
| 4861 * This is a mapping between each [ClassElement] and a map between the [String
] member | |
| 4862 * names and the associated [ExecutableElement] in the mixin and superclass ch
ain. | |
| 4863 */ | |
| 4864 Map<ClassElement, MemberMap> _classLookup; | |
| 4865 | |
| 4866 /** | |
| 4867 * This is a mapping between each [ClassElement] and a map between the [String
] member | |
| 4868 * names and the associated [ExecutableElement] in the interface set. | |
| 4869 */ | |
| 4870 Map<ClassElement, MemberMap> _interfaceLookup; | |
| 4871 | |
| 4872 /** | |
| 4873 * A map between each visited [ClassElement] and the set of [AnalysisError]s f
ound on | |
| 4874 * the class element. | |
| 4875 */ | |
| 4876 Map<ClassElement, Set<AnalysisError>> _errorsInClassElement = new Map<ClassEle
ment, Set<AnalysisError>>(); | |
| 4877 | |
| 4878 /** | |
| 4879 * Initialize a newly created inheritance manager. | |
| 4880 * | |
| 4881 * @param library the library element context that the inheritance mappings ar
e being generated | |
| 4882 */ | |
| 4883 InheritanceManager(LibraryElement library) { | |
| 4884 this._library = library; | |
| 4885 _classLookup = new Map<ClassElement, MemberMap>(); | |
| 4886 _interfaceLookup = new Map<ClassElement, MemberMap>(); | |
| 4887 } | |
| 4888 | |
| 4889 /** | |
| 4890 * Return the set of [AnalysisError]s found on the passed [ClassElement], or | |
| 4891 * `null` if there are none. | |
| 4892 * | |
| 4893 * @param classElt the class element to query | |
| 4894 * @return the set of [AnalysisError]s found on the passed [ClassElement], or | |
| 4895 * `null` if there are none | |
| 4896 */ | |
| 4897 Set<AnalysisError> getErrors(ClassElement classElt) => _errorsInClassElement[c
lassElt]; | |
| 4898 | |
| 4899 /** | |
| 4900 * Get and return a mapping between the set of all string names of the members
inherited from the | |
| 4901 * passed [ClassElement] superclass hierarchy, and the associated [ExecutableE
lement]. | |
| 4902 * | |
| 4903 * @param classElt the class element to query | |
| 4904 * @return a mapping between the set of all members inherited from the passed
[ClassElement] | |
| 4905 * superclass hierarchy, and the associated [ExecutableElement] | |
| 4906 */ | |
| 4907 MemberMap getMapOfMembersInheritedFromClasses(ClassElement classElt) => comput
eClassChainLookupMap(classElt, new Set<ClassElement>()); | |
| 4908 | |
| 4909 /** | |
| 4910 * Get and return a mapping between the set of all string names of the members
inherited from the | |
| 4911 * passed [ClassElement] interface hierarchy, and the associated [ExecutableEl
ement]. | |
| 4912 * | |
| 4913 * @param classElt the class element to query | |
| 4914 * @return a mapping between the set of all string names of the members inheri
ted from the passed | |
| 4915 * [ClassElement] interface hierarchy, and the associated [ExecutableE
lement]. | |
| 4916 */ | |
| 4917 MemberMap getMapOfMembersInheritedFromInterfaces(ClassElement classElt) => com
puteInterfaceLookupMap(classElt, new Set<ClassElement>()); | |
| 4918 | |
| 4919 /** | |
| 4920 * Given some [ClassElement] and some member name, this returns the | |
| 4921 * [ExecutableElement] that the class inherits from the mixins, | |
| 4922 * superclasses or interfaces, that has the member name, if no member is inher
ited `null` is | |
| 4923 * returned. | |
| 4924 * | |
| 4925 * @param classElt the class element to query | |
| 4926 * @param memberName the name of the executable element to find and return | |
| 4927 * @return the inherited executable element with the member name, or `null` if
no such | |
| 4928 * member exists | |
| 4929 */ | |
| 4930 ExecutableElement lookupInheritance(ClassElement classElt, String memberName)
{ | |
| 4931 if (memberName == null || memberName.isEmpty) { | |
| 4932 return null; | |
| 4933 } | |
| 4934 ExecutableElement executable = computeClassChainLookupMap(classElt, new Set<
ClassElement>()).get(memberName); | |
| 4935 if (executable == null) { | |
| 4936 return computeInterfaceLookupMap(classElt, new Set<ClassElement>()).get(me
mberName); | |
| 4937 } | |
| 4938 return executable; | |
| 4939 } | |
| 4940 | |
| 4941 /** | |
| 4942 * Given some [ClassElement] and some member name, this returns the | |
| 4943 * [ExecutableElement] that the class either declares itself, or | |
| 4944 * inherits, that has the member name, if no member is inherited `null` is ret
urned. | |
| 4945 * | |
| 4946 * @param classElt the class element to query | |
| 4947 * @param memberName the name of the executable element to find and return | |
| 4948 * @return the inherited executable element with the member name, or `null` if
no such | |
| 4949 * member exists | |
| 4950 */ | |
| 4951 ExecutableElement lookupMember(ClassElement classElt, String memberName) { | |
| 4952 ExecutableElement element = lookupMemberInClass(classElt, memberName); | |
| 4953 if (element != null) { | |
| 4954 return element; | |
| 4955 } | |
| 4956 return lookupInheritance(classElt, memberName); | |
| 4957 } | |
| 4958 | |
| 4959 /** | |
| 4960 * Given some [InterfaceType] and some member name, this returns the | |
| 4961 * [FunctionType] of the [ExecutableElement] that the | |
| 4962 * class either declares itself, or inherits, that has the member name, if no
member is inherited | |
| 4963 * `null` is returned. The returned [FunctionType] has all type | |
| 4964 * parameters substituted with corresponding type arguments from the given [In
terfaceType]. | |
| 4965 * | |
| 4966 * @param interfaceType the interface type to query | |
| 4967 * @param memberName the name of the executable element to find and return | |
| 4968 * @return the member's function type, or `null` if no such member exists | |
| 4969 */ | |
| 4970 FunctionType lookupMemberType(InterfaceType interfaceType, String memberName)
{ | |
| 4971 ExecutableElement iteratorMember = lookupMember(interfaceType.element, membe
rName); | |
| 4972 if (iteratorMember == null) { | |
| 4973 return null; | |
| 4974 } | |
| 4975 return substituteTypeArgumentsInMemberFromInheritance(iteratorMember.type, m
emberName, interfaceType); | |
| 4976 } | |
| 4977 | |
| 4978 /** | |
| 4979 * Set the new library element context. | |
| 4980 * | |
| 4981 * @param library the new library element | |
| 4982 */ | |
| 4983 void set libraryElement(LibraryElement library) { | |
| 4984 this._library = library; | |
| 4985 } | |
| 4986 | |
| 4987 /** | |
| 4988 * This method takes some inherited [FunctionType], and resolves all the param
eterized types | |
| 4989 * in the function type, dependent on the class in which it is being overridde
n. | |
| 4990 * | |
| 4991 * @param baseFunctionType the function type that is being overridden | |
| 4992 * @param memberName the name of the member, this is used to lookup the inheri
tance path of the | |
| 4993 * override | |
| 4994 * @param definingType the type that is overriding the member | |
| 4995 * @return the passed function type with any parameterized types substituted | |
| 4996 */ | |
| 4997 FunctionType substituteTypeArgumentsInMemberFromInheritance(FunctionType baseF
unctionType, String memberName, InterfaceType definingType) { | |
| 4998 if (baseFunctionType == null) { | |
| 4999 return baseFunctionType; | |
| 5000 } | |
| 5001 Queue<InterfaceType> inheritancePath = new Queue<InterfaceType>(); | |
| 5002 computeInheritancePath(inheritancePath, definingType, memberName); | |
| 5003 if (inheritancePath == null || inheritancePath.isEmpty) { | |
| 5004 return baseFunctionType; | |
| 5005 } | |
| 5006 FunctionType functionTypeToReturn = baseFunctionType; | |
| 5007 while (!inheritancePath.isEmpty) { | |
| 5008 InterfaceType lastType = inheritancePath.removeLast(); | |
| 5009 List<Type2> parameterTypes = lastType.element.type.typeArguments; | |
| 5010 List<Type2> argumentTypes = lastType.typeArguments; | |
| 5011 functionTypeToReturn = functionTypeToReturn.substitute2(argumentTypes, par
ameterTypes); | |
| 5012 } | |
| 5013 return functionTypeToReturn; | |
| 5014 } | |
| 5015 | |
| 5016 /** | |
| 5017 * Compute and return a mapping between the set of all string names of the mem
bers inherited from | |
| 5018 * the passed [ClassElement] superclass hierarchy, and the associated | |
| 5019 * [ExecutableElement]. | |
| 5020 * | |
| 5021 * @param classElt the class element to query | |
| 5022 * @param visitedClasses a set of visited classes passed back into this method
when it calls | |
| 5023 * itself recursively | |
| 5024 * @return a mapping between the set of all string names of the members inheri
ted from the passed | |
| 5025 * [ClassElement] superclass hierarchy, and the associated [Executable
Element] | |
| 5026 */ | |
| 5027 MemberMap computeClassChainLookupMap(ClassElement classElt, Set<ClassElement>
visitedClasses) { | |
| 5028 MemberMap resultMap = _classLookup[classElt]; | |
| 5029 if (resultMap != null) { | |
| 5030 return resultMap; | |
| 5031 } else { | |
| 5032 resultMap = new MemberMap(); | |
| 5033 } | |
| 5034 ClassElement superclassElt = null; | |
| 5035 InterfaceType supertype = classElt.supertype; | |
| 5036 if (supertype != null) { | |
| 5037 superclassElt = supertype.element; | |
| 5038 } else { | |
| 5039 _classLookup[classElt] = resultMap; | |
| 5040 return resultMap; | |
| 5041 } | |
| 5042 if (superclassElt != null) { | |
| 5043 if (!visitedClasses.contains(superclassElt)) { | |
| 5044 javaSetAdd(visitedClasses, classElt); | |
| 5045 resultMap = new MemberMap.con2(computeClassChainLookupMap(superclassElt,
visitedClasses)); | |
| 5046 } else { | |
| 5047 _classLookup[superclassElt] = resultMap; | |
| 5048 return resultMap; | |
| 5049 } | |
| 5050 substituteTypeParametersDownHierarchy(supertype, resultMap); | |
| 5051 recordMapWithClassMembers(resultMap, supertype); | |
| 5052 } | |
| 5053 List<InterfaceType> mixins = classElt.mixins; | |
| 5054 for (int i = mixins.length - 1; i >= 0; i--) { | |
| 5055 recordMapWithClassMembers(resultMap, mixins[i]); | |
| 5056 } | |
| 5057 _classLookup[classElt] = resultMap; | |
| 5058 return resultMap; | |
| 5059 } | |
| 5060 | |
| 5061 /** | |
| 5062 * Compute and return the inheritance path given the context of a type and a m
ember that is | |
| 5063 * overridden in the inheritance path (for which the type is in the path). | |
| 5064 * | |
| 5065 * @param chain the inheritance path that is built up as this method calls its
elf recursively, | |
| 5066 * when this method is called an empty [LinkedList] should be provide
d | |
| 5067 * @param currentType the current type in the inheritance path | |
| 5068 * @param memberName the name of the member that is being looked up the inheri
tance path | |
| 5069 */ | |
| 5070 void computeInheritancePath(Queue<InterfaceType> chain, InterfaceType currentT
ype, String memberName) { | |
| 5071 chain.add(currentType); | |
| 5072 ClassElement classElt = currentType.element; | |
| 5073 InterfaceType supertype = classElt.supertype; | |
| 5074 if (supertype == null) { | |
| 5075 return; | |
| 5076 } | |
| 5077 if (chain.length != 1) { | |
| 5078 if (lookupMemberInClass(classElt, memberName) != null) { | |
| 5079 return; | |
| 5080 } | |
| 5081 } | |
| 5082 List<InterfaceType> mixins = classElt.mixins; | |
| 5083 for (int i = mixins.length - 1; i >= 0; i--) { | |
| 5084 ClassElement mixinElement = mixins[i].element; | |
| 5085 if (mixinElement != null) { | |
| 5086 ExecutableElement elt = lookupMemberInClass(mixinElement, memberName); | |
| 5087 if (elt != null) { | |
| 5088 chain.add(mixins[i]); | |
| 5089 return; | |
| 5090 } | |
| 5091 } | |
| 5092 } | |
| 5093 ClassElement superclassElt = supertype.element; | |
| 5094 if (lookupMember(superclassElt, memberName) != null) { | |
| 5095 computeInheritancePath(chain, supertype, memberName); | |
| 5096 return; | |
| 5097 } | |
| 5098 List<InterfaceType> interfaces = classElt.interfaces; | |
| 5099 for (InterfaceType interfaceType in interfaces) { | |
| 5100 ClassElement interfaceElement = interfaceType.element; | |
| 5101 if (interfaceElement != null && lookupMember(interfaceElement, memberName)
!= null) { | |
| 5102 computeInheritancePath(chain, interfaceType, memberName); | |
| 5103 return; | |
| 5104 } | |
| 5105 } | |
| 5106 } | |
| 5107 | |
| 5108 /** | |
| 5109 * Compute and return a mapping between the set of all string names of the mem
bers inherited from | |
| 5110 * the passed [ClassElement] interface hierarchy, and the associated | |
| 5111 * [ExecutableElement]. | |
| 5112 * | |
| 5113 * @param classElt the class element to query | |
| 5114 * @param visitedInterfaces a set of visited classes passed back into this met
hod when it calls | |
| 5115 * itself recursively | |
| 5116 * @return a mapping between the set of all string names of the members inheri
ted from the passed | |
| 5117 * [ClassElement] interface hierarchy, and the associated [ExecutableE
lement] | |
| 5118 */ | |
| 5119 MemberMap computeInterfaceLookupMap(ClassElement classElt, Set<ClassElement> v
isitedInterfaces) { | |
| 5120 MemberMap resultMap = _interfaceLookup[classElt]; | |
| 5121 if (resultMap != null) { | |
| 5122 return resultMap; | |
| 5123 } else { | |
| 5124 resultMap = new MemberMap(); | |
| 5125 } | |
| 5126 InterfaceType supertype = classElt.supertype; | |
| 5127 ClassElement superclassElement = supertype != null ? supertype.element : nul
l; | |
| 5128 List<InterfaceType> mixins = classElt.mixins; | |
| 5129 List<InterfaceType> interfaces = classElt.interfaces; | |
| 5130 List<MemberMap> lookupMaps = new List<MemberMap>(); | |
| 5131 if (superclassElement != null) { | |
| 5132 if (!visitedInterfaces.contains(superclassElement)) { | |
| 5133 try { | |
| 5134 javaSetAdd(visitedInterfaces, superclassElement); | |
| 5135 MemberMap map = computeInterfaceLookupMap(superclassElement, visitedIn
terfaces); | |
| 5136 map = new MemberMap.con2(map); | |
| 5137 substituteTypeParametersDownHierarchy(supertype, map); | |
| 5138 recordMapWithClassMembers(map, supertype); | |
| 5139 lookupMaps.add(map); | |
| 5140 } finally { | |
| 5141 visitedInterfaces.remove(superclassElement); | |
| 5142 } | |
| 5143 } else { | |
| 5144 MemberMap map = _interfaceLookup[classElt]; | |
| 5145 if (map != null) { | |
| 5146 lookupMaps.add(map); | |
| 5147 } else { | |
| 5148 _interfaceLookup[superclassElement] = resultMap; | |
| 5149 return resultMap; | |
| 5150 } | |
| 5151 } | |
| 5152 } | |
| 5153 for (InterfaceType mixinType in mixins) { | |
| 5154 MemberMap mapWithMixinMembers = new MemberMap(); | |
| 5155 recordMapWithClassMembers(mapWithMixinMembers, mixinType); | |
| 5156 lookupMaps.add(mapWithMixinMembers); | |
| 5157 } | |
| 5158 for (InterfaceType interfaceType in interfaces) { | |
| 5159 ClassElement interfaceElement = interfaceType.element; | |
| 5160 if (interfaceElement != null) { | |
| 5161 if (!visitedInterfaces.contains(interfaceElement)) { | |
| 5162 try { | |
| 5163 javaSetAdd(visitedInterfaces, interfaceElement); | |
| 5164 MemberMap map = computeInterfaceLookupMap(interfaceElement, visitedI
nterfaces); | |
| 5165 map = new MemberMap.con2(map); | |
| 5166 substituteTypeParametersDownHierarchy(interfaceType, map); | |
| 5167 recordMapWithClassMembers(map, interfaceType); | |
| 5168 lookupMaps.add(map); | |
| 5169 } finally { | |
| 5170 visitedInterfaces.remove(interfaceElement); | |
| 5171 } | |
| 5172 } else { | |
| 5173 MemberMap map = _interfaceLookup[classElt]; | |
| 5174 if (map != null) { | |
| 5175 lookupMaps.add(map); | |
| 5176 } else { | |
| 5177 _interfaceLookup[interfaceElement] = resultMap; | |
| 5178 return resultMap; | |
| 5179 } | |
| 5180 } | |
| 5181 } | |
| 5182 } | |
| 5183 if (lookupMaps.length == 0) { | |
| 5184 _interfaceLookup[classElt] = resultMap; | |
| 5185 return resultMap; | |
| 5186 } | |
| 5187 Map<String, Set<ExecutableElement>> unionMap = new Map<String, Set<Executabl
eElement>>(); | |
| 5188 for (MemberMap lookupMap in lookupMaps) { | |
| 5189 for (int i = 0; i < lookupMap.size; i++) { | |
| 5190 String key = lookupMap.getKey(i); | |
| 5191 if (key == null) { | |
| 5192 break; | |
| 5193 } | |
| 5194 Set<ExecutableElement> set = unionMap[key]; | |
| 5195 if (set == null) { | |
| 5196 set = new Set<ExecutableElement>(); | |
| 5197 unionMap[key] = set; | |
| 5198 } | |
| 5199 javaSetAdd(set, lookupMap.getValue(i)); | |
| 5200 } | |
| 5201 } | |
| 5202 for (MapEntry<String, Set<ExecutableElement>> entry in getMapEntrySet(unionM
ap)) { | |
| 5203 String key = entry.getKey(); | |
| 5204 Set<ExecutableElement> set = entry.getValue(); | |
| 5205 int numOfEltsWithMatchingNames = set.length; | |
| 5206 if (numOfEltsWithMatchingNames == 1) { | |
| 5207 resultMap.put(key, new JavaIterator(set).next()); | |
| 5208 } else { | |
| 5209 bool allMethods = true; | |
| 5210 bool allSetters = true; | |
| 5211 bool allGetters = true; | |
| 5212 for (ExecutableElement executableElement in set) { | |
| 5213 if (executableElement is PropertyAccessorElement) { | |
| 5214 allMethods = false; | |
| 5215 if (((executableElement as PropertyAccessorElement)).isSetter) { | |
| 5216 allGetters = false; | |
| 5217 } else { | |
| 5218 allSetters = false; | |
| 5219 } | |
| 5220 } else { | |
| 5221 allGetters = false; | |
| 5222 allSetters = false; | |
| 5223 } | |
| 5224 } | |
| 5225 if (allMethods || allGetters || allSetters) { | |
| 5226 List<ExecutableElement> elements = new List.from(set); | |
| 5227 List<FunctionType> executableElementTypes = new List<FunctionType>(num
OfEltsWithMatchingNames); | |
| 5228 for (int i = 0; i < numOfEltsWithMatchingNames; i++) { | |
| 5229 executableElementTypes[i] = elements[i].type; | |
| 5230 } | |
| 5231 bool foundSubtypeOfAllTypes = false; | |
| 5232 for (int i = 0; i < numOfEltsWithMatchingNames; i++) { | |
| 5233 FunctionType subtype = executableElementTypes[i]; | |
| 5234 if (subtype == null) { | |
| 5235 continue; | |
| 5236 } | |
| 5237 bool subtypeOfAllTypes = true; | |
| 5238 for (int j = 0; j < numOfEltsWithMatchingNames && subtypeOfAllTypes;
j++) { | |
| 5239 if (i != j) { | |
| 5240 if (!subtype.isSubtypeOf(executableElementTypes[j])) { | |
| 5241 subtypeOfAllTypes = false; | |
| 5242 break; | |
| 5243 } | |
| 5244 } | |
| 5245 } | |
| 5246 if (subtypeOfAllTypes) { | |
| 5247 foundSubtypeOfAllTypes = true; | |
| 5248 resultMap.put(key, elements[i]); | |
| 5249 break; | |
| 5250 } | |
| 5251 } | |
| 5252 if (!foundSubtypeOfAllTypes) { | |
| 5253 reportError(classElt, classElt.nameOffset, classElt.displayName.leng
th, StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE, [key]); | |
| 5254 } | |
| 5255 } else { | |
| 5256 if (!allMethods && !allGetters) { | |
| 5257 reportError(classElt, classElt.nameOffset, classElt.displayName.leng
th, StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD, [key]); | |
| 5258 } | |
| 5259 resultMap.remove(entry.getKey()); | |
| 5260 } | |
| 5261 } | |
| 5262 } | |
| 5263 _interfaceLookup[classElt] = resultMap; | |
| 5264 return resultMap; | |
| 5265 } | |
| 5266 | |
| 5267 /** | |
| 5268 * Given some [ClassElement], this method finds and returns the [ExecutableEle
ment] of | |
| 5269 * the passed name in the class element. Static members, members in super type
s and members not | |
| 5270 * accessible from the current library are not considered. | |
| 5271 * | |
| 5272 * @param classElt the class element to query | |
| 5273 * @param memberName the name of the member to lookup in the class | |
| 5274 * @return the found [ExecutableElement], or `null` if no such member was foun
d | |
| 5275 */ | |
| 5276 ExecutableElement lookupMemberInClass(ClassElement classElt, String memberName
) { | |
| 5277 List<MethodElement> methods = classElt.methods; | |
| 5278 for (MethodElement method in methods) { | |
| 5279 if (memberName == method.name && method.isAccessibleIn(_library) && !metho
d.isStatic) { | |
| 5280 return method; | |
| 5281 } | |
| 5282 } | |
| 5283 List<PropertyAccessorElement> accessors = classElt.accessors; | |
| 5284 for (PropertyAccessorElement accessor in accessors) { | |
| 5285 if (memberName == accessor.name && accessor.isAccessibleIn(_library) && !a
ccessor.isStatic) { | |
| 5286 return accessor; | |
| 5287 } | |
| 5288 } | |
| 5289 return null; | |
| 5290 } | |
| 5291 | |
| 5292 /** | |
| 5293 * Record the passed map with the set of all members (methods, getters and set
ters) in the type | |
| 5294 * into the passed map. | |
| 5295 * | |
| 5296 * @param map some non-`null` map to put the methods and accessors from the pa
ssed | |
| 5297 * [ClassElement] into | |
| 5298 * @param type the type that will be recorded into the passed map | |
| 5299 */ | |
| 5300 void recordMapWithClassMembers(MemberMap map, InterfaceType type) { | |
| 5301 List<MethodElement> methods = type.methods; | |
| 5302 for (MethodElement method in methods) { | |
| 5303 if (method.isAccessibleIn(_library) && !method.isStatic) { | |
| 5304 map.put(method.name, method); | |
| 5305 } | |
| 5306 } | |
| 5307 List<PropertyAccessorElement> accessors = type.accessors; | |
| 5308 for (PropertyAccessorElement accessor in accessors) { | |
| 5309 if (accessor.isAccessibleIn(_library) && !accessor.isStatic) { | |
| 5310 map.put(accessor.name, accessor); | |
| 5311 } | |
| 5312 } | |
| 5313 } | |
| 5314 | |
| 5315 /** | |
| 5316 * This method is used to report errors on when they are found computing inher
itance information. | |
| 5317 * See [ErrorVerifier#checkForInconsistentMethodInheritance] to see where thes
e generated | |
| 5318 * error codes are reported back into the analysis engine. | |
| 5319 * | |
| 5320 * @param classElt the location of the source for which the exception occurred | |
| 5321 * @param offset the offset of the location of the error | |
| 5322 * @param length the length of the location of the error | |
| 5323 * @param errorCode the error code to be associated with this error | |
| 5324 * @param arguments the arguments used to build the error message | |
| 5325 */ | |
| 5326 void reportError(ClassElement classElt, int offset, int length, ErrorCode erro
rCode, List<Object> arguments) { | |
| 5327 Set<AnalysisError> errorSet = _errorsInClassElement[classElt]; | |
| 5328 if (errorSet == null) { | |
| 5329 errorSet = new Set<AnalysisError>(); | |
| 5330 _errorsInClassElement[classElt] = errorSet; | |
| 5331 } | |
| 5332 javaSetAdd(errorSet, new AnalysisError.con2(classElt.source, offset, length,
errorCode, arguments)); | |
| 5333 } | |
| 5334 | |
| 5335 /** | |
| 5336 * Loop through all of the members in some [MemberMap], performing type parame
ter | |
| 5337 * substitutions using a passed supertype. | |
| 5338 * | |
| 5339 * @param superType the supertype to substitute into the members of the [Membe
rMap] | |
| 5340 * @param map the MemberMap to perform the substitutions on | |
| 5341 */ | |
| 5342 void substituteTypeParametersDownHierarchy(InterfaceType superType, MemberMap
map) { | |
| 5343 for (int i = 0; i < map.size; i++) { | |
| 5344 String key = map.getKey(i); | |
| 5345 ExecutableElement executableElement = map.getValue(i); | |
| 5346 if (executableElement is MethodMember) { | |
| 5347 executableElement = MethodMember.from(executableElement as MethodMember,
superType); | |
| 5348 map.put(key, executableElement); | |
| 5349 } else if (executableElement is PropertyAccessorMember) { | |
| 5350 executableElement = PropertyAccessorMember.from(executableElement as Pro
pertyAccessorMember, superType); | |
| 5351 map.put(key, executableElement); | |
| 5352 } | |
| 5353 } | |
| 5354 } | |
| 5355 } | |
| 5356 /** | |
| 5357 * Instances of the class `Library` represent the data about a single library du
ring the | |
| 5358 * resolution of some (possibly different) library. They are not intended to be
used except during | |
| 5359 * the resolution process. | |
| 5360 * | |
| 5361 * @coverage dart.engine.resolver | |
| 5362 */ | |
| 5363 class Library { | |
| 5364 | |
| 5365 /** | |
| 5366 * The analysis context in which this library is being analyzed. | |
| 5367 */ | |
| 5368 InternalAnalysisContext _analysisContext; | |
| 5369 | |
| 5370 /** | |
| 5371 * The inheritance manager which is used for this member lookups in this libra
ry. | |
| 5372 */ | |
| 5373 InheritanceManager _inheritanceManager; | |
| 5374 | |
| 5375 /** | |
| 5376 * The listener to which analysis errors will be reported. | |
| 5377 */ | |
| 5378 AnalysisErrorListener _errorListener; | |
| 5379 | |
| 5380 /** | |
| 5381 * The source specifying the defining compilation unit of this library. | |
| 5382 */ | |
| 5383 Source librarySource; | |
| 5384 | |
| 5385 /** | |
| 5386 * The library element representing this library. | |
| 5387 */ | |
| 5388 LibraryElementImpl _libraryElement; | |
| 5389 | |
| 5390 /** | |
| 5391 * A list containing all of the libraries that are imported into this library. | |
| 5392 */ | |
| 5393 List<Library> imports = _EMPTY_ARRAY; | |
| 5394 | |
| 5395 /** | |
| 5396 * A table mapping URI-based directive to the actual URI value. | |
| 5397 */ | |
| 5398 Map<UriBasedDirective, String> _directiveUris = new Map<UriBasedDirective, Str
ing>(); | |
| 5399 | |
| 5400 /** | |
| 5401 * A flag indicating whether this library explicitly imports core. | |
| 5402 */ | |
| 5403 bool explicitlyImportsCore = false; | |
| 5404 | |
| 5405 /** | |
| 5406 * A list containing all of the libraries that are exported from this library. | |
| 5407 */ | |
| 5408 List<Library> exports = _EMPTY_ARRAY; | |
| 5409 | |
| 5410 /** | |
| 5411 * A table mapping the sources for the compilation units in this library to th
eir corresponding | |
| 5412 * AST structures. | |
| 5413 */ | |
| 5414 Map<Source, ResolvableCompilationUnit> _astMap = new Map<Source, ResolvableCom
pilationUnit>(); | |
| 5415 | |
| 5416 /** | |
| 5417 * The library scope used when resolving elements within this library's compil
ation units. | |
| 5418 */ | |
| 5419 LibraryScope _libraryScope; | |
| 5420 | |
| 5421 /** | |
| 5422 * An empty array that can be used to initialize lists of libraries. | |
| 5423 */ | |
| 5424 static List<Library> _EMPTY_ARRAY = new List<Library>(0); | |
| 5425 | |
| 5426 /** | |
| 5427 * Initialize a newly created data holder that can maintain the data associate
d with a library. | |
| 5428 * | |
| 5429 * @param analysisContext the analysis context in which this library is being
analyzed | |
| 5430 * @param errorListener the listener to which analysis errors will be reported | |
| 5431 * @param librarySource the source specifying the defining compilation unit of
this library | |
| 5432 */ | |
| 5433 Library(InternalAnalysisContext analysisContext, AnalysisErrorListener errorLi
stener, Source librarySource) { | |
| 5434 this._analysisContext = analysisContext; | |
| 5435 this._errorListener = errorListener; | |
| 5436 this.librarySource = librarySource; | |
| 5437 this._libraryElement = analysisContext.getLibraryElement(librarySource) as L
ibraryElementImpl; | |
| 5438 } | |
| 5439 | |
| 5440 /** | |
| 5441 * Return the AST structure associated with the given source. | |
| 5442 * | |
| 5443 * @param source the source representing the compilation unit whose AST is to
be returned | |
| 5444 * @return the AST structure associated with the given source | |
| 5445 * @throws AnalysisException if an AST structure could not be created for the
compilation unit | |
| 5446 */ | |
| 5447 CompilationUnit getAST(Source source) { | |
| 5448 ResolvableCompilationUnit holder = _astMap[source]; | |
| 5449 if (holder == null) { | |
| 5450 holder = _analysisContext.computeResolvableCompilationUnit(source); | |
| 5451 _astMap[source] = holder; | |
| 5452 } | |
| 5453 return holder.compilationUnit; | |
| 5454 } | |
| 5455 | |
| 5456 /** | |
| 5457 * Return an array of the [CompilationUnit]s that make up the library. The fir
st unit is | |
| 5458 * always the defining unit. | |
| 5459 * | |
| 5460 * @return an array of the [CompilationUnit]s that make up the library. The fi
rst unit is | |
| 5461 * always the defining unit | |
| 5462 */ | |
| 5463 List<CompilationUnit> get compilationUnits { | |
| 5464 List<CompilationUnit> unitArrayList = new List<CompilationUnit>(); | |
| 5465 unitArrayList.add(definingCompilationUnit); | |
| 5466 for (Source source in _astMap.keys.toSet()) { | |
| 5467 if (librarySource != source) { | |
| 5468 unitArrayList.add(getAST(source)); | |
| 5469 } | |
| 5470 } | |
| 5471 return new List.from(unitArrayList); | |
| 5472 } | |
| 5473 | |
| 5474 /** | |
| 5475 * Return a collection containing the sources for the compilation units in thi
s library, including | |
| 5476 * the defining compilation unit. | |
| 5477 * | |
| 5478 * @return the sources for the compilation units in this library | |
| 5479 */ | |
| 5480 Set<Source> get compilationUnitSources => _astMap.keys.toSet(); | |
| 5481 | |
| 5482 /** | |
| 5483 * Return the AST structure associated with the defining compilation unit for
this library. | |
| 5484 * | |
| 5485 * @return the AST structure associated with the defining compilation unit for
this library | |
| 5486 * @throws AnalysisException if an AST structure could not be created for the
defining compilation | |
| 5487 * unit | |
| 5488 */ | |
| 5489 CompilationUnit get definingCompilationUnit => getAST(librarySource); | |
| 5490 | |
| 5491 /** | |
| 5492 * Return an array containing the libraries that are either imported or export
ed from this | |
| 5493 * library. | |
| 5494 * | |
| 5495 * @return the libraries that are either imported or exported from this librar
y | |
| 5496 */ | |
| 5497 List<Library> get importsAndExports { | |
| 5498 Set<Library> libraries = new Set<Library>(); | |
| 5499 for (Library library in imports) { | |
| 5500 javaSetAdd(libraries, library); | |
| 5501 } | |
| 5502 for (Library library in exports) { | |
| 5503 javaSetAdd(libraries, library); | |
| 5504 } | |
| 5505 return new List.from(libraries); | |
| 5506 } | |
| 5507 | |
| 5508 /** | |
| 5509 * Return the inheritance manager for this library. | |
| 5510 * | |
| 5511 * @return the inheritance manager for this library | |
| 5512 */ | |
| 5513 InheritanceManager get inheritanceManager { | |
| 5514 if (_inheritanceManager == null) { | |
| 5515 return _inheritanceManager = new InheritanceManager(_libraryElement); | |
| 5516 } | |
| 5517 return _inheritanceManager; | |
| 5518 } | |
| 5519 | |
| 5520 /** | |
| 5521 * Return the library element representing this library, creating it if necess
ary. | |
| 5522 * | |
| 5523 * @return the library element representing this library | |
| 5524 */ | |
| 5525 LibraryElementImpl get libraryElement { | |
| 5526 if (_libraryElement == null) { | |
| 5527 try { | |
| 5528 _libraryElement = _analysisContext.computeLibraryElement(librarySource)
as LibraryElementImpl; | |
| 5529 } on AnalysisException catch (exception) { | |
| 5530 AnalysisEngine.instance.logger.logError2("Could not compute library elem
ent for ${librarySource.fullName}", exception); | |
| 5531 } | |
| 5532 } | |
| 5533 return _libraryElement; | |
| 5534 } | |
| 5535 | |
| 5536 /** | |
| 5537 * Return the library scope used when resolving elements within this library's
compilation units. | |
| 5538 * | |
| 5539 * @return the library scope used when resolving elements within this library'
s compilation units | |
| 5540 */ | |
| 5541 LibraryScope get libraryScope { | |
| 5542 if (_libraryScope == null) { | |
| 5543 _libraryScope = new LibraryScope(_libraryElement, _errorListener); | |
| 5544 } | |
| 5545 return _libraryScope; | |
| 5546 } | |
| 5547 | |
| 5548 /** | |
| 5549 * Return the modification time associated with the given source. | |
| 5550 * | |
| 5551 * @param source the source representing the compilation unit whose modificati
on time is to be | |
| 5552 * returned | |
| 5553 * @return the modification time associated with the given source | |
| 5554 * @throws AnalysisException if an AST structure could not be created for the
compilation unit | |
| 5555 */ | |
| 5556 int getModificationTime(Source source) { | |
| 5557 ResolvableCompilationUnit holder = _astMap[source]; | |
| 5558 if (holder == null) { | |
| 5559 holder = _analysisContext.computeResolvableCompilationUnit(source); | |
| 5560 _astMap[source] = holder; | |
| 5561 } | |
| 5562 return holder.modificationTime; | |
| 5563 } | |
| 5564 | |
| 5565 /** | |
| 5566 * Return the result of resolving the URI of the given URI-based directive aga
inst the URI of the | |
| 5567 * library, or `null` if the URI is not valid. If the URI is not valid, report
the error. | |
| 5568 * | |
| 5569 * @param directive the directive which URI should be resolved | |
| 5570 * @return the result of resolving the URI against the URI of the library | |
| 5571 */ | |
| 5572 Source getSource(UriBasedDirective directive) { | |
| 5573 StringLiteral uriLiteral = directive.uri; | |
| 5574 if (uriLiteral is StringInterpolation) { | |
| 5575 _errorListener.onError(new AnalysisError.con2(librarySource, uriLiteral.of
fset, uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION, [])); | |
| 5576 return null; | |
| 5577 } | |
| 5578 String uriContent = uriLiteral.stringValue.trim(); | |
| 5579 _directiveUris[directive] = uriContent; | |
| 5580 uriContent = Uri.encodeFull(uriContent); | |
| 5581 try { | |
| 5582 parseUriWithException(uriContent); | |
| 5583 Source source = _analysisContext.sourceFactory.resolveUri(librarySource, u
riContent); | |
| 5584 if (source == null || !source.exists()) { | |
| 5585 _errorListener.onError(new AnalysisError.con2(librarySource, uriLiteral.
offset, uriLiteral.length, CompileTimeErrorCode.URI_DOES_NOT_EXIST, [uriContent]
)); | |
| 5586 } | |
| 5587 return source; | |
| 5588 } on URISyntaxException catch (exception) { | |
| 5589 _errorListener.onError(new AnalysisError.con2(librarySource, uriLiteral.of
fset, uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent])); | |
| 5590 } | |
| 5591 return null; | |
| 5592 } | |
| 5593 | |
| 5594 /** | |
| 5595 * Returns the URI value of the given directive. | |
| 5596 */ | |
| 5597 String getUri(UriBasedDirective directive) => _directiveUris[directive]; | |
| 5598 | |
| 5599 /** | |
| 5600 * Set the AST structure associated with the defining compilation unit for thi
s library to the | |
| 5601 * given AST structure. | |
| 5602 * | |
| 5603 * @param modificationStamp the modification time of the source from which the
compilation unit | |
| 5604 * was created | |
| 5605 * @param unit the AST structure associated with the defining compilation unit
for this library | |
| 5606 */ | |
| 5607 void setDefiningCompilationUnit(int modificationStamp, CompilationUnit unit) { | |
| 5608 _astMap[librarySource] = new ResolvableCompilationUnit(modificationStamp, un
it); | |
| 5609 } | |
| 5610 | |
| 5611 /** | |
| 5612 * Set the libraries that are exported by this library to be those in the give
n array. | |
| 5613 * | |
| 5614 * @param exportedLibraries the libraries that are exported by this library | |
| 5615 */ | |
| 5616 void set exportedLibraries(List<Library> exportedLibraries) { | |
| 5617 this.exports = exportedLibraries; | |
| 5618 } | |
| 5619 | |
| 5620 /** | |
| 5621 * Set the libraries that are imported into this library to be those in the gi
ven array. | |
| 5622 * | |
| 5623 * @param importedLibraries the libraries that are imported into this library | |
| 5624 */ | |
| 5625 void set importedLibraries(List<Library> importedLibraries) { | |
| 5626 this.imports = importedLibraries; | |
| 5627 } | |
| 5628 | |
| 5629 /** | |
| 5630 * Set the library element representing this library to the given library elem
ent. | |
| 5631 * | |
| 5632 * @param libraryElement the library element representing this library | |
| 5633 */ | |
| 5634 void set libraryElement(LibraryElementImpl libraryElement) { | |
| 5635 this._libraryElement = libraryElement; | |
| 5636 if (_inheritanceManager != null) { | |
| 5637 _inheritanceManager.libraryElement = libraryElement; | |
| 5638 } | |
| 5639 } | |
| 5640 String toString() => librarySource.shortName; | |
| 5641 } | |
| 5642 /** | |
| 5643 * Instances of the class `LibraryElementBuilder` build an element model for a s
ingle library. | |
| 5644 * | |
| 5645 * @coverage dart.engine.resolver | |
| 5646 */ | |
| 5647 class LibraryElementBuilder { | |
| 5648 | |
| 5649 /** | |
| 5650 * The analysis context in which the element model will be built. | |
| 5651 */ | |
| 5652 InternalAnalysisContext _analysisContext; | |
| 5653 | |
| 5654 /** | |
| 5655 * The listener to which errors will be reported. | |
| 5656 */ | |
| 5657 AnalysisErrorListener _errorListener; | |
| 5658 | |
| 5659 /** | |
| 5660 * The name of the function used as an entry point. | |
| 5661 */ | |
| 5662 static String _ENTRY_POINT_NAME = "main"; | |
| 5663 | |
| 5664 /** | |
| 5665 * Initialize a newly created library element builder. | |
| 5666 * | |
| 5667 * @param resolver the resolver for which the element model is being built | |
| 5668 */ | |
| 5669 LibraryElementBuilder(LibraryResolver resolver) { | |
| 5670 this._analysisContext = resolver.analysisContext; | |
| 5671 this._errorListener = resolver.errorListener; | |
| 5672 } | |
| 5673 | |
| 5674 /** | |
| 5675 * Build the library element for the given library. | |
| 5676 * | |
| 5677 * @param library the library for which an element model is to be built | |
| 5678 * @return the library element that was built | |
| 5679 * @throws AnalysisException if the analysis could not be performed | |
| 5680 */ | |
| 5681 LibraryElementImpl buildLibrary(Library library) { | |
| 5682 CompilationUnitBuilder builder = new CompilationUnitBuilder(); | |
| 5683 Source librarySource = library.librarySource; | |
| 5684 CompilationUnit definingCompilationUnit = library.definingCompilationUnit; | |
| 5685 CompilationUnitElementImpl definingCompilationUnitElement = builder.buildCom
pilationUnit(librarySource, definingCompilationUnit); | |
| 5686 NodeList<Directive> directives = definingCompilationUnit.directives; | |
| 5687 LibraryIdentifier libraryNameNode = null; | |
| 5688 bool hasPartDirective = false; | |
| 5689 FunctionElement entryPoint = findEntryPoint(definingCompilationUnitElement); | |
| 5690 List<Directive> directivesToResolve = new List<Directive>(); | |
| 5691 List<CompilationUnitElementImpl> sourcedCompilationUnits = new List<Compilat
ionUnitElementImpl>(); | |
| 5692 for (Directive directive in directives) { | |
| 5693 if (directive is LibraryDirective) { | |
| 5694 if (libraryNameNode == null) { | |
| 5695 libraryNameNode = ((directive as LibraryDirective)).name; | |
| 5696 directivesToResolve.add(directive); | |
| 5697 } | |
| 5698 } else if (directive is PartDirective) { | |
| 5699 PartDirective partDirective = directive as PartDirective; | |
| 5700 StringLiteral partUri = partDirective.uri; | |
| 5701 Source partSource = library.getSource(partDirective); | |
| 5702 if (partSource != null && partSource.exists()) { | |
| 5703 hasPartDirective = true; | |
| 5704 CompilationUnitElementImpl part = builder.buildCompilationUnit(partSou
rce, library.getAST(partSource)); | |
| 5705 part.uri = library.getUri(partDirective); | |
| 5706 String partLibraryName = getPartLibraryName(library, partSource, direc
tivesToResolve); | |
| 5707 if (partLibraryName == null) { | |
| 5708 _errorListener.onError(new AnalysisError.con2(librarySource, partUri
.offset, partUri.length, CompileTimeErrorCode.PART_OF_NON_PART, [partUri.toSourc
e()])); | |
| 5709 } else if (libraryNameNode == null) { | |
| 5710 } else if (libraryNameNode.name != partLibraryName) { | |
| 5711 _errorListener.onError(new AnalysisError.con2(librarySource, partUri
.offset, partUri.length, StaticWarningCode.PART_OF_DIFFERENT_LIBRARY, [libraryNa
meNode.name, partLibraryName])); | |
| 5712 } | |
| 5713 if (entryPoint == null) { | |
| 5714 entryPoint = findEntryPoint(part); | |
| 5715 } | |
| 5716 directive.element = part; | |
| 5717 sourcedCompilationUnits.add(part); | |
| 5718 } | |
| 5719 } | |
| 5720 } | |
| 5721 if (hasPartDirective && libraryNameNode == null) { | |
| 5722 _errorListener.onError(new AnalysisError.con1(librarySource, ResolverError
Code.MISSING_LIBRARY_DIRECTIVE_WITH_PART, [])); | |
| 5723 } | |
| 5724 LibraryElementImpl libraryElement = new LibraryElementImpl(_analysisContext,
libraryNameNode); | |
| 5725 libraryElement.definingCompilationUnit = definingCompilationUnitElement; | |
| 5726 if (entryPoint != null) { | |
| 5727 libraryElement.entryPoint = entryPoint; | |
| 5728 } | |
| 5729 int sourcedUnitCount = sourcedCompilationUnits.length; | |
| 5730 libraryElement.parts = new List.from(sourcedCompilationUnits); | |
| 5731 for (Directive directive in directivesToResolve) { | |
| 5732 directive.element = libraryElement; | |
| 5733 } | |
| 5734 library.libraryElement = libraryElement; | |
| 5735 if (sourcedUnitCount > 0) { | |
| 5736 patchTopLevelAccessors(libraryElement); | |
| 5737 } | |
| 5738 return libraryElement; | |
| 5739 } | |
| 5740 | |
| 5741 /** | |
| 5742 * Add all of the non-synthetic getters and setters defined in the given compi
lation unit that | |
| 5743 * have no corresponding accessor to one of the given collections. | |
| 5744 * | |
| 5745 * @param getters the map to which getters are to be added | |
| 5746 * @param setters the list to which setters are to be added | |
| 5747 * @param unit the compilation unit defining the accessors that are potentiall
y being added | |
| 5748 */ | |
| 5749 void collectAccessors(Map<String, PropertyAccessorElement> getters, List<Prope
rtyAccessorElement> setters, CompilationUnitElement unit) { | |
| 5750 for (PropertyAccessorElement accessor in unit.accessors) { | |
| 5751 if (accessor.isGetter) { | |
| 5752 if (!accessor.isSynthetic && accessor.correspondingSetter == null) { | |
| 5753 getters[accessor.displayName] = accessor; | |
| 5754 } | |
| 5755 } else { | |
| 5756 if (!accessor.isSynthetic && accessor.correspondingGetter == null) { | |
| 5757 setters.add(accessor); | |
| 5758 } | |
| 5759 } | |
| 5760 } | |
| 5761 } | |
| 5762 | |
| 5763 /** | |
| 5764 * Search the top-level functions defined in the given compilation unit for th
e entry point. | |
| 5765 * | |
| 5766 * @param element the compilation unit to be searched | |
| 5767 * @return the entry point that was found, or `null` if the compilation unit d
oes not define | |
| 5768 * an entry point | |
| 5769 */ | |
| 5770 FunctionElement findEntryPoint(CompilationUnitElementImpl element) { | |
| 5771 for (FunctionElement function in element.functions) { | |
| 5772 if (function.name == _ENTRY_POINT_NAME) { | |
| 5773 return function; | |
| 5774 } | |
| 5775 } | |
| 5776 return null; | |
| 5777 } | |
| 5778 | |
| 5779 /** | |
| 5780 * Return the name of the library that the given part is declared to be a part
of, or `null` | |
| 5781 * if the part does not contain a part-of directive. | |
| 5782 * | |
| 5783 * @param library the library containing the part | |
| 5784 * @param partSource the source representing the part | |
| 5785 * @param directivesToResolve a list of directives that should be resolved to
the library being | |
| 5786 * built | |
| 5787 * @return the name of the library that the given part is declared to be a par
t of | |
| 5788 */ | |
| 5789 String getPartLibraryName(Library library, Source partSource, List<Directive>
directivesToResolve) { | |
| 5790 try { | |
| 5791 CompilationUnit partUnit = library.getAST(partSource); | |
| 5792 for (Directive directive in partUnit.directives) { | |
| 5793 if (directive is PartOfDirective) { | |
| 5794 directivesToResolve.add(directive); | |
| 5795 LibraryIdentifier libraryName = ((directive as PartOfDirective)).libra
ryName; | |
| 5796 if (libraryName != null) { | |
| 5797 return libraryName.name; | |
| 5798 } | |
| 5799 } | |
| 5800 } | |
| 5801 } on AnalysisException catch (exception) { | |
| 5802 } | |
| 5803 return null; | |
| 5804 } | |
| 5805 | |
| 5806 /** | |
| 5807 * Look through all of the compilation units defined for the given library, lo
oking for getters | |
| 5808 * and setters that are defined in different compilation units but that have t
he same names. If | |
| 5809 * any are found, make sure that they have the same variable element. | |
| 5810 * | |
| 5811 * @param libraryElement the library defining the compilation units to be proc
essed | |
| 5812 */ | |
| 5813 void patchTopLevelAccessors(LibraryElementImpl libraryElement) { | |
| 5814 Map<String, PropertyAccessorElement> getters = new Map<String, PropertyAcces
sorElement>(); | |
| 5815 List<PropertyAccessorElement> setters = new List<PropertyAccessorElement>(); | |
| 5816 collectAccessors(getters, setters, libraryElement.definingCompilationUnit); | |
| 5817 for (CompilationUnitElement unit in libraryElement.parts) { | |
| 5818 collectAccessors(getters, setters, unit); | |
| 5819 } | |
| 5820 for (PropertyAccessorElement setter in setters) { | |
| 5821 PropertyAccessorElement getter = getters[setter.displayName]; | |
| 5822 if (getter != null) { | |
| 5823 PropertyInducingElementImpl variable = getter.variable as PropertyInduci
ngElementImpl; | |
| 5824 variable.setter = setter; | |
| 5825 ((setter as PropertyAccessorElementImpl)).variable = variable; | |
| 5826 } | |
| 5827 } | |
| 5828 } | |
| 5829 } | |
| 5830 /** | |
| 5831 * Instances of the class `LibraryResolver` are used to resolve one or more mutu
ally dependent | |
| 5832 * libraries within a single context. | |
| 5833 * | |
| 5834 * @coverage dart.engine.resolver | |
| 5835 */ | |
| 5836 class LibraryResolver { | |
| 5837 | |
| 5838 /** | |
| 5839 * The analysis context in which the libraries are being analyzed. | |
| 5840 */ | |
| 5841 InternalAnalysisContext analysisContext; | |
| 5842 | |
| 5843 /** | |
| 5844 * The listener to which analysis errors will be reported, this error listener
is either | |
| 5845 * references [recordingErrorListener], or it unions the passed | |
| 5846 * [AnalysisErrorListener] with the [recordingErrorListener]. | |
| 5847 */ | |
| 5848 RecordingErrorListener errorListener; | |
| 5849 | |
| 5850 /** | |
| 5851 * A source object representing the core library (dart:core). | |
| 5852 */ | |
| 5853 Source _coreLibrarySource; | |
| 5854 | |
| 5855 /** | |
| 5856 * The object representing the core library. | |
| 5857 */ | |
| 5858 Library _coreLibrary; | |
| 5859 | |
| 5860 /** | |
| 5861 * The object used to access the types from the core library. | |
| 5862 */ | |
| 5863 TypeProvider _typeProvider; | |
| 5864 | |
| 5865 /** | |
| 5866 * A table mapping library sources to the information being maintained for tho
se libraries. | |
| 5867 */ | |
| 5868 Map<Source, Library> _libraryMap = new Map<Source, Library>(); | |
| 5869 | |
| 5870 /** | |
| 5871 * A collection containing the libraries that are being resolved together. | |
| 5872 */ | |
| 5873 Set<Library> resolvedLibraries; | |
| 5874 | |
| 5875 /** | |
| 5876 * Initialize a newly created library resolver to resolve libraries within the
given context. | |
| 5877 * | |
| 5878 * @param analysisContext the analysis context in which the library is being a
nalyzed | |
| 5879 */ | |
| 5880 LibraryResolver(InternalAnalysisContext analysisContext) { | |
| 5881 this.analysisContext = analysisContext; | |
| 5882 this.errorListener = new RecordingErrorListener(); | |
| 5883 _coreLibrarySource = analysisContext.sourceFactory.forUri(DartSdk.DART_CORE)
; | |
| 5884 } | |
| 5885 | |
| 5886 /** | |
| 5887 * Resolve the library specified by the given source in the given context. The
library is assumed | |
| 5888 * to be embedded in the given source. | |
| 5889 * | |
| 5890 * @param librarySource the source specifying the defining compilation unit of
the library to be | |
| 5891 * resolved | |
| 5892 * @param modificationStamp the time stamp of the source from which the compil
ation unit was | |
| 5893 * created | |
| 5894 * @param unit the compilation unit representing the embedded library | |
| 5895 * @param fullAnalysis `true` if a full analysis should be performed | |
| 5896 * @return the element representing the resolved library | |
| 5897 * @throws AnalysisException if the library could not be resolved for some rea
son | |
| 5898 */ | |
| 5899 LibraryElement resolveEmbeddedLibrary(Source librarySource, int modificationSt
amp, CompilationUnit unit, bool fullAnalysis) { | |
| 5900 InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engi
ne.LibraryResolver.resolveEmbeddedLibrary"); | |
| 5901 try { | |
| 5902 instrumentation.metric("fullAnalysis", fullAnalysis); | |
| 5903 instrumentation.data3("fullName", librarySource.fullName); | |
| 5904 Library targetLibrary = createLibrary2(librarySource, modificationStamp, u
nit); | |
| 5905 _coreLibrary = _libraryMap[_coreLibrarySource]; | |
| 5906 if (_coreLibrary == null) { | |
| 5907 _coreLibrary = createLibrary(_coreLibrarySource); | |
| 5908 } | |
| 5909 instrumentation.metric3("createLibrary", "complete"); | |
| 5910 computeLibraryDependencies2(targetLibrary, unit); | |
| 5911 resolvedLibraries = computeLibrariesInCycles(targetLibrary); | |
| 5912 buildElementModels(); | |
| 5913 instrumentation.metric3("buildElementModels", "complete"); | |
| 5914 LibraryElement coreElement = _coreLibrary.libraryElement; | |
| 5915 if (coreElement == null) { | |
| 5916 throw new AnalysisException.con1("Could not resolve dart:core"); | |
| 5917 } | |
| 5918 buildDirectiveModels(); | |
| 5919 instrumentation.metric3("buildDirectiveModels", "complete"); | |
| 5920 _typeProvider = new TypeProviderImpl(coreElement); | |
| 5921 buildTypeHierarchies(); | |
| 5922 instrumentation.metric3("buildTypeHierarchies", "complete"); | |
| 5923 resolveReferencesAndTypes(); | |
| 5924 instrumentation.metric3("resolveReferencesAndTypes", "complete"); | |
| 5925 performConstantEvaluation(); | |
| 5926 instrumentation.metric3("performConstantEvaluation", "complete"); | |
| 5927 return targetLibrary.libraryElement; | |
| 5928 } finally { | |
| 5929 instrumentation.log(); | |
| 5930 } | |
| 5931 } | |
| 5932 | |
| 5933 /** | |
| 5934 * Resolve the library specified by the given source in the given context. | |
| 5935 * | |
| 5936 * Note that because Dart allows circular imports between libraries, it is pos
sible that more than | |
| 5937 * one library will need to be resolved. In such cases the error listener can
receive errors from | |
| 5938 * multiple libraries. | |
| 5939 * | |
| 5940 * @param librarySource the source specifying the defining compilation unit of
the library to be | |
| 5941 * resolved | |
| 5942 * @param fullAnalysis `true` if a full analysis should be performed | |
| 5943 * @return the element representing the resolved library | |
| 5944 * @throws AnalysisException if the library could not be resolved for some rea
son | |
| 5945 */ | |
| 5946 LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) { | |
| 5947 InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engi
ne.LibraryResolver.resolveLibrary"); | |
| 5948 try { | |
| 5949 instrumentation.metric("fullAnalysis", fullAnalysis); | |
| 5950 instrumentation.data3("fullName", librarySource.fullName); | |
| 5951 Library targetLibrary = createLibrary(librarySource); | |
| 5952 _coreLibrary = _libraryMap[_coreLibrarySource]; | |
| 5953 if (_coreLibrary == null) { | |
| 5954 _coreLibrary = createLibrary(_coreLibrarySource); | |
| 5955 } | |
| 5956 instrumentation.metric3("createLibrary", "complete"); | |
| 5957 computeLibraryDependencies(targetLibrary); | |
| 5958 resolvedLibraries = computeLibrariesInCycles(targetLibrary); | |
| 5959 buildElementModels(); | |
| 5960 instrumentation.metric3("buildElementModels", "complete"); | |
| 5961 LibraryElement coreElement = _coreLibrary.libraryElement; | |
| 5962 if (coreElement == null) { | |
| 5963 throw new AnalysisException.con1("Could not resolve dart:core"); | |
| 5964 } | |
| 5965 buildDirectiveModels(); | |
| 5966 instrumentation.metric3("buildDirectiveModels", "complete"); | |
| 5967 _typeProvider = new TypeProviderImpl(coreElement); | |
| 5968 buildTypeHierarchies(); | |
| 5969 instrumentation.metric3("buildTypeHierarchies", "complete"); | |
| 5970 resolveReferencesAndTypes(); | |
| 5971 instrumentation.metric3("resolveReferencesAndTypes", "complete"); | |
| 5972 performConstantEvaluation(); | |
| 5973 instrumentation.metric3("performConstantEvaluation", "complete"); | |
| 5974 instrumentation.metric2("librariesInCycles", resolvedLibraries.length); | |
| 5975 for (Library lib in resolvedLibraries) { | |
| 5976 instrumentation.metric2("librariesInCycles-CompilationUnitSources-Size",
lib.compilationUnitSources.length); | |
| 5977 } | |
| 5978 return targetLibrary.libraryElement; | |
| 5979 } finally { | |
| 5980 instrumentation.log(); | |
| 5981 } | |
| 5982 } | |
| 5983 | |
| 5984 /** | |
| 5985 * Add a dependency to the given map from the referencing library to the refer
enced library. | |
| 5986 * | |
| 5987 * @param dependencyMap the map to which the dependency is to be added | |
| 5988 * @param referencingLibrary the library that references the referenced librar
y | |
| 5989 * @param referencedLibrary the library referenced by the referencing library | |
| 5990 */ | |
| 5991 void addDependencyToMap(Map<Library, List<Library>> dependencyMap, Library ref
erencingLibrary, Library referencedLibrary) { | |
| 5992 List<Library> dependentLibraries = dependencyMap[referencedLibrary]; | |
| 5993 if (dependentLibraries == null) { | |
| 5994 dependentLibraries = new List<Library>(); | |
| 5995 dependencyMap[referencedLibrary] = dependentLibraries; | |
| 5996 } | |
| 5997 dependentLibraries.add(referencingLibrary); | |
| 5998 } | |
| 5999 | |
| 6000 /** | |
| 6001 * Given a library that is part of a cycle that includes the root library, add
to the given set of | |
| 6002 * libraries all of the libraries reachable from the root library that are als
o included in the | |
| 6003 * cycle. | |
| 6004 * | |
| 6005 * @param library the library to be added to the collection of libraries in cy
cles | |
| 6006 * @param librariesInCycle a collection of the libraries that are in the cycle | |
| 6007 * @param dependencyMap a table mapping libraries to the collection of librari
es from which those | |
| 6008 * libraries are referenced | |
| 6009 */ | |
| 6010 void addLibrariesInCycle(Library library, Set<Library> librariesInCycle, Map<L
ibrary, List<Library>> dependencyMap) { | |
| 6011 if (javaSetAdd(librariesInCycle, library)) { | |
| 6012 List<Library> dependentLibraries = dependencyMap[library]; | |
| 6013 if (dependentLibraries != null) { | |
| 6014 for (Library dependentLibrary in dependentLibraries) { | |
| 6015 addLibrariesInCycle(dependentLibrary, librariesInCycle, dependencyMap)
; | |
| 6016 } | |
| 6017 } | |
| 6018 } | |
| 6019 } | |
| 6020 | |
| 6021 /** | |
| 6022 * Add the given library, and all libraries reachable from it that have not al
ready been visited, | |
| 6023 * to the given dependency map. | |
| 6024 * | |
| 6025 * @param library the library currently being added to the dependency map | |
| 6026 * @param dependencyMap the dependency map being computed | |
| 6027 * @param visitedLibraries the libraries that have already been visited, used
to prevent infinite | |
| 6028 * recursion | |
| 6029 */ | |
| 6030 void addToDependencyMap(Library library, Map<Library, List<Library>> dependenc
yMap, Set<Library> visitedLibraries) { | |
| 6031 if (javaSetAdd(visitedLibraries, library)) { | |
| 6032 for (Library referencedLibrary in library.importsAndExports) { | |
| 6033 addDependencyToMap(dependencyMap, library, referencedLibrary); | |
| 6034 addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries); | |
| 6035 } | |
| 6036 if (!library.explicitlyImportsCore && library != _coreLibrary) { | |
| 6037 addDependencyToMap(dependencyMap, library, _coreLibrary); | |
| 6038 } | |
| 6039 } | |
| 6040 } | |
| 6041 | |
| 6042 /** | |
| 6043 * Build the element model representing the combinators declared by the given
directive. | |
| 6044 * | |
| 6045 * @param directive the directive that declares the combinators | |
| 6046 * @return an array containing the import combinators that were built | |
| 6047 */ | |
| 6048 List<NamespaceCombinator> buildCombinators(NamespaceDirective directive) { | |
| 6049 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>(); | |
| 6050 for (Combinator combinator in directive.combinators) { | |
| 6051 if (combinator is HideCombinator) { | |
| 6052 HideElementCombinatorImpl hide = new HideElementCombinatorImpl(); | |
| 6053 hide.hiddenNames = getIdentifiers(((combinator as HideCombinator)).hidde
nNames); | |
| 6054 combinators.add(hide); | |
| 6055 } else { | |
| 6056 ShowElementCombinatorImpl show = new ShowElementCombinatorImpl(); | |
| 6057 show.offset = combinator.offset; | |
| 6058 show.end = combinator.end; | |
| 6059 show.shownNames = getIdentifiers(((combinator as ShowCombinator)).shownN
ames); | |
| 6060 combinators.add(show); | |
| 6061 } | |
| 6062 } | |
| 6063 return new List.from(combinators); | |
| 6064 } | |
| 6065 | |
| 6066 /** | |
| 6067 * Every library now has a corresponding [LibraryElement], so it is now possib
le to resolve | |
| 6068 * the import and export directives. | |
| 6069 * | |
| 6070 * @throws AnalysisException if the defining compilation unit for any of the l
ibraries could not | |
| 6071 * be accessed | |
| 6072 */ | |
| 6073 void buildDirectiveModels() { | |
| 6074 for (Library library in resolvedLibraries) { | |
| 6075 Map<String, PrefixElementImpl> nameToPrefixMap = new Map<String, PrefixEle
mentImpl>(); | |
| 6076 List<ImportElement> imports = new List<ImportElement>(); | |
| 6077 List<ExportElement> exports = new List<ExportElement>(); | |
| 6078 for (Directive directive in library.definingCompilationUnit.directives) { | |
| 6079 if (directive is ImportDirective) { | |
| 6080 ImportDirective importDirective = directive as ImportDirective; | |
| 6081 Source importedSource = library.getSource(importDirective); | |
| 6082 if (importedSource != null) { | |
| 6083 Library importedLibrary = _libraryMap[importedSource]; | |
| 6084 if (importedLibrary != null) { | |
| 6085 ImportElementImpl importElement = new ImportElementImpl(); | |
| 6086 importElement.offset = directive.offset; | |
| 6087 StringLiteral uriLiteral = importDirective.uri; | |
| 6088 if (uriLiteral != null) { | |
| 6089 importElement.uriEnd = uriLiteral.end; | |
| 6090 } | |
| 6091 importElement.uri = library.getUri(importDirective); | |
| 6092 importElement.combinators = buildCombinators(importDirective); | |
| 6093 LibraryElement importedLibraryElement = importedLibrary.libraryEle
ment; | |
| 6094 if (importedLibraryElement != null) { | |
| 6095 importElement.importedLibrary = importedLibraryElement; | |
| 6096 } | |
| 6097 SimpleIdentifier prefixNode = ((directive as ImportDirective)).pre
fix; | |
| 6098 if (prefixNode != null) { | |
| 6099 importElement.prefixOffset = prefixNode.offset; | |
| 6100 String prefixName = prefixNode.name; | |
| 6101 PrefixElementImpl prefix = nameToPrefixMap[prefixName]; | |
| 6102 if (prefix == null) { | |
| 6103 prefix = new PrefixElementImpl(prefixNode); | |
| 6104 nameToPrefixMap[prefixName] = prefix; | |
| 6105 } | |
| 6106 importElement.prefix = prefix; | |
| 6107 prefixNode.staticElement = prefix; | |
| 6108 } | |
| 6109 directive.element = importElement; | |
| 6110 imports.add(importElement); | |
| 6111 if (doesCompilationUnitHavePartOfDirective(importedLibrary.getAST(
importedSource))) { | |
| 6112 errorListener.onError(new AnalysisError.con2(library.librarySour
ce, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.IMPORT_OF_NON_LIB
RARY, [uriLiteral.toSource()])); | |
| 6113 } | |
| 6114 } | |
| 6115 } | |
| 6116 } else if (directive is ExportDirective) { | |
| 6117 ExportDirective exportDirective = directive as ExportDirective; | |
| 6118 Source exportedSource = library.getSource(exportDirective); | |
| 6119 if (exportedSource != null) { | |
| 6120 Library exportedLibrary = _libraryMap[exportedSource]; | |
| 6121 if (exportedLibrary != null) { | |
| 6122 ExportElementImpl exportElement = new ExportElementImpl(); | |
| 6123 exportElement.uri = library.getUri(exportDirective); | |
| 6124 exportElement.combinators = buildCombinators(exportDirective); | |
| 6125 LibraryElement exportedLibraryElement = exportedLibrary.libraryEle
ment; | |
| 6126 if (exportedLibraryElement != null) { | |
| 6127 exportElement.exportedLibrary = exportedLibraryElement; | |
| 6128 } | |
| 6129 directive.element = exportElement; | |
| 6130 exports.add(exportElement); | |
| 6131 if (doesCompilationUnitHavePartOfDirective(exportedLibrary.getAST(
exportedSource))) { | |
| 6132 StringLiteral uriLiteral = exportDirective.uri; | |
| 6133 errorListener.onError(new AnalysisError.con2(library.librarySour
ce, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.EXPORT_OF_NON_LIB
RARY, [uriLiteral.toSource()])); | |
| 6134 } | |
| 6135 } | |
| 6136 } | |
| 6137 } | |
| 6138 } | |
| 6139 Source librarySource = library.librarySource; | |
| 6140 if (!library.explicitlyImportsCore && _coreLibrarySource != librarySource)
{ | |
| 6141 ImportElementImpl importElement = new ImportElementImpl(); | |
| 6142 importElement.importedLibrary = _coreLibrary.libraryElement; | |
| 6143 importElement.synthetic = true; | |
| 6144 imports.add(importElement); | |
| 6145 } | |
| 6146 LibraryElementImpl libraryElement = library.libraryElement; | |
| 6147 libraryElement.imports = new List.from(imports); | |
| 6148 libraryElement.exports = new List.from(exports); | |
| 6149 } | |
| 6150 } | |
| 6151 | |
| 6152 /** | |
| 6153 * Build element models for all of the libraries in the current cycle. | |
| 6154 * | |
| 6155 * @throws AnalysisException if any of the element models cannot be built | |
| 6156 */ | |
| 6157 void buildElementModels() { | |
| 6158 for (Library library in resolvedLibraries) { | |
| 6159 LibraryElementBuilder builder = new LibraryElementBuilder(this); | |
| 6160 LibraryElementImpl libraryElement = builder.buildLibrary(library); | |
| 6161 library.libraryElement = libraryElement; | |
| 6162 } | |
| 6163 } | |
| 6164 | |
| 6165 /** | |
| 6166 * Resolve the type hierarchy across all of the types declared in the librarie
s in the current | |
| 6167 * cycle. | |
| 6168 * | |
| 6169 * @throws AnalysisException if any of the type hierarchies could not be resol
ved | |
| 6170 */ | |
| 6171 void buildTypeHierarchies() { | |
| 6172 TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.resolve.st
art(); | |
| 6173 try { | |
| 6174 for (Library library in resolvedLibraries) { | |
| 6175 for (Source source in library.compilationUnitSources) { | |
| 6176 TypeResolverVisitor visitor = new TypeResolverVisitor.con1(library, so
urce, _typeProvider); | |
| 6177 library.getAST(source).accept(visitor); | |
| 6178 } | |
| 6179 } | |
| 6180 } finally { | |
| 6181 timeCounter.stop(); | |
| 6182 } | |
| 6183 } | |
| 6184 | |
| 6185 /** | |
| 6186 * Compute a dependency map of libraries reachable from the given library. A d
ependency map is a | |
| 6187 * table that maps individual libraries to a list of the libraries that either
import or export | |
| 6188 * those libraries. | |
| 6189 * | |
| 6190 * This map is used to compute all of the libraries involved in a cycle that i
nclude the root | |
| 6191 * library. Given that we only add libraries that are reachable from the root
library, when we | |
| 6192 * work backward we are guaranteed to only get libraries in the cycle. | |
| 6193 * | |
| 6194 * @param library the library currently being added to the dependency map | |
| 6195 */ | |
| 6196 Map<Library, List<Library>> computeDependencyMap(Library library) { | |
| 6197 Map<Library, List<Library>> dependencyMap = new Map<Library, List<Library>>(
); | |
| 6198 addToDependencyMap(library, dependencyMap, new Set<Library>()); | |
| 6199 return dependencyMap; | |
| 6200 } | |
| 6201 | |
| 6202 /** | |
| 6203 * Return a collection containing all of the libraries reachable from the give
n library that are | |
| 6204 * contained in a cycle that includes the given library. | |
| 6205 * | |
| 6206 * @param library the library that must be included in any cycles whose member
s are to be returned | |
| 6207 * @return all of the libraries referenced by the given library that have a ci
rcular reference | |
| 6208 * back to the given library | |
| 6209 */ | |
| 6210 Set<Library> computeLibrariesInCycles(Library library) { | |
| 6211 Map<Library, List<Library>> dependencyMap = computeDependencyMap(library); | |
| 6212 Set<Library> librariesInCycle = new Set<Library>(); | |
| 6213 addLibrariesInCycle(library, librariesInCycle, dependencyMap); | |
| 6214 return librariesInCycle; | |
| 6215 } | |
| 6216 | |
| 6217 /** | |
| 6218 * Recursively traverse the libraries reachable from the given library, creati
ng instances of the | |
| 6219 * class [Library] to represent them, and record the references in the library
objects. | |
| 6220 * | |
| 6221 * @param library the library to be processed to find libraries that have not
yet been traversed | |
| 6222 * @throws AnalysisException if some portion of the library graph could not be
traversed | |
| 6223 */ | |
| 6224 void computeLibraryDependencies(Library library) { | |
| 6225 Source librarySource = library.librarySource; | |
| 6226 computeLibraryDependencies3(library, analysisContext.computeImportedLibrarie
s(librarySource), analysisContext.computeExportedLibraries(librarySource)); | |
| 6227 } | |
| 6228 | |
| 6229 /** | |
| 6230 * Recursively traverse the libraries reachable from the given library, creati
ng instances of the | |
| 6231 * class [Library] to represent them, and record the references in the library
objects. | |
| 6232 * | |
| 6233 * @param library the library to be processed to find libraries that have not
yet been traversed | |
| 6234 * @throws AnalysisException if some portion of the library graph could not be
traversed | |
| 6235 */ | |
| 6236 void computeLibraryDependencies2(Library library, CompilationUnit unit) { | |
| 6237 Source librarySource = library.librarySource; | |
| 6238 Set<Source> exportedSources = new Set<Source>(); | |
| 6239 Set<Source> importedSources = new Set<Source>(); | |
| 6240 for (Directive directive in unit.directives) { | |
| 6241 if (directive is ExportDirective) { | |
| 6242 Source exportSource = resolveSource(librarySource, directive as ExportDi
rective); | |
| 6243 if (exportSource != null) { | |
| 6244 javaSetAdd(exportedSources, exportSource); | |
| 6245 } | |
| 6246 } else if (directive is ImportDirective) { | |
| 6247 Source importSource = resolveSource(librarySource, directive as ImportDi
rective); | |
| 6248 if (importSource != null) { | |
| 6249 javaSetAdd(importedSources, importSource); | |
| 6250 } | |
| 6251 } | |
| 6252 } | |
| 6253 computeLibraryDependencies3(library, new List.from(importedSources), new Lis
t.from(exportedSources)); | |
| 6254 } | |
| 6255 | |
| 6256 /** | |
| 6257 * Recursively traverse the libraries reachable from the given library, creati
ng instances of the | |
| 6258 * class [Library] to represent them, and record the references in the library
objects. | |
| 6259 * | |
| 6260 * @param library the library to be processed to find libraries that have not
yet been traversed | |
| 6261 * @param importedSources an array containing the sources that are imported in
to the given library | |
| 6262 * @param exportedSources an array containing the sources that are exported fr
om the given library | |
| 6263 * @throws AnalysisException if some portion of the library graph could not be
traversed | |
| 6264 */ | |
| 6265 void computeLibraryDependencies3(Library library, List<Source> importedSources
, List<Source> exportedSources) { | |
| 6266 List<Library> importedLibraries = new List<Library>(); | |
| 6267 bool explicitlyImportsCore = false; | |
| 6268 for (Source importedSource in importedSources) { | |
| 6269 if (importedSource == _coreLibrarySource) { | |
| 6270 explicitlyImportsCore = true; | |
| 6271 } | |
| 6272 Library importedLibrary = _libraryMap[importedSource]; | |
| 6273 if (importedLibrary == null) { | |
| 6274 importedLibrary = createLibraryOrNull(importedSource); | |
| 6275 if (importedLibrary != null) { | |
| 6276 computeLibraryDependencies(importedLibrary); | |
| 6277 } | |
| 6278 } | |
| 6279 if (importedLibrary != null) { | |
| 6280 importedLibraries.add(importedLibrary); | |
| 6281 } | |
| 6282 } | |
| 6283 library.importedLibraries = new List.from(importedLibraries); | |
| 6284 List<Library> exportedLibraries = new List<Library>(); | |
| 6285 for (Source exportedSource in exportedSources) { | |
| 6286 Library exportedLibrary = _libraryMap[exportedSource]; | |
| 6287 if (exportedLibrary == null) { | |
| 6288 exportedLibrary = createLibraryOrNull(exportedSource); | |
| 6289 if (exportedLibrary != null) { | |
| 6290 computeLibraryDependencies(exportedLibrary); | |
| 6291 } | |
| 6292 } | |
| 6293 if (exportedLibrary != null) { | |
| 6294 exportedLibraries.add(exportedLibrary); | |
| 6295 } | |
| 6296 } | |
| 6297 library.exportedLibraries = new List.from(exportedLibraries); | |
| 6298 library.explicitlyImportsCore = explicitlyImportsCore; | |
| 6299 if (!explicitlyImportsCore && _coreLibrarySource != library.librarySource) { | |
| 6300 Library importedLibrary = _libraryMap[_coreLibrarySource]; | |
| 6301 if (importedLibrary == null) { | |
| 6302 importedLibrary = createLibraryOrNull(_coreLibrarySource); | |
| 6303 if (importedLibrary != null) { | |
| 6304 computeLibraryDependencies(importedLibrary); | |
| 6305 } | |
| 6306 } | |
| 6307 } | |
| 6308 } | |
| 6309 | |
| 6310 /** | |
| 6311 * Create an object to represent the information about the library defined by
the compilation unit | |
| 6312 * with the given source. | |
| 6313 * | |
| 6314 * @param librarySource the source of the library's defining compilation unit | |
| 6315 * @return the library object that was created | |
| 6316 * @throws AnalysisException if the library source is not valid | |
| 6317 */ | |
| 6318 Library createLibrary(Source librarySource) { | |
| 6319 Library library = new Library(analysisContext, errorListener, librarySource)
; | |
| 6320 library.definingCompilationUnit; | |
| 6321 _libraryMap[librarySource] = library; | |
| 6322 return library; | |
| 6323 } | |
| 6324 | |
| 6325 /** | |
| 6326 * Create an object to represent the information about the library defined by
the compilation unit | |
| 6327 * with the given source. | |
| 6328 * | |
| 6329 * @param librarySource the source of the library's defining compilation unit | |
| 6330 * @param modificationStamp the modification time of the source from which the
compilation unit | |
| 6331 * was created | |
| 6332 * @param unit the compilation unit that defines the library | |
| 6333 * @return the library object that was created | |
| 6334 * @throws AnalysisException if the library source is not valid | |
| 6335 */ | |
| 6336 Library createLibrary2(Source librarySource, int modificationStamp, Compilatio
nUnit unit) { | |
| 6337 Library library = new Library(analysisContext, errorListener, librarySource)
; | |
| 6338 library.setDefiningCompilationUnit(modificationStamp, unit); | |
| 6339 _libraryMap[librarySource] = library; | |
| 6340 return library; | |
| 6341 } | |
| 6342 | |
| 6343 /** | |
| 6344 * Create an object to represent the information about the library defined by
the compilation unit | |
| 6345 * with the given source. Return the library object that was created, or `null
` if the | |
| 6346 * source is not valid. | |
| 6347 * | |
| 6348 * @param librarySource the source of the library's defining compilation unit | |
| 6349 * @return the library object that was created | |
| 6350 */ | |
| 6351 Library createLibraryOrNull(Source librarySource) { | |
| 6352 if (!librarySource.exists()) { | |
| 6353 return null; | |
| 6354 } | |
| 6355 Library library = new Library(analysisContext, errorListener, librarySource)
; | |
| 6356 _libraryMap[librarySource] = library; | |
| 6357 return library; | |
| 6358 } | |
| 6359 | |
| 6360 /** | |
| 6361 * Return `true` if and only if the passed [CompilationUnit] has a part-of dir
ective. | |
| 6362 * | |
| 6363 * @param node the [CompilationUnit] to test | |
| 6364 * @return `true` if and only if the passed [CompilationUnit] has a part-of di
rective | |
| 6365 */ | |
| 6366 bool doesCompilationUnitHavePartOfDirective(CompilationUnit node) { | |
| 6367 NodeList<Directive> directives = node.directives; | |
| 6368 for (Directive directive in directives) { | |
| 6369 if (directive is PartOfDirective) { | |
| 6370 return true; | |
| 6371 } | |
| 6372 } | |
| 6373 return false; | |
| 6374 } | |
| 6375 | |
| 6376 /** | |
| 6377 * Return an array containing the lexical identifiers associated with the node
s in the given list. | |
| 6378 * | |
| 6379 * @param names the AST nodes representing the identifiers | |
| 6380 * @return the lexical identifiers associated with the nodes in the list | |
| 6381 */ | |
| 6382 List<String> getIdentifiers(NodeList<SimpleIdentifier> names) { | |
| 6383 int count = names.length; | |
| 6384 List<String> identifiers = new List<String>(count); | |
| 6385 for (int i = 0; i < count; i++) { | |
| 6386 identifiers[i] = names[i].name; | |
| 6387 } | |
| 6388 return identifiers; | |
| 6389 } | |
| 6390 | |
| 6391 /** | |
| 6392 * Compute a value for all of the constants in the libraries being analyzed. | |
| 6393 */ | |
| 6394 void performConstantEvaluation() { | |
| 6395 TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.resolve.st
art(); | |
| 6396 try { | |
| 6397 ConstantValueComputer computer = new ConstantValueComputer(); | |
| 6398 for (Library library in resolvedLibraries) { | |
| 6399 for (Source source in library.compilationUnitSources) { | |
| 6400 try { | |
| 6401 CompilationUnit unit = library.getAST(source); | |
| 6402 if (unit != null) { | |
| 6403 computer.add(unit); | |
| 6404 } | |
| 6405 } on AnalysisException catch (exception) { | |
| 6406 AnalysisEngine.instance.logger.logError2("Internal Error: Could not
access AST for ${source.fullName} during constant evaluation", exception); | |
| 6407 } | |
| 6408 } | |
| 6409 } | |
| 6410 computer.computeValues(); | |
| 6411 } finally { | |
| 6412 timeCounter.stop(); | |
| 6413 } | |
| 6414 } | |
| 6415 | |
| 6416 /** | |
| 6417 * Resolve the identifiers and perform type analysis in the libraries in the c
urrent cycle. | |
| 6418 * | |
| 6419 * @throws AnalysisException if any of the identifiers could not be resolved o
r if any of the | |
| 6420 * libraries could not have their types analyzed | |
| 6421 */ | |
| 6422 void resolveReferencesAndTypes() { | |
| 6423 for (Library library in resolvedLibraries) { | |
| 6424 resolveReferencesAndTypes2(library); | |
| 6425 } | |
| 6426 } | |
| 6427 | |
| 6428 /** | |
| 6429 * Resolve the identifiers and perform type analysis in the given library. | |
| 6430 * | |
| 6431 * @param library the library to be resolved | |
| 6432 * @throws AnalysisException if any of the identifiers could not be resolved o
r if the types in | |
| 6433 * the library cannot be analyzed | |
| 6434 */ | |
| 6435 void resolveReferencesAndTypes2(Library library) { | |
| 6436 TimeCounter_TimeCounterHandle timeCounter = PerformanceStatistics.resolve.st
art(); | |
| 6437 try { | |
| 6438 for (Source source in library.compilationUnitSources) { | |
| 6439 CompilationUnit ast = library.getAST(source); | |
| 6440 ast.accept(new VariableResolverVisitor(library, source, _typeProvider)); | |
| 6441 ResolverVisitor visitor = new ResolverVisitor.con1(library, source, _typ
eProvider); | |
| 6442 ast.accept(visitor); | |
| 6443 for (ProxyConditionalAnalysisError conditionalCode in visitor.proxyCondi
tionalAnalysisErrors) { | |
| 6444 if (conditionalCode.shouldIncludeErrorCode()) { | |
| 6445 visitor.reportError(conditionalCode.analysisError); | |
| 6446 } | |
| 6447 } | |
| 6448 } | |
| 6449 } finally { | |
| 6450 timeCounter.stop(); | |
| 6451 } | |
| 6452 } | |
| 6453 | |
| 6454 /** | |
| 6455 * Return the result of resolving the URI of the given URI-based directive aga
inst the URI of the | |
| 6456 * given library, or `null` if the URI is not valid. | |
| 6457 * | |
| 6458 * @param librarySource the source representing the library containing the dir
ective | |
| 6459 * @param directive the directive which URI should be resolved | |
| 6460 * @return the result of resolving the URI against the URI of the library | |
| 6461 */ | |
| 6462 Source resolveSource(Source librarySource, UriBasedDirective directive) { | |
| 6463 StringLiteral uriLiteral = directive.uri; | |
| 6464 if (uriLiteral is StringInterpolation) { | |
| 6465 return null; | |
| 6466 } | |
| 6467 String uriContent = uriLiteral.stringValue.trim(); | |
| 6468 if (uriContent == null || uriContent.isEmpty) { | |
| 6469 return null; | |
| 6470 } | |
| 6471 uriContent = Uri.encodeFull(uriContent); | |
| 6472 return analysisContext.sourceFactory.resolveUri(librarySource, uriContent); | |
| 6473 } | |
| 6474 } | |
| 6475 /** | |
| 6476 * This class is used to replace uses of `HashMap<String, ExecutableElement>` wh
ich are not as | |
| 6477 * performant as this class. | |
| 6478 */ | |
| 6479 class MemberMap { | |
| 6480 | |
| 6481 /** | |
| 6482 * The current size of this map. | |
| 6483 */ | |
| 6484 int size = 0; | |
| 6485 | |
| 6486 /** | |
| 6487 * The array of keys. | |
| 6488 */ | |
| 6489 List<String> _keys; | |
| 6490 | |
| 6491 /** | |
| 6492 * The array of ExecutableElement values. | |
| 6493 */ | |
| 6494 List<ExecutableElement> _values; | |
| 6495 | |
| 6496 /** | |
| 6497 * Default constructor. | |
| 6498 */ | |
| 6499 MemberMap() : this.con1(10); | |
| 6500 | |
| 6501 /** | |
| 6502 * This constructor takes an initial capacity of the map. | |
| 6503 * | |
| 6504 * @param initialCapacity the initial capacity | |
| 6505 */ | |
| 6506 MemberMap.con1(int initialCapacity) { | |
| 6507 initArrays(initialCapacity); | |
| 6508 } | |
| 6509 | |
| 6510 /** | |
| 6511 * Copy constructor. | |
| 6512 */ | |
| 6513 MemberMap.con2(MemberMap memberMap) { | |
| 6514 initArrays(memberMap.size + 5); | |
| 6515 for (int i = 0; i < memberMap.size; i++) { | |
| 6516 _keys[i] = memberMap._keys[i]; | |
| 6517 _values[i] = memberMap._values[i]; | |
| 6518 } | |
| 6519 size = memberMap.size; | |
| 6520 } | |
| 6521 | |
| 6522 /** | |
| 6523 * Given some key, return the ExecutableElement value from the map, if the key
does not exist in | |
| 6524 * the map, `null` is returned. | |
| 6525 * | |
| 6526 * @param key some key to look up in the map | |
| 6527 * @return the associated ExecutableElement value from the map, if the key doe
s not exist in the | |
| 6528 * map, `null` is returned | |
| 6529 */ | |
| 6530 ExecutableElement get(String key) { | |
| 6531 for (int i = 0; i < size; i++) { | |
| 6532 if (_keys[i] != null && _keys[i] == key) { | |
| 6533 return _values[i]; | |
| 6534 } | |
| 6535 } | |
| 6536 return null; | |
| 6537 } | |
| 6538 | |
| 6539 /** | |
| 6540 * Get and return the key at the specified location. If the key/value pair has
been removed from | |
| 6541 * the set, then `null` is returned. | |
| 6542 * | |
| 6543 * @param i some non-zero value less than size | |
| 6544 * @return the key at the passed index | |
| 6545 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe
d index is less than | |
| 6546 * zero or greater than or equal to the capacity of the arrays | |
| 6547 */ | |
| 6548 String getKey(int i) => _keys[i]; | |
| 6549 | |
| 6550 /** | |
| 6551 * Get and return the ExecutableElement at the specified location. If the key/
value pair has been | |
| 6552 * removed from the set, then then `null` is returned. | |
| 6553 * | |
| 6554 * @param i some non-zero value less than size | |
| 6555 * @return the key at the passed index | |
| 6556 * @throw ArrayIndexOutOfBoundsException this exception is thrown if the passe
d index is less than | |
| 6557 * zero or greater than or equal to the capacity of the arrays | |
| 6558 */ | |
| 6559 ExecutableElement getValue(int i) => _values[i]; | |
| 6560 | |
| 6561 /** | |
| 6562 * Given some key/value pair, store the pair in the map. If the key exists alr
eady, then the new | |
| 6563 * value overrides the old value. | |
| 6564 * | |
| 6565 * @param key the key to store in the map | |
| 6566 * @param value the ExecutableElement value to store in the map | |
| 6567 */ | |
| 6568 void put(String key, ExecutableElement value) { | |
| 6569 for (int i = 0; i < size; i++) { | |
| 6570 if (_keys[i] != null && _keys[i] == key) { | |
| 6571 _values[i] = value; | |
| 6572 return; | |
| 6573 } | |
| 6574 } | |
| 6575 if (size == _keys.length) { | |
| 6576 int newArrayLength = size * 2; | |
| 6577 List<String> keys_new_array = new List<String>(newArrayLength); | |
| 6578 List<ExecutableElement> values_new_array = new List<ExecutableElement>(new
ArrayLength); | |
| 6579 for (int i = 0; i < size; i++) { | |
| 6580 keys_new_array[i] = _keys[i]; | |
| 6581 } | |
| 6582 for (int i = 0; i < size; i++) { | |
| 6583 values_new_array[i] = _values[i]; | |
| 6584 } | |
| 6585 _keys = keys_new_array; | |
| 6586 _values = values_new_array; | |
| 6587 } | |
| 6588 _keys[size] = key; | |
| 6589 _values[size] = value; | |
| 6590 size++; | |
| 6591 } | |
| 6592 | |
| 6593 /** | |
| 6594 * Given some String key, this method replaces the associated key and value pa
ir with `null` | |
| 6595 * . The size is not decremented with this call, instead it is expected that t
he users check for | |
| 6596 * `null`. | |
| 6597 * | |
| 6598 * @param key the key of the key/value pair to remove from the map | |
| 6599 */ | |
| 6600 void remove(String key) { | |
| 6601 for (int i = 0; i < size; i++) { | |
| 6602 if (_keys[i] == key) { | |
| 6603 _keys[i] = null; | |
| 6604 _values[i] = null; | |
| 6605 return; | |
| 6606 } | |
| 6607 } | |
| 6608 } | |
| 6609 | |
| 6610 /** | |
| 6611 * Initializes [keys] and [values]. | |
| 6612 */ | |
| 6613 void initArrays(int initialCapacity) { | |
| 6614 _keys = new List<String>(initialCapacity); | |
| 6615 _values = new List<ExecutableElement>(initialCapacity); | |
| 6616 } | |
| 6617 } | |
| 6618 /** | |
| 6619 * This class is a wrapper for an [AnalysisError] which can also be queried afte
r resolution | |
| 6620 * to find out if the error should actually be reported. In this case, these err
ors are conditional | |
| 6621 * on the non-existence of an `@proxy` annotation. | |
| 6622 * | |
| 6623 * If we have other conditional error codes in the future, we should have this c
lass implement some | |
| 6624 * ConditionalErrorCode so that after resolution, a list of ConditionalErrorCode
can be visited | |
| 6625 * instead of multiple lists of *ConditionalErrorCodes. | |
| 6626 */ | |
| 6627 class ProxyConditionalAnalysisError { | |
| 6628 | |
| 6629 /** | |
| 6630 * The name of the proxy annotation, from the meta pub package. | |
| 6631 */ | |
| 6632 static String _PROXY_ANNOTATION_NAME = "proxy"; | |
| 6633 | |
| 6634 /** | |
| 6635 * The name of the meta library name, from the meta pub package. | |
| 6636 */ | |
| 6637 static String _META_LIBRARY_NAME = "meta"; | |
| 6638 | |
| 6639 /** | |
| 6640 * Return `true` if the given element represents a class that has the proxy an
notation. | |
| 6641 * | |
| 6642 * @param element the class being tested | |
| 6643 * @return `true` if the given element represents a class that has the proxy a
nnotation | |
| 6644 */ | |
| 6645 static bool classHasProxyAnnotation(Element element) { | |
| 6646 if (element is ClassElement) { | |
| 6647 ClassElement classElement = element as ClassElement; | |
| 6648 List<ElementAnnotation> annotations = classElement.metadata; | |
| 6649 for (ElementAnnotation annotation in annotations) { | |
| 6650 Element elementAnnotation = annotation.element; | |
| 6651 if (elementAnnotation != null) { | |
| 6652 LibraryElement lib = elementAnnotation.library; | |
| 6653 if (elementAnnotation.name == _PROXY_ANNOTATION_NAME && lib != null &&
lib.name == _META_LIBRARY_NAME) { | |
| 6654 return true; | |
| 6655 } | |
| 6656 } | |
| 6657 } | |
| 6658 } | |
| 6659 return false; | |
| 6660 } | |
| 6661 | |
| 6662 /** | |
| 6663 * The enclosing [ClassElement], this is what will determine if the error code
should, or | |
| 6664 * should not, be generated on the source. | |
| 6665 */ | |
| 6666 Element _enclosingElement; | |
| 6667 | |
| 6668 /** | |
| 6669 * The conditional analysis error. | |
| 6670 */ | |
| 6671 AnalysisError analysisError; | |
| 6672 | |
| 6673 /** | |
| 6674 * Instantiate a new ProxyConditionalErrorCode with some enclosing element and
the conditional | |
| 6675 * analysis error. | |
| 6676 * | |
| 6677 * @param enclosingElement the enclosing element | |
| 6678 * @param analysisError the conditional analysis error | |
| 6679 */ | |
| 6680 ProxyConditionalAnalysisError(Element enclosingElement, AnalysisError analysis
Error) { | |
| 6681 this._enclosingElement = enclosingElement; | |
| 6682 this.analysisError = analysisError; | |
| 6683 } | |
| 6684 | |
| 6685 /** | |
| 6686 * Return `true` iff the enclosing class has the proxy annotation. | |
| 6687 * | |
| 6688 * @return `true` iff the enclosing class has the proxy annotation | |
| 6689 */ | |
| 6690 bool shouldIncludeErrorCode() => !classHasProxyAnnotation(_enclosingElement); | |
| 6691 } | |
| 6692 /** | |
| 6693 * Instances of the class `ResolverVisitor` are used to resolve the nodes within
a single | |
| 6694 * compilation unit. | |
| 6695 * | |
| 6696 * @coverage dart.engine.resolver | |
| 6697 */ | |
| 6698 class ResolverVisitor extends ScopedVisitor { | |
| 6699 | |
| 6700 /** | |
| 6701 * The manager for the inheritance mappings. | |
| 6702 */ | |
| 6703 InheritanceManager _inheritanceManager; | |
| 6704 | |
| 6705 /** | |
| 6706 * The object used to resolve the element associated with the current node. | |
| 6707 */ | |
| 6708 ElementResolver _elementResolver; | |
| 6709 | |
| 6710 /** | |
| 6711 * The object used to compute the type associated with the current node. | |
| 6712 */ | |
| 6713 StaticTypeAnalyzer _typeAnalyzer; | |
| 6714 | |
| 6715 /** | |
| 6716 * The class element representing the class containing the current node, or `n
ull` if the | |
| 6717 * current node is not contained in a class. | |
| 6718 */ | |
| 6719 ClassElement enclosingClass = null; | |
| 6720 | |
| 6721 /** | |
| 6722 * The element representing the function containing the current node, or `null
` if the | |
| 6723 * current node is not contained in a function. | |
| 6724 */ | |
| 6725 ExecutableElement enclosingFunction = null; | |
| 6726 | |
| 6727 /** | |
| 6728 * The object keeping track of which elements have had their types overridden. | |
| 6729 */ | |
| 6730 final TypeOverrideManager overrideManager = new TypeOverrideManager(); | |
| 6731 | |
| 6732 /** | |
| 6733 * The object keeping track of which elements have had their types promoted. | |
| 6734 */ | |
| 6735 final TypePromotionManager promoteManager = new TypePromotionManager(); | |
| 6736 | |
| 6737 /** | |
| 6738 * Proxy conditional error codes. | |
| 6739 */ | |
| 6740 final List<ProxyConditionalAnalysisError> proxyConditionalAnalysisErrors = new
List<ProxyConditionalAnalysisError>(); | |
| 6741 | |
| 6742 /** | |
| 6743 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 6744 * | |
| 6745 * @param library the library containing the compilation unit being resolved | |
| 6746 * @param source the source representing the compilation unit being visited | |
| 6747 * @param typeProvider the object used to access the types from the core libra
ry | |
| 6748 */ | |
| 6749 ResolverVisitor.con1(Library library, Source source, TypeProvider typeProvider
) : super.con1(library, source, typeProvider) { | |
| 6750 this._inheritanceManager = library.inheritanceManager; | |
| 6751 this._elementResolver = new ElementResolver(this); | |
| 6752 this._typeAnalyzer = new StaticTypeAnalyzer(this); | |
| 6753 } | |
| 6754 | |
| 6755 /** | |
| 6756 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 6757 * | |
| 6758 * @param definingLibrary the element for the library containing the compilati
on unit being | |
| 6759 * visited | |
| 6760 * @param source the source representing the compilation unit being visited | |
| 6761 * @param typeProvider the object used to access the types from the core libra
ry | |
| 6762 * @param errorListener the error listener that will be informed of any errors
that are found | |
| 6763 * during resolution | |
| 6764 */ | |
| 6765 ResolverVisitor.con2(LibraryElement definingLibrary, Source source, TypeProvid
er typeProvider, InheritanceManager inheritanceManager, AnalysisErrorListener er
rorListener) : super.con2(definingLibrary, source, typeProvider, errorListener)
{ | |
| 6766 this._inheritanceManager = inheritanceManager; | |
| 6767 this._elementResolver = new ElementResolver(this); | |
| 6768 this._typeAnalyzer = new StaticTypeAnalyzer(this); | |
| 6769 } | |
| 6770 Object visitAsExpression(AsExpression node) { | |
| 6771 super.visitAsExpression(node); | |
| 6772 override(node.expression, node.type.type); | |
| 6773 return null; | |
| 6774 } | |
| 6775 Object visitAssertStatement(AssertStatement node) { | |
| 6776 super.visitAssertStatement(node); | |
| 6777 propagateTrueState(node.condition); | |
| 6778 return null; | |
| 6779 } | |
| 6780 Object visitBinaryExpression(BinaryExpression node) { | |
| 6781 sc.TokenType operatorType = node.operator.type; | |
| 6782 Expression leftOperand = node.leftOperand; | |
| 6783 Expression rightOperand = node.rightOperand; | |
| 6784 if (identical(operatorType, sc.TokenType.AMPERSAND_AMPERSAND)) { | |
| 6785 safelyVisit(leftOperand); | |
| 6786 if (rightOperand != null) { | |
| 6787 try { | |
| 6788 overrideManager.enterScope(); | |
| 6789 promoteManager.enterScope(); | |
| 6790 propagateTrueState(leftOperand); | |
| 6791 promoteTypes(leftOperand); | |
| 6792 clearTypePromotionsIfPotentiallyMutatedIn(leftOperand); | |
| 6793 clearTypePromotionsIfPotentiallyMutatedIn(rightOperand); | |
| 6794 clearTypePromotionsIfAccessedInScopeAndProtentiallyMutated(rightOperan
d); | |
| 6795 rightOperand.accept(this); | |
| 6796 } finally { | |
| 6797 overrideManager.exitScope(); | |
| 6798 promoteManager.exitScope(); | |
| 6799 } | |
| 6800 } | |
| 6801 } else if (identical(operatorType, sc.TokenType.BAR_BAR)) { | |
| 6802 safelyVisit(leftOperand); | |
| 6803 if (rightOperand != null) { | |
| 6804 try { | |
| 6805 overrideManager.enterScope(); | |
| 6806 propagateFalseState(leftOperand); | |
| 6807 rightOperand.accept(this); | |
| 6808 } finally { | |
| 6809 overrideManager.exitScope(); | |
| 6810 } | |
| 6811 } | |
| 6812 } else { | |
| 6813 safelyVisit(leftOperand); | |
| 6814 safelyVisit(rightOperand); | |
| 6815 } | |
| 6816 node.accept(_elementResolver); | |
| 6817 node.accept(_typeAnalyzer); | |
| 6818 return null; | |
| 6819 } | |
| 6820 Object visitBlockFunctionBody(BlockFunctionBody node) { | |
| 6821 try { | |
| 6822 overrideManager.enterScope(); | |
| 6823 super.visitBlockFunctionBody(node); | |
| 6824 } finally { | |
| 6825 overrideManager.exitScope(); | |
| 6826 } | |
| 6827 return null; | |
| 6828 } | |
| 6829 Object visitBreakStatement(BreakStatement node) { | |
| 6830 node.accept(_elementResolver); | |
| 6831 node.accept(_typeAnalyzer); | |
| 6832 return null; | |
| 6833 } | |
| 6834 Object visitClassDeclaration(ClassDeclaration node) { | |
| 6835 ClassElement outerType = enclosingClass; | |
| 6836 try { | |
| 6837 enclosingClass = node.element; | |
| 6838 _typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.ty
pe; | |
| 6839 super.visitClassDeclaration(node); | |
| 6840 } finally { | |
| 6841 _typeAnalyzer.thisType = outerType == null ? null : outerType.type; | |
| 6842 enclosingClass = outerType; | |
| 6843 } | |
| 6844 return null; | |
| 6845 } | |
| 6846 Object visitCommentReference(CommentReference node) { | |
| 6847 node.accept(_elementResolver); | |
| 6848 node.accept(_typeAnalyzer); | |
| 6849 return null; | |
| 6850 } | |
| 6851 Object visitCompilationUnit(CompilationUnit node) { | |
| 6852 try { | |
| 6853 overrideManager.enterScope(); | |
| 6854 for (Directive directive in node.directives) { | |
| 6855 directive.accept(this); | |
| 6856 } | |
| 6857 List<CompilationUnitMember> classes = new List<CompilationUnitMember>(); | |
| 6858 for (CompilationUnitMember declaration in node.declarations) { | |
| 6859 if (declaration is ClassDeclaration) { | |
| 6860 classes.add(declaration); | |
| 6861 } else { | |
| 6862 declaration.accept(this); | |
| 6863 } | |
| 6864 } | |
| 6865 for (CompilationUnitMember declaration in classes) { | |
| 6866 declaration.accept(this); | |
| 6867 } | |
| 6868 } finally { | |
| 6869 overrideManager.exitScope(); | |
| 6870 } | |
| 6871 node.accept(_elementResolver); | |
| 6872 node.accept(_typeAnalyzer); | |
| 6873 return null; | |
| 6874 } | |
| 6875 Object visitConditionalExpression(ConditionalExpression node) { | |
| 6876 Expression condition = node.condition; | |
| 6877 safelyVisit(condition); | |
| 6878 Expression thenExpression = node.thenExpression; | |
| 6879 if (thenExpression != null) { | |
| 6880 try { | |
| 6881 overrideManager.enterScope(); | |
| 6882 promoteManager.enterScope(); | |
| 6883 propagateTrueState(condition); | |
| 6884 promoteTypes(condition); | |
| 6885 clearTypePromotionsIfPotentiallyMutatedIn(thenExpression); | |
| 6886 clearTypePromotionsIfAccessedInScopeAndProtentiallyMutated(thenExpressio
n); | |
| 6887 thenExpression.accept(this); | |
| 6888 } finally { | |
| 6889 overrideManager.exitScope(); | |
| 6890 promoteManager.exitScope(); | |
| 6891 } | |
| 6892 } | |
| 6893 Expression elseExpression = node.elseExpression; | |
| 6894 if (elseExpression != null) { | |
| 6895 try { | |
| 6896 overrideManager.enterScope(); | |
| 6897 propagateFalseState(condition); | |
| 6898 elseExpression.accept(this); | |
| 6899 } finally { | |
| 6900 overrideManager.exitScope(); | |
| 6901 } | |
| 6902 } | |
| 6903 node.accept(_elementResolver); | |
| 6904 node.accept(_typeAnalyzer); | |
| 6905 bool thenIsAbrupt = isAbruptTermination(thenExpression); | |
| 6906 bool elseIsAbrupt = isAbruptTermination(elseExpression); | |
| 6907 if (elseIsAbrupt && !thenIsAbrupt) { | |
| 6908 propagateTrueState(condition); | |
| 6909 propagateState(thenExpression); | |
| 6910 } else if (thenIsAbrupt && !elseIsAbrupt) { | |
| 6911 propagateFalseState(condition); | |
| 6912 propagateState(elseExpression); | |
| 6913 } | |
| 6914 return null; | |
| 6915 } | |
| 6916 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 6917 ExecutableElement outerFunction = enclosingFunction; | |
| 6918 try { | |
| 6919 enclosingFunction = node.element; | |
| 6920 super.visitConstructorDeclaration(node); | |
| 6921 } finally { | |
| 6922 enclosingFunction = outerFunction; | |
| 6923 } | |
| 6924 return null; | |
| 6925 } | |
| 6926 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 6927 safelyVisit(node.expression); | |
| 6928 node.accept(_elementResolver); | |
| 6929 node.accept(_typeAnalyzer); | |
| 6930 return null; | |
| 6931 } | |
| 6932 Object visitConstructorName(ConstructorName node) { | |
| 6933 node.accept(_elementResolver); | |
| 6934 node.accept(_typeAnalyzer); | |
| 6935 return null; | |
| 6936 } | |
| 6937 Object visitContinueStatement(ContinueStatement node) { | |
| 6938 node.accept(_elementResolver); | |
| 6939 node.accept(_typeAnalyzer); | |
| 6940 return null; | |
| 6941 } | |
| 6942 Object visitDoStatement(DoStatement node) { | |
| 6943 try { | |
| 6944 overrideManager.enterScope(); | |
| 6945 super.visitDoStatement(node); | |
| 6946 } finally { | |
| 6947 overrideManager.exitScope(); | |
| 6948 } | |
| 6949 return null; | |
| 6950 } | |
| 6951 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { | |
| 6952 try { | |
| 6953 overrideManager.enterScope(); | |
| 6954 super.visitExpressionFunctionBody(node); | |
| 6955 } finally { | |
| 6956 overrideManager.exitScope(); | |
| 6957 } | |
| 6958 return null; | |
| 6959 } | |
| 6960 Object visitFieldDeclaration(FieldDeclaration node) { | |
| 6961 try { | |
| 6962 overrideManager.enterScope(); | |
| 6963 super.visitFieldDeclaration(node); | |
| 6964 } finally { | |
| 6965 Map<Element, Type2> overrides = overrideManager.captureOverrides(node.fiel
ds); | |
| 6966 overrideManager.exitScope(); | |
| 6967 overrideManager.applyOverrides(overrides); | |
| 6968 } | |
| 6969 return null; | |
| 6970 } | |
| 6971 Object visitForEachStatement(ForEachStatement node) { | |
| 6972 try { | |
| 6973 overrideManager.enterScope(); | |
| 6974 super.visitForEachStatement(node); | |
| 6975 } finally { | |
| 6976 overrideManager.exitScope(); | |
| 6977 } | |
| 6978 return null; | |
| 6979 } | |
| 6980 Object visitForStatement(ForStatement node) { | |
| 6981 try { | |
| 6982 overrideManager.enterScope(); | |
| 6983 super.visitForStatement(node); | |
| 6984 } finally { | |
| 6985 overrideManager.exitScope(); | |
| 6986 } | |
| 6987 return null; | |
| 6988 } | |
| 6989 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 6990 ExecutableElement outerFunction = enclosingFunction; | |
| 6991 try { | |
| 6992 SimpleIdentifier functionName = node.name; | |
| 6993 enclosingFunction = functionName.staticElement as ExecutableElement; | |
| 6994 super.visitFunctionDeclaration(node); | |
| 6995 } finally { | |
| 6996 enclosingFunction = outerFunction; | |
| 6997 } | |
| 6998 return null; | |
| 6999 } | |
| 7000 Object visitFunctionExpression(FunctionExpression node) { | |
| 7001 ExecutableElement outerFunction = enclosingFunction; | |
| 7002 try { | |
| 7003 enclosingFunction = node.element; | |
| 7004 overrideManager.enterScope(); | |
| 7005 super.visitFunctionExpression(node); | |
| 7006 } finally { | |
| 7007 overrideManager.exitScope(); | |
| 7008 enclosingFunction = outerFunction; | |
| 7009 } | |
| 7010 return null; | |
| 7011 } | |
| 7012 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 7013 safelyVisit(node.function); | |
| 7014 node.accept(_elementResolver); | |
| 7015 inferFunctionExpressionsParametersTypes(node.argumentList); | |
| 7016 safelyVisit(node.argumentList); | |
| 7017 node.accept(_typeAnalyzer); | |
| 7018 return null; | |
| 7019 } | |
| 7020 Object visitHideCombinator(HideCombinator node) => null; | |
| 7021 Object visitIfStatement(IfStatement node) { | |
| 7022 Expression condition = node.condition; | |
| 7023 safelyVisit(condition); | |
| 7024 Map<Element, Type2> thenOverrides = null; | |
| 7025 Statement thenStatement = node.thenStatement; | |
| 7026 if (thenStatement != null) { | |
| 7027 try { | |
| 7028 overrideManager.enterScope(); | |
| 7029 promoteManager.enterScope(); | |
| 7030 propagateTrueState(condition); | |
| 7031 promoteTypes(condition); | |
| 7032 clearTypePromotionsIfPotentiallyMutatedIn(thenStatement); | |
| 7033 clearTypePromotionsIfAccessedInScopeAndProtentiallyMutated(thenStatement
); | |
| 7034 visitStatementInScope(thenStatement); | |
| 7035 } finally { | |
| 7036 thenOverrides = overrideManager.captureLocalOverrides(); | |
| 7037 overrideManager.exitScope(); | |
| 7038 promoteManager.exitScope(); | |
| 7039 } | |
| 7040 } | |
| 7041 Map<Element, Type2> elseOverrides = null; | |
| 7042 Statement elseStatement = node.elseStatement; | |
| 7043 if (elseStatement != null) { | |
| 7044 try { | |
| 7045 overrideManager.enterScope(); | |
| 7046 propagateFalseState(condition); | |
| 7047 visitStatementInScope(elseStatement); | |
| 7048 } finally { | |
| 7049 elseOverrides = overrideManager.captureLocalOverrides(); | |
| 7050 overrideManager.exitScope(); | |
| 7051 } | |
| 7052 } | |
| 7053 node.accept(_elementResolver); | |
| 7054 node.accept(_typeAnalyzer); | |
| 7055 bool thenIsAbrupt = isAbruptTermination2(thenStatement); | |
| 7056 bool elseIsAbrupt = isAbruptTermination2(elseStatement); | |
| 7057 if (elseIsAbrupt && !thenIsAbrupt) { | |
| 7058 propagateTrueState(condition); | |
| 7059 if (thenOverrides != null) { | |
| 7060 overrideManager.applyOverrides(thenOverrides); | |
| 7061 } | |
| 7062 } else if (thenIsAbrupt && !elseIsAbrupt) { | |
| 7063 propagateFalseState(condition); | |
| 7064 if (elseOverrides != null) { | |
| 7065 overrideManager.applyOverrides(elseOverrides); | |
| 7066 } | |
| 7067 } | |
| 7068 return null; | |
| 7069 } | |
| 7070 Object visitLabel(Label node) => null; | |
| 7071 Object visitLibraryIdentifier(LibraryIdentifier node) => null; | |
| 7072 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 7073 ExecutableElement outerFunction = enclosingFunction; | |
| 7074 try { | |
| 7075 enclosingFunction = node.element; | |
| 7076 super.visitMethodDeclaration(node); | |
| 7077 } finally { | |
| 7078 enclosingFunction = outerFunction; | |
| 7079 } | |
| 7080 return null; | |
| 7081 } | |
| 7082 Object visitMethodInvocation(MethodInvocation node) { | |
| 7083 safelyVisit(node.target); | |
| 7084 node.accept(_elementResolver); | |
| 7085 inferFunctionExpressionsParametersTypes(node.argumentList); | |
| 7086 safelyVisit(node.argumentList); | |
| 7087 node.accept(_typeAnalyzer); | |
| 7088 return null; | |
| 7089 } | |
| 7090 Object visitNode(ASTNode node) { | |
| 7091 node.visitChildren(this); | |
| 7092 node.accept(_elementResolver); | |
| 7093 node.accept(_typeAnalyzer); | |
| 7094 return null; | |
| 7095 } | |
| 7096 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 7097 safelyVisit(node.prefix); | |
| 7098 node.accept(_elementResolver); | |
| 7099 node.accept(_typeAnalyzer); | |
| 7100 return null; | |
| 7101 } | |
| 7102 Object visitPropertyAccess(PropertyAccess node) { | |
| 7103 safelyVisit(node.target); | |
| 7104 node.accept(_elementResolver); | |
| 7105 node.accept(_typeAnalyzer); | |
| 7106 return null; | |
| 7107 } | |
| 7108 Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation
node) { | |
| 7109 safelyVisit(node.argumentList); | |
| 7110 node.accept(_elementResolver); | |
| 7111 node.accept(_typeAnalyzer); | |
| 7112 return null; | |
| 7113 } | |
| 7114 Object visitShowCombinator(ShowCombinator node) => null; | |
| 7115 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 7116 safelyVisit(node.argumentList); | |
| 7117 node.accept(_elementResolver); | |
| 7118 node.accept(_typeAnalyzer); | |
| 7119 return null; | |
| 7120 } | |
| 7121 Object visitSwitchCase(SwitchCase node) { | |
| 7122 try { | |
| 7123 overrideManager.enterScope(); | |
| 7124 super.visitSwitchCase(node); | |
| 7125 } finally { | |
| 7126 overrideManager.exitScope(); | |
| 7127 } | |
| 7128 return null; | |
| 7129 } | |
| 7130 Object visitSwitchDefault(SwitchDefault node) { | |
| 7131 try { | |
| 7132 overrideManager.enterScope(); | |
| 7133 super.visitSwitchDefault(node); | |
| 7134 } finally { | |
| 7135 overrideManager.exitScope(); | |
| 7136 } | |
| 7137 return null; | |
| 7138 } | |
| 7139 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| 7140 try { | |
| 7141 overrideManager.enterScope(); | |
| 7142 super.visitTopLevelVariableDeclaration(node); | |
| 7143 } finally { | |
| 7144 Map<Element, Type2> overrides = overrideManager.captureOverrides(node.vari
ables); | |
| 7145 overrideManager.exitScope(); | |
| 7146 overrideManager.applyOverrides(overrides); | |
| 7147 } | |
| 7148 return null; | |
| 7149 } | |
| 7150 Object visitTypeName(TypeName node) => null; | |
| 7151 Object visitWhileStatement(WhileStatement node) { | |
| 7152 Expression condition = node.condition; | |
| 7153 safelyVisit(condition); | |
| 7154 Statement body = node.body; | |
| 7155 if (body != null) { | |
| 7156 try { | |
| 7157 overrideManager.enterScope(); | |
| 7158 propagateTrueState(condition); | |
| 7159 visitStatementInScope(body); | |
| 7160 } finally { | |
| 7161 overrideManager.exitScope(); | |
| 7162 } | |
| 7163 } | |
| 7164 node.accept(_elementResolver); | |
| 7165 node.accept(_typeAnalyzer); | |
| 7166 return null; | |
| 7167 } | |
| 7168 | |
| 7169 /** | |
| 7170 * Return the propagated element associated with the given expression whose ty
pe can be | |
| 7171 * overridden, or `null` if there is no element whose type can be overridden. | |
| 7172 * | |
| 7173 * @param expression the expression with which the element is associated | |
| 7174 * @return the element associated with the given expression | |
| 7175 */ | |
| 7176 VariableElement getOverridablePropagatedElement(Expression expression) { | |
| 7177 Element element = null; | |
| 7178 if (expression is SimpleIdentifier) { | |
| 7179 element = ((expression as SimpleIdentifier)).propagatedElement; | |
| 7180 } else if (expression is PrefixedIdentifier) { | |
| 7181 element = ((expression as PrefixedIdentifier)).propagatedElement; | |
| 7182 } else if (expression is PropertyAccess) { | |
| 7183 element = ((expression as PropertyAccess)).propertyName.propagatedElement; | |
| 7184 } | |
| 7185 if (element is VariableElement) { | |
| 7186 return element as VariableElement; | |
| 7187 } | |
| 7188 return null; | |
| 7189 } | |
| 7190 | |
| 7191 /** | |
| 7192 * Return the static element associated with the given expression whose type c
an be overridden, or | |
| 7193 * `null` if there is no element whose type can be overridden. | |
| 7194 * | |
| 7195 * @param expression the expression with which the element is associated | |
| 7196 * @return the element associated with the given expression | |
| 7197 */ | |
| 7198 VariableElement getOverridableStaticElement(Expression expression) { | |
| 7199 Element element = null; | |
| 7200 if (expression is SimpleIdentifier) { | |
| 7201 element = ((expression as SimpleIdentifier)).staticElement; | |
| 7202 } else if (expression is PrefixedIdentifier) { | |
| 7203 element = ((expression as PrefixedIdentifier)).staticElement; | |
| 7204 } else if (expression is PropertyAccess) { | |
| 7205 element = ((expression as PropertyAccess)).propertyName.staticElement; | |
| 7206 } | |
| 7207 if (element is VariableElement) { | |
| 7208 return element as VariableElement; | |
| 7209 } | |
| 7210 return null; | |
| 7211 } | |
| 7212 | |
| 7213 /** | |
| 7214 * Return the static element associated with the given expression whose type c
an be promoted, or | |
| 7215 * `null` if there is no element whose type can be promoted. | |
| 7216 * | |
| 7217 * @param expression the expression with which the element is associated | |
| 7218 * @return the element associated with the given expression | |
| 7219 */ | |
| 7220 VariableElement getPromotionStaticElement(Expression expression) { | |
| 7221 if (expression is! SimpleIdentifier) { | |
| 7222 return null; | |
| 7223 } | |
| 7224 SimpleIdentifier identifier = expression as SimpleIdentifier; | |
| 7225 Element element = identifier.staticElement; | |
| 7226 if (element is! VariableElement) { | |
| 7227 return null; | |
| 7228 } | |
| 7229 ElementKind kind = element.kind; | |
| 7230 if (identical(kind, ElementKind.LOCAL_VARIABLE)) { | |
| 7231 return element as VariableElement; | |
| 7232 } | |
| 7233 if (identical(kind, ElementKind.PARAMETER)) { | |
| 7234 return element as VariableElement; | |
| 7235 } | |
| 7236 return null; | |
| 7237 } | |
| 7238 | |
| 7239 /** | |
| 7240 * If it is appropriate to do so, override the current type of the static and
propagated elements | |
| 7241 * associated with the given expression with the given type. Generally speakin
g, it is appropriate | |
| 7242 * if the given type is more specific than the current type. | |
| 7243 * | |
| 7244 * @param expression the expression used to access the static and propagated e
lements whose types | |
| 7245 * might be overridden | |
| 7246 * @param potentialType the potential type of the elements | |
| 7247 */ | |
| 7248 void override(Expression expression, Type2 potentialType) { | |
| 7249 VariableElement element = getOverridableStaticElement(expression); | |
| 7250 if (element != null) { | |
| 7251 override2(element, potentialType); | |
| 7252 } | |
| 7253 element = getOverridablePropagatedElement(expression); | |
| 7254 if (element != null) { | |
| 7255 override2(element, potentialType); | |
| 7256 } | |
| 7257 } | |
| 7258 | |
| 7259 /** | |
| 7260 * If it is appropriate to do so, override the current type of the given eleme
nt with the given | |
| 7261 * type. Generally speaking, it is appropriate if the given type is more speci
fic than the current | |
| 7262 * type. | |
| 7263 * | |
| 7264 * @param element the element whose type might be overridden | |
| 7265 * @param potentialType the potential type of the element | |
| 7266 */ | |
| 7267 void override2(VariableElement element, Type2 potentialType) { | |
| 7268 if (potentialType == null || potentialType.isBottom) { | |
| 7269 return; | |
| 7270 } | |
| 7271 if (element is PropertyInducingElement) { | |
| 7272 PropertyInducingElement variable = element as PropertyInducingElement; | |
| 7273 if (!variable.isConst && !variable.isFinal) { | |
| 7274 return; | |
| 7275 } | |
| 7276 } | |
| 7277 Type2 currentType = getBestType(element); | |
| 7278 if (currentType == null || !currentType.isMoreSpecificThan(potentialType)) { | |
| 7279 overrideManager.setType(element, potentialType); | |
| 7280 } | |
| 7281 } | |
| 7282 | |
| 7283 /** | |
| 7284 * If it is appropriate to do so, promotes the current type of the static elem
ent associated with | |
| 7285 * the given expression with the given type. Generally speaking, it is appropr
iate if the given | |
| 7286 * type is more specific than the current type. | |
| 7287 * | |
| 7288 * @param expression the expression used to access the static element whose ty
pes might be | |
| 7289 * promoted | |
| 7290 * @param potentialType the potential type of the elements | |
| 7291 */ | |
| 7292 void promote(Expression expression, Type2 potentialType) { | |
| 7293 VariableElement element = getPromotionStaticElement(expression); | |
| 7294 if (element != null) { | |
| 7295 Type2 type = expression.staticType; | |
| 7296 if (type == null || type.isDynamic) { | |
| 7297 return; | |
| 7298 } | |
| 7299 if (potentialType == null || potentialType.isDynamic) { | |
| 7300 return; | |
| 7301 } | |
| 7302 if (!potentialType.isMoreSpecificThan(type)) { | |
| 7303 return; | |
| 7304 } | |
| 7305 promoteManager.setType(element, potentialType); | |
| 7306 } | |
| 7307 } | |
| 7308 | |
| 7309 /** | |
| 7310 * Report a conditional analysis error with the given error code and arguments
. | |
| 7311 * | |
| 7312 * @param enclosingElement the enclosing element | |
| 7313 * @param errorCode the error code of the error to be reported | |
| 7314 * @param node the node specifying the location of the error | |
| 7315 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 7316 */ | |
| 7317 void reportErrorProxyConditionalAnalysisError(Element enclosingElement, ErrorC
ode errorCode, ASTNode node, List<Object> arguments) { | |
| 7318 proxyConditionalAnalysisErrors.add(new ProxyConditionalAnalysisError(enclosi
ngElement, new AnalysisError.con2(source, node.offset, node.length, errorCode, a
rguments))); | |
| 7319 } | |
| 7320 | |
| 7321 /** | |
| 7322 * Report a conditional analysis error with the given error code and arguments
. | |
| 7323 * | |
| 7324 * @param enclosingElement the enclosing element | |
| 7325 * @param errorCode the error code of the error to be reported | |
| 7326 * @param offset the offset of the location of the error | |
| 7327 * @param length the length of the location of the error | |
| 7328 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 7329 */ | |
| 7330 void reportErrorProxyConditionalAnalysisError2(Element enclosingElement, Error
Code errorCode, int offset, int length, List<Object> arguments) { | |
| 7331 proxyConditionalAnalysisErrors.add(new ProxyConditionalAnalysisError(enclosi
ngElement, new AnalysisError.con2(source, offset, length, errorCode, arguments))
); | |
| 7332 } | |
| 7333 | |
| 7334 /** | |
| 7335 * Report a conditional analysis error with the given error code and arguments
. | |
| 7336 * | |
| 7337 * @param enclosingElement the enclosing element | |
| 7338 * @param errorCode the error code of the error to be reported | |
| 7339 * @param token the token specifying the location of the error | |
| 7340 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 7341 */ | |
| 7342 void reportErrorProxyConditionalAnalysisError3(Element enclosingElement, Error
Code errorCode, sc.Token token, List<Object> arguments) { | |
| 7343 proxyConditionalAnalysisErrors.add(new ProxyConditionalAnalysisError(enclosi
ngElement, new AnalysisError.con2(source, token.offset, token.length, errorCode,
arguments))); | |
| 7344 } | |
| 7345 void visitForEachStatementInScope(ForEachStatement node) { | |
| 7346 Expression iterator = node.iterator; | |
| 7347 safelyVisit(iterator); | |
| 7348 DeclaredIdentifier loopVariable = node.loopVariable; | |
| 7349 SimpleIdentifier identifier = node.identifier; | |
| 7350 safelyVisit(loopVariable); | |
| 7351 safelyVisit(identifier); | |
| 7352 Statement body = node.body; | |
| 7353 if (body != null) { | |
| 7354 try { | |
| 7355 overrideManager.enterScope(); | |
| 7356 if (loopVariable != null && iterator != null) { | |
| 7357 LocalVariableElement loopElement = loopVariable.element; | |
| 7358 if (loopElement != null) { | |
| 7359 Type2 iteratorElementType = getIteratorElementType(iterator); | |
| 7360 override2(loopElement, iteratorElementType); | |
| 7361 recordPropagatedType(loopVariable.identifier, iteratorElementType); | |
| 7362 } | |
| 7363 } else if (identifier != null && iterator != null) { | |
| 7364 Element identifierElement = identifier.staticElement; | |
| 7365 if (identifierElement is VariableElement) { | |
| 7366 Type2 iteratorElementType = getIteratorElementType(iterator); | |
| 7367 override2(identifierElement as VariableElement, iteratorElementType)
; | |
| 7368 recordPropagatedType(identifier, iteratorElementType); | |
| 7369 } | |
| 7370 } | |
| 7371 visitStatementInScope(body); | |
| 7372 } finally { | |
| 7373 overrideManager.exitScope(); | |
| 7374 } | |
| 7375 } | |
| 7376 node.accept(_elementResolver); | |
| 7377 node.accept(_typeAnalyzer); | |
| 7378 } | |
| 7379 void visitForStatementInScope(ForStatement node) { | |
| 7380 safelyVisit(node.variables); | |
| 7381 safelyVisit(node.initialization); | |
| 7382 safelyVisit(node.condition); | |
| 7383 overrideManager.enterScope(); | |
| 7384 try { | |
| 7385 propagateTrueState(node.condition); | |
| 7386 visitStatementInScope(node.body); | |
| 7387 node.updaters.accept(this); | |
| 7388 } finally { | |
| 7389 overrideManager.exitScope(); | |
| 7390 } | |
| 7391 } | |
| 7392 | |
| 7393 /** | |
| 7394 * Checks each promoted variable in the current scope for compliance with the
following | |
| 7395 * specification statement: | |
| 7396 * | |
| 7397 * If the variable <i>v</i> is accessed by a closure in <i>s<sub>1</sub></i> t
hen the variable | |
| 7398 * <i>v</i> is not potentially mutated anywhere in the scope of <i>v</i>. | |
| 7399 */ | |
| 7400 void clearTypePromotionsIfAccessedInScopeAndProtentiallyMutated(ASTNode target
) { | |
| 7401 for (Element element in promoteManager.promotedElements) { | |
| 7402 if (((element as VariableElementImpl)).isPotentiallyMutated) { | |
| 7403 if (isVariableAccessedInClosure(element, target)) { | |
| 7404 promoteManager.setType(element, null); | |
| 7405 } | |
| 7406 } | |
| 7407 } | |
| 7408 } | |
| 7409 | |
| 7410 /** | |
| 7411 * Checks each promoted variable in the current scope for compliance with the
following | |
| 7412 * specification statement: | |
| 7413 * | |
| 7414 * <i>v</i> is not potentially mutated in <i>s<sub>1</sub></i> or within a clo
sure. | |
| 7415 */ | |
| 7416 void clearTypePromotionsIfPotentiallyMutatedIn(ASTNode target) { | |
| 7417 for (Element element in promoteManager.promotedElements) { | |
| 7418 if (isVariablePotentiallyMutatedIn(element, target)) { | |
| 7419 promoteManager.setType(element, null); | |
| 7420 } | |
| 7421 } | |
| 7422 } | |
| 7423 | |
| 7424 /** | |
| 7425 * Return the best type information available for the given element. If the ty
pe of the element | |
| 7426 * has been overridden, then return the overriding type. Otherwise, return the
static type. | |
| 7427 * | |
| 7428 * @param element the element for which type information is to be returned | |
| 7429 * @return the best type information available for the given element | |
| 7430 */ | |
| 7431 Type2 getBestType(Element element) { | |
| 7432 Type2 bestType = overrideManager.getType(element); | |
| 7433 if (bestType == null) { | |
| 7434 if (element is LocalVariableElement) { | |
| 7435 bestType = ((element as LocalVariableElement)).type; | |
| 7436 } else if (element is ParameterElement) { | |
| 7437 bestType = ((element as ParameterElement)).type; | |
| 7438 } | |
| 7439 } | |
| 7440 return bestType; | |
| 7441 } | |
| 7442 | |
| 7443 /** | |
| 7444 * The given expression is the expression used to compute the iterator for a f
or-each statement. | |
| 7445 * Attempt to compute the type of objects that will be assigned to the loop va
riable and return | |
| 7446 * that type. Return `null` if the type could not be determined. | |
| 7447 * | |
| 7448 * @param iterator the iterator for a for-each statement | |
| 7449 * @return the type of objects that will be assigned to the loop variable | |
| 7450 */ | |
| 7451 Type2 getIteratorElementType(Expression iteratorExpression) { | |
| 7452 Type2 expressionType = iteratorExpression.staticType; | |
| 7453 if (expressionType is InterfaceType) { | |
| 7454 InterfaceType interfaceType = expressionType as InterfaceType; | |
| 7455 FunctionType iteratorFunction = _inheritanceManager.lookupMemberType(inter
faceType, "iterator"); | |
| 7456 if (iteratorFunction == null) { | |
| 7457 return null; | |
| 7458 } | |
| 7459 Type2 iteratorType = iteratorFunction.returnType; | |
| 7460 if (iteratorType is InterfaceType) { | |
| 7461 InterfaceType iteratorInterfaceType = iteratorType as InterfaceType; | |
| 7462 FunctionType currentFunction = _inheritanceManager.lookupMemberType(iter
atorInterfaceType, "current"); | |
| 7463 if (currentFunction == null) { | |
| 7464 return null; | |
| 7465 } | |
| 7466 return currentFunction.returnType; | |
| 7467 } | |
| 7468 } | |
| 7469 return null; | |
| 7470 } | |
| 7471 | |
| 7472 /** | |
| 7473 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters
types and its | |
| 7474 * required type is [FunctionType], then infer parameters types from [Function
Type]. | |
| 7475 */ | |
| 7476 void inferFunctionExpressionParametersTypes(Expression mayBeClosure, Type2 may
ByFunctionType) { | |
| 7477 if (mayBeClosure is! FunctionExpression) { | |
| 7478 return; | |
| 7479 } | |
| 7480 FunctionExpression closure = mayBeClosure as FunctionExpression; | |
| 7481 if (mayByFunctionType is! FunctionType) { | |
| 7482 return; | |
| 7483 } | |
| 7484 FunctionType expectedClosureType = mayByFunctionType as FunctionType; | |
| 7485 closure.propagatedType = expectedClosureType; | |
| 7486 NodeList<FormalParameter> parameters = closure.parameters.parameters; | |
| 7487 List<ParameterElement> expectedParameters = expectedClosureType.parameters; | |
| 7488 for (int i = 0; i < parameters.length && i < expectedParameters.length; i++)
{ | |
| 7489 FormalParameter parameter = parameters[i]; | |
| 7490 ParameterElement element = parameter.element; | |
| 7491 Type2 currentType = getBestType(element); | |
| 7492 Type2 expectedType = expectedParameters[i].type; | |
| 7493 if (currentType == null || expectedType.isMoreSpecificThan(currentType)) { | |
| 7494 overrideManager.setType(element, expectedType); | |
| 7495 } | |
| 7496 } | |
| 7497 } | |
| 7498 | |
| 7499 /** | |
| 7500 * Try to infer types of parameters of the [FunctionExpression] arguments. | |
| 7501 */ | |
| 7502 void inferFunctionExpressionsParametersTypes(ArgumentList argumentList) { | |
| 7503 for (Expression argument in argumentList.arguments) { | |
| 7504 ParameterElement parameter = argument.propagatedParameterElement; | |
| 7505 if (parameter == null) { | |
| 7506 parameter = argument.staticParameterElement; | |
| 7507 } | |
| 7508 if (parameter != null) { | |
| 7509 inferFunctionExpressionParametersTypes(argument, parameter.type); | |
| 7510 } | |
| 7511 } | |
| 7512 } | |
| 7513 | |
| 7514 /** | |
| 7515 * Return `true` if the given expression terminates abruptly (that is, if any
expression | |
| 7516 * following the given expression will not be reached). | |
| 7517 * | |
| 7518 * @param expression the expression being tested | |
| 7519 * @return `true` if the given expression terminates abruptly | |
| 7520 */ | |
| 7521 bool isAbruptTermination(Expression expression) { | |
| 7522 while (expression is ParenthesizedExpression) { | |
| 7523 expression = ((expression as ParenthesizedExpression)).expression; | |
| 7524 } | |
| 7525 return expression is ThrowExpression || expression is RethrowExpression; | |
| 7526 } | |
| 7527 | |
| 7528 /** | |
| 7529 * Return `true` if the given statement terminates abruptly (that is, if any s
tatement | |
| 7530 * following the given statement will not be reached). | |
| 7531 * | |
| 7532 * @param statement the statement being tested | |
| 7533 * @return `true` if the given statement terminates abruptly | |
| 7534 */ | |
| 7535 bool isAbruptTermination2(Statement statement) { | |
| 7536 if (statement is ReturnStatement || statement is BreakStatement || statement
is ContinueStatement) { | |
| 7537 return true; | |
| 7538 } else if (statement is ExpressionStatement) { | |
| 7539 return isAbruptTermination(((statement as ExpressionStatement)).expression
); | |
| 7540 } else if (statement is Block) { | |
| 7541 NodeList<Statement> statements = ((statement as Block)).statements; | |
| 7542 int size = statements.length; | |
| 7543 if (size == 0) { | |
| 7544 return false; | |
| 7545 } | |
| 7546 return isAbruptTermination2(statements[size - 1]); | |
| 7547 } | |
| 7548 return false; | |
| 7549 } | |
| 7550 | |
| 7551 /** | |
| 7552 * Return `true` if the given variable is accessed within a closure in the giv
en | |
| 7553 * [ASTNode] and also mutated somewhere in variable scope. This information is
only | |
| 7554 * available for local variables (including parameters). | |
| 7555 * | |
| 7556 * @param variable the variable to check | |
| 7557 * @param target the [ASTNode] to check within | |
| 7558 * @return `true` if this variable is potentially mutated somewhere in the giv
en ASTNode | |
| 7559 */ | |
| 7560 bool isVariableAccessedInClosure(Element variable, ASTNode target) { | |
| 7561 List<bool> result = [false]; | |
| 7562 target.accept(new RecursiveASTVisitor_7(result, variable)); | |
| 7563 return result[0]; | |
| 7564 } | |
| 7565 | |
| 7566 /** | |
| 7567 * Return `true` if the given variable is potentially mutated somewhere in the
given | |
| 7568 * [ASTNode]. This information is only available for local variables (includin
g parameters). | |
| 7569 * | |
| 7570 * @param variable the variable to check | |
| 7571 * @param target the [ASTNode] to check within | |
| 7572 * @return `true` if this variable is potentially mutated somewhere in the giv
en ASTNode | |
| 7573 */ | |
| 7574 bool isVariablePotentiallyMutatedIn(Element variable, ASTNode target) { | |
| 7575 List<bool> result = [false]; | |
| 7576 target.accept(new RecursiveASTVisitor_8(result, variable)); | |
| 7577 return result[0]; | |
| 7578 } | |
| 7579 | |
| 7580 /** | |
| 7581 * Promotes type information using given condition. | |
| 7582 */ | |
| 7583 void promoteTypes(Expression condition) { | |
| 7584 if (condition is BinaryExpression) { | |
| 7585 BinaryExpression binary = condition as BinaryExpression; | |
| 7586 if (identical(binary.operator.type, sc.TokenType.AMPERSAND_AMPERSAND)) { | |
| 7587 Expression left = binary.leftOperand; | |
| 7588 Expression right = binary.rightOperand; | |
| 7589 promoteTypes(left); | |
| 7590 promoteTypes(right); | |
| 7591 clearTypePromotionsIfPotentiallyMutatedIn(right); | |
| 7592 } | |
| 7593 } else if (condition is IsExpression) { | |
| 7594 IsExpression is2 = condition as IsExpression; | |
| 7595 if (is2.notOperator == null) { | |
| 7596 promote(is2.expression, is2.type.type); | |
| 7597 } | |
| 7598 } else if (condition is ParenthesizedExpression) { | |
| 7599 promoteTypes(((condition as ParenthesizedExpression)).expression); | |
| 7600 } | |
| 7601 } | |
| 7602 | |
| 7603 /** | |
| 7604 * Propagate any type information that results from knowing that the given con
dition will have | |
| 7605 * been evaluated to 'false'. | |
| 7606 * | |
| 7607 * @param condition the condition that will have evaluated to 'false' | |
| 7608 */ | |
| 7609 void propagateFalseState(Expression condition) { | |
| 7610 if (condition is BinaryExpression) { | |
| 7611 BinaryExpression binary = condition as BinaryExpression; | |
| 7612 if (identical(binary.operator.type, sc.TokenType.BAR_BAR)) { | |
| 7613 propagateFalseState(binary.leftOperand); | |
| 7614 propagateFalseState(binary.rightOperand); | |
| 7615 } | |
| 7616 } else if (condition is IsExpression) { | |
| 7617 IsExpression is2 = condition as IsExpression; | |
| 7618 if (is2.notOperator != null) { | |
| 7619 override(is2.expression, is2.type.type); | |
| 7620 } | |
| 7621 } else if (condition is PrefixExpression) { | |
| 7622 PrefixExpression prefix = condition as PrefixExpression; | |
| 7623 if (identical(prefix.operator.type, sc.TokenType.BANG)) { | |
| 7624 propagateTrueState(prefix.operand); | |
| 7625 } | |
| 7626 } else if (condition is ParenthesizedExpression) { | |
| 7627 propagateFalseState(((condition as ParenthesizedExpression)).expression); | |
| 7628 } | |
| 7629 } | |
| 7630 | |
| 7631 /** | |
| 7632 * Propagate any type information that results from knowing that the given exp
ression will have | |
| 7633 * been evaluated without altering the flow of execution. | |
| 7634 * | |
| 7635 * @param expression the expression that will have been evaluated | |
| 7636 */ | |
| 7637 void propagateState(Expression expression) { | |
| 7638 } | |
| 7639 | |
| 7640 /** | |
| 7641 * Propagate any type information that results from knowing that the given con
dition will have | |
| 7642 * been evaluated to 'true'. | |
| 7643 * | |
| 7644 * @param condition the condition that will have evaluated to 'true' | |
| 7645 */ | |
| 7646 void propagateTrueState(Expression condition) { | |
| 7647 if (condition is BinaryExpression) { | |
| 7648 BinaryExpression binary = condition as BinaryExpression; | |
| 7649 if (identical(binary.operator.type, sc.TokenType.AMPERSAND_AMPERSAND)) { | |
| 7650 propagateTrueState(binary.leftOperand); | |
| 7651 propagateTrueState(binary.rightOperand); | |
| 7652 } | |
| 7653 } else if (condition is IsExpression) { | |
| 7654 IsExpression is2 = condition as IsExpression; | |
| 7655 if (is2.notOperator == null) { | |
| 7656 override(is2.expression, is2.type.type); | |
| 7657 } | |
| 7658 } else if (condition is PrefixExpression) { | |
| 7659 PrefixExpression prefix = condition as PrefixExpression; | |
| 7660 if (identical(prefix.operator.type, sc.TokenType.BANG)) { | |
| 7661 propagateFalseState(prefix.operand); | |
| 7662 } | |
| 7663 } else if (condition is ParenthesizedExpression) { | |
| 7664 propagateTrueState(((condition as ParenthesizedExpression)).expression); | |
| 7665 } | |
| 7666 } | |
| 7667 | |
| 7668 /** | |
| 7669 * Record that the propagated type of the given node is the given type. | |
| 7670 * | |
| 7671 * @param expression the node whose type is to be recorded | |
| 7672 * @param type the propagated type of the node | |
| 7673 */ | |
| 7674 void recordPropagatedType(Expression expression, Type2 type) { | |
| 7675 if (type != null && !type.isDynamic) { | |
| 7676 expression.propagatedType = type; | |
| 7677 } | |
| 7678 } | |
| 7679 get elementResolver_J2DAccessor => _elementResolver; | |
| 7680 set elementResolver_J2DAccessor(__v) => _elementResolver = __v; | |
| 7681 get labelScope_J2DAccessor => labelScope; | |
| 7682 set labelScope_J2DAccessor(__v) => labelScope = __v; | |
| 7683 get nameScope_J2DAccessor => nameScope; | |
| 7684 set nameScope_J2DAccessor(__v) => nameScope = __v; | |
| 7685 get typeAnalyzer_J2DAccessor => _typeAnalyzer; | |
| 7686 set typeAnalyzer_J2DAccessor(__v) => _typeAnalyzer = __v; | |
| 7687 get enclosingClass_J2DAccessor => enclosingClass; | |
| 7688 set enclosingClass_J2DAccessor(__v) => enclosingClass = __v; | |
| 7689 } | |
| 7690 class RecursiveASTVisitor_7 extends RecursiveASTVisitor<Object> { | |
| 7691 List<bool> result; | |
| 7692 Element variable; | |
| 7693 RecursiveASTVisitor_7(this.result, this.variable) : super(); | |
| 7694 bool _inClosure = false; | |
| 7695 Object visitFunctionExpression(FunctionExpression node) { | |
| 7696 bool inClosure = this._inClosure; | |
| 7697 try { | |
| 7698 this._inClosure = true; | |
| 7699 return super.visitFunctionExpression(node); | |
| 7700 } finally { | |
| 7701 this._inClosure = inClosure; | |
| 7702 } | |
| 7703 } | |
| 7704 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 7705 if (result[0]) { | |
| 7706 return null; | |
| 7707 } | |
| 7708 if (_inClosure && identical(node.staticElement, variable)) { | |
| 7709 result[0] = javaBooleanOr(result[0], true); | |
| 7710 } | |
| 7711 return null; | |
| 7712 } | |
| 7713 } | |
| 7714 class RecursiveASTVisitor_8 extends RecursiveASTVisitor<Object> { | |
| 7715 List<bool> result; | |
| 7716 Element variable; | |
| 7717 RecursiveASTVisitor_8(this.result, this.variable) : super(); | |
| 7718 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 7719 if (result[0]) { | |
| 7720 return null; | |
| 7721 } | |
| 7722 if (identical(node.staticElement, variable)) { | |
| 7723 if (node.inSetterContext()) { | |
| 7724 result[0] = javaBooleanOr(result[0], true); | |
| 7725 } | |
| 7726 } | |
| 7727 return null; | |
| 7728 } | |
| 7729 } | |
| 7730 /** | |
| 7731 * The abstract class `ScopedVisitor` maintains name and label scopes as an AST
structure is | |
| 7732 * being visited. | |
| 7733 * | |
| 7734 * @coverage dart.engine.resolver | |
| 7735 */ | |
| 7736 abstract class ScopedVisitor extends UnifyingASTVisitor<Object> { | |
| 7737 | |
| 7738 /** | |
| 7739 * The element for the library containing the compilation unit being visited. | |
| 7740 */ | |
| 7741 LibraryElement definingLibrary; | |
| 7742 | |
| 7743 /** | |
| 7744 * The source representing the compilation unit being visited. | |
| 7745 */ | |
| 7746 Source source; | |
| 7747 | |
| 7748 /** | |
| 7749 * The error listener that will be informed of any errors that are found durin
g resolution. | |
| 7750 */ | |
| 7751 AnalysisErrorListener _errorListener; | |
| 7752 | |
| 7753 /** | |
| 7754 * The scope used to resolve identifiers. | |
| 7755 */ | |
| 7756 Scope nameScope; | |
| 7757 | |
| 7758 /** | |
| 7759 * The object used to access the types from the core library. | |
| 7760 */ | |
| 7761 TypeProvider typeProvider; | |
| 7762 | |
| 7763 /** | |
| 7764 * The scope used to resolve labels for `break` and `continue` statements, or | |
| 7765 * `null` if no labels have been defined in the current context. | |
| 7766 */ | |
| 7767 LabelScope labelScope; | |
| 7768 | |
| 7769 /** | |
| 7770 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 7771 * | |
| 7772 * @param library the library containing the compilation unit being resolved | |
| 7773 * @param source the source representing the compilation unit being visited | |
| 7774 * @param typeProvider the object used to access the types from the core libra
ry | |
| 7775 */ | |
| 7776 ScopedVisitor.con1(Library library, Source source, TypeProvider typeProvider)
{ | |
| 7777 this.definingLibrary = library.libraryElement; | |
| 7778 this.source = source; | |
| 7779 LibraryScope libraryScope = library.libraryScope; | |
| 7780 this._errorListener = libraryScope.errorListener; | |
| 7781 this.nameScope = libraryScope; | |
| 7782 this.typeProvider = typeProvider; | |
| 7783 } | |
| 7784 | |
| 7785 /** | |
| 7786 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 7787 * | |
| 7788 * @param definingLibrary the element for the library containing the compilati
on unit being | |
| 7789 * visited | |
| 7790 * @param source the source representing the compilation unit being visited | |
| 7791 * @param typeProvider the object used to access the types from the core libra
ry | |
| 7792 * @param errorListener the error listener that will be informed of any errors
that are found | |
| 7793 * during resolution | |
| 7794 */ | |
| 7795 ScopedVisitor.con2(LibraryElement definingLibrary, Source source, TypeProvider
typeProvider, AnalysisErrorListener errorListener) { | |
| 7796 this.definingLibrary = definingLibrary; | |
| 7797 this.source = source; | |
| 7798 this._errorListener = errorListener; | |
| 7799 this.nameScope = new LibraryScope(definingLibrary, errorListener); | |
| 7800 this.typeProvider = typeProvider; | |
| 7801 } | |
| 7802 | |
| 7803 /** | |
| 7804 * Report an error with the given analysis error. | |
| 7805 * | |
| 7806 * @param errorCode analysis error | |
| 7807 */ | |
| 7808 void reportError(AnalysisError analysisError) { | |
| 7809 _errorListener.onError(analysisError); | |
| 7810 } | |
| 7811 Object visitBlock(Block node) { | |
| 7812 Scope outerScope = nameScope; | |
| 7813 try { | |
| 7814 EnclosedScope enclosedScope = new EnclosedScope(nameScope); | |
| 7815 hideNamesDefinedInBlock(enclosedScope, node); | |
| 7816 nameScope = enclosedScope; | |
| 7817 super.visitBlock(node); | |
| 7818 } finally { | |
| 7819 nameScope = outerScope; | |
| 7820 } | |
| 7821 return null; | |
| 7822 } | |
| 7823 Object visitCatchClause(CatchClause node) { | |
| 7824 SimpleIdentifier exception = node.exceptionParameter; | |
| 7825 if (exception != null) { | |
| 7826 Scope outerScope = nameScope; | |
| 7827 try { | |
| 7828 nameScope = new EnclosedScope(nameScope); | |
| 7829 nameScope.define(exception.staticElement); | |
| 7830 SimpleIdentifier stackTrace = node.stackTraceParameter; | |
| 7831 if (stackTrace != null) { | |
| 7832 nameScope.define(stackTrace.staticElement); | |
| 7833 } | |
| 7834 super.visitCatchClause(node); | |
| 7835 } finally { | |
| 7836 nameScope = outerScope; | |
| 7837 } | |
| 7838 } else { | |
| 7839 super.visitCatchClause(node); | |
| 7840 } | |
| 7841 return null; | |
| 7842 } | |
| 7843 Object visitClassDeclaration(ClassDeclaration node) { | |
| 7844 Scope outerScope = nameScope; | |
| 7845 try { | |
| 7846 nameScope = new ClassScope(nameScope, node.element); | |
| 7847 super.visitClassDeclaration(node); | |
| 7848 } finally { | |
| 7849 nameScope = outerScope; | |
| 7850 } | |
| 7851 return null; | |
| 7852 } | |
| 7853 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 7854 Scope outerScope = nameScope; | |
| 7855 try { | |
| 7856 nameScope = new ClassScope(nameScope, node.element); | |
| 7857 super.visitClassTypeAlias(node); | |
| 7858 } finally { | |
| 7859 nameScope = outerScope; | |
| 7860 } | |
| 7861 return null; | |
| 7862 } | |
| 7863 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 7864 Scope outerScope = nameScope; | |
| 7865 try { | |
| 7866 nameScope = new FunctionScope(nameScope, node.element); | |
| 7867 super.visitConstructorDeclaration(node); | |
| 7868 } finally { | |
| 7869 nameScope = outerScope; | |
| 7870 } | |
| 7871 return null; | |
| 7872 } | |
| 7873 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 7874 VariableElement element = node.element; | |
| 7875 if (element != null) { | |
| 7876 nameScope.define(element); | |
| 7877 } | |
| 7878 super.visitDeclaredIdentifier(node); | |
| 7879 return null; | |
| 7880 } | |
| 7881 Object visitDoStatement(DoStatement node) { | |
| 7882 LabelScope outerLabelScope = labelScope; | |
| 7883 try { | |
| 7884 labelScope = new LabelScope.con1(labelScope, false, false); | |
| 7885 visitStatementInScope(node.body); | |
| 7886 safelyVisit(node.condition); | |
| 7887 } finally { | |
| 7888 labelScope = outerLabelScope; | |
| 7889 } | |
| 7890 return null; | |
| 7891 } | |
| 7892 Object visitForEachStatement(ForEachStatement node) { | |
| 7893 Scope outerNameScope = nameScope; | |
| 7894 LabelScope outerLabelScope = labelScope; | |
| 7895 try { | |
| 7896 nameScope = new EnclosedScope(nameScope); | |
| 7897 labelScope = new LabelScope.con1(outerLabelScope, false, false); | |
| 7898 visitForEachStatementInScope(node); | |
| 7899 } finally { | |
| 7900 labelScope = outerLabelScope; | |
| 7901 nameScope = outerNameScope; | |
| 7902 } | |
| 7903 return null; | |
| 7904 } | |
| 7905 Object visitFormalParameterList(FormalParameterList node) { | |
| 7906 super.visitFormalParameterList(node); | |
| 7907 if (nameScope is FunctionScope) { | |
| 7908 ((nameScope as FunctionScope)).defineParameters(); | |
| 7909 } | |
| 7910 if (nameScope is FunctionTypeScope) { | |
| 7911 ((nameScope as FunctionTypeScope)).defineParameters(); | |
| 7912 } | |
| 7913 return null; | |
| 7914 } | |
| 7915 Object visitForStatement(ForStatement node) { | |
| 7916 Scope outerNameScope = nameScope; | |
| 7917 LabelScope outerLabelScope = labelScope; | |
| 7918 try { | |
| 7919 nameScope = new EnclosedScope(nameScope); | |
| 7920 labelScope = new LabelScope.con1(outerLabelScope, false, false); | |
| 7921 visitForStatementInScope(node); | |
| 7922 } finally { | |
| 7923 labelScope = outerLabelScope; | |
| 7924 nameScope = outerNameScope; | |
| 7925 } | |
| 7926 return null; | |
| 7927 } | |
| 7928 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 7929 ExecutableElement function = node.element; | |
| 7930 Scope outerScope = nameScope; | |
| 7931 try { | |
| 7932 nameScope = new FunctionScope(nameScope, function); | |
| 7933 super.visitFunctionDeclaration(node); | |
| 7934 } finally { | |
| 7935 nameScope = outerScope; | |
| 7936 } | |
| 7937 if (function.enclosingElement is! CompilationUnitElement) { | |
| 7938 nameScope.define(function); | |
| 7939 } | |
| 7940 return null; | |
| 7941 } | |
| 7942 Object visitFunctionExpression(FunctionExpression node) { | |
| 7943 if (node.parent is FunctionDeclaration) { | |
| 7944 super.visitFunctionExpression(node); | |
| 7945 } else { | |
| 7946 Scope outerScope = nameScope; | |
| 7947 try { | |
| 7948 ExecutableElement functionElement = node.element; | |
| 7949 if (functionElement == null) { | |
| 7950 } else { | |
| 7951 nameScope = new FunctionScope(nameScope, functionElement); | |
| 7952 } | |
| 7953 super.visitFunctionExpression(node); | |
| 7954 } finally { | |
| 7955 nameScope = outerScope; | |
| 7956 } | |
| 7957 } | |
| 7958 return null; | |
| 7959 } | |
| 7960 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 7961 Scope outerScope = nameScope; | |
| 7962 try { | |
| 7963 nameScope = new FunctionTypeScope(nameScope, node.element); | |
| 7964 super.visitFunctionTypeAlias(node); | |
| 7965 } finally { | |
| 7966 nameScope = outerScope; | |
| 7967 } | |
| 7968 return null; | |
| 7969 } | |
| 7970 Object visitIfStatement(IfStatement node) { | |
| 7971 safelyVisit(node.condition); | |
| 7972 visitStatementInScope(node.thenStatement); | |
| 7973 visitStatementInScope(node.elseStatement); | |
| 7974 return null; | |
| 7975 } | |
| 7976 Object visitLabeledStatement(LabeledStatement node) { | |
| 7977 LabelScope outerScope = addScopesFor(node.labels); | |
| 7978 try { | |
| 7979 super.visitLabeledStatement(node); | |
| 7980 } finally { | |
| 7981 labelScope = outerScope; | |
| 7982 } | |
| 7983 return null; | |
| 7984 } | |
| 7985 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 7986 Scope outerScope = nameScope; | |
| 7987 try { | |
| 7988 nameScope = new FunctionScope(nameScope, node.element); | |
| 7989 super.visitMethodDeclaration(node); | |
| 7990 } finally { | |
| 7991 nameScope = outerScope; | |
| 7992 } | |
| 7993 return null; | |
| 7994 } | |
| 7995 Object visitSwitchCase(SwitchCase node) { | |
| 7996 node.expression.accept(this); | |
| 7997 Scope outerNameScope = nameScope; | |
| 7998 try { | |
| 7999 nameScope = new EnclosedScope(nameScope); | |
| 8000 node.statements.accept(this); | |
| 8001 } finally { | |
| 8002 nameScope = outerNameScope; | |
| 8003 } | |
| 8004 return null; | |
| 8005 } | |
| 8006 Object visitSwitchDefault(SwitchDefault node) { | |
| 8007 Scope outerNameScope = nameScope; | |
| 8008 try { | |
| 8009 nameScope = new EnclosedScope(nameScope); | |
| 8010 node.statements.accept(this); | |
| 8011 } finally { | |
| 8012 nameScope = outerNameScope; | |
| 8013 } | |
| 8014 return null; | |
| 8015 } | |
| 8016 Object visitSwitchStatement(SwitchStatement node) { | |
| 8017 LabelScope outerScope = labelScope; | |
| 8018 try { | |
| 8019 labelScope = new LabelScope.con1(outerScope, true, false); | |
| 8020 for (SwitchMember member in node.members) { | |
| 8021 for (Label label in member.labels) { | |
| 8022 SimpleIdentifier labelName = label.label; | |
| 8023 LabelElement labelElement = labelName.staticElement as LabelElement; | |
| 8024 labelScope = new LabelScope.con2(labelScope, labelName.name, labelElem
ent); | |
| 8025 } | |
| 8026 } | |
| 8027 super.visitSwitchStatement(node); | |
| 8028 } finally { | |
| 8029 labelScope = outerScope; | |
| 8030 } | |
| 8031 return null; | |
| 8032 } | |
| 8033 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 8034 if (node.parent.parent is! TopLevelVariableDeclaration && node.parent.parent
is! FieldDeclaration) { | |
| 8035 VariableElement element = node.element; | |
| 8036 if (element != null) { | |
| 8037 nameScope.define(element); | |
| 8038 } | |
| 8039 } | |
| 8040 super.visitVariableDeclaration(node); | |
| 8041 return null; | |
| 8042 } | |
| 8043 Object visitWhileStatement(WhileStatement node) { | |
| 8044 LabelScope outerScope = labelScope; | |
| 8045 try { | |
| 8046 labelScope = new LabelScope.con1(outerScope, false, false); | |
| 8047 safelyVisit(node.condition); | |
| 8048 visitStatementInScope(node.body); | |
| 8049 } finally { | |
| 8050 labelScope = outerScope; | |
| 8051 } | |
| 8052 return null; | |
| 8053 } | |
| 8054 | |
| 8055 /** | |
| 8056 * Report an error with the given error code and arguments. | |
| 8057 * | |
| 8058 * @param errorCode the error code of the error to be reported | |
| 8059 * @param node the node specifying the location of the error | |
| 8060 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 8061 */ | |
| 8062 void reportError5(ErrorCode errorCode, ASTNode node, List<Object> arguments) { | |
| 8063 _errorListener.onError(new AnalysisError.con2(source, node.offset, node.leng
th, errorCode, arguments)); | |
| 8064 } | |
| 8065 | |
| 8066 /** | |
| 8067 * Report an error with the given error code and arguments. | |
| 8068 * | |
| 8069 * @param errorCode the error code of the error to be reported | |
| 8070 * @param offset the offset of the location of the error | |
| 8071 * @param length the length of the location of the error | |
| 8072 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 8073 */ | |
| 8074 void reportError6(ErrorCode errorCode, int offset, int length, List<Object> ar
guments) { | |
| 8075 _errorListener.onError(new AnalysisError.con2(source, offset, length, errorC
ode, arguments)); | |
| 8076 } | |
| 8077 | |
| 8078 /** | |
| 8079 * Report an error with the given error code and arguments. | |
| 8080 * | |
| 8081 * @param errorCode the error code of the error to be reported | |
| 8082 * @param token the token specifying the location of the error | |
| 8083 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 8084 */ | |
| 8085 void reportError7(ErrorCode errorCode, sc.Token token, List<Object> arguments)
{ | |
| 8086 _errorListener.onError(new AnalysisError.con2(source, token.offset, token.le
ngth, errorCode, arguments)); | |
| 8087 } | |
| 8088 | |
| 8089 /** | |
| 8090 * Visit the given AST node if it is not null. | |
| 8091 * | |
| 8092 * @param node the node to be visited | |
| 8093 */ | |
| 8094 void safelyVisit(ASTNode node) { | |
| 8095 if (node != null) { | |
| 8096 node.accept(this); | |
| 8097 } | |
| 8098 } | |
| 8099 | |
| 8100 /** | |
| 8101 * Visit the given statement after it's scope has been created. This replaces
the normal call to | |
| 8102 * the inherited visit method so that ResolverVisitor can intervene when type
propagation is | |
| 8103 * enabled. | |
| 8104 * | |
| 8105 * @param node the statement to be visited | |
| 8106 */ | |
| 8107 void visitForEachStatementInScope(ForEachStatement node) { | |
| 8108 safelyVisit(node.identifier); | |
| 8109 safelyVisit(node.iterator); | |
| 8110 safelyVisit(node.loopVariable); | |
| 8111 visitStatementInScope(node.body); | |
| 8112 } | |
| 8113 | |
| 8114 /** | |
| 8115 * Visit the given statement after it's scope has been created. This replaces
the normal call to | |
| 8116 * the inherited visit method so that ResolverVisitor can intervene when type
propagation is | |
| 8117 * enabled. | |
| 8118 * | |
| 8119 * @param node the statement to be visited | |
| 8120 */ | |
| 8121 void visitForStatementInScope(ForStatement node) { | |
| 8122 safelyVisit(node.variables); | |
| 8123 safelyVisit(node.initialization); | |
| 8124 safelyVisit(node.condition); | |
| 8125 node.updaters.accept(this); | |
| 8126 visitStatementInScope(node.body); | |
| 8127 } | |
| 8128 | |
| 8129 /** | |
| 8130 * Visit the given statement after it's scope has been created. This is used b
y ResolverVisitor to | |
| 8131 * correctly visit the 'then' and 'else' statements of an 'if' statement. | |
| 8132 * | |
| 8133 * @param node the statement to be visited | |
| 8134 */ | |
| 8135 void visitStatementInScope(Statement node) { | |
| 8136 if (node is Block) { | |
| 8137 visitBlock(node as Block); | |
| 8138 } else if (node != null) { | |
| 8139 Scope outerNameScope = nameScope; | |
| 8140 try { | |
| 8141 nameScope = new EnclosedScope(nameScope); | |
| 8142 node.accept(this); | |
| 8143 } finally { | |
| 8144 nameScope = outerNameScope; | |
| 8145 } | |
| 8146 } | |
| 8147 } | |
| 8148 | |
| 8149 /** | |
| 8150 * Add scopes for each of the given labels. | |
| 8151 * | |
| 8152 * @param labels the labels for which new scopes are to be added | |
| 8153 * @return the scope that was in effect before the new scopes were added | |
| 8154 */ | |
| 8155 LabelScope addScopesFor(NodeList<Label> labels) { | |
| 8156 LabelScope outerScope = labelScope; | |
| 8157 for (Label label in labels) { | |
| 8158 SimpleIdentifier labelNameNode = label.label; | |
| 8159 String labelName = labelNameNode.name; | |
| 8160 LabelElement labelElement = labelNameNode.staticElement as LabelElement; | |
| 8161 labelScope = new LabelScope.con2(labelScope, labelName, labelElement); | |
| 8162 } | |
| 8163 return outerScope; | |
| 8164 } | |
| 8165 | |
| 8166 /** | |
| 8167 * Marks the local declarations of the given [Block] hidden in the enclosing s
cope. | |
| 8168 * According to the scoping rules name is hidden if block defines it, but name
is defined after | |
| 8169 * its declaration statement. | |
| 8170 */ | |
| 8171 void hideNamesDefinedInBlock(EnclosedScope scope, Block block) { | |
| 8172 for (Statement statement in block.statements) { | |
| 8173 if (statement is VariableDeclarationStatement) { | |
| 8174 VariableDeclarationStatement vds = statement as VariableDeclarationState
ment; | |
| 8175 for (VariableDeclaration variableDeclaration in vds.variables.variables)
{ | |
| 8176 Element element = variableDeclaration.element; | |
| 8177 scope.hide(element); | |
| 8178 } | |
| 8179 } | |
| 8180 if (statement is FunctionDeclarationStatement) { | |
| 8181 FunctionDeclarationStatement fds = statement as FunctionDeclarationState
ment; | |
| 8182 Element element = fds.functionDeclaration.element; | |
| 8183 scope.hide(element); | |
| 8184 } | |
| 8185 } | |
| 8186 } | |
| 8187 } | |
| 8188 /** | |
| 8189 * Instances of the class `StaticTypeAnalyzer` perform two type-related tasks. F
irst, they | |
| 8190 * compute the static type of every expression. Second, they look for any static
type errors or | |
| 8191 * warnings that might need to be generated. The requirements for the type analy
zer are: | |
| 8192 * <ol> | |
| 8193 * * Every element that refers to types should be fully populated. | |
| 8194 * * Every node representing an expression should be resolved to the Type of the
expression. | |
| 8195 * </ol> | |
| 8196 * | |
| 8197 * @coverage dart.engine.resolver | |
| 8198 */ | |
| 8199 class StaticTypeAnalyzer extends SimpleASTVisitor<Object> { | |
| 8200 | |
| 8201 /** | |
| 8202 * Create a table mapping HTML tag names to the names of the classes (in 'dart
:html') that | |
| 8203 * implement those tags. | |
| 8204 * | |
| 8205 * @return the table that was created | |
| 8206 */ | |
| 8207 static Map<String, String> createHtmlTagToClassMap() { | |
| 8208 Map<String, String> map = new Map<String, String>(); | |
| 8209 map["a"] = "AnchorElement"; | |
| 8210 map["area"] = "AreaElement"; | |
| 8211 map["br"] = "BRElement"; | |
| 8212 map["base"] = "BaseElement"; | |
| 8213 map["body"] = "BodyElement"; | |
| 8214 map["button"] = "ButtonElement"; | |
| 8215 map["canvas"] = "CanvasElement"; | |
| 8216 map["content"] = "ContentElement"; | |
| 8217 map["dl"] = "DListElement"; | |
| 8218 map["datalist"] = "DataListElement"; | |
| 8219 map["details"] = "DetailsElement"; | |
| 8220 map["div"] = "DivElement"; | |
| 8221 map["embed"] = "EmbedElement"; | |
| 8222 map["fieldset"] = "FieldSetElement"; | |
| 8223 map["form"] = "FormElement"; | |
| 8224 map["hr"] = "HRElement"; | |
| 8225 map["head"] = "HeadElement"; | |
| 8226 map["h1"] = "HeadingElement"; | |
| 8227 map["h2"] = "HeadingElement"; | |
| 8228 map["h3"] = "HeadingElement"; | |
| 8229 map["h4"] = "HeadingElement"; | |
| 8230 map["h5"] = "HeadingElement"; | |
| 8231 map["h6"] = "HeadingElement"; | |
| 8232 map["html"] = "HtmlElement"; | |
| 8233 map["iframe"] = "IFrameElement"; | |
| 8234 map["img"] = "ImageElement"; | |
| 8235 map["input"] = "InputElement"; | |
| 8236 map["keygen"] = "KeygenElement"; | |
| 8237 map["li"] = "LIElement"; | |
| 8238 map["label"] = "LabelElement"; | |
| 8239 map["legend"] = "LegendElement"; | |
| 8240 map["link"] = "LinkElement"; | |
| 8241 map["map"] = "MapElement"; | |
| 8242 map["menu"] = "MenuElement"; | |
| 8243 map["meter"] = "MeterElement"; | |
| 8244 map["ol"] = "OListElement"; | |
| 8245 map["object"] = "ObjectElement"; | |
| 8246 map["optgroup"] = "OptGroupElement"; | |
| 8247 map["output"] = "OutputElement"; | |
| 8248 map["p"] = "ParagraphElement"; | |
| 8249 map["param"] = "ParamElement"; | |
| 8250 map["pre"] = "PreElement"; | |
| 8251 map["progress"] = "ProgressElement"; | |
| 8252 map["script"] = "ScriptElement"; | |
| 8253 map["select"] = "SelectElement"; | |
| 8254 map["source"] = "SourceElement"; | |
| 8255 map["span"] = "SpanElement"; | |
| 8256 map["style"] = "StyleElement"; | |
| 8257 map["caption"] = "TableCaptionElement"; | |
| 8258 map["td"] = "TableCellElement"; | |
| 8259 map["col"] = "TableColElement"; | |
| 8260 map["table"] = "TableElement"; | |
| 8261 map["tr"] = "TableRowElement"; | |
| 8262 map["textarea"] = "TextAreaElement"; | |
| 8263 map["title"] = "TitleElement"; | |
| 8264 map["track"] = "TrackElement"; | |
| 8265 map["ul"] = "UListElement"; | |
| 8266 map["video"] = "VideoElement"; | |
| 8267 return map; | |
| 8268 } | |
| 8269 | |
| 8270 /** | |
| 8271 * The resolver driving the resolution and type analysis. | |
| 8272 */ | |
| 8273 ResolverVisitor _resolver; | |
| 8274 | |
| 8275 /** | |
| 8276 * The object providing access to the types defined by the language. | |
| 8277 */ | |
| 8278 TypeProvider _typeProvider; | |
| 8279 | |
| 8280 /** | |
| 8281 * The type representing the type 'dynamic'. | |
| 8282 */ | |
| 8283 Type2 _dynamicType; | |
| 8284 | |
| 8285 /** | |
| 8286 * The type representing the class containing the nodes being analyzed, or `nu
ll` if the | |
| 8287 * nodes are not within a class. | |
| 8288 */ | |
| 8289 InterfaceType _thisType; | |
| 8290 | |
| 8291 /** | |
| 8292 * The object keeping track of which elements have had their types overridden. | |
| 8293 */ | |
| 8294 TypeOverrideManager _overrideManager; | |
| 8295 | |
| 8296 /** | |
| 8297 * The object keeping track of which elements have had their types promoted. | |
| 8298 */ | |
| 8299 TypePromotionManager _promoteManager; | |
| 8300 | |
| 8301 /** | |
| 8302 * A table mapping [ExecutableElement]s to their propagated return types. | |
| 8303 */ | |
| 8304 Map<ExecutableElement, Type2> _propagatedReturnTypes = new Map<ExecutableEleme
nt, Type2>(); | |
| 8305 | |
| 8306 /** | |
| 8307 * A table mapping HTML tag names to the names of the classes (in 'dart:html')
that implement | |
| 8308 * those tags. | |
| 8309 */ | |
| 8310 static Map<String, String> _HTML_ELEMENT_TO_CLASS_MAP = createHtmlTagToClassMa
p(); | |
| 8311 | |
| 8312 /** | |
| 8313 * Initialize a newly created type analyzer. | |
| 8314 * | |
| 8315 * @param resolver the resolver driving this participant | |
| 8316 */ | |
| 8317 StaticTypeAnalyzer(ResolverVisitor resolver) { | |
| 8318 this._resolver = resolver; | |
| 8319 _typeProvider = resolver.typeProvider; | |
| 8320 _dynamicType = _typeProvider.dynamicType; | |
| 8321 _overrideManager = resolver.overrideManager; | |
| 8322 _promoteManager = resolver.promoteManager; | |
| 8323 } | |
| 8324 | |
| 8325 /** | |
| 8326 * Set the type of the class being analyzed to the given type. | |
| 8327 * | |
| 8328 * @param thisType the type representing the class containing the nodes being
analyzed | |
| 8329 */ | |
| 8330 void set thisType(InterfaceType thisType) { | |
| 8331 this._thisType = thisType; | |
| 8332 } | |
| 8333 | |
| 8334 /** | |
| 8335 * The Dart Language Specification, 12.5: <blockquote>The static type of a str
ing literal is | |
| 8336 * `String`.</blockquote> | |
| 8337 */ | |
| 8338 Object visitAdjacentStrings(AdjacentStrings node) { | |
| 8339 recordStaticType(node, _typeProvider.stringType); | |
| 8340 return null; | |
| 8341 } | |
| 8342 | |
| 8343 /** | |
| 8344 * The Dart Language Specification, 12.33: <blockquote>The static type of an a
rgument definition | |
| 8345 * test is `bool`.</blockquote> | |
| 8346 */ | |
| 8347 Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) { | |
| 8348 recordStaticType(node, _typeProvider.boolType); | |
| 8349 return null; | |
| 8350 } | |
| 8351 | |
| 8352 /** | |
| 8353 * The Dart Language Specification, 12.32: <blockquote>... the cast expression
<i>e as T</i> ... | |
| 8354 * | |
| 8355 * It is a static warning if <i>T</i> does not denote a type available in the
current lexical | |
| 8356 * scope. | |
| 8357 * | |
| 8358 * The static type of a cast expression <i>e as T</i> is <i>T</i>.</blockquote
> | |
| 8359 */ | |
| 8360 Object visitAsExpression(AsExpression node) { | |
| 8361 recordStaticType(node, getType2(node.type)); | |
| 8362 return null; | |
| 8363 } | |
| 8364 | |
| 8365 /** | |
| 8366 * The Dart Language Specification, 12.18: <blockquote>... an assignment <i>a<
/i> of the form <i>v | |
| 8367 * = e</i> ... | |
| 8368 * | |
| 8369 * It is a static type warning if the static type of <i>e</i> may not be assig
ned to the static | |
| 8370 * type of <i>v</i>. | |
| 8371 * | |
| 8372 * The static type of the expression <i>v = e</i> is the static type of <i>e</
i>. | |
| 8373 * | |
| 8374 * ... an assignment of the form <i>C.v = e</i> ... | |
| 8375 * | |
| 8376 * It is a static type warning if the static type of <i>e</i> may not be assig
ned to the static | |
| 8377 * type of <i>C.v</i>. | |
| 8378 * | |
| 8379 * The static type of the expression <i>C.v = e</i> is the static type of <i>e
</i>. | |
| 8380 * | |
| 8381 * ... an assignment of the form <i>e<sub>1</sub>.v = e<sub>2</sub></i> ... | |
| 8382 * | |
| 8383 * Let <i>T</i> be the static type of <i>e<sub>1</sub></i>. It is a static typ
e warning if | |
| 8384 * <i>T</i> does not have an accessible instance setter named <i>v=</i>. It is
a static type | |
| 8385 * warning if the static type of <i>e<sub>2</sub></i> may not be assigned to <
i>T</i>. | |
| 8386 * | |
| 8387 * The static type of the expression <i>e<sub>1</sub>.v = e<sub>2</sub></i> is
the static type of | |
| 8388 * <i>e<sub>2</sub></i>. | |
| 8389 * | |
| 8390 * ... an assignment of the form <i>e<sub>1</sub>[e<sub>2</sub>] = e<sub>3</su
b></i> ... | |
| 8391 * | |
| 8392 * The static type of the expression <i>e<sub>1</sub>[e<sub>2</sub>] = e<sub>3
</sub></i> is the | |
| 8393 * static type of <i>e<sub>3</sub></i>. | |
| 8394 * | |
| 8395 * A compound assignment of the form <i>v op= e</i> is equivalent to <i>v = v
op e</i>. A compound | |
| 8396 * assignment of the form <i>C.v op= e</i> is equivalent to <i>C.v = C.v op e<
/i>. A compound | |
| 8397 * assignment of the form <i>e<sub>1</sub>.v op= e<sub>2</sub></i> is equivale
nt to <i>((x) => x.v | |
| 8398 * = x.v op e<sub>2</sub>)(e<sub>1</sub>)</i> where <i>x</i> is a variable tha
t is not used in | |
| 8399 * <i>e<sub>2</sub></i>. A compound assignment of the form <i>e<sub>1</sub>[e<
sub>2</sub>] op= | |
| 8400 * e<sub>3</sub></i> is equivalent to <i>((a, i) => a[i] = a[i] op e<sub>3</su
b>)(e<sub>1</sub>, | |
| 8401 * e<sub>2</sub>)</i> where <i>a</i> and <i>i</i> are a variables that are not
used in | |
| 8402 * <i>e<sub>3</sub></i>.</blockquote> | |
| 8403 */ | |
| 8404 Object visitAssignmentExpression(AssignmentExpression node) { | |
| 8405 sc.TokenType operator = node.operator.type; | |
| 8406 if (identical(operator, sc.TokenType.EQ)) { | |
| 8407 Expression rightHandSide = node.rightHandSide; | |
| 8408 Type2 staticType = getStaticType(rightHandSide); | |
| 8409 recordStaticType(node, staticType); | |
| 8410 Type2 overrideType = staticType; | |
| 8411 Type2 propagatedType = rightHandSide.propagatedType; | |
| 8412 if (propagatedType != null) { | |
| 8413 if (propagatedType.isMoreSpecificThan(staticType)) { | |
| 8414 recordPropagatedType2(node, propagatedType); | |
| 8415 } | |
| 8416 overrideType = propagatedType; | |
| 8417 } | |
| 8418 _resolver.override(node.leftHandSide, overrideType); | |
| 8419 } else { | |
| 8420 ExecutableElement staticMethodElement = node.staticElement; | |
| 8421 Type2 staticType = computeStaticReturnType(staticMethodElement); | |
| 8422 recordStaticType(node, staticType); | |
| 8423 MethodElement propagatedMethodElement = node.propagatedElement; | |
| 8424 if (propagatedMethodElement != staticMethodElement) { | |
| 8425 Type2 propagatedType = computeStaticReturnType(propagatedMethodElement); | |
| 8426 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticTy
pe)) { | |
| 8427 recordPropagatedType2(node, propagatedType); | |
| 8428 } | |
| 8429 } | |
| 8430 } | |
| 8431 return null; | |
| 8432 } | |
| 8433 | |
| 8434 /** | |
| 8435 * The Dart Language Specification, 12.20: <blockquote>The static type of a lo
gical boolean | |
| 8436 * expression is `bool`.</blockquote> | |
| 8437 * | |
| 8438 * The Dart Language Specification, 12.21:<blockquote>A bitwise expression of
the form | |
| 8439 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n | |
| 8440 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A bitwise expression of the form <i
>super op | |
| 8441 * e<sub>2</sub></i> is equivalent to the method invocation | |
| 8442 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> | |
| 8443 * | |
| 8444 * The Dart Language Specification, 12.22: <blockquote>The static type of an e
quality expression | |
| 8445 * is `bool`.</blockquote> | |
| 8446 * | |
| 8447 * The Dart Language Specification, 12.23: <blockquote>A relational expression
of the form | |
| 8448 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n | |
| 8449 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A relational expression of the form
<i>super op | |
| 8450 * e<sub>2</sub></i> is equivalent to the method invocation | |
| 8451 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> | |
| 8452 * | |
| 8453 * The Dart Language Specification, 12.24: <blockquote>A shift expression of t
he form | |
| 8454 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n | |
| 8455 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A shift expression of the form <i>s
uper op | |
| 8456 * e<sub>2</sub></i> is equivalent to the method invocation | |
| 8457 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> | |
| 8458 * | |
| 8459 * The Dart Language Specification, 12.25: <blockquote>An additive expression
of the form | |
| 8460 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n | |
| 8461 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. An additive expression of the form
<i>super op | |
| 8462 * e<sub>2</sub></i> is equivalent to the method invocation | |
| 8463 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> | |
| 8464 * | |
| 8465 * The Dart Language Specification, 12.26: <blockquote>A multiplicative expres
sion of the form | |
| 8466 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n | |
| 8467 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A multiplicative expression of the
form <i>super op | |
| 8468 * e<sub>2</sub></i> is equivalent to the method invocation | |
| 8469 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> | |
| 8470 */ | |
| 8471 Object visitBinaryExpression(BinaryExpression node) { | |
| 8472 ExecutableElement staticMethodElement = node.staticElement; | |
| 8473 Type2 staticType = computeStaticReturnType(staticMethodElement); | |
| 8474 staticType = refineBinaryExpressionType(node, staticType); | |
| 8475 recordStaticType(node, staticType); | |
| 8476 MethodElement propagatedMethodElement = node.propagatedElement; | |
| 8477 if (propagatedMethodElement != staticMethodElement) { | |
| 8478 Type2 propagatedType = computeStaticReturnType(propagatedMethodElement); | |
| 8479 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType
)) { | |
| 8480 recordPropagatedType2(node, propagatedType); | |
| 8481 } | |
| 8482 } | |
| 8483 return null; | |
| 8484 } | |
| 8485 | |
| 8486 /** | |
| 8487 * The Dart Language Specification, 12.4: <blockquote>The static type of a boo
lean literal is | |
| 8488 * bool.</blockquote> | |
| 8489 */ | |
| 8490 Object visitBooleanLiteral(BooleanLiteral node) { | |
| 8491 recordStaticType(node, _typeProvider.boolType); | |
| 8492 return null; | |
| 8493 } | |
| 8494 | |
| 8495 /** | |
| 8496 * The Dart Language Specification, 12.15.2: <blockquote>A cascaded method inv
ocation expression | |
| 8497 * of the form <i>e..suffix</i> is equivalent to the expression <i>(t) {t.suff
ix; return | |
| 8498 * t;}(e)</i>.</blockquote> | |
| 8499 */ | |
| 8500 Object visitCascadeExpression(CascadeExpression node) { | |
| 8501 recordStaticType(node, getStaticType(node.target)); | |
| 8502 recordPropagatedType2(node, node.target.propagatedType); | |
| 8503 return null; | |
| 8504 } | |
| 8505 | |
| 8506 /** | |
| 8507 * The Dart Language Specification, 12.19: <blockquote> ... a conditional expr
ession <i>c</i> of | |
| 8508 * the form <i>e<sub>1</sub> ? e<sub>2</sub> : e<sub>3</sub></i> ... | |
| 8509 * | |
| 8510 * It is a static type warning if the type of e<sub>1</sub> may not be assigne
d to `bool`. | |
| 8511 * | |
| 8512 * The static type of <i>c</i> is the least upper bound of the static type of
<i>e<sub>2</sub></i> | |
| 8513 * and the static type of <i>e<sub>3</sub></i>.</blockquote> | |
| 8514 */ | |
| 8515 Object visitConditionalExpression(ConditionalExpression node) { | |
| 8516 Type2 staticThenType = getStaticType(node.thenExpression); | |
| 8517 Type2 staticElseType = getStaticType(node.elseExpression); | |
| 8518 if (staticThenType == null) { | |
| 8519 staticThenType = _dynamicType; | |
| 8520 } | |
| 8521 if (staticElseType == null) { | |
| 8522 staticElseType = _dynamicType; | |
| 8523 } | |
| 8524 Type2 staticType = staticThenType.getLeastUpperBound(staticElseType); | |
| 8525 if (staticType == null) { | |
| 8526 staticType = _dynamicType; | |
| 8527 } | |
| 8528 recordStaticType(node, staticType); | |
| 8529 Type2 propagatedThenType = node.thenExpression.propagatedType; | |
| 8530 Type2 propagatedElseType = node.elseExpression.propagatedType; | |
| 8531 if (propagatedThenType != null || propagatedElseType != null) { | |
| 8532 if (propagatedThenType == null) { | |
| 8533 propagatedThenType = staticThenType; | |
| 8534 } | |
| 8535 if (propagatedElseType == null) { | |
| 8536 propagatedElseType = staticElseType; | |
| 8537 } | |
| 8538 Type2 propagatedType = propagatedThenType.getLeastUpperBound(propagatedEls
eType); | |
| 8539 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType
)) { | |
| 8540 recordPropagatedType2(node, propagatedType); | |
| 8541 } | |
| 8542 } | |
| 8543 return null; | |
| 8544 } | |
| 8545 | |
| 8546 /** | |
| 8547 * The Dart Language Specification, 12.3: <blockquote>The static type of a lit
eral double is | |
| 8548 * double.</blockquote> | |
| 8549 */ | |
| 8550 Object visitDoubleLiteral(DoubleLiteral node) { | |
| 8551 recordStaticType(node, _typeProvider.doubleType); | |
| 8552 return null; | |
| 8553 } | |
| 8554 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 8555 FunctionExpression function = node.functionExpression; | |
| 8556 ExecutableElementImpl functionElement = node.element as ExecutableElementImp
l; | |
| 8557 functionElement.returnType = computeStaticReturnType2(node); | |
| 8558 recordPropagatedType(functionElement, function.body); | |
| 8559 recordStaticType(function, functionElement.type); | |
| 8560 return null; | |
| 8561 } | |
| 8562 | |
| 8563 /** | |
| 8564 * The Dart Language Specification, 12.9: <blockquote>The static type of a fun
ction literal of the | |
| 8565 * form <i>(T<sub>1</sub> a<sub>1</sub>, …, T<sub>n</sub> a<sub>n</sub>
, [T<sub>n+1</sub> | |
| 8566 * x<sub>n+1</sub> = d1, …, T<sub>n+k</sub> x<sub>n+k</sub> = dk]) => e
</i> is | |
| 8567 * <i>(T<sub>1</sub>, …, Tn, [T<sub>n+1</sub> x<sub>n+1</sub>, …
, T<sub>n+k</sub> | |
| 8568 * x<sub>n+k</sub>]) → T<sub>0</sub></i>, where <i>T<sub>0</sub></i> is t
he static type of | |
| 8569 * <i>e</i>. In any case where <i>T<sub>i</sub>, 1 <= i <= n</i>, is not
specified, it is | |
| 8570 * considered to have been specified as dynamic. | |
| 8571 * | |
| 8572 * The static type of a function literal of the form <i>(T<sub>1</sub> a<sub>1
</sub>, …, | |
| 8573 * T<sub>n</sub> a<sub>n</sub>, {T<sub>n+1</sub> x<sub>n+1</sub> : d1, &hellip
;, T<sub>n+k</sub> | |
| 8574 * x<sub>n+k</sub> : dk}) => e</i> is <i>(T<sub>1</sub>, …, T<sub>n</su
b>, {T<sub>n+1</sub> | |
| 8575 * x<sub>n+1</sub>, …, T<sub>n+k</sub> x<sub>n+k</sub>}) → T<sub>0
</sub></i>, where | |
| 8576 * <i>T<sub>0</sub></i> is the static type of <i>e</i>. In any case where <i>T
<sub>i</sub>, 1 | |
| 8577 * <= i <= n</i>, is not specified, it is considered to have been specif
ied as dynamic. | |
| 8578 * | |
| 8579 * The static type of a function literal of the form <i>(T<sub>1</sub> a<sub>1
</sub>, …, | |
| 8580 * T<sub>n</sub> a<sub>n</sub>, [T<sub>n+1</sub> x<sub>n+1</sub> = d1, &hellip
;, T<sub>n+k</sub> | |
| 8581 * x<sub>n+k</sub> = dk]) {s}</i> is <i>(T<sub>1</sub>, …, T<sub>n</sub
>, [T<sub>n+1</sub> | |
| 8582 * x<sub>n+1</sub>, …, T<sub>n+k</sub> x<sub>n+k</sub>]) → dynamic
</i>. In any case | |
| 8583 * where <i>T<sub>i</sub>, 1 <= i <= n</i>, is not specified, it is cons
idered to have been | |
| 8584 * specified as dynamic. | |
| 8585 * | |
| 8586 * The static type of a function literal of the form <i>(T<sub>1</sub> a<sub>1
</sub>, …, | |
| 8587 * T<sub>n</sub> a<sub>n</sub>, {T<sub>n+1</sub> x<sub>n+1</sub> : d1, &hellip
;, T<sub>n+k</sub> | |
| 8588 * x<sub>n+k</sub> : dk}) {s}</i> is <i>(T<sub>1</sub>, …, T<sub>n</sub
>, {T<sub>n+1</sub> | |
| 8589 * x<sub>n+1</sub>, …, T<sub>n+k</sub> x<sub>n+k</sub>}) → dynamic
</i>. In any case | |
| 8590 * where <i>T<sub>i</sub>, 1 <= i <= n</i>, is not specified, it is cons
idered to have been | |
| 8591 * specified as dynamic.</blockquote> | |
| 8592 */ | |
| 8593 Object visitFunctionExpression(FunctionExpression node) { | |
| 8594 if (node.parent is FunctionDeclaration) { | |
| 8595 return null; | |
| 8596 } | |
| 8597 ExecutableElementImpl functionElement = node.element as ExecutableElementImp
l; | |
| 8598 functionElement.returnType = computeStaticReturnType3(node); | |
| 8599 recordPropagatedType(functionElement, node.body); | |
| 8600 recordStaticType(node, node.element.type); | |
| 8601 return null; | |
| 8602 } | |
| 8603 | |
| 8604 /** | |
| 8605 * The Dart Language Specification, 12.14.4: <blockquote>A function expression
invocation <i>i</i> | |
| 8606 * has the form <i>e<sub>f</sub>(a<sub>1</sub>, …, a<sub>n</sub>, x<sub
>n+1</sub>: | |
| 8607 * a<sub>n+1</sub>, …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>, where <i>
e<sub>f</sub></i> is | |
| 8608 * an expression. | |
| 8609 * | |
| 8610 * It is a static type warning if the static type <i>F</i> of <i>e<sub>f</sub>
</i> may not be | |
| 8611 * assigned to a function type. | |
| 8612 * | |
| 8613 * If <i>F</i> is not a function type, the static type of <i>i</i> is dynamic.
Otherwise the | |
| 8614 * static type of <i>i</i> is the declared return type of <i>F</i>.</blockquot
e> | |
| 8615 */ | |
| 8616 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 8617 ExecutableElement staticMethodElement = node.staticElement; | |
| 8618 Type2 staticStaticType = computeStaticReturnType(staticMethodElement); | |
| 8619 recordStaticType(node, staticStaticType); | |
| 8620 Type2 staticPropagatedType = computePropagatedReturnType(staticMethodElement
); | |
| 8621 if (staticPropagatedType != null && (staticStaticType == null || staticPropa
gatedType.isMoreSpecificThan(staticStaticType))) { | |
| 8622 recordPropagatedType2(node, staticPropagatedType); | |
| 8623 } | |
| 8624 ExecutableElement propagatedMethodElement = node.propagatedElement; | |
| 8625 if (propagatedMethodElement != staticMethodElement) { | |
| 8626 Type2 propagatedStaticType = computeStaticReturnType(propagatedMethodEleme
nt); | |
| 8627 if (propagatedStaticType != null && (staticStaticType == null || propagate
dStaticType.isMoreSpecificThan(staticStaticType)) && (staticPropagatedType == nu
ll || propagatedStaticType.isMoreSpecificThan(staticPropagatedType))) { | |
| 8628 recordPropagatedType2(node, propagatedStaticType); | |
| 8629 } | |
| 8630 Type2 propagatedPropagatedType = computePropagatedReturnType(propagatedMet
hodElement); | |
| 8631 if (propagatedPropagatedType != null && (staticStaticType == null || propa
gatedPropagatedType.isMoreSpecificThan(staticStaticType)) && (staticPropagatedTy
pe == null || propagatedPropagatedType.isMoreSpecificThan(staticPropagatedType))
&& (propagatedStaticType == null || propagatedPropagatedType.isMoreSpecificThan
(propagatedStaticType))) { | |
| 8632 recordPropagatedType2(node, propagatedPropagatedType); | |
| 8633 } | |
| 8634 } | |
| 8635 return null; | |
| 8636 } | |
| 8637 | |
| 8638 /** | |
| 8639 * The Dart Language Specification, 12.29: <blockquote>An assignable expressio
n of the form | |
| 8640 * <i>e<sub>1</sub>[e<sub>2</sub>]</i> is evaluated as a method invocation of
the operator method | |
| 8641 * <i>[]</i> on <i>e<sub>1</sub></i> with argument <i>e<sub>2</sub></i>.</bloc
kquote> | |
| 8642 */ | |
| 8643 Object visitIndexExpression(IndexExpression node) { | |
| 8644 if (node.inSetterContext()) { | |
| 8645 ExecutableElement staticMethodElement = node.staticElement; | |
| 8646 Type2 staticType = computeArgumentType(staticMethodElement); | |
| 8647 recordStaticType(node, staticType); | |
| 8648 MethodElement propagatedMethodElement = node.propagatedElement; | |
| 8649 if (propagatedMethodElement != staticMethodElement) { | |
| 8650 Type2 propagatedType = computeArgumentType(propagatedMethodElement); | |
| 8651 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticTy
pe)) { | |
| 8652 recordPropagatedType2(node, propagatedType); | |
| 8653 } | |
| 8654 } | |
| 8655 } else { | |
| 8656 ExecutableElement staticMethodElement = node.staticElement; | |
| 8657 Type2 staticType = computeStaticReturnType(staticMethodElement); | |
| 8658 recordStaticType(node, staticType); | |
| 8659 MethodElement propagatedMethodElement = node.propagatedElement; | |
| 8660 if (propagatedMethodElement != staticMethodElement) { | |
| 8661 Type2 propagatedType = computeStaticReturnType(propagatedMethodElement); | |
| 8662 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticTy
pe)) { | |
| 8663 recordPropagatedType2(node, propagatedType); | |
| 8664 } | |
| 8665 } | |
| 8666 } | |
| 8667 return null; | |
| 8668 } | |
| 8669 | |
| 8670 /** | |
| 8671 * The Dart Language Specification, 12.11.1: <blockquote>The static type of a
new expression of | |
| 8672 * either the form <i>new T.id(a<sub>1</sub>, …, a<sub>n</sub>)</i> or
the form <i>new | |
| 8673 * T(a<sub>1</sub>, …, a<sub>n</sub>)</i> is <i>T</i>.</blockquote> | |
| 8674 * | |
| 8675 * The Dart Language Specification, 12.11.2: <blockquote>The static type of a
constant object | |
| 8676 * expression of either the form <i>const T.id(a<sub>1</sub>, …, a<sub>
n</sub>)</i> or the | |
| 8677 * form <i>const T(a<sub>1</sub>, …, a<sub>n</sub>)</i> is <i>T</i>. </
blockquote> | |
| 8678 */ | |
| 8679 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 8680 recordStaticType(node, node.constructorName.type.type); | |
| 8681 ConstructorElement element = node.staticElement; | |
| 8682 if (element != null && "Element" == element.enclosingElement.name) { | |
| 8683 LibraryElement library = element.library; | |
| 8684 if (isHtmlLibrary(library)) { | |
| 8685 String constructorName = element.name; | |
| 8686 if ("tag" == constructorName) { | |
| 8687 Type2 returnType = getFirstArgumentAsType2(library, node.argumentList,
_HTML_ELEMENT_TO_CLASS_MAP); | |
| 8688 if (returnType != null) { | |
| 8689 recordPropagatedType2(node, returnType); | |
| 8690 } | |
| 8691 } else { | |
| 8692 Type2 returnType = getElementNameAsType(library, constructorName, _HTM
L_ELEMENT_TO_CLASS_MAP); | |
| 8693 if (returnType != null) { | |
| 8694 recordPropagatedType2(node, returnType); | |
| 8695 } | |
| 8696 } | |
| 8697 } | |
| 8698 } | |
| 8699 return null; | |
| 8700 } | |
| 8701 | |
| 8702 /** | |
| 8703 * The Dart Language Specification, 12.3: <blockquote>The static type of an in
teger literal is | |
| 8704 * `int`.</blockquote> | |
| 8705 */ | |
| 8706 Object visitIntegerLiteral(IntegerLiteral node) { | |
| 8707 recordStaticType(node, _typeProvider.intType); | |
| 8708 return null; | |
| 8709 } | |
| 8710 | |
| 8711 /** | |
| 8712 * The Dart Language Specification, 12.31: <blockquote>It is a static warning
if <i>T</i> does not | |
| 8713 * denote a type available in the current lexical scope. | |
| 8714 * | |
| 8715 * The static type of an is-expression is `bool`.</blockquote> | |
| 8716 */ | |
| 8717 Object visitIsExpression(IsExpression node) { | |
| 8718 recordStaticType(node, _typeProvider.boolType); | |
| 8719 return null; | |
| 8720 } | |
| 8721 | |
| 8722 /** | |
| 8723 * The Dart Language Specification, 12.6: <blockquote>The static type of a lis
t literal of the | |
| 8724 * form <i><b>const</b> <E>[e<sub>1</sub>, …, e<sub>n</sub>]</i>
or the form | |
| 8725 * <i><E>[e<sub>1</sub>, …, e<sub>n</sub>]</i> is `List<E>`
. The static | |
| 8726 * type a list literal of the form <i><b>const</b> [e<sub>1</sub>, …, e
<sub>n</sub>]</i> or | |
| 8727 * the form <i>[e<sub>1</sub>, …, e<sub>n</sub>]</i> is `List<dynami
c>` | |
| 8728 * .</blockquote> | |
| 8729 */ | |
| 8730 Object visitListLiteral(ListLiteral node) { | |
| 8731 Type2 staticType = _dynamicType; | |
| 8732 TypeArgumentList typeArguments = node.typeArguments; | |
| 8733 if (typeArguments != null) { | |
| 8734 NodeList<TypeName> arguments = typeArguments.arguments; | |
| 8735 if (arguments != null && arguments.length == 1) { | |
| 8736 TypeName argumentTypeName = arguments[0]; | |
| 8737 Type2 argumentType = getType2(argumentTypeName); | |
| 8738 if (argumentType != null) { | |
| 8739 staticType = argumentType; | |
| 8740 } | |
| 8741 } | |
| 8742 } | |
| 8743 recordStaticType(node, _typeProvider.listType.substitute4(<Type2> [staticTyp
e])); | |
| 8744 NodeList<Expression> elements = node.elements; | |
| 8745 int count = elements.length; | |
| 8746 if (count > 0) { | |
| 8747 Type2 propagatedType = elements[0].bestType; | |
| 8748 for (int i = 1; i < count; i++) { | |
| 8749 Type2 elementType = elements[i].bestType; | |
| 8750 if (propagatedType != elementType) { | |
| 8751 propagatedType = _dynamicType; | |
| 8752 } else { | |
| 8753 propagatedType = propagatedType.getLeastUpperBound(elementType); | |
| 8754 if (propagatedType == null) { | |
| 8755 propagatedType = _dynamicType; | |
| 8756 } | |
| 8757 } | |
| 8758 } | |
| 8759 if (propagatedType.isMoreSpecificThan(staticType)) { | |
| 8760 recordPropagatedType2(node, _typeProvider.listType.substitute4(<Type2> [
propagatedType])); | |
| 8761 } | |
| 8762 } | |
| 8763 return null; | |
| 8764 } | |
| 8765 | |
| 8766 /** | |
| 8767 * The Dart Language Specification, 12.7: <blockquote>The static type of a map
literal of the form | |
| 8768 * <i><b>const</b> <String, V> {k<sub>1</sub>:e<sub>1</sub>, …, | |
| 8769 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i><String, V> {k<sub>1<
/sub>:e<sub>1</sub>, | |
| 8770 * …, k<sub>n</sub>:e<sub>n</sub>}</i> is `Map<String, V>`. The s
tatic type a | |
| 8771 * map literal of the form <i><b>const</b> {k<sub>1</sub>:e<sub>1</sub>, &hell
ip;, | |
| 8772 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>{k<sub>1</sub>:e<sub>1</sub
>, …, | |
| 8773 * k<sub>n</sub>:e<sub>n</sub>}</i> is `Map<String, dynamic>`. | |
| 8774 * | |
| 8775 * It is a compile-time error if the first type argument to a map literal is n
ot | |
| 8776 * <i>String</i>.</blockquote> | |
| 8777 */ | |
| 8778 Object visitMapLiteral(MapLiteral node) { | |
| 8779 Type2 staticKeyType = _dynamicType; | |
| 8780 Type2 staticValueType = _dynamicType; | |
| 8781 TypeArgumentList typeArguments = node.typeArguments; | |
| 8782 if (typeArguments != null) { | |
| 8783 NodeList<TypeName> arguments = typeArguments.arguments; | |
| 8784 if (arguments != null && arguments.length == 2) { | |
| 8785 TypeName entryKeyTypeName = arguments[0]; | |
| 8786 Type2 entryKeyType = getType2(entryKeyTypeName); | |
| 8787 if (entryKeyType != null) { | |
| 8788 staticKeyType = entryKeyType; | |
| 8789 } | |
| 8790 TypeName entryValueTypeName = arguments[1]; | |
| 8791 Type2 entryValueType = getType2(entryValueTypeName); | |
| 8792 if (entryValueType != null) { | |
| 8793 staticValueType = entryValueType; | |
| 8794 } | |
| 8795 } | |
| 8796 } | |
| 8797 recordStaticType(node, _typeProvider.mapType.substitute4(<Type2> [staticKeyT
ype, staticValueType])); | |
| 8798 NodeList<MapLiteralEntry> entries = node.entries; | |
| 8799 int count = entries.length; | |
| 8800 if (count > 0) { | |
| 8801 MapLiteralEntry entry = entries[0]; | |
| 8802 Type2 propagatedKeyType = entry.key.bestType; | |
| 8803 Type2 propagatedValueType = entry.value.bestType; | |
| 8804 for (int i = 1; i < count; i++) { | |
| 8805 entry = entries[i]; | |
| 8806 Type2 elementKeyType = entry.key.bestType; | |
| 8807 if (propagatedKeyType != elementKeyType) { | |
| 8808 propagatedKeyType = _dynamicType; | |
| 8809 } else { | |
| 8810 propagatedKeyType = propagatedKeyType.getLeastUpperBound(elementKeyTyp
e); | |
| 8811 if (propagatedKeyType == null) { | |
| 8812 propagatedKeyType = _dynamicType; | |
| 8813 } | |
| 8814 } | |
| 8815 Type2 elementValueType = entry.value.bestType; | |
| 8816 if (propagatedValueType != elementValueType) { | |
| 8817 propagatedValueType = _dynamicType; | |
| 8818 } else { | |
| 8819 propagatedValueType = propagatedValueType.getLeastUpperBound(elementVa
lueType); | |
| 8820 if (propagatedValueType == null) { | |
| 8821 propagatedValueType = _dynamicType; | |
| 8822 } | |
| 8823 } | |
| 8824 } | |
| 8825 bool betterKey = propagatedKeyType != null && propagatedKeyType.isMoreSpec
ificThan(staticKeyType); | |
| 8826 bool betterValue = propagatedValueType != null && propagatedValueType.isMo
reSpecificThan(staticValueType); | |
| 8827 if (betterKey || betterValue) { | |
| 8828 if (!betterKey) { | |
| 8829 propagatedKeyType = staticKeyType; | |
| 8830 } | |
| 8831 if (!betterValue) { | |
| 8832 propagatedValueType = staticValueType; | |
| 8833 } | |
| 8834 recordPropagatedType2(node, _typeProvider.mapType.substitute4(<Type2> [p
ropagatedKeyType, propagatedValueType])); | |
| 8835 } | |
| 8836 } | |
| 8837 return null; | |
| 8838 } | |
| 8839 | |
| 8840 /** | |
| 8841 * The Dart Language Specification, 12.15.1: <blockquote>An ordinary method in
vocation <i>i</i> | |
| 8842 * has the form <i>o.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>
: a<sub>n+1</sub>, | |
| 8843 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. | |
| 8844 * | |
| 8845 * Let <i>T</i> be the static type of <i>o</i>. It is a static type warning if
<i>T</i> does not | |
| 8846 * have an accessible instance member named <i>m</i>. If <i>T.m</i> exists, it
is a static warning | |
| 8847 * if the type <i>F</i> of <i>T.m</i> may not be assigned to a function type. | |
| 8848 * | |
| 8849 * If <i>T.m</i> does not exist, or if <i>F</i> is not a function type, the st
atic type of | |
| 8850 * <i>i</i> is dynamic. Otherwise the static type of <i>i</i> is the declared
return type of | |
| 8851 * <i>F</i>.</blockquote> | |
| 8852 * | |
| 8853 * The Dart Language Specification, 11.15.3: <blockquote>A static method invoc
ation <i>i</i> has | |
| 8854 * the form <i>C.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>: a<
sub>n+1</sub>, | |
| 8855 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. | |
| 8856 * | |
| 8857 * It is a static type warning if the type <i>F</i> of <i>C.m</i> may not be a
ssigned to a | |
| 8858 * function type. | |
| 8859 * | |
| 8860 * If <i>F</i> is not a function type, or if <i>C.m</i> does not exist, the st
atic type of i is | |
| 8861 * dynamic. Otherwise the static type of <i>i</i> is the declared return type
of | |
| 8862 * <i>F</i>.</blockquote> | |
| 8863 * | |
| 8864 * The Dart Language Specification, 11.15.4: <blockquote>A super method invoca
tion <i>i</i> has | |
| 8865 * the form <i>super.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>
: a<sub>n+1</sub>, | |
| 8866 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. | |
| 8867 * | |
| 8868 * It is a static type warning if <i>S</i> does not have an accessible instanc
e member named m. If | |
| 8869 * <i>S.m</i> exists, it is a static warning if the type <i>F</i> of <i>S.m</i
> may not be | |
| 8870 * assigned to a function type. | |
| 8871 * | |
| 8872 * If <i>S.m</i> does not exist, or if <i>F</i> is not a function type, the st
atic type of | |
| 8873 * <i>i</i> is dynamic. Otherwise the static type of <i>i</i> is the declared
return type of | |
| 8874 * <i>F</i>.</blockquote> | |
| 8875 */ | |
| 8876 Object visitMethodInvocation(MethodInvocation node) { | |
| 8877 SimpleIdentifier methodNameNode = node.methodName; | |
| 8878 Element staticMethodElement = methodNameNode.staticElement; | |
| 8879 Type2 staticStaticType = computeStaticReturnType(staticMethodElement); | |
| 8880 recordStaticType(node, staticStaticType); | |
| 8881 Type2 staticPropagatedType = computePropagatedReturnType(staticMethodElement
); | |
| 8882 if (staticPropagatedType != null && (staticStaticType == null || staticPropa
gatedType.isMoreSpecificThan(staticStaticType))) { | |
| 8883 recordPropagatedType2(node, staticPropagatedType); | |
| 8884 } | |
| 8885 String methodName = methodNameNode.name; | |
| 8886 if (methodName == "then") { | |
| 8887 Expression target = node.realTarget; | |
| 8888 Type2 targetType = target == null ? null : target.bestType; | |
| 8889 if (isAsyncFutureType(targetType)) { | |
| 8890 NodeList<Expression> arguments = node.argumentList.arguments; | |
| 8891 if (arguments.length == 1) { | |
| 8892 Expression closureArg = arguments[0]; | |
| 8893 if (closureArg is FunctionExpression) { | |
| 8894 FunctionExpression closureExpr = closureArg as FunctionExpression; | |
| 8895 Type2 returnType = computePropagatedReturnType(closureExpr.element); | |
| 8896 if (returnType != null) { | |
| 8897 InterfaceTypeImpl newFutureType; | |
| 8898 if (isAsyncFutureType(returnType)) { | |
| 8899 newFutureType = returnType as InterfaceTypeImpl; | |
| 8900 } else { | |
| 8901 InterfaceType futureType = targetType as InterfaceType; | |
| 8902 newFutureType = new InterfaceTypeImpl.con1(futureType.element); | |
| 8903 newFutureType.typeArguments = <Type2> [returnType]; | |
| 8904 } | |
| 8905 recordPropagatedType2(node, newFutureType); | |
| 8906 return null; | |
| 8907 } | |
| 8908 } | |
| 8909 } | |
| 8910 } | |
| 8911 } | |
| 8912 if (methodName == "\$dom_createEvent") { | |
| 8913 Expression target = node.realTarget; | |
| 8914 if (target != null) { | |
| 8915 Type2 targetType = target.bestType; | |
| 8916 if (targetType is InterfaceType && (targetType.name == "HtmlDocument" ||
targetType.name == "Document")) { | |
| 8917 LibraryElement library = targetType.element.library; | |
| 8918 if (isHtmlLibrary(library)) { | |
| 8919 Type2 returnType = getFirstArgumentAsType(library, node.argumentList
); | |
| 8920 if (returnType != null) { | |
| 8921 recordPropagatedType2(node, returnType); | |
| 8922 } | |
| 8923 } | |
| 8924 } | |
| 8925 } | |
| 8926 } else if (methodName == "query") { | |
| 8927 Expression target = node.realTarget; | |
| 8928 if (target == null) { | |
| 8929 Element methodElement = methodNameNode.bestElement; | |
| 8930 if (methodElement != null) { | |
| 8931 LibraryElement library = methodElement.library; | |
| 8932 if (isHtmlLibrary(library)) { | |
| 8933 Type2 returnType = getFirstArgumentAsQuery(library, node.argumentLis
t); | |
| 8934 if (returnType != null) { | |
| 8935 recordPropagatedType2(node, returnType); | |
| 8936 } | |
| 8937 } | |
| 8938 } | |
| 8939 } else { | |
| 8940 Type2 targetType = target.bestType; | |
| 8941 if (targetType is InterfaceType && (targetType.name == "HtmlDocument" ||
targetType.name == "Document")) { | |
| 8942 LibraryElement library = targetType.element.library; | |
| 8943 if (isHtmlLibrary(library)) { | |
| 8944 Type2 returnType = getFirstArgumentAsQuery(library, node.argumentLis
t); | |
| 8945 if (returnType != null) { | |
| 8946 recordPropagatedType2(node, returnType); | |
| 8947 } | |
| 8948 } | |
| 8949 } | |
| 8950 } | |
| 8951 } else if (methodName == "\$dom_createElement") { | |
| 8952 Expression target = node.realTarget; | |
| 8953 Type2 targetType = target.bestType; | |
| 8954 if (targetType is InterfaceType && (targetType.name == "HtmlDocument" || t
argetType.name == "Document")) { | |
| 8955 LibraryElement library = targetType.element.library; | |
| 8956 if (isHtmlLibrary(library)) { | |
| 8957 Type2 returnType = getFirstArgumentAsQuery(library, node.argumentList)
; | |
| 8958 if (returnType != null) { | |
| 8959 recordPropagatedType2(node, returnType); | |
| 8960 } | |
| 8961 } | |
| 8962 } | |
| 8963 } else if (methodName == "JS") { | |
| 8964 Type2 returnType = getFirstArgumentAsType(_typeProvider.objectType.element
.library, node.argumentList); | |
| 8965 if (returnType != null) { | |
| 8966 recordPropagatedType2(node, returnType); | |
| 8967 } | |
| 8968 } else { | |
| 8969 Element propagatedElement = methodNameNode.propagatedElement; | |
| 8970 if (propagatedElement != staticMethodElement) { | |
| 8971 Type2 propagatedStaticType = computeStaticReturnType(propagatedElement); | |
| 8972 if (propagatedStaticType != null && (staticStaticType == null || propaga
tedStaticType.isMoreSpecificThan(staticStaticType)) && (staticPropagatedType ==
null || propagatedStaticType.isMoreSpecificThan(staticPropagatedType))) { | |
| 8973 recordPropagatedType2(node, propagatedStaticType); | |
| 8974 } | |
| 8975 Type2 propagatedPropagatedType = computePropagatedReturnType(propagatedE
lement); | |
| 8976 if (propagatedPropagatedType != null && (staticStaticType == null || pro
pagatedPropagatedType.isMoreSpecificThan(staticStaticType)) && (staticPropagated
Type == null || propagatedPropagatedType.isMoreSpecificThan(staticPropagatedType
)) && (propagatedStaticType == null || propagatedPropagatedType.isMoreSpecificTh
an(propagatedStaticType))) { | |
| 8977 recordPropagatedType2(node, propagatedPropagatedType); | |
| 8978 } | |
| 8979 } | |
| 8980 } | |
| 8981 return null; | |
| 8982 } | |
| 8983 Object visitNamedExpression(NamedExpression node) { | |
| 8984 Expression expression = node.expression; | |
| 8985 recordStaticType(node, getStaticType(expression)); | |
| 8986 recordPropagatedType2(node, expression.propagatedType); | |
| 8987 return null; | |
| 8988 } | |
| 8989 | |
| 8990 /** | |
| 8991 * The Dart Language Specification, 12.2: <blockquote>The static type of `null
` is bottom. | |
| 8992 * </blockquote> | |
| 8993 */ | |
| 8994 Object visitNullLiteral(NullLiteral node) { | |
| 8995 recordStaticType(node, _typeProvider.bottomType); | |
| 8996 return null; | |
| 8997 } | |
| 8998 Object visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 8999 Expression expression = node.expression; | |
| 9000 recordStaticType(node, getStaticType(expression)); | |
| 9001 recordPropagatedType2(node, expression.propagatedType); | |
| 9002 return null; | |
| 9003 } | |
| 9004 | |
| 9005 /** | |
| 9006 * The Dart Language Specification, 12.28: <blockquote>A postfix expression of
the form | |
| 9007 * <i>v++</i>, where <i>v</i> is an identifier, is equivalent to <i>(){var r =
v; v = r + 1; | |
| 9008 * return r}()</i>. | |
| 9009 * | |
| 9010 * A postfix expression of the form <i>C.v++</i> is equivalent to <i>(){var r
= C.v; C.v = r + 1; | |
| 9011 * return r}()</i>. | |
| 9012 * | |
| 9013 * A postfix expression of the form <i>e1.v++</i> is equivalent to <i>(x){var
r = x.v; x.v = r + | |
| 9014 * 1; return r}(e1)</i>. | |
| 9015 * | |
| 9016 * A postfix expression of the form <i>e1[e2]++</i> is equivalent to <i>(a, i)
{var r = a[i]; a[i] | |
| 9017 * = r + 1; return r}(e1, e2)</i> | |
| 9018 * | |
| 9019 * A postfix expression of the form <i>v--</i>, where <i>v</i> is an identifie
r, is equivalent to | |
| 9020 * <i>(){var r = v; v = r - 1; return r}()</i>. | |
| 9021 * | |
| 9022 * A postfix expression of the form <i>C.v--</i> is equivalent to <i>(){var r
= C.v; C.v = r - 1; | |
| 9023 * return r}()</i>. | |
| 9024 * | |
| 9025 * A postfix expression of the form <i>e1.v--</i> is equivalent to <i>(x){var
r = x.v; x.v = r - | |
| 9026 * 1; return r}(e1)</i>. | |
| 9027 * | |
| 9028 * A postfix expression of the form <i>e1[e2]--</i> is equivalent to <i>(a, i)
{var r = a[i]; a[i] | |
| 9029 * = r - 1; return r}(e1, e2)</i></blockquote> | |
| 9030 */ | |
| 9031 Object visitPostfixExpression(PostfixExpression node) { | |
| 9032 Expression operand = node.operand; | |
| 9033 Type2 staticType = getStaticType(operand); | |
| 9034 sc.TokenType operator = node.operator.type; | |
| 9035 if (identical(operator, sc.TokenType.MINUS_MINUS) || identical(operator, sc.
TokenType.PLUS_PLUS)) { | |
| 9036 Type2 intType = _typeProvider.intType; | |
| 9037 if (identical(getStaticType(node.operand), intType)) { | |
| 9038 staticType = intType; | |
| 9039 } | |
| 9040 } | |
| 9041 recordStaticType(node, staticType); | |
| 9042 recordPropagatedType2(node, operand.propagatedType); | |
| 9043 return null; | |
| 9044 } | |
| 9045 | |
| 9046 /** | |
| 9047 * See [visitSimpleIdentifier]. | |
| 9048 */ | |
| 9049 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 9050 SimpleIdentifier prefixedIdentifier = node.identifier; | |
| 9051 Element staticElement = prefixedIdentifier.staticElement; | |
| 9052 Type2 staticType = _dynamicType; | |
| 9053 if (staticElement is ClassElement) { | |
| 9054 if (isNotTypeLiteral(node)) { | |
| 9055 staticType = ((staticElement as ClassElement)).type; | |
| 9056 } else { | |
| 9057 staticType = _typeProvider.typeType; | |
| 9058 } | |
| 9059 } else if (staticElement is FunctionTypeAliasElement) { | |
| 9060 staticType = ((staticElement as FunctionTypeAliasElement)).type; | |
| 9061 } else if (staticElement is MethodElement) { | |
| 9062 staticType = ((staticElement as MethodElement)).type; | |
| 9063 } else if (staticElement is PropertyAccessorElement) { | |
| 9064 staticType = getType(staticElement as PropertyAccessorElement, node.prefix
.staticType); | |
| 9065 } else if (staticElement is ExecutableElement) { | |
| 9066 staticType = ((staticElement as ExecutableElement)).type; | |
| 9067 } else if (staticElement is TypeParameterElement) { | |
| 9068 staticType = ((staticElement as TypeParameterElement)).type; | |
| 9069 } else if (staticElement is VariableElement) { | |
| 9070 staticType = ((staticElement as VariableElement)).type; | |
| 9071 } | |
| 9072 recordStaticType(prefixedIdentifier, staticType); | |
| 9073 recordStaticType(node, staticType); | |
| 9074 Element propagatedElement = prefixedIdentifier.propagatedElement; | |
| 9075 Type2 propagatedType = null; | |
| 9076 if (propagatedElement is ClassElement) { | |
| 9077 if (isNotTypeLiteral(node)) { | |
| 9078 propagatedType = ((propagatedElement as ClassElement)).type; | |
| 9079 } else { | |
| 9080 propagatedType = _typeProvider.typeType; | |
| 9081 } | |
| 9082 } else if (propagatedElement is FunctionTypeAliasElement) { | |
| 9083 propagatedType = ((propagatedElement as FunctionTypeAliasElement)).type; | |
| 9084 } else if (propagatedElement is MethodElement) { | |
| 9085 propagatedType = ((propagatedElement as MethodElement)).type; | |
| 9086 } else if (propagatedElement is PropertyAccessorElement) { | |
| 9087 propagatedType = getType(propagatedElement as PropertyAccessorElement, nod
e.prefix.staticType); | |
| 9088 } else if (propagatedElement is ExecutableElement) { | |
| 9089 propagatedType = ((propagatedElement as ExecutableElement)).type; | |
| 9090 } else if (propagatedElement is TypeParameterElement) { | |
| 9091 propagatedType = ((propagatedElement as TypeParameterElement)).type; | |
| 9092 } else if (propagatedElement is VariableElement) { | |
| 9093 propagatedType = ((propagatedElement as VariableElement)).type; | |
| 9094 } | |
| 9095 Type2 overriddenType = _overrideManager.getType(propagatedElement); | |
| 9096 if (propagatedType == null || (overriddenType != null && overriddenType.isMo
reSpecificThan(propagatedType))) { | |
| 9097 propagatedType = overriddenType; | |
| 9098 } | |
| 9099 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType))
{ | |
| 9100 recordPropagatedType2(prefixedIdentifier, propagatedType); | |
| 9101 recordPropagatedType2(node, propagatedType); | |
| 9102 } | |
| 9103 return null; | |
| 9104 } | |
| 9105 | |
| 9106 /** | |
| 9107 * The Dart Language Specification, 12.27: <blockquote>A unary expression <i>u
</i> of the form | |
| 9108 * <i>op e</i> is equivalent to a method invocation <i>expression e.op()</i>.
An expression of the | |
| 9109 * form <i>op super</i> is equivalent to the method invocation <i>super.op()<i
>.</blockquote> | |
| 9110 */ | |
| 9111 Object visitPrefixExpression(PrefixExpression node) { | |
| 9112 sc.TokenType operator = node.operator.type; | |
| 9113 if (identical(operator, sc.TokenType.BANG)) { | |
| 9114 recordStaticType(node, _typeProvider.boolType); | |
| 9115 } else { | |
| 9116 ExecutableElement staticMethodElement = node.staticElement; | |
| 9117 Type2 staticType = computeStaticReturnType(staticMethodElement); | |
| 9118 if (identical(operator, sc.TokenType.MINUS_MINUS) || identical(operator, s
c.TokenType.PLUS_PLUS)) { | |
| 9119 Type2 intType = _typeProvider.intType; | |
| 9120 if (identical(getStaticType(node.operand), intType)) { | |
| 9121 staticType = intType; | |
| 9122 } | |
| 9123 } | |
| 9124 recordStaticType(node, staticType); | |
| 9125 MethodElement propagatedMethodElement = node.propagatedElement; | |
| 9126 if (propagatedMethodElement != staticMethodElement) { | |
| 9127 Type2 propagatedType = computeStaticReturnType(propagatedMethodElement); | |
| 9128 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticTy
pe)) { | |
| 9129 recordPropagatedType2(node, propagatedType); | |
| 9130 } | |
| 9131 } | |
| 9132 } | |
| 9133 return null; | |
| 9134 } | |
| 9135 | |
| 9136 /** | |
| 9137 * The Dart Language Specification, 12.13: <blockquote> Property extraction al
lows for a member of | |
| 9138 * an object to be concisely extracted from the object. If <i>o</i> is an obje
ct, and if <i>m</i> | |
| 9139 * is the name of a method member of <i>o</i>, then | |
| 9140 * | |
| 9141 * * <i>o.m</i> is defined to be equivalent to: <i>(r<sub>1</sub>, …, r
<sub>n</sub>, | |
| 9142 * {p<sub>1</sub> : d<sub>1</sub>, …, p<sub>k</sub> : d<sub>k</sub>}){r
eturn | |
| 9143 * o.m(r<sub>1</sub>, …, r<sub>n</sub>, p<sub>1</sub>: p<sub>1</sub>, &
hellip;, | |
| 9144 * p<sub>k</sub>: p<sub>k</sub>);}</i> if <i>m</i> has required parameters <i>
r<sub>1</sub>, | |
| 9145 * …, r<sub>n</sub></i>, and named parameters <i>p<sub>1</sub> …
p<sub>k</sub></i> | |
| 9146 * with defaults <i>d<sub>1</sub>, …, d<sub>k</sub></i>. | |
| 9147 * * <i>(r<sub>1</sub>, …, r<sub>n</sub>, [p<sub>1</sub> = d<sub>1</sub
>, …, | |
| 9148 * p<sub>k</sub> = d<sub>k</sub>]){return o.m(r<sub>1</sub>, …, r<sub>n
</sub>, | |
| 9149 * p<sub>1</sub>, …, p<sub>k</sub>);}</i> if <i>m</i> has required para
meters | |
| 9150 * <i>r<sub>1</sub>, …, r<sub>n</sub></i>, and optional positional para
meters | |
| 9151 * <i>p<sub>1</sub> … p<sub>k</sub></i> with defaults <i>d<sub>1</sub>,
…, | |
| 9152 * d<sub>k</sub></i>. | |
| 9153 * | |
| 9154 * Otherwise, if <i>m</i> is the name of a getter member of <i>o</i> (declared
implicitly or | |
| 9155 * explicitly) then <i>o.m</i> evaluates to the result of invoking the getter.
</blockquote> | |
| 9156 * | |
| 9157 * The Dart Language Specification, 12.17: <blockquote> ... a getter invocatio
n <i>i</i> of the | |
| 9158 * form <i>e.m</i> ... | |
| 9159 * | |
| 9160 * Let <i>T</i> be the static type of <i>e</i>. It is a static type warning if
<i>T</i> does not | |
| 9161 * have a getter named <i>m</i>. | |
| 9162 * | |
| 9163 * The static type of <i>i</i> is the declared return type of <i>T.m</i>, if <
i>T.m</i> exists; | |
| 9164 * otherwise the static type of <i>i</i> is dynamic. | |
| 9165 * | |
| 9166 * ... a getter invocation <i>i</i> of the form <i>C.m</i> ... | |
| 9167 * | |
| 9168 * It is a static warning if there is no class <i>C</i> in the enclosing lexic
al scope of | |
| 9169 * <i>i</i>, or if <i>C</i> does not declare, implicitly or explicitly, a gett
er named <i>m</i>. | |
| 9170 * | |
| 9171 * The static type of <i>i</i> is the declared return type of <i>C.m</i> if it
exists or dynamic | |
| 9172 * otherwise. | |
| 9173 * | |
| 9174 * ... a top-level getter invocation <i>i</i> of the form <i>m</i>, where <i>m
</i> is an | |
| 9175 * identifier ... | |
| 9176 * | |
| 9177 * The static type of <i>i</i> is the declared return type of <i>m</i>.</block
quote> | |
| 9178 */ | |
| 9179 Object visitPropertyAccess(PropertyAccess node) { | |
| 9180 SimpleIdentifier propertyName = node.propertyName; | |
| 9181 Element element = propertyName.staticElement; | |
| 9182 Type2 staticType = _dynamicType; | |
| 9183 if (element is MethodElement) { | |
| 9184 staticType = ((element as MethodElement)).type; | |
| 9185 } else if (element is PropertyAccessorElement) { | |
| 9186 staticType = getType(element as PropertyAccessorElement, node.target != nu
ll ? getStaticType(node.target) : null); | |
| 9187 } else { | |
| 9188 } | |
| 9189 recordStaticType(propertyName, staticType); | |
| 9190 recordStaticType(node, staticType); | |
| 9191 Type2 propagatedType = _overrideManager.getType(element); | |
| 9192 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType))
{ | |
| 9193 recordPropagatedType2(node, propagatedType); | |
| 9194 } | |
| 9195 return null; | |
| 9196 } | |
| 9197 | |
| 9198 /** | |
| 9199 * The Dart Language Specification, 12.9: <blockquote>The static type of a ret
hrow expression is | |
| 9200 * bottom.</blockquote> | |
| 9201 */ | |
| 9202 Object visitRethrowExpression(RethrowExpression node) { | |
| 9203 recordStaticType(node, _typeProvider.bottomType); | |
| 9204 return null; | |
| 9205 } | |
| 9206 | |
| 9207 /** | |
| 9208 * The Dart Language Specification, 12.30: <blockquote>Evaluation of an identi
fier expression | |
| 9209 * <i>e</i> of the form <i>id</i> proceeds as follows: | |
| 9210 * | |
| 9211 * Let <i>d</i> be the innermost declaration in the enclosing lexical scope wh
ose name is | |
| 9212 * <i>id</i>. If no such declaration exists in the lexical scope, let <i>d</i>
be the declaration | |
| 9213 * of the inherited member named <i>id</i> if it exists. | |
| 9214 * | |
| 9215 * * If <i>d</i> is a class or type alias <i>T</i>, the value of <i>e</i> is t
he unique instance | |
| 9216 * of class `Type` reifying <i>T</i>. | |
| 9217 * * If <i>d</i> is a type parameter <i>T</i>, then the value of <i>e</i> is t
he value of the | |
| 9218 * actual type argument corresponding to <i>T</i> that was passed to the gener
ative constructor | |
| 9219 * that created the current binding of this. We are assured that this is well
defined, because if | |
| 9220 * we were in a static member the reference to <i>T</i> would be a compile-tim
e error. | |
| 9221 * * If <i>d</i> is a library variable then: | |
| 9222 * | |
| 9223 * * If <i>d</i> is of one of the forms <i>var v = e<sub>i</sub>;</i>, <i>T v
= | |
| 9224 * e<sub>i</sub>;</i>, <i>final v = e<sub>i</sub>;</i>, <i>final T v = e<sub>i
</sub>;</i>, and no | |
| 9225 * value has yet been stored into <i>v</i> then the initializer expression <i>
e<sub>i</sub></i> is | |
| 9226 * evaluated. If, during the evaluation of <i>e<sub>i</sub></i>, the getter fo
r <i>v</i> is | |
| 9227 * referenced, a CyclicInitializationError is thrown. If the evaluation succee
ded yielding an | |
| 9228 * object <i>o</i>, let <i>r = o</i>, otherwise let <i>r = null</i>. In any ca
se, <i>r</i> is | |
| 9229 * stored into <i>v</i>. The value of <i>e</i> is <i>r</i>. | |
| 9230 * * If <i>d</i> is of one of the forms <i>const v = e;</i> or <i>const T v =
e;</i> the result | |
| 9231 * of the getter is the value of the compile time constant <i>e</i>. Otherwise | |
| 9232 * * <i>e</i> evaluates to the current binding of <i>id</i>. | |
| 9233 * | |
| 9234 * * If <i>d</i> is a local variable or formal parameter then <i>e</i> evaluat
es to the current | |
| 9235 * binding of <i>id</i>. | |
| 9236 * * If <i>d</i> is a static method, top level function or local function then
<i>e</i> | |
| 9237 * evaluates to the function defined by <i>d</i>. | |
| 9238 * * If <i>d</i> is the declaration of a static variable or static getter decl
ared in class | |
| 9239 * <i>C</i>, then <i>e</i> is equivalent to the getter invocation <i>C.id</i>. | |
| 9240 * * If <i>d</i> is the declaration of a top level getter, then <i>e</i> is eq
uivalent to the | |
| 9241 * getter invocation <i>id</i>. | |
| 9242 * * Otherwise, if <i>e</i> occurs inside a top level or static function (be i
t function, | |
| 9243 * method, getter, or setter) or variable initializer, evaluation of e causes
a NoSuchMethodError | |
| 9244 * to be thrown. | |
| 9245 * * Otherwise <i>e</i> is equivalent to the property extraction <i>this.id</i
>. | |
| 9246 * | |
| 9247 * </blockquote> | |
| 9248 */ | |
| 9249 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 9250 Element element = node.staticElement; | |
| 9251 Type2 staticType = _dynamicType; | |
| 9252 if (element is ClassElement) { | |
| 9253 if (isNotTypeLiteral(node)) { | |
| 9254 staticType = ((element as ClassElement)).type; | |
| 9255 } else { | |
| 9256 staticType = _typeProvider.typeType; | |
| 9257 } | |
| 9258 } else if (element is FunctionTypeAliasElement) { | |
| 9259 staticType = ((element as FunctionTypeAliasElement)).type; | |
| 9260 } else if (element is MethodElement) { | |
| 9261 staticType = ((element as MethodElement)).type; | |
| 9262 } else if (element is PropertyAccessorElement) { | |
| 9263 staticType = getType(element as PropertyAccessorElement, null); | |
| 9264 } else if (element is ExecutableElement) { | |
| 9265 staticType = ((element as ExecutableElement)).type; | |
| 9266 } else if (element is TypeParameterElement) { | |
| 9267 staticType = ((element as TypeParameterElement)).type; | |
| 9268 } else if (element is VariableElement) { | |
| 9269 VariableElement variable = element as VariableElement; | |
| 9270 staticType = _promoteManager.getStaticType(variable); | |
| 9271 } else if (element is PrefixElement) { | |
| 9272 return null; | |
| 9273 } else { | |
| 9274 staticType = _dynamicType; | |
| 9275 } | |
| 9276 recordStaticType(node, staticType); | |
| 9277 Type2 propagatedType = _overrideManager.getType(element); | |
| 9278 if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType))
{ | |
| 9279 recordPropagatedType2(node, propagatedType); | |
| 9280 } | |
| 9281 return null; | |
| 9282 } | |
| 9283 | |
| 9284 /** | |
| 9285 * The Dart Language Specification, 12.5: <blockquote>The static type of a str
ing literal is | |
| 9286 * `String`.</blockquote> | |
| 9287 */ | |
| 9288 Object visitSimpleStringLiteral(SimpleStringLiteral node) { | |
| 9289 recordStaticType(node, _typeProvider.stringType); | |
| 9290 return null; | |
| 9291 } | |
| 9292 | |
| 9293 /** | |
| 9294 * The Dart Language Specification, 12.5: <blockquote>The static type of a str
ing literal is | |
| 9295 * `String`.</blockquote> | |
| 9296 */ | |
| 9297 Object visitStringInterpolation(StringInterpolation node) { | |
| 9298 recordStaticType(node, _typeProvider.stringType); | |
| 9299 return null; | |
| 9300 } | |
| 9301 Object visitSuperExpression(SuperExpression node) { | |
| 9302 if (_thisType == null) { | |
| 9303 recordStaticType(node, _dynamicType); | |
| 9304 } else { | |
| 9305 recordStaticType(node, _thisType); | |
| 9306 } | |
| 9307 return null; | |
| 9308 } | |
| 9309 Object visitSymbolLiteral(SymbolLiteral node) { | |
| 9310 recordStaticType(node, _typeProvider.symbolType); | |
| 9311 return null; | |
| 9312 } | |
| 9313 | |
| 9314 /** | |
| 9315 * The Dart Language Specification, 12.10: <blockquote>The static type of `thi
s` is the | |
| 9316 * interface of the immediately enclosing class.</blockquote> | |
| 9317 */ | |
| 9318 Object visitThisExpression(ThisExpression node) { | |
| 9319 if (_thisType == null) { | |
| 9320 recordStaticType(node, _dynamicType); | |
| 9321 } else { | |
| 9322 recordStaticType(node, _thisType); | |
| 9323 } | |
| 9324 return null; | |
| 9325 } | |
| 9326 | |
| 9327 /** | |
| 9328 * The Dart Language Specification, 12.8: <blockquote>The static type of a thr
ow expression is | |
| 9329 * bottom.</blockquote> | |
| 9330 */ | |
| 9331 Object visitThrowExpression(ThrowExpression node) { | |
| 9332 recordStaticType(node, _typeProvider.bottomType); | |
| 9333 return null; | |
| 9334 } | |
| 9335 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 9336 Expression initializer = node.initializer; | |
| 9337 if (initializer != null) { | |
| 9338 Type2 rightType = initializer.bestType; | |
| 9339 SimpleIdentifier name = node.name; | |
| 9340 recordPropagatedType2(name, rightType); | |
| 9341 VariableElement element = name.staticElement as VariableElement; | |
| 9342 if (element != null) { | |
| 9343 _resolver.override2(element, rightType); | |
| 9344 } | |
| 9345 } | |
| 9346 return null; | |
| 9347 } | |
| 9348 | |
| 9349 /** | |
| 9350 * Record that the static type of the given node is the type of the second arg
ument to the method | |
| 9351 * represented by the given element. | |
| 9352 * | |
| 9353 * @param element the element representing the method invoked by the given nod
e | |
| 9354 */ | |
| 9355 Type2 computeArgumentType(ExecutableElement element) { | |
| 9356 if (element != null) { | |
| 9357 List<ParameterElement> parameters = element.parameters; | |
| 9358 if (parameters != null && parameters.length == 2) { | |
| 9359 return parameters[1].type; | |
| 9360 } | |
| 9361 } | |
| 9362 return _dynamicType; | |
| 9363 } | |
| 9364 | |
| 9365 /** | |
| 9366 * Compute the propagated return type of the method or function represented by
the given element. | |
| 9367 * | |
| 9368 * @param element the element representing the method or function invoked by t
he given node | |
| 9369 * @return the propagated return type that was computed | |
| 9370 */ | |
| 9371 Type2 computePropagatedReturnType(Element element) { | |
| 9372 if (element is ExecutableElement) { | |
| 9373 return _propagatedReturnTypes[element]; | |
| 9374 } | |
| 9375 return null; | |
| 9376 } | |
| 9377 | |
| 9378 /** | |
| 9379 * Given a function body, compute the propagated return type of the function.
The propagated | |
| 9380 * return type of functions with a block body is the least upper bound of all | |
| 9381 * [ReturnStatement] expressions, with an expression body it is the type of th
e expression. | |
| 9382 * | |
| 9383 * @param body the boy of the function whose propagated return type is to be c
omputed | |
| 9384 * @return the propagated return type that was computed | |
| 9385 */ | |
| 9386 Type2 computePropagatedReturnType2(FunctionBody body) { | |
| 9387 if (body is ExpressionFunctionBody) { | |
| 9388 ExpressionFunctionBody expressionBody = body as ExpressionFunctionBody; | |
| 9389 return expressionBody.expression.bestType; | |
| 9390 } | |
| 9391 if (body is BlockFunctionBody) { | |
| 9392 List<Type2> result = [null]; | |
| 9393 body.accept(new GeneralizingASTVisitor_9(result)); | |
| 9394 return result[0]; | |
| 9395 } | |
| 9396 return null; | |
| 9397 } | |
| 9398 | |
| 9399 /** | |
| 9400 * Compute the static return type of the method or function represented by the
given element. | |
| 9401 * | |
| 9402 * @param element the element representing the method or function invoked by t
he given node | |
| 9403 * @return the static return type that was computed | |
| 9404 */ | |
| 9405 Type2 computeStaticReturnType(Element element) { | |
| 9406 if (element is PropertyAccessorElement) { | |
| 9407 FunctionType propertyType = ((element as PropertyAccessorElement)).type; | |
| 9408 if (propertyType != null) { | |
| 9409 Type2 returnType = propertyType.returnType; | |
| 9410 if (returnType.isDartCoreFunction) { | |
| 9411 return _dynamicType; | |
| 9412 } else if (returnType is InterfaceType) { | |
| 9413 MethodElement callMethod = ((returnType as InterfaceType)).lookUpMetho
d(ElementResolver.CALL_METHOD_NAME, _resolver.definingLibrary); | |
| 9414 if (callMethod != null) { | |
| 9415 return callMethod.type.returnType; | |
| 9416 } | |
| 9417 } else if (returnType is FunctionType) { | |
| 9418 Type2 innerReturnType = ((returnType as FunctionType)).returnType; | |
| 9419 if (innerReturnType != null) { | |
| 9420 return innerReturnType; | |
| 9421 } | |
| 9422 } | |
| 9423 if (returnType != null) { | |
| 9424 return returnType; | |
| 9425 } | |
| 9426 } | |
| 9427 } else if (element is ExecutableElement) { | |
| 9428 FunctionType type = ((element as ExecutableElement)).type; | |
| 9429 if (type != null) { | |
| 9430 return type.returnType; | |
| 9431 } | |
| 9432 } else if (element is VariableElement) { | |
| 9433 VariableElement variable = element as VariableElement; | |
| 9434 Type2 variableType = _promoteManager.getStaticType(variable); | |
| 9435 if (variableType is FunctionType) { | |
| 9436 return ((variableType as FunctionType)).returnType; | |
| 9437 } | |
| 9438 } | |
| 9439 return _dynamicType; | |
| 9440 } | |
| 9441 | |
| 9442 /** | |
| 9443 * Given a function declaration, compute the return static type of the functio
n. The return type | |
| 9444 * of functions with a block body is `dynamicType`, with an expression body it
is the type | |
| 9445 * of the expression. | |
| 9446 * | |
| 9447 * @param node the function expression whose static return type is to be compu
ted | |
| 9448 * @return the static return type that was computed | |
| 9449 */ | |
| 9450 Type2 computeStaticReturnType2(FunctionDeclaration node) { | |
| 9451 TypeName returnType = node.returnType; | |
| 9452 if (returnType == null) { | |
| 9453 return _dynamicType; | |
| 9454 } | |
| 9455 return returnType.type; | |
| 9456 } | |
| 9457 | |
| 9458 /** | |
| 9459 * Given a function expression, compute the return type of the function. The r
eturn type of | |
| 9460 * functions with a block body is `dynamicType`, with an expression body it is
the type of | |
| 9461 * the expression. | |
| 9462 * | |
| 9463 * @param node the function expression whose return type is to be computed | |
| 9464 * @return the return type that was computed | |
| 9465 */ | |
| 9466 Type2 computeStaticReturnType3(FunctionExpression node) { | |
| 9467 FunctionBody body = node.body; | |
| 9468 if (body is ExpressionFunctionBody) { | |
| 9469 return getStaticType(((body as ExpressionFunctionBody)).expression); | |
| 9470 } | |
| 9471 return _dynamicType; | |
| 9472 } | |
| 9473 | |
| 9474 /** | |
| 9475 * If the given element name can be mapped to the name of a class defined with
in the given | |
| 9476 * library, return the type specified by the argument. | |
| 9477 * | |
| 9478 * @param library the library in which the specified type would be defined | |
| 9479 * @param elementName the name of the element for which a type is being sought | |
| 9480 * @param nameMap an optional map used to map the element name to a type name | |
| 9481 * @return the type specified by the first argument in the argument list | |
| 9482 */ | |
| 9483 Type2 getElementNameAsType(LibraryElement library, String elementName, Map<Str
ing, String> nameMap) { | |
| 9484 if (elementName != null) { | |
| 9485 if (nameMap != null) { | |
| 9486 elementName = nameMap[elementName.toLowerCase()]; | |
| 9487 } | |
| 9488 ClassElement returnType = library.getType(elementName); | |
| 9489 if (returnType != null) { | |
| 9490 return returnType.type; | |
| 9491 } | |
| 9492 } | |
| 9493 return null; | |
| 9494 } | |
| 9495 | |
| 9496 /** | |
| 9497 * If the given argument list contains at least one argument, and if the argum
ent is a simple | |
| 9498 * string literal, then parse that argument as a query string and return the t
ype specified by the | |
| 9499 * argument. | |
| 9500 * | |
| 9501 * @param library the library in which the specified type would be defined | |
| 9502 * @param argumentList the list of arguments from which a type is to be extrac
ted | |
| 9503 * @return the type specified by the first argument in the argument list | |
| 9504 */ | |
| 9505 Type2 getFirstArgumentAsQuery(LibraryElement library, ArgumentList argumentLis
t) { | |
| 9506 String argumentValue = getFirstArgumentAsString(argumentList); | |
| 9507 if (argumentValue != null) { | |
| 9508 if (argumentValue.contains(" ")) { | |
| 9509 return null; | |
| 9510 } | |
| 9511 String tag = argumentValue; | |
| 9512 tag = StringUtilities.substringBefore(tag, ":"); | |
| 9513 tag = StringUtilities.substringBefore(tag, "["); | |
| 9514 tag = StringUtilities.substringBefore(tag, "."); | |
| 9515 tag = StringUtilities.substringBefore(tag, "#"); | |
| 9516 tag = _HTML_ELEMENT_TO_CLASS_MAP[tag.toLowerCase()]; | |
| 9517 ClassElement returnType = library.getType(tag); | |
| 9518 if (returnType != null) { | |
| 9519 return returnType.type; | |
| 9520 } | |
| 9521 } | |
| 9522 return null; | |
| 9523 } | |
| 9524 | |
| 9525 /** | |
| 9526 * If the given argument list contains at least one argument, and if the argum
ent is a simple | |
| 9527 * string literal, return the String value of the argument. | |
| 9528 * | |
| 9529 * @param argumentList the list of arguments from which a string value is to b
e extracted | |
| 9530 * @return the string specified by the first argument in the argument list | |
| 9531 */ | |
| 9532 String getFirstArgumentAsString(ArgumentList argumentList) { | |
| 9533 NodeList<Expression> arguments = argumentList.arguments; | |
| 9534 if (arguments.length > 0) { | |
| 9535 Expression argument = arguments[0]; | |
| 9536 if (argument is SimpleStringLiteral) { | |
| 9537 return ((argument as SimpleStringLiteral)).value; | |
| 9538 } | |
| 9539 } | |
| 9540 return null; | |
| 9541 } | |
| 9542 | |
| 9543 /** | |
| 9544 * If the given argument list contains at least one argument, and if the argum
ent is a simple | |
| 9545 * string literal, and if the value of the argument is the name of a class def
ined within the | |
| 9546 * given library, return the type specified by the argument. | |
| 9547 * | |
| 9548 * @param library the library in which the specified type would be defined | |
| 9549 * @param argumentList the list of arguments from which a type is to be extrac
ted | |
| 9550 * @return the type specified by the first argument in the argument list | |
| 9551 */ | |
| 9552 Type2 getFirstArgumentAsType(LibraryElement library, ArgumentList argumentList
) => getFirstArgumentAsType2(library, argumentList, null); | |
| 9553 | |
| 9554 /** | |
| 9555 * If the given argument list contains at least one argument, and if the argum
ent is a simple | |
| 9556 * string literal, and if the value of the argument is the name of a class def
ined within the | |
| 9557 * given library, return the type specified by the argument. | |
| 9558 * | |
| 9559 * @param library the library in which the specified type would be defined | |
| 9560 * @param argumentList the list of arguments from which a type is to be extrac
ted | |
| 9561 * @param nameMap an optional map used to map the element name to a type name | |
| 9562 * @return the type specified by the first argument in the argument list | |
| 9563 */ | |
| 9564 Type2 getFirstArgumentAsType2(LibraryElement library, ArgumentList argumentLis
t, Map<String, String> nameMap) => getElementNameAsType(library, getFirstArgumen
tAsString(argumentList), nameMap); | |
| 9565 | |
| 9566 /** | |
| 9567 * Return the static type of the given expression. | |
| 9568 * | |
| 9569 * @param expression the expression whose type is to be returned | |
| 9570 * @return the static type of the given expression | |
| 9571 */ | |
| 9572 Type2 getStaticType(Expression expression) { | |
| 9573 Type2 type = expression.staticType; | |
| 9574 if (type == null) { | |
| 9575 return _dynamicType; | |
| 9576 } | |
| 9577 return type; | |
| 9578 } | |
| 9579 | |
| 9580 /** | |
| 9581 * Return the type that should be recorded for a node that resolved to the giv
en accessor. | |
| 9582 * | |
| 9583 * @param accessor the accessor that the node resolved to | |
| 9584 * @param context if the accessor element has context [by being the RHS of a | |
| 9585 * [PrefixedIdentifier] or [PropertyAccess]], and the return type of
the | |
| 9586 * accessor is a parameter type, then the type of the LHS can be used
to get more | |
| 9587 * specific type information | |
| 9588 * @return the type that should be recorded for a node that resolved to the gi
ven accessor | |
| 9589 */ | |
| 9590 Type2 getType(PropertyAccessorElement accessor, Type2 context) { | |
| 9591 FunctionType functionType = accessor.type; | |
| 9592 if (functionType == null) { | |
| 9593 return _dynamicType; | |
| 9594 } | |
| 9595 if (accessor.isSetter) { | |
| 9596 List<Type2> parameterTypes = functionType.normalParameterTypes; | |
| 9597 if (parameterTypes != null && parameterTypes.length > 0) { | |
| 9598 return parameterTypes[0]; | |
| 9599 } | |
| 9600 PropertyAccessorElement getter = accessor.variable.getter; | |
| 9601 if (getter != null) { | |
| 9602 functionType = getter.type; | |
| 9603 if (functionType != null) { | |
| 9604 return functionType.returnType; | |
| 9605 } | |
| 9606 } | |
| 9607 return _dynamicType; | |
| 9608 } | |
| 9609 Type2 returnType = functionType.returnType; | |
| 9610 if (returnType is TypeParameterType && context is InterfaceType) { | |
| 9611 InterfaceType interfaceTypeContext = context as InterfaceType; | |
| 9612 List<TypeParameterElement> typeParameterElements = interfaceTypeContext.el
ement != null ? interfaceTypeContext.element.typeParameters : null; | |
| 9613 if (typeParameterElements != null) { | |
| 9614 for (int i = 0; i < typeParameterElements.length; i++) { | |
| 9615 TypeParameterElement typeParameterElement = typeParameterElements[i]; | |
| 9616 if (returnType.name == typeParameterElement.name) { | |
| 9617 return interfaceTypeContext.typeArguments[i]; | |
| 9618 } | |
| 9619 } | |
| 9620 } | |
| 9621 } | |
| 9622 return returnType; | |
| 9623 } | |
| 9624 | |
| 9625 /** | |
| 9626 * Return the type represented by the given type name. | |
| 9627 * | |
| 9628 * @param typeName the type name representing the type to be returned | |
| 9629 * @return the type represented by the type name | |
| 9630 */ | |
| 9631 Type2 getType2(TypeName typeName) { | |
| 9632 Type2 type = typeName.type; | |
| 9633 if (type == null) { | |
| 9634 return _dynamicType; | |
| 9635 } | |
| 9636 return type; | |
| 9637 } | |
| 9638 | |
| 9639 /** | |
| 9640 * Return `true` if the given [Type] is the `Future` form the 'dart:async' | |
| 9641 * library. | |
| 9642 */ | |
| 9643 bool isAsyncFutureType(Type2 type) => type is InterfaceType && type.name == "F
uture" && isAsyncLibrary(type.element.library); | |
| 9644 | |
| 9645 /** | |
| 9646 * Return `true` if the given library is the 'dart:async' library. | |
| 9647 * | |
| 9648 * @param library the library being tested | |
| 9649 * @return `true` if the library is 'dart:async' | |
| 9650 */ | |
| 9651 bool isAsyncLibrary(LibraryElement library) => library.name == "dart.async"; | |
| 9652 | |
| 9653 /** | |
| 9654 * Return `true` if the given library is the 'dart:html' library. | |
| 9655 * | |
| 9656 * @param library the library being tested | |
| 9657 * @return `true` if the library is 'dart:html' | |
| 9658 */ | |
| 9659 bool isHtmlLibrary(LibraryElement library) => library != null && "dart.dom.htm
l" == library.name; | |
| 9660 | |
| 9661 /** | |
| 9662 * Return `true` if the given node is not a type literal. | |
| 9663 * | |
| 9664 * @param node the node being tested | |
| 9665 * @return `true` if the given node is not a type literal | |
| 9666 */ | |
| 9667 bool isNotTypeLiteral(Identifier node) { | |
| 9668 ASTNode parent = node.parent; | |
| 9669 return parent is TypeName || (parent is PrefixedIdentifier && (parent.parent
is TypeName || identical(((parent as PrefixedIdentifier)).prefix, node))) || (p
arent is PropertyAccess && identical(((parent as PropertyAccess)).target, node))
|| (parent is MethodInvocation && identical(node, ((parent as MethodInvocation)
).target)); | |
| 9670 } | |
| 9671 | |
| 9672 /** | |
| 9673 * Given a function element and its body, compute and record the propagated re
turn type of the | |
| 9674 * function. | |
| 9675 * | |
| 9676 * @param functionElement the function element to record propagated return typ
e for | |
| 9677 * @param body the boy of the function whose propagated return type is to be c
omputed | |
| 9678 * @return the propagated return type that was computed, may be `null` if it i
s not more | |
| 9679 * specific than the static return type. | |
| 9680 */ | |
| 9681 void recordPropagatedType(ExecutableElement functionElement, FunctionBody body
) { | |
| 9682 Type2 propagatedReturnType = computePropagatedReturnType2(body); | |
| 9683 if (propagatedReturnType == null) { | |
| 9684 return; | |
| 9685 } | |
| 9686 if (propagatedReturnType.isBottom) { | |
| 9687 return; | |
| 9688 } | |
| 9689 Type2 staticReturnType = functionElement.returnType; | |
| 9690 if (!propagatedReturnType.isMoreSpecificThan(staticReturnType)) { | |
| 9691 return; | |
| 9692 } | |
| 9693 _propagatedReturnTypes[functionElement] = propagatedReturnType; | |
| 9694 } | |
| 9695 | |
| 9696 /** | |
| 9697 * Record that the propagated type of the given node is the given type. | |
| 9698 * | |
| 9699 * @param expression the node whose type is to be recorded | |
| 9700 * @param type the propagated type of the node | |
| 9701 */ | |
| 9702 void recordPropagatedType2(Expression expression, Type2 type) { | |
| 9703 if (type != null && !type.isDynamic) { | |
| 9704 expression.propagatedType = type; | |
| 9705 } | |
| 9706 } | |
| 9707 | |
| 9708 /** | |
| 9709 * Record that the static type of the given node is the given type. | |
| 9710 * | |
| 9711 * @param expression the node whose type is to be recorded | |
| 9712 * @param type the static type of the node | |
| 9713 */ | |
| 9714 void recordStaticType(Expression expression, Type2 type) { | |
| 9715 if (type == null) { | |
| 9716 expression.staticType = _dynamicType; | |
| 9717 } else { | |
| 9718 expression.staticType = type; | |
| 9719 } | |
| 9720 } | |
| 9721 | |
| 9722 /** | |
| 9723 * Attempts to make a better guess for the static type of the given binary exp
ression. | |
| 9724 * | |
| 9725 * @param node the binary expression to analyze | |
| 9726 * @param staticType the static type of the expression as resolved | |
| 9727 * @return the better type guess, or the same static type as given | |
| 9728 */ | |
| 9729 Type2 refineBinaryExpressionType(BinaryExpression node, Type2 staticType) { | |
| 9730 sc.TokenType operator = node.operator.type; | |
| 9731 if (identical(operator, sc.TokenType.AMPERSAND_AMPERSAND) || identical(opera
tor, sc.TokenType.BAR_BAR) || identical(operator, sc.TokenType.EQ_EQ) || identic
al(operator, sc.TokenType.BANG_EQ)) { | |
| 9732 return _typeProvider.boolType; | |
| 9733 } | |
| 9734 Type2 intType = _typeProvider.intType; | |
| 9735 if (getStaticType(node.leftOperand) == intType) { | |
| 9736 if (identical(operator, sc.TokenType.MINUS) || identical(operator, sc.Toke
nType.PERCENT) || identical(operator, sc.TokenType.PLUS) || identical(operator,
sc.TokenType.STAR)) { | |
| 9737 Type2 doubleType = _typeProvider.doubleType; | |
| 9738 if (getStaticType(node.rightOperand) == doubleType) { | |
| 9739 return doubleType; | |
| 9740 } | |
| 9741 } | |
| 9742 if (identical(operator, sc.TokenType.MINUS) || identical(operator, sc.Toke
nType.PERCENT) || identical(operator, sc.TokenType.PLUS) || identical(operator,
sc.TokenType.STAR) || identical(operator, sc.TokenType.TILDE_SLASH)) { | |
| 9743 if (getStaticType(node.rightOperand) == intType) { | |
| 9744 staticType = intType; | |
| 9745 } | |
| 9746 } | |
| 9747 } | |
| 9748 return staticType; | |
| 9749 } | |
| 9750 get thisType_J2DAccessor => _thisType; | |
| 9751 set thisType_J2DAccessor(__v) => _thisType = __v; | |
| 9752 } | |
| 9753 class GeneralizingASTVisitor_9 extends GeneralizingASTVisitor<Object> { | |
| 9754 List<Type2> result; | |
| 9755 GeneralizingASTVisitor_9(this.result) : super(); | |
| 9756 Object visitExpression(Expression node) => null; | |
| 9757 Object visitReturnStatement(ReturnStatement node) { | |
| 9758 Type2 type; | |
| 9759 Expression expression = node.expression; | |
| 9760 if (expression != null) { | |
| 9761 type = expression.bestType; | |
| 9762 } else { | |
| 9763 type = BottomTypeImpl.instance; | |
| 9764 } | |
| 9765 if (result[0] == null) { | |
| 9766 result[0] = type; | |
| 9767 } else { | |
| 9768 result[0] = result[0].getLeastUpperBound(type); | |
| 9769 } | |
| 9770 return null; | |
| 9771 } | |
| 9772 } | |
| 9773 /** | |
| 9774 * Instances of this class manage the knowledge of what the set of subtypes are
for a given type. | |
| 9775 */ | |
| 9776 class SubtypeManager { | |
| 9777 | |
| 9778 /** | |
| 9779 * A map between [ClassElement]s and a set of [ClassElement]s that are subtype
s of the | |
| 9780 * key. | |
| 9781 */ | |
| 9782 Map<ClassElement, Set<ClassElement>> _subtypeMap = new Map<ClassElement, Set<C
lassElement>>(); | |
| 9783 | |
| 9784 /** | |
| 9785 * The set of all [LibraryElement]s that have been visited by the manager. Thi
s is used both | |
| 9786 * to prevent infinite loops in the recursive methods, and also as a marker fo
r the scope of the | |
| 9787 * libraries visited by this manager. | |
| 9788 */ | |
| 9789 Set<LibraryElement> _visitedLibraries = new Set<LibraryElement>(); | |
| 9790 | |
| 9791 /** | |
| 9792 * Given some [ClassElement], return the set of all subtypes, and subtypes of
subtypes. | |
| 9793 * | |
| 9794 * @param classElement the class to recursively return the set of subtypes of | |
| 9795 */ | |
| 9796 Set<ClassElement> computeAllSubtypes(ClassElement classElement) { | |
| 9797 computeSubtypesInLibrary(classElement.library); | |
| 9798 Set<ClassElement> allSubtypes = new Set<ClassElement>(); | |
| 9799 computeAllSubtypes2(classElement, new Set<ClassElement>(), allSubtypes); | |
| 9800 return allSubtypes; | |
| 9801 } | |
| 9802 | |
| 9803 /** | |
| 9804 * Given some [LibraryElement], visit all of the types in the library, the pas
sed library, | |
| 9805 * and any imported libraries, will be in the [visitedLibraries] set. | |
| 9806 * | |
| 9807 * @param libraryElement the library to visit, it it hasn't been visited alrea
dy | |
| 9808 */ | |
| 9809 void ensureLibraryVisited(LibraryElement libraryElement) { | |
| 9810 computeSubtypesInLibrary(libraryElement); | |
| 9811 } | |
| 9812 | |
| 9813 /** | |
| 9814 * Given some [ClassElement] and a [HashSet<ClassElement>], this method recurs
ively | |
| 9815 * adds all of the subtypes of the [ClassElement] to the passed array. | |
| 9816 * | |
| 9817 * @param classElement the type to compute the set of subtypes of | |
| 9818 * @param visitedClasses the set of class elements that this method has alread
y recursively seen | |
| 9819 * @param allSubtypes the computed set of subtypes of the passed class element | |
| 9820 */ | |
| 9821 void computeAllSubtypes2(ClassElement classElement, Set<ClassElement> visitedC
lasses, Set<ClassElement> allSubtypes) { | |
| 9822 if (!javaSetAdd(visitedClasses, classElement)) { | |
| 9823 return; | |
| 9824 } | |
| 9825 Set<ClassElement> subtypes = _subtypeMap[classElement]; | |
| 9826 if (subtypes == null) { | |
| 9827 return; | |
| 9828 } | |
| 9829 for (ClassElement subtype in subtypes) { | |
| 9830 computeAllSubtypes2(subtype, visitedClasses, allSubtypes); | |
| 9831 } | |
| 9832 allSubtypes.addAll(subtypes); | |
| 9833 } | |
| 9834 | |
| 9835 /** | |
| 9836 * Given some [ClassElement], this method adds all of the pairs combinations o
f itself and | |
| 9837 * all of its supertypes to the [subtypeMap] map. | |
| 9838 * | |
| 9839 * @param classElement the class element | |
| 9840 */ | |
| 9841 void computeSubtypesInClass(ClassElement classElement) { | |
| 9842 InterfaceType supertypeType = classElement.supertype; | |
| 9843 if (supertypeType != null) { | |
| 9844 ClassElement supertypeElement = supertypeType.element; | |
| 9845 if (supertypeElement != null) { | |
| 9846 putInSubtypeMap(supertypeElement, classElement); | |
| 9847 } | |
| 9848 } | |
| 9849 List<InterfaceType> interfaceTypes = classElement.interfaces; | |
| 9850 for (InterfaceType interfaceType in interfaceTypes) { | |
| 9851 ClassElement interfaceElement = interfaceType.element; | |
| 9852 if (interfaceElement != null) { | |
| 9853 putInSubtypeMap(interfaceElement, classElement); | |
| 9854 } | |
| 9855 } | |
| 9856 List<InterfaceType> mixinTypes = classElement.mixins; | |
| 9857 for (InterfaceType mixinType in mixinTypes) { | |
| 9858 ClassElement mixinElement = mixinType.element; | |
| 9859 if (mixinElement != null) { | |
| 9860 putInSubtypeMap(mixinElement, classElement); | |
| 9861 } | |
| 9862 } | |
| 9863 } | |
| 9864 | |
| 9865 /** | |
| 9866 * Given some [CompilationUnitElement], this method calls | |
| 9867 * [computeAllSubtypes] on all of the [ClassElement]s in the | |
| 9868 * compilation unit. | |
| 9869 * | |
| 9870 * @param unitElement the compilation unit element | |
| 9871 */ | |
| 9872 void computeSubtypesInCompilationUnit(CompilationUnitElement unitElement) { | |
| 9873 List<ClassElement> classElements = unitElement.types; | |
| 9874 for (ClassElement classElement in classElements) { | |
| 9875 computeSubtypesInClass(classElement); | |
| 9876 } | |
| 9877 } | |
| 9878 | |
| 9879 /** | |
| 9880 * Given some [LibraryElement], this method calls | |
| 9881 * [computeAllSubtypes] on all of the [ClassElement]s in the | |
| 9882 * compilation unit, and itself for all imported and exported libraries. All v
isited libraries are | |
| 9883 * added to the [visitedLibraries] set. | |
| 9884 * | |
| 9885 * @param libraryElement the library element | |
| 9886 */ | |
| 9887 void computeSubtypesInLibrary(LibraryElement libraryElement) { | |
| 9888 if (libraryElement == null || _visitedLibraries.contains(libraryElement)) { | |
| 9889 return; | |
| 9890 } | |
| 9891 javaSetAdd(_visitedLibraries, libraryElement); | |
| 9892 computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit); | |
| 9893 List<CompilationUnitElement> parts = libraryElement.parts; | |
| 9894 for (CompilationUnitElement part in parts) { | |
| 9895 computeSubtypesInCompilationUnit(part); | |
| 9896 } | |
| 9897 List<LibraryElement> imports = libraryElement.importedLibraries; | |
| 9898 for (LibraryElement importElt in imports) { | |
| 9899 computeSubtypesInLibrary(importElt.library); | |
| 9900 } | |
| 9901 List<LibraryElement> exports = libraryElement.exportedLibraries; | |
| 9902 for (LibraryElement exportElt in exports) { | |
| 9903 computeSubtypesInLibrary(exportElt.library); | |
| 9904 } | |
| 9905 } | |
| 9906 | |
| 9907 /** | |
| 9908 * Add some key/ value pair into the [subtypeMap] map. | |
| 9909 * | |
| 9910 * @param supertypeElement the key for the [subtypeMap] map | |
| 9911 * @param subtypeElement the value for the [subtypeMap] map | |
| 9912 */ | |
| 9913 void putInSubtypeMap(ClassElement supertypeElement, ClassElement subtypeElemen
t) { | |
| 9914 Set<ClassElement> subtypes = _subtypeMap[supertypeElement]; | |
| 9915 if (subtypes == null) { | |
| 9916 subtypes = new Set<ClassElement>(); | |
| 9917 _subtypeMap[supertypeElement] = subtypes; | |
| 9918 } | |
| 9919 javaSetAdd(subtypes, subtypeElement); | |
| 9920 } | |
| 9921 } | |
| 9922 /** | |
| 9923 * Instances of the class `TypeOverrideManager` manage the ability to override t
he type of an | |
| 9924 * element within a given context. | |
| 9925 */ | |
| 9926 class TypeOverrideManager { | |
| 9927 | |
| 9928 /** | |
| 9929 * The current override scope, or `null` if no scope has been entered. | |
| 9930 */ | |
| 9931 TypeOverrideManager_TypeOverrideScope _currentScope; | |
| 9932 | |
| 9933 /** | |
| 9934 * Apply a set of overrides that were previously captured. | |
| 9935 * | |
| 9936 * @param overrides the overrides to be applied | |
| 9937 */ | |
| 9938 void applyOverrides(Map<Element, Type2> overrides) { | |
| 9939 if (_currentScope == null) { | |
| 9940 throw new IllegalStateException("Cannot apply overrides without a scope"); | |
| 9941 } | |
| 9942 _currentScope.applyOverrides(overrides); | |
| 9943 } | |
| 9944 | |
| 9945 /** | |
| 9946 * Return a table mapping the elements whose type is overridden in the current
scope to the | |
| 9947 * overriding type. | |
| 9948 * | |
| 9949 * @return the overrides in the current scope | |
| 9950 */ | |
| 9951 Map<Element, Type2> captureLocalOverrides() { | |
| 9952 if (_currentScope == null) { | |
| 9953 throw new IllegalStateException("Cannot capture local overrides without a
scope"); | |
| 9954 } | |
| 9955 return _currentScope.captureLocalOverrides(); | |
| 9956 } | |
| 9957 | |
| 9958 /** | |
| 9959 * Return a map from the elements for the variables in the given list that hav
e their types | |
| 9960 * overridden to the overriding type. | |
| 9961 * | |
| 9962 * @param variableList the list of variables whose overriding types are to be
captured | |
| 9963 * @return a table mapping elements to their overriding types | |
| 9964 */ | |
| 9965 Map<Element, Type2> captureOverrides(VariableDeclarationList variableList) { | |
| 9966 if (_currentScope == null) { | |
| 9967 throw new IllegalStateException("Cannot capture overrides without a scope"
); | |
| 9968 } | |
| 9969 return _currentScope.captureOverrides(variableList); | |
| 9970 } | |
| 9971 | |
| 9972 /** | |
| 9973 * Enter a new override scope. | |
| 9974 */ | |
| 9975 void enterScope() { | |
| 9976 _currentScope = new TypeOverrideManager_TypeOverrideScope(_currentScope); | |
| 9977 } | |
| 9978 | |
| 9979 /** | |
| 9980 * Exit the current override scope. | |
| 9981 */ | |
| 9982 void exitScope() { | |
| 9983 if (_currentScope == null) { | |
| 9984 throw new IllegalStateException("No scope to exit"); | |
| 9985 } | |
| 9986 _currentScope = _currentScope._outerScope; | |
| 9987 } | |
| 9988 | |
| 9989 /** | |
| 9990 * Return the overridden type of the given element, or `null` if the type of t
he element has | |
| 9991 * not been overridden. | |
| 9992 * | |
| 9993 * @param element the element whose type might have been overridden | |
| 9994 * @return the overridden type of the given element | |
| 9995 */ | |
| 9996 Type2 getType(Element element) { | |
| 9997 if (_currentScope == null) { | |
| 9998 return null; | |
| 9999 } | |
| 10000 return _currentScope.getType(element); | |
| 10001 } | |
| 10002 | |
| 10003 /** | |
| 10004 * Set the overridden type of the given element to the given type | |
| 10005 * | |
| 10006 * @param element the element whose type might have been overridden | |
| 10007 * @param type the overridden type of the given element | |
| 10008 */ | |
| 10009 void setType(Element element, Type2 type) { | |
| 10010 if (_currentScope == null) { | |
| 10011 throw new IllegalStateException("Cannot override without a scope"); | |
| 10012 } | |
| 10013 _currentScope.setType(element, type); | |
| 10014 } | |
| 10015 } | |
| 10016 /** | |
| 10017 * Instances of the class `TypeOverrideScope` represent a scope in which the typ
es of | |
| 10018 * elements can be overridden. | |
| 10019 */ | |
| 10020 class TypeOverrideManager_TypeOverrideScope { | |
| 10021 | |
| 10022 /** | |
| 10023 * The outer scope in which types might be overridden. | |
| 10024 */ | |
| 10025 TypeOverrideManager_TypeOverrideScope _outerScope; | |
| 10026 | |
| 10027 /** | |
| 10028 * A table mapping elements to the overridden type of that element. | |
| 10029 */ | |
| 10030 Map<Element, Type2> _overridenTypes = new Map<Element, Type2>(); | |
| 10031 | |
| 10032 /** | |
| 10033 * Initialize a newly created scope to be an empty child of the given scope. | |
| 10034 * | |
| 10035 * @param outerScope the outer scope in which types might be overridden | |
| 10036 */ | |
| 10037 TypeOverrideManager_TypeOverrideScope(TypeOverrideManager_TypeOverrideScope ou
terScope) { | |
| 10038 this._outerScope = outerScope; | |
| 10039 } | |
| 10040 | |
| 10041 /** | |
| 10042 * Apply a set of overrides that were previously captured. | |
| 10043 * | |
| 10044 * @param overrides the overrides to be applied | |
| 10045 */ | |
| 10046 void applyOverrides(Map<Element, Type2> overrides) { | |
| 10047 for (MapEntry<Element, Type2> entry in getMapEntrySet(overrides)) { | |
| 10048 _overridenTypes[entry.getKey()] = entry.getValue(); | |
| 10049 } | |
| 10050 } | |
| 10051 | |
| 10052 /** | |
| 10053 * Return a table mapping the elements whose type is overridden in the current
scope to the | |
| 10054 * overriding type. | |
| 10055 * | |
| 10056 * @return the overrides in the current scope | |
| 10057 */ | |
| 10058 Map<Element, Type2> captureLocalOverrides() => _overridenTypes; | |
| 10059 | |
| 10060 /** | |
| 10061 * Return a map from the elements for the variables in the given list that hav
e their types | |
| 10062 * overridden to the overriding type. | |
| 10063 * | |
| 10064 * @param variableList the list of variables whose overriding types are to be
captured | |
| 10065 * @return a table mapping elements to their overriding types | |
| 10066 */ | |
| 10067 Map<Element, Type2> captureOverrides(VariableDeclarationList variableList) { | |
| 10068 Map<Element, Type2> overrides = new Map<Element, Type2>(); | |
| 10069 if (variableList.isConst || variableList.isFinal) { | |
| 10070 for (VariableDeclaration variable in variableList.variables) { | |
| 10071 Element element = variable.element; | |
| 10072 if (element != null) { | |
| 10073 Type2 type = _overridenTypes[element]; | |
| 10074 if (type != null) { | |
| 10075 overrides[element] = type; | |
| 10076 } | |
| 10077 } | |
| 10078 } | |
| 10079 } | |
| 10080 return overrides; | |
| 10081 } | |
| 10082 | |
| 10083 /** | |
| 10084 * Return the overridden type of the given element, or `null` if the type of t
he element | |
| 10085 * has not been overridden. | |
| 10086 * | |
| 10087 * @param element the element whose type might have been overridden | |
| 10088 * @return the overridden type of the given element | |
| 10089 */ | |
| 10090 Type2 getType(Element element) { | |
| 10091 Type2 type = _overridenTypes[element]; | |
| 10092 if (type == null && element is PropertyAccessorElement) { | |
| 10093 type = _overridenTypes[((element as PropertyAccessorElement)).variable]; | |
| 10094 } | |
| 10095 if (type != null) { | |
| 10096 return type; | |
| 10097 } else if (_outerScope != null) { | |
| 10098 return _outerScope.getType(element); | |
| 10099 } | |
| 10100 return null; | |
| 10101 } | |
| 10102 | |
| 10103 /** | |
| 10104 * Set the overridden type of the given element to the given type | |
| 10105 * | |
| 10106 * @param element the element whose type might have been overridden | |
| 10107 * @param type the overridden type of the given element | |
| 10108 */ | |
| 10109 void setType(Element element, Type2 type) { | |
| 10110 _overridenTypes[element] = type; | |
| 10111 } | |
| 10112 } | |
| 10113 /** | |
| 10114 * Instances of the class `TypePromotionManager` manage the ability to promote t
ypes of local | |
| 10115 * variables and formal parameters from their declared types based on control fl
ow. | |
| 10116 */ | |
| 10117 class TypePromotionManager { | |
| 10118 | |
| 10119 /** | |
| 10120 * The current promotion scope, or `null` if no scope has been entered. | |
| 10121 */ | |
| 10122 TypePromotionManager_TypePromoteScope _currentScope; | |
| 10123 | |
| 10124 /** | |
| 10125 * Enter a new promotions scope. | |
| 10126 */ | |
| 10127 void enterScope() { | |
| 10128 _currentScope = new TypePromotionManager_TypePromoteScope(_currentScope); | |
| 10129 } | |
| 10130 | |
| 10131 /** | |
| 10132 * Exit the current promotion scope. | |
| 10133 */ | |
| 10134 void exitScope() { | |
| 10135 if (_currentScope == null) { | |
| 10136 throw new IllegalStateException("No scope to exit"); | |
| 10137 } | |
| 10138 _currentScope = _currentScope._outerScope; | |
| 10139 } | |
| 10140 | |
| 10141 /** | |
| 10142 * Returns the elements with promoted types. | |
| 10143 */ | |
| 10144 Iterable<Element> get promotedElements => _currentScope.promotedElements; | |
| 10145 | |
| 10146 /** | |
| 10147 * Returns static type of the given variable - declared or promoted. | |
| 10148 * | |
| 10149 * @return the static type of the given variable - declared or promoted | |
| 10150 */ | |
| 10151 Type2 getStaticType(VariableElement variable) { | |
| 10152 Type2 staticType = getType(variable); | |
| 10153 if (staticType == null) { | |
| 10154 staticType = variable.type; | |
| 10155 } | |
| 10156 return staticType; | |
| 10157 } | |
| 10158 | |
| 10159 /** | |
| 10160 * Return the promoted type of the given element, or `null` if the type of the
element has | |
| 10161 * not been promoted. | |
| 10162 * | |
| 10163 * @param element the element whose type might have been promoted | |
| 10164 * @return the promoted type of the given element | |
| 10165 */ | |
| 10166 Type2 getType(Element element) { | |
| 10167 if (_currentScope == null) { | |
| 10168 return null; | |
| 10169 } | |
| 10170 return _currentScope.getType(element); | |
| 10171 } | |
| 10172 | |
| 10173 /** | |
| 10174 * Set the promoted type of the given element to the given type. | |
| 10175 * | |
| 10176 * @param element the element whose type might have been promoted | |
| 10177 * @param type the promoted type of the given element | |
| 10178 */ | |
| 10179 void setType(Element element, Type2 type) { | |
| 10180 if (_currentScope == null) { | |
| 10181 throw new IllegalStateException("Cannot promote without a scope"); | |
| 10182 } | |
| 10183 _currentScope.setType(element, type); | |
| 10184 } | |
| 10185 } | |
| 10186 /** | |
| 10187 * Instances of the class `TypePromoteScope` represent a scope in which the type
s of | |
| 10188 * elements can be promoted. | |
| 10189 */ | |
| 10190 class TypePromotionManager_TypePromoteScope { | |
| 10191 | |
| 10192 /** | |
| 10193 * The outer scope in which types might be promoter. | |
| 10194 */ | |
| 10195 TypePromotionManager_TypePromoteScope _outerScope; | |
| 10196 | |
| 10197 /** | |
| 10198 * A table mapping elements to the promoted type of that element. | |
| 10199 */ | |
| 10200 Map<Element, Type2> _promotedTypes = new Map<Element, Type2>(); | |
| 10201 | |
| 10202 /** | |
| 10203 * Initialize a newly created scope to be an empty child of the given scope. | |
| 10204 * | |
| 10205 * @param outerScope the outer scope in which types might be promoted | |
| 10206 */ | |
| 10207 TypePromotionManager_TypePromoteScope(TypePromotionManager_TypePromoteScope ou
terScope) { | |
| 10208 this._outerScope = outerScope; | |
| 10209 } | |
| 10210 | |
| 10211 /** | |
| 10212 * Returns the elements with promoted types. | |
| 10213 */ | |
| 10214 Iterable<Element> get promotedElements => _promotedTypes.keys.toSet(); | |
| 10215 | |
| 10216 /** | |
| 10217 * Return the promoted type of the given element, or `null` if the type of the
element has | |
| 10218 * not been promoted. | |
| 10219 * | |
| 10220 * @param element the element whose type might have been promoted | |
| 10221 * @return the promoted type of the given element | |
| 10222 */ | |
| 10223 Type2 getType(Element element) { | |
| 10224 Type2 type = _promotedTypes[element]; | |
| 10225 if (type == null && element is PropertyAccessorElement) { | |
| 10226 type = _promotedTypes[((element as PropertyAccessorElement)).variable]; | |
| 10227 } | |
| 10228 if (type != null) { | |
| 10229 return type; | |
| 10230 } else if (_outerScope != null) { | |
| 10231 return _outerScope.getType(element); | |
| 10232 } | |
| 10233 return null; | |
| 10234 } | |
| 10235 | |
| 10236 /** | |
| 10237 * Set the promoted type of the given element to the given type. | |
| 10238 * | |
| 10239 * @param element the element whose type might have been promoted | |
| 10240 * @param type the promoted type of the given element | |
| 10241 */ | |
| 10242 void setType(Element element, Type2 type) { | |
| 10243 _promotedTypes[element] = type; | |
| 10244 } | |
| 10245 } | |
| 10246 /** | |
| 10247 * The interface `TypeProvider` defines the behavior of objects that provide acc
ess to types | |
| 10248 * defined by the language. | |
| 10249 * | |
| 10250 * @coverage dart.engine.resolver | |
| 10251 */ | |
| 10252 abstract class TypeProvider { | |
| 10253 | |
| 10254 /** | |
| 10255 * Return the type representing the built-in type 'Null'. | |
| 10256 * | |
| 10257 * @return the type representing the built-in type 'null' | |
| 10258 */ | |
| 10259 InterfaceType get nullType; | |
| 10260 | |
| 10261 /** | |
| 10262 * Return the type representing the built-in type 'bool'. | |
| 10263 * | |
| 10264 * @return the type representing the built-in type 'bool' | |
| 10265 */ | |
| 10266 InterfaceType get boolType; | |
| 10267 | |
| 10268 /** | |
| 10269 * Return the type representing the type 'bottom'. | |
| 10270 * | |
| 10271 * @return the type representing the type 'bottom' | |
| 10272 */ | |
| 10273 Type2 get bottomType; | |
| 10274 | |
| 10275 /** | |
| 10276 * Return the type representing the built-in type 'double'. | |
| 10277 * | |
| 10278 * @return the type representing the built-in type 'double' | |
| 10279 */ | |
| 10280 InterfaceType get doubleType; | |
| 10281 | |
| 10282 /** | |
| 10283 * Return the type representing the built-in type 'dynamic'. | |
| 10284 * | |
| 10285 * @return the type representing the built-in type 'dynamic' | |
| 10286 */ | |
| 10287 Type2 get dynamicType; | |
| 10288 | |
| 10289 /** | |
| 10290 * Return the type representing the built-in type 'Function'. | |
| 10291 * | |
| 10292 * @return the type representing the built-in type 'Function' | |
| 10293 */ | |
| 10294 InterfaceType get functionType; | |
| 10295 | |
| 10296 /** | |
| 10297 * Return the type representing the built-in type 'int'. | |
| 10298 * | |
| 10299 * @return the type representing the built-in type 'int' | |
| 10300 */ | |
| 10301 InterfaceType get intType; | |
| 10302 | |
| 10303 /** | |
| 10304 * Return the type representing the built-in type 'List'. | |
| 10305 * | |
| 10306 * @return the type representing the built-in type 'List' | |
| 10307 */ | |
| 10308 InterfaceType get listType; | |
| 10309 | |
| 10310 /** | |
| 10311 * Return the type representing the built-in type 'Map'. | |
| 10312 * | |
| 10313 * @return the type representing the built-in type 'Map' | |
| 10314 */ | |
| 10315 InterfaceType get mapType; | |
| 10316 | |
| 10317 /** | |
| 10318 * Return the type representing the built-in type 'num'. | |
| 10319 * | |
| 10320 * @return the type representing the built-in type 'num' | |
| 10321 */ | |
| 10322 InterfaceType get numType; | |
| 10323 | |
| 10324 /** | |
| 10325 * Return the type representing the built-in type 'Object'. | |
| 10326 * | |
| 10327 * @return the type representing the built-in type 'Object' | |
| 10328 */ | |
| 10329 InterfaceType get objectType; | |
| 10330 | |
| 10331 /** | |
| 10332 * Return the type representing the built-in type 'StackTrace'. | |
| 10333 * | |
| 10334 * @return the type representing the built-in type 'StackTrace' | |
| 10335 */ | |
| 10336 InterfaceType get stackTraceType; | |
| 10337 | |
| 10338 /** | |
| 10339 * Return the type representing the built-in type 'String'. | |
| 10340 * | |
| 10341 * @return the type representing the built-in type 'String' | |
| 10342 */ | |
| 10343 InterfaceType get stringType; | |
| 10344 | |
| 10345 /** | |
| 10346 * Return the type representing the built-in type 'Symbol'. | |
| 10347 * | |
| 10348 * @return the type representing the built-in type 'Symbol' | |
| 10349 */ | |
| 10350 InterfaceType get symbolType; | |
| 10351 | |
| 10352 /** | |
| 10353 * Return the type representing the built-in type 'Type'. | |
| 10354 * | |
| 10355 * @return the type representing the built-in type 'Type' | |
| 10356 */ | |
| 10357 InterfaceType get typeType; | |
| 10358 } | |
| 10359 /** | |
| 10360 * Instances of the class `TypeProviderImpl` provide access to types defined by
the language | |
| 10361 * by looking for those types in the element model for the core library. | |
| 10362 * | |
| 10363 * @coverage dart.engine.resolver | |
| 10364 */ | |
| 10365 class TypeProviderImpl implements TypeProvider { | |
| 10366 | |
| 10367 /** | |
| 10368 * The type representing the built-in type 'bool'. | |
| 10369 */ | |
| 10370 InterfaceType _boolType; | |
| 10371 | |
| 10372 /** | |
| 10373 * The type representing the type 'bottom'. | |
| 10374 */ | |
| 10375 Type2 _bottomType; | |
| 10376 | |
| 10377 /** | |
| 10378 * The type representing the built-in type 'double'. | |
| 10379 */ | |
| 10380 InterfaceType _doubleType; | |
| 10381 | |
| 10382 /** | |
| 10383 * The type representing the built-in type 'dynamic'. | |
| 10384 */ | |
| 10385 Type2 _dynamicType; | |
| 10386 | |
| 10387 /** | |
| 10388 * The type representing the built-in type 'Function'. | |
| 10389 */ | |
| 10390 InterfaceType _functionType; | |
| 10391 | |
| 10392 /** | |
| 10393 * The type representing the built-in type 'int'. | |
| 10394 */ | |
| 10395 InterfaceType _intType; | |
| 10396 | |
| 10397 /** | |
| 10398 * The type representing the built-in type 'List'. | |
| 10399 */ | |
| 10400 InterfaceType _listType; | |
| 10401 | |
| 10402 /** | |
| 10403 * The type representing the built-in type 'Map'. | |
| 10404 */ | |
| 10405 InterfaceType _mapType; | |
| 10406 | |
| 10407 /** | |
| 10408 * The type representing the type 'Null'. | |
| 10409 */ | |
| 10410 InterfaceType _nullType; | |
| 10411 | |
| 10412 /** | |
| 10413 * The type representing the built-in type 'num'. | |
| 10414 */ | |
| 10415 InterfaceType _numType; | |
| 10416 | |
| 10417 /** | |
| 10418 * The type representing the built-in type 'Object'. | |
| 10419 */ | |
| 10420 InterfaceType _objectType; | |
| 10421 | |
| 10422 /** | |
| 10423 * The type representing the built-in type 'StackTrace'. | |
| 10424 */ | |
| 10425 InterfaceType _stackTraceType; | |
| 10426 | |
| 10427 /** | |
| 10428 * The type representing the built-in type 'String'. | |
| 10429 */ | |
| 10430 InterfaceType _stringType; | |
| 10431 | |
| 10432 /** | |
| 10433 * The type representing the built-in type 'Symbol'. | |
| 10434 */ | |
| 10435 InterfaceType _symbolType; | |
| 10436 | |
| 10437 /** | |
| 10438 * The type representing the built-in type 'Type'. | |
| 10439 */ | |
| 10440 InterfaceType _typeType; | |
| 10441 | |
| 10442 /** | |
| 10443 * Initialize a newly created type provider to provide the types defined in th
e given library. | |
| 10444 * | |
| 10445 * @param coreLibrary the element representing the core library (dart:core). | |
| 10446 */ | |
| 10447 TypeProviderImpl(LibraryElement coreLibrary) { | |
| 10448 initializeFrom(coreLibrary); | |
| 10449 } | |
| 10450 InterfaceType get boolType => _boolType; | |
| 10451 Type2 get bottomType => _bottomType; | |
| 10452 InterfaceType get doubleType => _doubleType; | |
| 10453 Type2 get dynamicType => _dynamicType; | |
| 10454 InterfaceType get functionType => _functionType; | |
| 10455 InterfaceType get intType => _intType; | |
| 10456 InterfaceType get listType => _listType; | |
| 10457 InterfaceType get mapType => _mapType; | |
| 10458 InterfaceType get nullType => _nullType; | |
| 10459 InterfaceType get numType => _numType; | |
| 10460 InterfaceType get objectType => _objectType; | |
| 10461 InterfaceType get stackTraceType => _stackTraceType; | |
| 10462 InterfaceType get stringType => _stringType; | |
| 10463 InterfaceType get symbolType => _symbolType; | |
| 10464 InterfaceType get typeType => _typeType; | |
| 10465 | |
| 10466 /** | |
| 10467 * Return the type with the given name from the given namespace, or `null` if
there is no | |
| 10468 * class with the given name. | |
| 10469 * | |
| 10470 * @param namespace the namespace in which to search for the given name | |
| 10471 * @param typeName the name of the type being searched for | |
| 10472 * @return the type that was found | |
| 10473 */ | |
| 10474 InterfaceType getType(Namespace namespace, String typeName) { | |
| 10475 Element element = namespace.get(typeName); | |
| 10476 if (element == null) { | |
| 10477 AnalysisEngine.instance.logger.logInformation("No definition of type ${typ
eName}"); | |
| 10478 return null; | |
| 10479 } | |
| 10480 return ((element as ClassElement)).type; | |
| 10481 } | |
| 10482 | |
| 10483 /** | |
| 10484 * Initialize the types provided by this type provider from the given library. | |
| 10485 * | |
| 10486 * @param library the library containing the definitions of the core types | |
| 10487 */ | |
| 10488 void initializeFrom(LibraryElement library) { | |
| 10489 Namespace namespace = new NamespaceBuilder().createPublicNamespace(library); | |
| 10490 _boolType = getType(namespace, "bool"); | |
| 10491 _bottomType = BottomTypeImpl.instance; | |
| 10492 _doubleType = getType(namespace, "double"); | |
| 10493 _dynamicType = DynamicTypeImpl.instance; | |
| 10494 _functionType = getType(namespace, "Function"); | |
| 10495 _intType = getType(namespace, "int"); | |
| 10496 _listType = getType(namespace, "List"); | |
| 10497 _mapType = getType(namespace, "Map"); | |
| 10498 _nullType = getType(namespace, "Null"); | |
| 10499 _numType = getType(namespace, "num"); | |
| 10500 _objectType = getType(namespace, "Object"); | |
| 10501 _stackTraceType = getType(namespace, "StackTrace"); | |
| 10502 _stringType = getType(namespace, "String"); | |
| 10503 _symbolType = getType(namespace, "Symbol"); | |
| 10504 _typeType = getType(namespace, "Type"); | |
| 10505 } | |
| 10506 } | |
| 10507 /** | |
| 10508 * Instances of the class `TypeResolverVisitor` are used to resolve the types as
sociated with | |
| 10509 * the elements in the element model. This includes the types of superclasses, m
ixins, interfaces, | |
| 10510 * fields, methods, parameters, and local variables. As a side-effect, this also
finishes building | |
| 10511 * the type hierarchy. | |
| 10512 * | |
| 10513 * @coverage dart.engine.resolver | |
| 10514 */ | |
| 10515 class TypeResolverVisitor extends ScopedVisitor { | |
| 10516 | |
| 10517 /** | |
| 10518 * @return `true` if the name of the given [TypeName] is an built-in identifie
r. | |
| 10519 */ | |
| 10520 static bool isBuiltInIdentifier(TypeName node) { | |
| 10521 sc.Token token = node.name.beginToken; | |
| 10522 return identical(token.type, sc.TokenType.KEYWORD); | |
| 10523 } | |
| 10524 | |
| 10525 /** | |
| 10526 * @return `true` if given [TypeName] is used as a type annotation. | |
| 10527 */ | |
| 10528 static bool isTypeAnnotation(TypeName node) { | |
| 10529 ASTNode parent = node.parent; | |
| 10530 if (parent is VariableDeclarationList) { | |
| 10531 return identical(((parent as VariableDeclarationList)).type, node); | |
| 10532 } | |
| 10533 if (parent is FieldFormalParameter) { | |
| 10534 return identical(((parent as FieldFormalParameter)).type, node); | |
| 10535 } | |
| 10536 if (parent is SimpleFormalParameter) { | |
| 10537 return identical(((parent as SimpleFormalParameter)).type, node); | |
| 10538 } | |
| 10539 return false; | |
| 10540 } | |
| 10541 | |
| 10542 /** | |
| 10543 * The type representing the type 'dynamic'. | |
| 10544 */ | |
| 10545 Type2 _dynamicType; | |
| 10546 | |
| 10547 /** | |
| 10548 * The flag specifying if currently visited class references 'super' expressio
n. | |
| 10549 */ | |
| 10550 bool _hasReferenceToSuper = false; | |
| 10551 | |
| 10552 /** | |
| 10553 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 10554 * | |
| 10555 * @param library the library containing the compilation unit being resolved | |
| 10556 * @param source the source representing the compilation unit being visited | |
| 10557 * @param typeProvider the object used to access the types from the core libra
ry | |
| 10558 */ | |
| 10559 TypeResolverVisitor.con1(Library library, Source source, TypeProvider typeProv
ider) : super.con1(library, source, typeProvider) { | |
| 10560 _dynamicType = typeProvider.dynamicType; | |
| 10561 } | |
| 10562 | |
| 10563 /** | |
| 10564 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 10565 * | |
| 10566 * @param definingLibrary the element for the library containing the compilati
on unit being | |
| 10567 * visited | |
| 10568 * @param source the source representing the compilation unit being visited | |
| 10569 * @param typeProvider the object used to access the types from the core libra
ry | |
| 10570 * @param errorListener the error listener that will be informed of any errors
that are found | |
| 10571 * during resolution | |
| 10572 */ | |
| 10573 TypeResolverVisitor.con2(LibraryElement definingLibrary, Source source, TypePr
ovider typeProvider, AnalysisErrorListener errorListener) : super.con2(definingL
ibrary, source, typeProvider, errorListener) { | |
| 10574 _dynamicType = typeProvider.dynamicType; | |
| 10575 } | |
| 10576 Object visitCatchClause(CatchClause node) { | |
| 10577 super.visitCatchClause(node); | |
| 10578 SimpleIdentifier exception = node.exceptionParameter; | |
| 10579 if (exception != null) { | |
| 10580 TypeName exceptionTypeName = node.exceptionType; | |
| 10581 Type2 exceptionType; | |
| 10582 if (exceptionTypeName == null) { | |
| 10583 exceptionType = typeProvider.dynamicType; | |
| 10584 } else { | |
| 10585 exceptionType = getType3(exceptionTypeName); | |
| 10586 } | |
| 10587 recordType(exception, exceptionType); | |
| 10588 Element element = exception.staticElement; | |
| 10589 if (element is VariableElementImpl) { | |
| 10590 ((element as VariableElementImpl)).type = exceptionType; | |
| 10591 } else { | |
| 10592 } | |
| 10593 } | |
| 10594 SimpleIdentifier stackTrace = node.stackTraceParameter; | |
| 10595 if (stackTrace != null) { | |
| 10596 recordType(stackTrace, typeProvider.stackTraceType); | |
| 10597 } | |
| 10598 return null; | |
| 10599 } | |
| 10600 Object visitClassDeclaration(ClassDeclaration node) { | |
| 10601 _hasReferenceToSuper = false; | |
| 10602 super.visitClassDeclaration(node); | |
| 10603 ClassElementImpl classElement = getClassElement(node.name); | |
| 10604 InterfaceType superclassType = null; | |
| 10605 ExtendsClause extendsClause = node.extendsClause; | |
| 10606 if (extendsClause != null) { | |
| 10607 ErrorCode errorCode = (node.withClause == null ? CompileTimeErrorCode.EXTE
NDS_NON_CLASS : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS) as ErrorCo
de; | |
| 10608 superclassType = resolveType(extendsClause.superclass, errorCode, errorCod
e); | |
| 10609 if (superclassType != typeProvider.objectType) { | |
| 10610 classElement.validMixin = false; | |
| 10611 } | |
| 10612 } | |
| 10613 if (classElement != null) { | |
| 10614 if (superclassType == null) { | |
| 10615 InterfaceType objectType = typeProvider.objectType; | |
| 10616 if (classElement.type != objectType) { | |
| 10617 superclassType = objectType; | |
| 10618 } | |
| 10619 } | |
| 10620 classElement.supertype = superclassType; | |
| 10621 classElement.hasReferenceToSuper2 = _hasReferenceToSuper; | |
| 10622 } | |
| 10623 resolve(classElement, node.withClause, node.implementsClause); | |
| 10624 return null; | |
| 10625 } | |
| 10626 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 10627 super.visitClassTypeAlias(node); | |
| 10628 ClassElementImpl classElement = getClassElement(node.name); | |
| 10629 ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS; | |
| 10630 InterfaceType superclassType = resolveType(node.superclass, errorCode, error
Code); | |
| 10631 if (superclassType == null) { | |
| 10632 superclassType = typeProvider.objectType; | |
| 10633 } | |
| 10634 if (classElement != null && superclassType != null) { | |
| 10635 classElement.supertype = superclassType; | |
| 10636 } | |
| 10637 resolve(classElement, node.withClause, node.implementsClause); | |
| 10638 return null; | |
| 10639 } | |
| 10640 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 10641 super.visitConstructorDeclaration(node); | |
| 10642 ExecutableElementImpl element = node.element as ExecutableElementImpl; | |
| 10643 ClassElement definingClass = element.enclosingElement as ClassElement; | |
| 10644 element.returnType = definingClass.type; | |
| 10645 FunctionTypeImpl type = new FunctionTypeImpl.con1(element); | |
| 10646 type.typeArguments = definingClass.type.typeArguments; | |
| 10647 element.type = type; | |
| 10648 return null; | |
| 10649 } | |
| 10650 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 10651 super.visitDeclaredIdentifier(node); | |
| 10652 Type2 declaredType; | |
| 10653 TypeName typeName = node.type; | |
| 10654 if (typeName == null) { | |
| 10655 declaredType = _dynamicType; | |
| 10656 } else { | |
| 10657 declaredType = getType3(typeName); | |
| 10658 } | |
| 10659 LocalVariableElementImpl element = node.element as LocalVariableElementImpl; | |
| 10660 element.type = declaredType; | |
| 10661 return null; | |
| 10662 } | |
| 10663 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 10664 super.visitDefaultFormalParameter(node); | |
| 10665 return null; | |
| 10666 } | |
| 10667 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 10668 super.visitFieldFormalParameter(node); | |
| 10669 Element element = node.identifier.staticElement; | |
| 10670 if (element is ParameterElementImpl) { | |
| 10671 ParameterElementImpl parameter = element as ParameterElementImpl; | |
| 10672 FormalParameterList parameterList = node.parameters; | |
| 10673 if (parameterList == null) { | |
| 10674 Type2 type; | |
| 10675 TypeName typeName = node.type; | |
| 10676 if (typeName == null) { | |
| 10677 type = _dynamicType; | |
| 10678 } else { | |
| 10679 type = getType3(typeName); | |
| 10680 } | |
| 10681 parameter.type = type; | |
| 10682 } else { | |
| 10683 setFunctionTypedParameterType(parameter, node.type, node.parameters); | |
| 10684 } | |
| 10685 } else { | |
| 10686 } | |
| 10687 return null; | |
| 10688 } | |
| 10689 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 10690 super.visitFunctionDeclaration(node); | |
| 10691 ExecutableElementImpl element = node.element as ExecutableElementImpl; | |
| 10692 element.returnType = computeReturnType(node.returnType); | |
| 10693 FunctionTypeImpl type = new FunctionTypeImpl.con1(element); | |
| 10694 ClassElement definingClass = element.getAncestor(ClassElement); | |
| 10695 if (definingClass != null) { | |
| 10696 type.typeArguments = definingClass.type.typeArguments; | |
| 10697 } | |
| 10698 element.type = type; | |
| 10699 return null; | |
| 10700 } | |
| 10701 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 10702 super.visitFunctionTypeAlias(node); | |
| 10703 FunctionTypeAliasElementImpl element = node.element as FunctionTypeAliasElem
entImpl; | |
| 10704 element.returnType = computeReturnType(node.returnType); | |
| 10705 return null; | |
| 10706 } | |
| 10707 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 10708 super.visitFunctionTypedFormalParameter(node); | |
| 10709 Element element = node.identifier.staticElement; | |
| 10710 if (element is ParameterElementImpl) { | |
| 10711 setFunctionTypedParameterType(element as ParameterElementImpl, node.return
Type, node.parameters); | |
| 10712 } else { | |
| 10713 } | |
| 10714 return null; | |
| 10715 } | |
| 10716 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 10717 super.visitMethodDeclaration(node); | |
| 10718 ExecutableElementImpl element = node.element as ExecutableElementImpl; | |
| 10719 element.returnType = computeReturnType(node.returnType); | |
| 10720 FunctionTypeImpl type = new FunctionTypeImpl.con1(element); | |
| 10721 ClassElement definingClass = element.getAncestor(ClassElement); | |
| 10722 if (definingClass != null) { | |
| 10723 type.typeArguments = definingClass.type.typeArguments; | |
| 10724 } | |
| 10725 element.type = type; | |
| 10726 if (element is PropertyAccessorElement) { | |
| 10727 PropertyAccessorElement accessor = element as PropertyAccessorElement; | |
| 10728 PropertyInducingElementImpl variable = accessor.variable as PropertyInduci
ngElementImpl; | |
| 10729 if (accessor.isGetter) { | |
| 10730 variable.type = type.returnType; | |
| 10731 } else if (variable.type == null) { | |
| 10732 List<Type2> parameterTypes = type.normalParameterTypes; | |
| 10733 if (parameterTypes != null && parameterTypes.length > 0) { | |
| 10734 variable.type = parameterTypes[0]; | |
| 10735 } | |
| 10736 } | |
| 10737 } | |
| 10738 return null; | |
| 10739 } | |
| 10740 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 10741 super.visitSimpleFormalParameter(node); | |
| 10742 Type2 declaredType; | |
| 10743 TypeName typeName = node.type; | |
| 10744 if (typeName == null) { | |
| 10745 declaredType = _dynamicType; | |
| 10746 } else { | |
| 10747 declaredType = getType3(typeName); | |
| 10748 } | |
| 10749 Element element = node.identifier.staticElement; | |
| 10750 if (element is ParameterElement) { | |
| 10751 ((element as ParameterElementImpl)).type = declaredType; | |
| 10752 } else { | |
| 10753 } | |
| 10754 return null; | |
| 10755 } | |
| 10756 Object visitSuperExpression(SuperExpression node) { | |
| 10757 _hasReferenceToSuper = true; | |
| 10758 return super.visitSuperExpression(node); | |
| 10759 } | |
| 10760 Object visitTypeName(TypeName node) { | |
| 10761 super.visitTypeName(node); | |
| 10762 Identifier typeName = node.name; | |
| 10763 TypeArgumentList argumentList = node.typeArguments; | |
| 10764 Element element = nameScope.lookup(typeName, definingLibrary); | |
| 10765 if (element == null) { | |
| 10766 if (typeName.name == this._dynamicType.name) { | |
| 10767 setElement(typeName, this._dynamicType.element); | |
| 10768 if (argumentList != null) { | |
| 10769 } | |
| 10770 typeName.staticType = this._dynamicType; | |
| 10771 node.type = this._dynamicType; | |
| 10772 return null; | |
| 10773 } | |
| 10774 VoidTypeImpl voidType = VoidTypeImpl.instance; | |
| 10775 if (typeName.name == voidType.name) { | |
| 10776 if (argumentList != null) { | |
| 10777 } | |
| 10778 typeName.staticType = voidType; | |
| 10779 node.type = voidType; | |
| 10780 return null; | |
| 10781 } | |
| 10782 ASTNode parent = node.parent; | |
| 10783 if (typeName is PrefixedIdentifier && parent is ConstructorName && argumen
tList == null) { | |
| 10784 ConstructorName name = parent as ConstructorName; | |
| 10785 if (name.name == null) { | |
| 10786 PrefixedIdentifier prefixedIdentifier = typeName as PrefixedIdentifier
; | |
| 10787 SimpleIdentifier prefix = prefixedIdentifier.prefix; | |
| 10788 element = nameScope.lookup(prefix, definingLibrary); | |
| 10789 if (element is PrefixElement) { | |
| 10790 if (parent.parent is InstanceCreationExpression && ((parent.parent a
s InstanceCreationExpression)).isConst) { | |
| 10791 reportError5(CompileTimeErrorCode.CONST_WITH_NON_TYPE, prefixedIde
ntifier.identifier, [prefixedIdentifier.identifier.name]); | |
| 10792 } else { | |
| 10793 reportError5(StaticWarningCode.NEW_WITH_NON_TYPE, prefixedIdentifi
er.identifier, [prefixedIdentifier.identifier.name]); | |
| 10794 } | |
| 10795 setElement(prefix, element); | |
| 10796 return null; | |
| 10797 } else if (element != null) { | |
| 10798 name.name = prefixedIdentifier.identifier; | |
| 10799 name.period = prefixedIdentifier.period; | |
| 10800 node.name = prefix; | |
| 10801 typeName = prefix; | |
| 10802 } | |
| 10803 } | |
| 10804 } | |
| 10805 } | |
| 10806 bool elementValid = element is! MultiplyDefinedElement; | |
| 10807 if (elementValid && element is! ClassElement && isTypeNameInInstanceCreation
Expression(node)) { | |
| 10808 SimpleIdentifier typeNameSimple = getTypeSimpleIdentifier(typeName); | |
| 10809 InstanceCreationExpression creation = node.parent.parent as InstanceCreati
onExpression; | |
| 10810 if (creation.isConst) { | |
| 10811 if (element == null) { | |
| 10812 reportError5(CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [ty
peName]); | |
| 10813 } else { | |
| 10814 reportError5(CompileTimeErrorCode.CONST_WITH_NON_TYPE, typeNameSimple,
[typeName]); | |
| 10815 } | |
| 10816 elementValid = false; | |
| 10817 } else { | |
| 10818 if (element != null) { | |
| 10819 reportError5(StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typ
eName]); | |
| 10820 elementValid = false; | |
| 10821 } | |
| 10822 } | |
| 10823 } | |
| 10824 if (elementValid && element == null) { | |
| 10825 SimpleIdentifier typeNameSimple = getTypeSimpleIdentifier(typeName); | |
| 10826 if (isBuiltInIdentifier(node) && isTypeAnnotation(node)) { | |
| 10827 reportError5(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, typeName,
[typeName.name]); | |
| 10828 } else if (typeNameSimple.name == "boolean") { | |
| 10829 reportError5(StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple,
[]); | |
| 10830 } else if (isTypeNameInCatchClause(node)) { | |
| 10831 reportError5(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [type
Name.name]); | |
| 10832 } else if (isTypeNameInAsExpression(node)) { | |
| 10833 reportError5(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.nam
e]); | |
| 10834 } else if (isTypeNameInIsExpression(node)) { | |
| 10835 reportError5(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.n
ame]); | |
| 10836 } else if (isTypeNameTargetInRedirectedConstructor(node)) { | |
| 10837 reportError5(StaticWarningCode.REDIRECT_TO_NON_CLASS, typeName, [typeNam
e.name]); | |
| 10838 } else if (isTypeNameInTypeArgumentList(node)) { | |
| 10839 reportError5(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName,
[typeName.name]); | |
| 10840 } else { | |
| 10841 reportError5(StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name
]); | |
| 10842 } | |
| 10843 elementValid = false; | |
| 10844 } | |
| 10845 if (!elementValid) { | |
| 10846 if (element is MultiplyDefinedElement) { | |
| 10847 setElement(typeName, element); | |
| 10848 } else { | |
| 10849 setElement(typeName, this._dynamicType.element); | |
| 10850 } | |
| 10851 typeName.staticType = this._dynamicType; | |
| 10852 node.type = this._dynamicType; | |
| 10853 return null; | |
| 10854 } | |
| 10855 Type2 type = null; | |
| 10856 if (element is ClassElement) { | |
| 10857 setElement(typeName, element); | |
| 10858 type = ((element as ClassElement)).type; | |
| 10859 } else if (element is FunctionTypeAliasElement) { | |
| 10860 setElement(typeName, element); | |
| 10861 type = ((element as FunctionTypeAliasElement)).type; | |
| 10862 } else if (element is TypeParameterElement) { | |
| 10863 setElement(typeName, element); | |
| 10864 type = ((element as TypeParameterElement)).type; | |
| 10865 if (argumentList != null) { | |
| 10866 } | |
| 10867 } else if (element is MultiplyDefinedElement) { | |
| 10868 List<Element> elements = ((element as MultiplyDefinedElement)).conflicting
Elements; | |
| 10869 type = getType(elements); | |
| 10870 if (type != null) { | |
| 10871 node.type = type; | |
| 10872 } | |
| 10873 } else { | |
| 10874 if (isTypeNameInCatchClause(node)) { | |
| 10875 reportError5(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [type
Name.name]); | |
| 10876 } else if (isTypeNameInAsExpression(node)) { | |
| 10877 reportError5(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.nam
e]); | |
| 10878 } else if (isTypeNameInIsExpression(node)) { | |
| 10879 reportError5(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.n
ame]); | |
| 10880 } else if (isTypeNameTargetInRedirectedConstructor(node)) { | |
| 10881 reportError5(StaticWarningCode.REDIRECT_TO_NON_CLASS, typeName, [typeNam
e.name]); | |
| 10882 } else if (isTypeNameInTypeArgumentList(node)) { | |
| 10883 reportError5(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName,
[typeName.name]); | |
| 10884 } else { | |
| 10885 ASTNode parent = typeName.parent; | |
| 10886 while (parent is TypeName) { | |
| 10887 parent = parent.parent; | |
| 10888 } | |
| 10889 if (parent is ExtendsClause || parent is ImplementsClause || parent is W
ithClause || parent is ClassTypeAlias) { | |
| 10890 } else { | |
| 10891 reportError5(StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]); | |
| 10892 } | |
| 10893 } | |
| 10894 setElement(typeName, this._dynamicType.element); | |
| 10895 typeName.staticType = this._dynamicType; | |
| 10896 node.type = this._dynamicType; | |
| 10897 return null; | |
| 10898 } | |
| 10899 if (argumentList != null) { | |
| 10900 NodeList<TypeName> arguments = argumentList.arguments; | |
| 10901 int argumentCount = arguments.length; | |
| 10902 List<Type2> parameters = getTypeArguments(type); | |
| 10903 int parameterCount = parameters.length; | |
| 10904 int count = Math.min(argumentCount, parameterCount); | |
| 10905 List<Type2> typeArguments = new List<Type2>(); | |
| 10906 for (int i = 0; i < count; i++) { | |
| 10907 Type2 argumentType = getType3(arguments[i]); | |
| 10908 if (argumentType != null) { | |
| 10909 typeArguments.add(argumentType); | |
| 10910 } | |
| 10911 } | |
| 10912 if (argumentCount != parameterCount) { | |
| 10913 reportError5(getInvalidTypeParametersErrorCode(node), node, [typeName.na
me, parameterCount, argumentCount]); | |
| 10914 } | |
| 10915 argumentCount = typeArguments.length; | |
| 10916 if (argumentCount < parameterCount) { | |
| 10917 for (int i = argumentCount; i < parameterCount; i++) { | |
| 10918 typeArguments.add(this._dynamicType); | |
| 10919 } | |
| 10920 } | |
| 10921 if (type is InterfaceTypeImpl) { | |
| 10922 InterfaceTypeImpl interfaceType = type as InterfaceTypeImpl; | |
| 10923 type = interfaceType.substitute4(new List.from(typeArguments)); | |
| 10924 } else if (type is FunctionTypeImpl) { | |
| 10925 FunctionTypeImpl functionType = type as FunctionTypeImpl; | |
| 10926 type = functionType.substitute3(new List.from(typeArguments)); | |
| 10927 } else { | |
| 10928 } | |
| 10929 } else { | |
| 10930 List<Type2> parameters = getTypeArguments(type); | |
| 10931 int parameterCount = parameters.length; | |
| 10932 if (parameterCount > 0) { | |
| 10933 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance; | |
| 10934 List<Type2> arguments = new List<Type2>(parameterCount); | |
| 10935 for (int i = 0; i < parameterCount; i++) { | |
| 10936 arguments[i] = dynamicType; | |
| 10937 } | |
| 10938 type = type.substitute2(arguments, parameters); | |
| 10939 } | |
| 10940 } | |
| 10941 typeName.staticType = type; | |
| 10942 node.type = type; | |
| 10943 return null; | |
| 10944 } | |
| 10945 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 10946 super.visitVariableDeclaration(node); | |
| 10947 Type2 declaredType; | |
| 10948 TypeName typeName = ((node.parent as VariableDeclarationList)).type; | |
| 10949 if (typeName == null) { | |
| 10950 declaredType = _dynamicType; | |
| 10951 } else { | |
| 10952 declaredType = getType3(typeName); | |
| 10953 } | |
| 10954 Element element = node.name.staticElement; | |
| 10955 if (element is VariableElement) { | |
| 10956 ((element as VariableElementImpl)).type = declaredType; | |
| 10957 if (element is PropertyInducingElement) { | |
| 10958 PropertyInducingElement variableElement = element as PropertyInducingEle
ment; | |
| 10959 PropertyAccessorElementImpl getter = variableElement.getter as PropertyA
ccessorElementImpl; | |
| 10960 getter.returnType = declaredType; | |
| 10961 FunctionTypeImpl getterType = new FunctionTypeImpl.con1(getter); | |
| 10962 ClassElement definingClass = element.getAncestor(ClassElement); | |
| 10963 if (definingClass != null) { | |
| 10964 getterType.typeArguments = definingClass.type.typeArguments; | |
| 10965 } | |
| 10966 getter.type = getterType; | |
| 10967 PropertyAccessorElementImpl setter = variableElement.setter as PropertyA
ccessorElementImpl; | |
| 10968 if (setter != null) { | |
| 10969 List<ParameterElement> parameters = setter.parameters; | |
| 10970 if (parameters.length > 0) { | |
| 10971 ((parameters[0] as ParameterElementImpl)).type = declaredType; | |
| 10972 } | |
| 10973 setter.returnType = VoidTypeImpl.instance; | |
| 10974 FunctionTypeImpl setterType = new FunctionTypeImpl.con1(setter); | |
| 10975 if (definingClass != null) { | |
| 10976 setterType.typeArguments = definingClass.type.typeArguments; | |
| 10977 } | |
| 10978 setter.type = setterType; | |
| 10979 } | |
| 10980 } | |
| 10981 } else { | |
| 10982 } | |
| 10983 return null; | |
| 10984 } | |
| 10985 | |
| 10986 /** | |
| 10987 * Given a type name representing the return type of a function, compute the r
eturn type of the | |
| 10988 * function. | |
| 10989 * | |
| 10990 * @param returnType the type name representing the return type of the functio
n | |
| 10991 * @return the return type that was computed | |
| 10992 */ | |
| 10993 Type2 computeReturnType(TypeName returnType) { | |
| 10994 if (returnType == null) { | |
| 10995 return _dynamicType; | |
| 10996 } else { | |
| 10997 return returnType.type; | |
| 10998 } | |
| 10999 } | |
| 11000 | |
| 11001 /** | |
| 11002 * Return the class element that represents the class whose name was provided. | |
| 11003 * | |
| 11004 * @param identifier the name from the declaration of a class | |
| 11005 * @return the class element that represents the class | |
| 11006 */ | |
| 11007 ClassElementImpl getClassElement(SimpleIdentifier identifier) { | |
| 11008 if (identifier == null) { | |
| 11009 return null; | |
| 11010 } | |
| 11011 Element element = identifier.staticElement; | |
| 11012 if (element is! ClassElementImpl) { | |
| 11013 return null; | |
| 11014 } | |
| 11015 return element as ClassElementImpl; | |
| 11016 } | |
| 11017 | |
| 11018 /** | |
| 11019 * Return an array containing all of the elements associated with the paramete
rs in the given | |
| 11020 * list. | |
| 11021 * | |
| 11022 * @param parameterList the list of parameters whose elements are to be return
ed | |
| 11023 * @return the elements associated with the parameters | |
| 11024 */ | |
| 11025 List<ParameterElement> getElements(FormalParameterList parameterList) { | |
| 11026 List<ParameterElement> elements = new List<ParameterElement>(); | |
| 11027 for (FormalParameter parameter in parameterList.parameters) { | |
| 11028 ParameterElement element = parameter.identifier.staticElement as Parameter
Element; | |
| 11029 if (element != null) { | |
| 11030 elements.add(element); | |
| 11031 } | |
| 11032 } | |
| 11033 return new List.from(elements); | |
| 11034 } | |
| 11035 | |
| 11036 /** | |
| 11037 * The number of type arguments in the given type name does not match the numb
er of parameters in | |
| 11038 * the corresponding class element. Return the error code that should be used
to report this | |
| 11039 * error. | |
| 11040 * | |
| 11041 * @param node the type name with the wrong number of type arguments | |
| 11042 * @return the error code that should be used to report that the wrong number
of type arguments | |
| 11043 * were provided | |
| 11044 */ | |
| 11045 ErrorCode getInvalidTypeParametersErrorCode(TypeName node) { | |
| 11046 ASTNode parent = node.parent; | |
| 11047 if (parent is ConstructorName) { | |
| 11048 parent = parent.parent; | |
| 11049 if (parent is InstanceCreationExpression) { | |
| 11050 if (((parent as InstanceCreationExpression)).isConst) { | |
| 11051 return CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS; | |
| 11052 } else { | |
| 11053 return StaticWarningCode.NEW_WITH_INVALID_TYPE_PARAMETERS; | |
| 11054 } | |
| 11055 } | |
| 11056 } | |
| 11057 return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS; | |
| 11058 } | |
| 11059 | |
| 11060 /** | |
| 11061 * Given the multiple elements to which a single name could potentially be res
olved, return the | |
| 11062 * single interface type that should be used, or `null` if there is no clear c
hoice. | |
| 11063 * | |
| 11064 * @param elements the elements to which a single name could potentially be re
solved | |
| 11065 * @return the single interface type that should be used for the type name | |
| 11066 */ | |
| 11067 InterfaceType getType(List<Element> elements) { | |
| 11068 InterfaceType type = null; | |
| 11069 for (Element element in elements) { | |
| 11070 if (element is ClassElement) { | |
| 11071 if (type != null) { | |
| 11072 return null; | |
| 11073 } | |
| 11074 type = ((element as ClassElement)).type; | |
| 11075 } | |
| 11076 } | |
| 11077 return type; | |
| 11078 } | |
| 11079 | |
| 11080 /** | |
| 11081 * Return the type represented by the given type name. | |
| 11082 * | |
| 11083 * @param typeName the type name representing the type to be returned | |
| 11084 * @return the type represented by the type name | |
| 11085 */ | |
| 11086 Type2 getType3(TypeName typeName) { | |
| 11087 Type2 type = typeName.type; | |
| 11088 if (type == null) { | |
| 11089 return _dynamicType; | |
| 11090 } | |
| 11091 return type; | |
| 11092 } | |
| 11093 | |
| 11094 /** | |
| 11095 * Return the type arguments associated with the given type. | |
| 11096 * | |
| 11097 * @param type the type whole type arguments are to be returned | |
| 11098 * @return the type arguments associated with the given type | |
| 11099 */ | |
| 11100 List<Type2> getTypeArguments(Type2 type) { | |
| 11101 if (type is InterfaceType) { | |
| 11102 return ((type as InterfaceType)).typeArguments; | |
| 11103 } else if (type is FunctionType) { | |
| 11104 return ((type as FunctionType)).typeArguments; | |
| 11105 } | |
| 11106 return TypeImpl.EMPTY_ARRAY; | |
| 11107 } | |
| 11108 | |
| 11109 /** | |
| 11110 * Returns the simple identifier of the given (may be qualified) type name. | |
| 11111 * | |
| 11112 * @param typeName the (may be qualified) qualified type name | |
| 11113 * @return the simple identifier of the given (may be qualified) type name. | |
| 11114 */ | |
| 11115 SimpleIdentifier getTypeSimpleIdentifier(Identifier typeName) { | |
| 11116 if (typeName is SimpleIdentifier) { | |
| 11117 return typeName as SimpleIdentifier; | |
| 11118 } else { | |
| 11119 return ((typeName as PrefixedIdentifier)).identifier; | |
| 11120 } | |
| 11121 } | |
| 11122 | |
| 11123 /** | |
| 11124 * Checks if the given type name is used as the type in an as expression. | |
| 11125 * | |
| 11126 * @param typeName the type name to analyzer | |
| 11127 * @return `true` if the given type name is used as the type in an as expressi
on | |
| 11128 */ | |
| 11129 bool isTypeNameInAsExpression(TypeName typeName) { | |
| 11130 ASTNode parent = typeName.parent; | |
| 11131 if (parent is AsExpression) { | |
| 11132 AsExpression asExpression = parent as AsExpression; | |
| 11133 return identical(asExpression.type, typeName); | |
| 11134 } | |
| 11135 return false; | |
| 11136 } | |
| 11137 | |
| 11138 /** | |
| 11139 * Checks if the given type name is used as the exception type in a catch clau
se. | |
| 11140 * | |
| 11141 * @param typeName the type name to analyzer | |
| 11142 * @return `true` if the given type name is used as the exception type in a ca
tch clause | |
| 11143 */ | |
| 11144 bool isTypeNameInCatchClause(TypeName typeName) { | |
| 11145 ASTNode parent = typeName.parent; | |
| 11146 if (parent is CatchClause) { | |
| 11147 CatchClause catchClause = parent as CatchClause; | |
| 11148 return identical(catchClause.exceptionType, typeName); | |
| 11149 } | |
| 11150 return false; | |
| 11151 } | |
| 11152 | |
| 11153 /** | |
| 11154 * Checks if the given type name is used as the type in an instance creation e
xpression. | |
| 11155 * | |
| 11156 * @param typeName the type name to analyzer | |
| 11157 * @return `true` if the given type name is used as the type in an instance cr
eation | |
| 11158 * expression | |
| 11159 */ | |
| 11160 bool isTypeNameInInstanceCreationExpression(TypeName typeName) { | |
| 11161 ASTNode parent = typeName.parent; | |
| 11162 if (parent is ConstructorName && parent.parent is InstanceCreationExpression
) { | |
| 11163 ConstructorName constructorName = parent as ConstructorName; | |
| 11164 return constructorName != null && identical(constructorName.type, typeName
); | |
| 11165 } | |
| 11166 return false; | |
| 11167 } | |
| 11168 | |
| 11169 /** | |
| 11170 * Checks if the given type name is used as the type in an is expression. | |
| 11171 * | |
| 11172 * @param typeName the type name to analyzer | |
| 11173 * @return `true` if the given type name is used as the type in an is expressi
on | |
| 11174 */ | |
| 11175 bool isTypeNameInIsExpression(TypeName typeName) { | |
| 11176 ASTNode parent = typeName.parent; | |
| 11177 if (parent is IsExpression) { | |
| 11178 IsExpression isExpression = parent as IsExpression; | |
| 11179 return identical(isExpression.type, typeName); | |
| 11180 } | |
| 11181 return false; | |
| 11182 } | |
| 11183 | |
| 11184 /** | |
| 11185 * Checks if the given type name used in a type argument list. | |
| 11186 * | |
| 11187 * @param typeName the type name to analyzer | |
| 11188 * @return `true` if the given type name is in a type argument list | |
| 11189 */ | |
| 11190 bool isTypeNameInTypeArgumentList(TypeName typeName) => typeName.parent is Typ
eArgumentList; | |
| 11191 | |
| 11192 /** | |
| 11193 * Checks if the given type name is the target in a redirected constructor. | |
| 11194 * | |
| 11195 * @param typeName the type name to analyzer | |
| 11196 * @return `true` if the given type name is used as the type in a redirected c
onstructor | |
| 11197 */ | |
| 11198 bool isTypeNameTargetInRedirectedConstructor(TypeName typeName) { | |
| 11199 ASTNode parent = typeName.parent; | |
| 11200 if (parent is ConstructorName) { | |
| 11201 ConstructorName constructorName = parent as ConstructorName; | |
| 11202 parent = constructorName.parent; | |
| 11203 if (parent is ConstructorDeclaration) { | |
| 11204 ConstructorDeclaration constructorDeclaration = parent as ConstructorDec
laration; | |
| 11205 return constructorName == constructorDeclaration.redirectedConstructor; | |
| 11206 } | |
| 11207 } | |
| 11208 return false; | |
| 11209 } | |
| 11210 | |
| 11211 /** | |
| 11212 * Record that the static type of the given node is the given type. | |
| 11213 * | |
| 11214 * @param expression the node whose type is to be recorded | |
| 11215 * @param type the static type of the node | |
| 11216 */ | |
| 11217 Object recordType(Expression expression, Type2 type) { | |
| 11218 if (type == null) { | |
| 11219 expression.staticType = _dynamicType; | |
| 11220 } else { | |
| 11221 expression.staticType = type; | |
| 11222 } | |
| 11223 return null; | |
| 11224 } | |
| 11225 | |
| 11226 /** | |
| 11227 * Resolve the types in the given with and implements clauses and associate th
ose types with the | |
| 11228 * given class element. | |
| 11229 * | |
| 11230 * @param classElement the class element with which the mixin and interface ty
pes are to be | |
| 11231 * associated | |
| 11232 * @param withClause the with clause to be resolved | |
| 11233 * @param implementsClause the implements clause to be resolved | |
| 11234 */ | |
| 11235 void resolve(ClassElementImpl classElement, WithClause withClause, ImplementsC
lause implementsClause) { | |
| 11236 if (withClause != null) { | |
| 11237 List<InterfaceType> mixinTypes = resolveTypes(withClause.mixinTypes, Compi
leTimeErrorCode.MIXIN_OF_NON_CLASS, CompileTimeErrorCode.MIXIN_OF_NON_CLASS); | |
| 11238 if (classElement != null) { | |
| 11239 classElement.mixins = mixinTypes; | |
| 11240 } | |
| 11241 } | |
| 11242 if (implementsClause != null) { | |
| 11243 NodeList<TypeName> interfaces = implementsClause.interfaces; | |
| 11244 List<InterfaceType> interfaceTypes = resolveTypes(interfaces, CompileTimeE
rrorCode.IMPLEMENTS_NON_CLASS, CompileTimeErrorCode.IMPLEMENTS_DYNAMIC); | |
| 11245 if (classElement != null) { | |
| 11246 classElement.interfaces = interfaceTypes; | |
| 11247 } | |
| 11248 List<TypeName> typeNames = new List.from(interfaces); | |
| 11249 List<bool> detectedRepeatOnIndex = new List<bool>.filled(typeNames.length,
false); | |
| 11250 for (int i = 0; i < detectedRepeatOnIndex.length; i++) { | |
| 11251 detectedRepeatOnIndex[i] = false; | |
| 11252 } | |
| 11253 for (int i = 0; i < typeNames.length; i++) { | |
| 11254 TypeName typeName = typeNames[i]; | |
| 11255 if (!detectedRepeatOnIndex[i]) { | |
| 11256 Element element = typeName.name.staticElement; | |
| 11257 for (int j = i + 1; j < typeNames.length; j++) { | |
| 11258 TypeName typeName2 = typeNames[j]; | |
| 11259 Identifier identifier2 = typeName2.name; | |
| 11260 String name2 = identifier2.name; | |
| 11261 Element element2 = identifier2.staticElement; | |
| 11262 if (element != null && element == element2) { | |
| 11263 detectedRepeatOnIndex[j] = true; | |
| 11264 reportError5(CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2,
[name2]); | |
| 11265 } | |
| 11266 } | |
| 11267 } | |
| 11268 } | |
| 11269 } | |
| 11270 } | |
| 11271 | |
| 11272 /** | |
| 11273 * Return the type specified by the given name. | |
| 11274 * | |
| 11275 * @param typeName the type name specifying the type to be returned | |
| 11276 * @param nonTypeError the error to produce if the type name is defined to be
something other than | |
| 11277 * a type | |
| 11278 * @param dynamicTypeError the error to produce if the type name is "dynamic" | |
| 11279 * @return the type specified by the type name | |
| 11280 */ | |
| 11281 InterfaceType resolveType(TypeName typeName, ErrorCode nonTypeError, ErrorCode
dynamicTypeError) { | |
| 11282 Type2 type = typeName.type; | |
| 11283 if (type is InterfaceType) { | |
| 11284 return type as InterfaceType; | |
| 11285 } | |
| 11286 Identifier name = typeName.name; | |
| 11287 if (name.name == sc.Keyword.DYNAMIC.syntax) { | |
| 11288 reportError5(dynamicTypeError, name, [name.name]); | |
| 11289 } else { | |
| 11290 reportError5(nonTypeError, name, [name.name]); | |
| 11291 } | |
| 11292 return null; | |
| 11293 } | |
| 11294 | |
| 11295 /** | |
| 11296 * Resolve the types in the given list of type names. | |
| 11297 * | |
| 11298 * @param typeNames the type names to be resolved | |
| 11299 * @param nonTypeError the error to produce if the type name is defined to be
something other than | |
| 11300 * a type | |
| 11301 * @param dynamicTypeError the error to produce if the type name is "dynamic" | |
| 11302 * @return an array containing all of the types that were resolved. | |
| 11303 */ | |
| 11304 List<InterfaceType> resolveTypes(NodeList<TypeName> typeNames, ErrorCode nonTy
peError, ErrorCode dynamicTypeError) { | |
| 11305 List<InterfaceType> types = new List<InterfaceType>(); | |
| 11306 for (TypeName typeName in typeNames) { | |
| 11307 InterfaceType type = resolveType(typeName, nonTypeError, dynamicTypeError)
; | |
| 11308 if (type != null) { | |
| 11309 types.add(type); | |
| 11310 } | |
| 11311 } | |
| 11312 return new List.from(types); | |
| 11313 } | |
| 11314 void setElement(Identifier typeName, Element element) { | |
| 11315 if (element != null) { | |
| 11316 if (typeName is SimpleIdentifier) { | |
| 11317 ((typeName as SimpleIdentifier)).staticElement = element; | |
| 11318 } else if (typeName is PrefixedIdentifier) { | |
| 11319 PrefixedIdentifier identifier = typeName as PrefixedIdentifier; | |
| 11320 identifier.identifier.staticElement = element; | |
| 11321 SimpleIdentifier prefix = identifier.prefix; | |
| 11322 Element prefixElement = nameScope.lookup(prefix, definingLibrary); | |
| 11323 if (prefixElement != null) { | |
| 11324 prefix.staticElement = prefixElement; | |
| 11325 } | |
| 11326 } | |
| 11327 } | |
| 11328 } | |
| 11329 | |
| 11330 /** | |
| 11331 * Given a parameter element, create a function type based on the given return
type and parameter | |
| 11332 * list and associate the created type with the element. | |
| 11333 * | |
| 11334 * @param element the parameter element whose type is to be set | |
| 11335 * @param returnType the (possibly `null`) return type of the function | |
| 11336 * @param parameterList the list of parameters to the function | |
| 11337 */ | |
| 11338 void setFunctionTypedParameterType(ParameterElementImpl element, TypeName retu
rnType, FormalParameterList parameterList) { | |
| 11339 List<ParameterElement> parameters = getElements(parameterList); | |
| 11340 FunctionTypeAliasElementImpl aliasElement = new FunctionTypeAliasElementImpl
(null); | |
| 11341 aliasElement.synthetic = true; | |
| 11342 aliasElement.shareParameters(parameters); | |
| 11343 aliasElement.returnType = computeReturnType(returnType); | |
| 11344 FunctionTypeImpl type = new FunctionTypeImpl.con2(aliasElement); | |
| 11345 ClassElement definingClass = element.getAncestor(ClassElement); | |
| 11346 if (definingClass != null) { | |
| 11347 aliasElement.shareTypeParameters(definingClass.typeParameters); | |
| 11348 type.typeArguments = definingClass.type.typeArguments; | |
| 11349 } else { | |
| 11350 FunctionTypeAliasElement alias = element.getAncestor(FunctionTypeAliasElem
ent); | |
| 11351 while (alias != null && alias.isSynthetic) { | |
| 11352 alias = alias.getAncestor(FunctionTypeAliasElement); | |
| 11353 } | |
| 11354 if (alias != null) { | |
| 11355 aliasElement.typeParameters = alias.typeParameters; | |
| 11356 type.typeArguments = alias.type.typeArguments; | |
| 11357 } else { | |
| 11358 type.typeArguments = TypeImpl.EMPTY_ARRAY; | |
| 11359 } | |
| 11360 } | |
| 11361 element.type = type; | |
| 11362 } | |
| 11363 } | |
| 11364 /** | |
| 11365 * Instances of the class `VariableResolverVisitor` are used to resolve | |
| 11366 * [SimpleIdentifier]s to local variables and formal parameters. | |
| 11367 * | |
| 11368 * @coverage dart.engine.resolver | |
| 11369 */ | |
| 11370 class VariableResolverVisitor extends ScopedVisitor { | |
| 11371 | |
| 11372 /** | |
| 11373 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. | |
| 11374 * | |
| 11375 * @param library the library containing the compilation unit being resolved | |
| 11376 * @param source the source representing the compilation unit being visited | |
| 11377 * @param typeProvider the object used to access the types from the core libra
ry | |
| 11378 */ | |
| 11379 VariableResolverVisitor(Library library, Source source, TypeProvider typeProvi
der) : super.con1(library, source, typeProvider); | |
| 11380 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 11381 if (node.staticElement != null) { | |
| 11382 return null; | |
| 11383 } | |
| 11384 ASTNode parent = node.parent; | |
| 11385 if (parent is PrefixedIdentifier && identical(((parent as PrefixedIdentifier
)).identifier, node)) { | |
| 11386 return null; | |
| 11387 } | |
| 11388 if (parent is PropertyAccess && identical(((parent as PropertyAccess)).prope
rtyName, node)) { | |
| 11389 return null; | |
| 11390 } | |
| 11391 if (parent is MethodInvocation && identical(((parent as MethodInvocation)).m
ethodName, node)) { | |
| 11392 return null; | |
| 11393 } | |
| 11394 if (parent is ConstructorName) { | |
| 11395 return null; | |
| 11396 } | |
| 11397 if (parent is Label) { | |
| 11398 return null; | |
| 11399 } | |
| 11400 Element element = nameScope.lookup(node, definingLibrary); | |
| 11401 if (element is! VariableElement) { | |
| 11402 return null; | |
| 11403 } | |
| 11404 ElementKind kind = element.kind; | |
| 11405 if (identical(kind, ElementKind.LOCAL_VARIABLE)) { | |
| 11406 node.staticElement = element; | |
| 11407 if (node.inSetterContext()) { | |
| 11408 ((element as LocalVariableElementImpl)).markPotentiallyMutated(); | |
| 11409 } | |
| 11410 } else if (identical(kind, ElementKind.PARAMETER)) { | |
| 11411 node.staticElement = element; | |
| 11412 if (node.inSetterContext()) { | |
| 11413 ((element as ParameterElementImpl)).markPotentiallyMutated(); | |
| 11414 } | |
| 11415 } | |
| 11416 return null; | |
| 11417 } | |
| 11418 } | |
| 11419 /** | |
| 11420 * Instances of the class `ClassScope` implement the scope defined by a class. | |
| 11421 * | |
| 11422 * @coverage dart.engine.resolver | |
| 11423 */ | |
| 11424 class ClassScope extends EnclosedScope { | |
| 11425 | |
| 11426 /** | |
| 11427 * Initialize a newly created scope enclosed within another scope. | |
| 11428 * | |
| 11429 * @param enclosingScope the scope in which this scope is lexically enclosed | |
| 11430 * @param typeElement the element representing the type represented by this sc
ope | |
| 11431 */ | |
| 11432 ClassScope(Scope enclosingScope, ClassElement typeElement) : super(new Enclose
dScope(enclosingScope)) { | |
| 11433 defineTypeParameters(typeElement); | |
| 11434 defineMembers(typeElement); | |
| 11435 } | |
| 11436 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { | |
| 11437 if (existing is PropertyAccessorElement && duplicate is MethodElement) { | |
| 11438 if (existing.nameOffset < duplicate.nameOffset) { | |
| 11439 return new AnalysisError.con2(duplicate.source, duplicate.nameOffset, du
plicate.displayName.length, CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAM
E, [existing.displayName]); | |
| 11440 } else { | |
| 11441 return new AnalysisError.con2(existing.source, existing.nameOffset, exis
ting.displayName.length, CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
[existing.displayName]); | |
| 11442 } | |
| 11443 } | |
| 11444 return super.getErrorForDuplicate(existing, duplicate); | |
| 11445 } | |
| 11446 | |
| 11447 /** | |
| 11448 * Define the instance members defined by the class. | |
| 11449 * | |
| 11450 * @param typeElement the element representing the type represented by this sc
ope | |
| 11451 */ | |
| 11452 void defineMembers(ClassElement typeElement) { | |
| 11453 for (PropertyAccessorElement accessor in typeElement.accessors) { | |
| 11454 define(accessor); | |
| 11455 } | |
| 11456 for (MethodElement method in typeElement.methods) { | |
| 11457 define(method); | |
| 11458 } | |
| 11459 } | |
| 11460 | |
| 11461 /** | |
| 11462 * Define the type parameters for the class. | |
| 11463 * | |
| 11464 * @param typeElement the element representing the type represented by this sc
ope | |
| 11465 */ | |
| 11466 void defineTypeParameters(ClassElement typeElement) { | |
| 11467 Scope parameterScope = enclosingScope; | |
| 11468 for (TypeParameterElement typeParameter in typeElement.typeParameters) { | |
| 11469 parameterScope.define(typeParameter); | |
| 11470 } | |
| 11471 } | |
| 11472 } | |
| 11473 /** | |
| 11474 * Instances of the class `EnclosedScope` implement a scope that is lexically en
closed in | |
| 11475 * another scope. | |
| 11476 * | |
| 11477 * @coverage dart.engine.resolver | |
| 11478 */ | |
| 11479 class EnclosedScope extends Scope { | |
| 11480 | |
| 11481 /** | |
| 11482 * The scope in which this scope is lexically enclosed. | |
| 11483 */ | |
| 11484 Scope enclosingScope; | |
| 11485 | |
| 11486 /** | |
| 11487 * A set of names that will be defined in this scope, but right now are not de
fined. However | |
| 11488 * according to the scoping rules these names are hidden, even if they were de
fined in an outer | |
| 11489 * scope. | |
| 11490 */ | |
| 11491 Set<String> _hiddenNames = new Set<String>(); | |
| 11492 | |
| 11493 /** | |
| 11494 * Initialize a newly created scope enclosed within another scope. | |
| 11495 * | |
| 11496 * @param enclosingScope the scope in which this scope is lexically enclosed | |
| 11497 */ | |
| 11498 EnclosedScope(Scope enclosingScope) { | |
| 11499 this.enclosingScope = enclosingScope; | |
| 11500 } | |
| 11501 LibraryElement get definingLibrary => enclosingScope.definingLibrary; | |
| 11502 AnalysisErrorListener get errorListener => enclosingScope.errorListener; | |
| 11503 | |
| 11504 /** | |
| 11505 * Hides the name of the given element in this scope. If there is already an e
lement with the | |
| 11506 * given name defined in an outer scope, then it will become unavailable. | |
| 11507 * | |
| 11508 * @param element the element to be hidden in this scope | |
| 11509 */ | |
| 11510 void hide(Element element) { | |
| 11511 if (element != null) { | |
| 11512 String name = element.name; | |
| 11513 if (name != null && !name.isEmpty) { | |
| 11514 javaSetAdd(_hiddenNames, name); | |
| 11515 } | |
| 11516 } | |
| 11517 } | |
| 11518 Element lookup3(Identifier identifier, String name, LibraryElement referencing
Library) { | |
| 11519 Element element = localLookup(name, referencingLibrary); | |
| 11520 if (element != null) { | |
| 11521 return element; | |
| 11522 } | |
| 11523 if (_hiddenNames.contains(name)) { | |
| 11524 errorListener.onError(new AnalysisError.con2(source, identifier.offset, id
entifier.length, CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, [])); | |
| 11525 } | |
| 11526 return enclosingScope.lookup3(identifier, name, referencingLibrary); | |
| 11527 } | |
| 11528 } | |
| 11529 /** | |
| 11530 * Instances of the class `FunctionScope` implement the scope defined by a funct
ion. | |
| 11531 * | |
| 11532 * @coverage dart.engine.resolver | |
| 11533 */ | |
| 11534 class FunctionScope extends EnclosedScope { | |
| 11535 ExecutableElement _functionElement; | |
| 11536 bool _parametersDefined = false; | |
| 11537 | |
| 11538 /** | |
| 11539 * Initialize a newly created scope enclosed within another scope. | |
| 11540 * | |
| 11541 * @param enclosingScope the scope in which this scope is lexically enclosed | |
| 11542 * @param functionElement the element representing the type represented by thi
s scope | |
| 11543 */ | |
| 11544 FunctionScope(Scope enclosingScope, ExecutableElement functionElement) : super
(new EnclosedScope(enclosingScope)) { | |
| 11545 this._functionElement = functionElement; | |
| 11546 } | |
| 11547 | |
| 11548 /** | |
| 11549 * Define the parameters for the given function in the scope that encloses thi
s function. | |
| 11550 */ | |
| 11551 void defineParameters() { | |
| 11552 if (_parametersDefined) { | |
| 11553 return; | |
| 11554 } | |
| 11555 _parametersDefined = true; | |
| 11556 Scope parameterScope = enclosingScope; | |
| 11557 if (_functionElement.enclosingElement is ExecutableElement) { | |
| 11558 String name = _functionElement.name; | |
| 11559 if (name != null && !name.isEmpty) { | |
| 11560 parameterScope.define(_functionElement); | |
| 11561 } | |
| 11562 } | |
| 11563 for (ParameterElement parameter in _functionElement.parameters) { | |
| 11564 if (!parameter.isInitializingFormal) { | |
| 11565 parameterScope.define(parameter); | |
| 11566 } | |
| 11567 } | |
| 11568 } | |
| 11569 } | |
| 11570 /** | |
| 11571 * Instances of the class `FunctionTypeScope` implement the scope defined by a f
unction type | |
| 11572 * alias. | |
| 11573 * | |
| 11574 * @coverage dart.engine.resolver | |
| 11575 */ | |
| 11576 class FunctionTypeScope extends EnclosedScope { | |
| 11577 FunctionTypeAliasElement _typeElement; | |
| 11578 bool _parametersDefined = false; | |
| 11579 | |
| 11580 /** | |
| 11581 * Initialize a newly created scope enclosed within another scope. | |
| 11582 * | |
| 11583 * @param enclosingScope the scope in which this scope is lexically enclosed | |
| 11584 * @param typeElement the element representing the type alias represented by t
his scope | |
| 11585 */ | |
| 11586 FunctionTypeScope(Scope enclosingScope, FunctionTypeAliasElement typeElement)
: super(new EnclosedScope(enclosingScope)) { | |
| 11587 this._typeElement = typeElement; | |
| 11588 defineTypeParameters(); | |
| 11589 } | |
| 11590 | |
| 11591 /** | |
| 11592 * Define the parameters for the function type alias. | |
| 11593 * | |
| 11594 * @param typeElement the element representing the type represented by this sc
ope | |
| 11595 */ | |
| 11596 void defineParameters() { | |
| 11597 if (_parametersDefined) { | |
| 11598 return; | |
| 11599 } | |
| 11600 _parametersDefined = true; | |
| 11601 for (ParameterElement parameter in _typeElement.parameters) { | |
| 11602 define(parameter); | |
| 11603 } | |
| 11604 } | |
| 11605 | |
| 11606 /** | |
| 11607 * Define the type parameters for the function type alias. | |
| 11608 * | |
| 11609 * @param typeElement the element representing the type represented by this sc
ope | |
| 11610 */ | |
| 11611 void defineTypeParameters() { | |
| 11612 Scope typeParameterScope = enclosingScope; | |
| 11613 for (TypeParameterElement typeParameter in _typeElement.typeParameters) { | |
| 11614 typeParameterScope.define(typeParameter); | |
| 11615 } | |
| 11616 } | |
| 11617 } | |
| 11618 /** | |
| 11619 * Instances of the class `LabelScope` represent a scope in which a single label
is defined. | |
| 11620 * | |
| 11621 * @coverage dart.engine.resolver | |
| 11622 */ | |
| 11623 class LabelScope { | |
| 11624 | |
| 11625 /** | |
| 11626 * The label scope enclosing this label scope. | |
| 11627 */ | |
| 11628 LabelScope _outerScope; | |
| 11629 | |
| 11630 /** | |
| 11631 * The label defined in this scope. | |
| 11632 */ | |
| 11633 String _label; | |
| 11634 | |
| 11635 /** | |
| 11636 * The element to which the label resolves. | |
| 11637 */ | |
| 11638 LabelElement _element; | |
| 11639 | |
| 11640 /** | |
| 11641 * The marker used to look up a label element for an unlabeled `break` or `con
tinue`. | |
| 11642 */ | |
| 11643 static String EMPTY_LABEL = ""; | |
| 11644 | |
| 11645 /** | |
| 11646 * The label element returned for scopes that can be the target of an unlabele
d `break` or | |
| 11647 * `continue`. | |
| 11648 */ | |
| 11649 static SimpleIdentifier _EMPTY_LABEL_IDENTIFIER = new SimpleIdentifier.full(ne
w sc.StringToken(sc.TokenType.IDENTIFIER, "", 0)); | |
| 11650 | |
| 11651 /** | |
| 11652 * Initialize a newly created scope to represent the potential target of an un
labeled | |
| 11653 * `break` or `continue`. | |
| 11654 * | |
| 11655 * @param outerScope the label scope enclosing the new label scope | |
| 11656 * @param onSwitchStatement `true` if this label is associated with a `switch` | |
| 11657 * statement | |
| 11658 * @param onSwitchMember `true` if this label is associated with a `switch` me
mber | |
| 11659 */ | |
| 11660 LabelScope.con1(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMe
mber) : this.con2(outerScope, EMPTY_LABEL, new LabelElementImpl(_EMPTY_LABEL_IDE
NTIFIER, onSwitchStatement, onSwitchMember)); | |
| 11661 | |
| 11662 /** | |
| 11663 * Initialize a newly created scope to represent the given label. | |
| 11664 * | |
| 11665 * @param outerScope the label scope enclosing the new label scope | |
| 11666 * @param label the label defined in this scope | |
| 11667 * @param element the element to which the label resolves | |
| 11668 */ | |
| 11669 LabelScope.con2(LabelScope outerScope, String label, LabelElement element) { | |
| 11670 this._outerScope = outerScope; | |
| 11671 this._label = label; | |
| 11672 this._element = element; | |
| 11673 } | |
| 11674 | |
| 11675 /** | |
| 11676 * Return the label element corresponding to the given label, or `null` if the
given label | |
| 11677 * is not defined in this scope. | |
| 11678 * | |
| 11679 * @param targetLabel the label being looked up | |
| 11680 * @return the label element corresponding to the given label | |
| 11681 */ | |
| 11682 LabelElement lookup(SimpleIdentifier targetLabel) => lookup2(targetLabel.name)
; | |
| 11683 | |
| 11684 /** | |
| 11685 * Return the label element corresponding to the given label, or `null` if the
given label | |
| 11686 * is not defined in this scope. | |
| 11687 * | |
| 11688 * @param targetLabel the label being looked up | |
| 11689 * @return the label element corresponding to the given label | |
| 11690 */ | |
| 11691 LabelElement lookup2(String targetLabel) { | |
| 11692 if (_label == targetLabel) { | |
| 11693 return _element; | |
| 11694 } else if (_outerScope != null) { | |
| 11695 return _outerScope.lookup2(targetLabel); | |
| 11696 } else { | |
| 11697 return null; | |
| 11698 } | |
| 11699 } | |
| 11700 } | |
| 11701 /** | |
| 11702 * Instances of the class `LibraryImportScope` represent the scope containing al
l of the names | |
| 11703 * available from imported libraries. | |
| 11704 * | |
| 11705 * @coverage dart.engine.resolver | |
| 11706 */ | |
| 11707 class LibraryImportScope extends Scope { | |
| 11708 | |
| 11709 /** | |
| 11710 * The element representing the library in which this scope is enclosed. | |
| 11711 */ | |
| 11712 LibraryElement _definingLibrary; | |
| 11713 | |
| 11714 /** | |
| 11715 * The listener that is to be informed when an error is encountered. | |
| 11716 */ | |
| 11717 AnalysisErrorListener _errorListener; | |
| 11718 | |
| 11719 /** | |
| 11720 * A list of the namespaces representing the names that are available in this
scope from imported | |
| 11721 * libraries. | |
| 11722 */ | |
| 11723 List<Namespace> _importedNamespaces = new List<Namespace>(); | |
| 11724 | |
| 11725 /** | |
| 11726 * Initialize a newly created scope representing the names imported into the g
iven library. | |
| 11727 * | |
| 11728 * @param definingLibrary the element representing the library that imports th
e names defined in | |
| 11729 * this scope | |
| 11730 * @param errorListener the listener that is to be informed when an error is e
ncountered | |
| 11731 */ | |
| 11732 LibraryImportScope(LibraryElement definingLibrary, AnalysisErrorListener error
Listener) { | |
| 11733 this._definingLibrary = definingLibrary; | |
| 11734 this._errorListener = errorListener; | |
| 11735 createImportedNamespaces(definingLibrary); | |
| 11736 } | |
| 11737 void define(Element element) { | |
| 11738 if (!Scope.isPrivateName(element.displayName)) { | |
| 11739 super.define(element); | |
| 11740 } | |
| 11741 } | |
| 11742 LibraryElement get definingLibrary => _definingLibrary; | |
| 11743 AnalysisErrorListener get errorListener => _errorListener; | |
| 11744 Element lookup3(Identifier identifier, String name, LibraryElement referencing
Library) { | |
| 11745 Element foundElement = localLookup(name, referencingLibrary); | |
| 11746 if (foundElement != null) { | |
| 11747 return foundElement; | |
| 11748 } | |
| 11749 for (Namespace nameSpace in _importedNamespaces) { | |
| 11750 Element element = nameSpace.get(name); | |
| 11751 if (element != null) { | |
| 11752 if (foundElement == null) { | |
| 11753 foundElement = element; | |
| 11754 } else if (foundElement != element) { | |
| 11755 foundElement = MultiplyDefinedElementImpl.fromElements(_definingLibrar
y.context, foundElement, element); | |
| 11756 } | |
| 11757 } | |
| 11758 } | |
| 11759 if (foundElement is MultiplyDefinedElementImpl) { | |
| 11760 foundElement = removeSdkElements(identifier, name, foundElement as Multipl
yDefinedElementImpl); | |
| 11761 } | |
| 11762 if (foundElement is MultiplyDefinedElementImpl) { | |
| 11763 String foundEltName = foundElement.displayName; | |
| 11764 List<Element> conflictingMembers = ((foundElement as MultiplyDefinedElemen
tImpl)).conflictingElements; | |
| 11765 String libName1 = getLibraryName(conflictingMembers[0], ""); | |
| 11766 String libName2 = getLibraryName(conflictingMembers[1], ""); | |
| 11767 _errorListener.onError(new AnalysisError.con2(getSource2(identifier), iden
tifier.offset, identifier.length, StaticWarningCode.AMBIGUOUS_IMPORT, [foundEltN
ame, libName1, libName2])); | |
| 11768 return foundElement; | |
| 11769 } | |
| 11770 if (foundElement != null) { | |
| 11771 defineWithoutChecking2(name, foundElement); | |
| 11772 } | |
| 11773 return foundElement; | |
| 11774 } | |
| 11775 | |
| 11776 /** | |
| 11777 * Create all of the namespaces associated with the libraries imported into th
is library. The | |
| 11778 * names are not added to this scope, but are stored for later reference. | |
| 11779 * | |
| 11780 * @param definingLibrary the element representing the library that imports th
e libraries for | |
| 11781 * which namespaces will be created | |
| 11782 */ | |
| 11783 void createImportedNamespaces(LibraryElement definingLibrary) { | |
| 11784 NamespaceBuilder builder = new NamespaceBuilder(); | |
| 11785 for (ImportElement element in definingLibrary.imports) { | |
| 11786 _importedNamespaces.add(builder.createImportNamespace(element)); | |
| 11787 } | |
| 11788 } | |
| 11789 | |
| 11790 /** | |
| 11791 * Returns the name of the library that defines given element. | |
| 11792 * | |
| 11793 * @param element the element to get library name | |
| 11794 * @param def the default name to use | |
| 11795 * @return the name of the library that defines given element | |
| 11796 */ | |
| 11797 String getLibraryName(Element element, String def) { | |
| 11798 if (element == null) { | |
| 11799 return def; | |
| 11800 } | |
| 11801 LibraryElement library = element.library; | |
| 11802 if (library == null) { | |
| 11803 return def; | |
| 11804 } | |
| 11805 return library.definingCompilationUnit.displayName; | |
| 11806 } | |
| 11807 | |
| 11808 /** | |
| 11809 * Return the source that contains the given identifier, or the source associa
ted with this scope | |
| 11810 * if the source containing the identifier could not be determined. | |
| 11811 * | |
| 11812 * @param identifier the identifier whose source is to be returned | |
| 11813 * @return the source that contains the given identifier | |
| 11814 */ | |
| 11815 Source getSource2(Identifier identifier) { | |
| 11816 CompilationUnit unit = identifier.getAncestor(CompilationUnit); | |
| 11817 if (unit != null) { | |
| 11818 CompilationUnitElement element = unit.element; | |
| 11819 if (element != null) { | |
| 11820 Source source = element.source; | |
| 11821 if (source != null) { | |
| 11822 return source; | |
| 11823 } | |
| 11824 } | |
| 11825 } | |
| 11826 return this.source; | |
| 11827 } | |
| 11828 | |
| 11829 /** | |
| 11830 * Given a collection of elements that a single name could all be mapped to, r
emove from the list | |
| 11831 * all of the names defined in the SDK. Return the element(s) that remain. | |
| 11832 * | |
| 11833 * @param identifier the identifier node to lookup element for, used to report
correct kind of a | |
| 11834 * problem and associate problem with | |
| 11835 * @param name the name associated with the element | |
| 11836 * @param foundElement the element encapsulating the collection of elements | |
| 11837 * @return all of the elements that are not defined in the SDK | |
| 11838 */ | |
| 11839 Element removeSdkElements(Identifier identifier, String name, MultiplyDefinedE
lementImpl foundElement) { | |
| 11840 List<Element> conflictingMembers = foundElement.conflictingElements; | |
| 11841 int length = conflictingMembers.length; | |
| 11842 int to = 0; | |
| 11843 Element sdkElement = null; | |
| 11844 for (Element member in conflictingMembers) { | |
| 11845 if (member.library.isInSdk) { | |
| 11846 sdkElement = member; | |
| 11847 } else { | |
| 11848 conflictingMembers[to++] = member; | |
| 11849 } | |
| 11850 } | |
| 11851 if (sdkElement != null && to > 0) { | |
| 11852 String sdkLibName = getLibraryName(sdkElement, ""); | |
| 11853 String otherLibName = getLibraryName(conflictingMembers[0], ""); | |
| 11854 _errorListener.onError(new AnalysisError.con2(getSource2(identifier), iden
tifier.offset, identifier.length, StaticWarningCode.CONFLICTING_DART_IMPORT, [na
me, sdkLibName, otherLibName])); | |
| 11855 } | |
| 11856 if (to == length) { | |
| 11857 return foundElement; | |
| 11858 } else if (to == 1) { | |
| 11859 return conflictingMembers[0]; | |
| 11860 } else if (to == 0) { | |
| 11861 AnalysisEngine.instance.logger.logInformation("Multiply defined SDK elemen
t: ${foundElement}"); | |
| 11862 return foundElement; | |
| 11863 } | |
| 11864 List<Element> remaining = new List<Element>(to); | |
| 11865 JavaSystem.arraycopy(conflictingMembers, 0, remaining, 0, to); | |
| 11866 return new MultiplyDefinedElementImpl(_definingLibrary.context, remaining); | |
| 11867 } | |
| 11868 } | |
| 11869 /** | |
| 11870 * Instances of the class `LibraryScope` implement a scope containing all of the
names defined | |
| 11871 * in a given library. | |
| 11872 * | |
| 11873 * @coverage dart.engine.resolver | |
| 11874 */ | |
| 11875 class LibraryScope extends EnclosedScope { | |
| 11876 | |
| 11877 /** | |
| 11878 * Initialize a newly created scope representing the names defined in the give
n library. | |
| 11879 * | |
| 11880 * @param definingLibrary the element representing the library represented by
this scope | |
| 11881 * @param errorListener the listener that is to be informed when an error is e
ncountered | |
| 11882 */ | |
| 11883 LibraryScope(LibraryElement definingLibrary, AnalysisErrorListener errorListen
er) : super(new LibraryImportScope(definingLibrary, errorListener)) { | |
| 11884 defineTopLevelNames(definingLibrary); | |
| 11885 } | |
| 11886 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { | |
| 11887 if (existing is PrefixElement) { | |
| 11888 int offset = duplicate.nameOffset; | |
| 11889 if (duplicate is PropertyAccessorElement) { | |
| 11890 PropertyAccessorElement accessor = duplicate as PropertyAccessorElement; | |
| 11891 if (accessor.isSynthetic) { | |
| 11892 offset = accessor.variable.nameOffset; | |
| 11893 } | |
| 11894 } | |
| 11895 return new AnalysisError.con2(source, offset, duplicate.displayName.length
, CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER, [existing.displayN
ame]); | |
| 11896 } | |
| 11897 return super.getErrorForDuplicate(existing, duplicate); | |
| 11898 } | |
| 11899 | |
| 11900 /** | |
| 11901 * Add to this scope all of the public top-level names that are defined in the
given compilation | |
| 11902 * unit. | |
| 11903 * | |
| 11904 * @param compilationUnit the compilation unit defining the top-level names to
be added to this | |
| 11905 * scope | |
| 11906 */ | |
| 11907 void defineLocalNames(CompilationUnitElement compilationUnit) { | |
| 11908 for (PropertyAccessorElement element in compilationUnit.accessors) { | |
| 11909 define(element); | |
| 11910 } | |
| 11911 for (FunctionElement element in compilationUnit.functions) { | |
| 11912 define(element); | |
| 11913 } | |
| 11914 for (FunctionTypeAliasElement element in compilationUnit.functionTypeAliases
) { | |
| 11915 define(element); | |
| 11916 } | |
| 11917 for (ClassElement element in compilationUnit.types) { | |
| 11918 define(element); | |
| 11919 } | |
| 11920 } | |
| 11921 | |
| 11922 /** | |
| 11923 * Add to this scope all of the names that are explicitly defined in the given
library. | |
| 11924 * | |
| 11925 * @param definingLibrary the element representing the library that defines th
e names in this | |
| 11926 * scope | |
| 11927 */ | |
| 11928 void defineTopLevelNames(LibraryElement definingLibrary) { | |
| 11929 for (PrefixElement prefix in definingLibrary.prefixes) { | |
| 11930 define(prefix); | |
| 11931 } | |
| 11932 defineLocalNames(definingLibrary.definingCompilationUnit); | |
| 11933 for (CompilationUnitElement compilationUnit in definingLibrary.parts) { | |
| 11934 defineLocalNames(compilationUnit); | |
| 11935 } | |
| 11936 } | |
| 11937 } | |
| 11938 /** | |
| 11939 * Instances of the class `Namespace` implement a mapping of identifiers to the
elements | |
| 11940 * represented by those identifiers. Namespaces are the building blocks for scop
es. | |
| 11941 * | |
| 11942 * @coverage dart.engine.resolver | |
| 11943 */ | |
| 11944 class Namespace { | |
| 11945 | |
| 11946 /** | |
| 11947 * A table mapping names that are defined in this namespace to the element rep
resenting the thing | |
| 11948 * declared with that name. | |
| 11949 */ | |
| 11950 Map<String, Element> _definedNames; | |
| 11951 | |
| 11952 /** | |
| 11953 * An empty namespace. | |
| 11954 */ | |
| 11955 static Namespace EMPTY = new Namespace(new Map<String, Element>()); | |
| 11956 | |
| 11957 /** | |
| 11958 * Initialize a newly created namespace to have the given defined names. | |
| 11959 * | |
| 11960 * @param definedNames the mapping from names that are defined in this namespa
ce to the | |
| 11961 * corresponding elements | |
| 11962 */ | |
| 11963 Namespace(Map<String, Element> definedNames) { | |
| 11964 this._definedNames = definedNames; | |
| 11965 } | |
| 11966 | |
| 11967 /** | |
| 11968 * Return the element in this namespace that is available to the containing sc
ope using the given | |
| 11969 * name. | |
| 11970 * | |
| 11971 * @param name the name used to reference the | |
| 11972 * @return the element represented by the given identifier | |
| 11973 */ | |
| 11974 Element get(String name) => _definedNames[name]; | |
| 11975 | |
| 11976 /** | |
| 11977 * Return a table containing the same mappings as those defined by this namesp
ace. | |
| 11978 * | |
| 11979 * @return a table containing the same mappings as those defined by this names
pace | |
| 11980 */ | |
| 11981 Map<String, Element> get definedNames => new Map<String, Element>.from(_define
dNames); | |
| 11982 } | |
| 11983 /** | |
| 11984 * Instances of the class `NamespaceBuilder` are used to build a `Namespace`. Na
mespace | |
| 11985 * builders are thread-safe and re-usable. | |
| 11986 * | |
| 11987 * @coverage dart.engine.resolver | |
| 11988 */ | |
| 11989 class NamespaceBuilder { | |
| 11990 | |
| 11991 /** | |
| 11992 * Create a namespace representing the export namespace of the given [ExportEl
ement]. | |
| 11993 * | |
| 11994 * @param element the export element whose export namespace is to be created | |
| 11995 * @return the export namespace that was created | |
| 11996 */ | |
| 11997 Namespace createExportNamespace(ExportElement element) { | |
| 11998 LibraryElement exportedLibrary = element.exportedLibrary; | |
| 11999 if (exportedLibrary == null) { | |
| 12000 return Namespace.EMPTY; | |
| 12001 } | |
| 12002 Map<String, Element> definedNames = createExportMapping(exportedLibrary, new
Set<LibraryElement>()); | |
| 12003 definedNames = apply(definedNames, element.combinators); | |
| 12004 return new Namespace(definedNames); | |
| 12005 } | |
| 12006 | |
| 12007 /** | |
| 12008 * Create a namespace representing the export namespace of the given library. | |
| 12009 * | |
| 12010 * @param library the library whose export namespace is to be created | |
| 12011 * @return the export namespace that was created | |
| 12012 */ | |
| 12013 Namespace createExportNamespace2(LibraryElement library) => new Namespace(crea
teExportMapping(library, new Set<LibraryElement>())); | |
| 12014 | |
| 12015 /** | |
| 12016 * Create a namespace representing the import namespace of the given library. | |
| 12017 * | |
| 12018 * @param library the library whose import namespace is to be created | |
| 12019 * @return the import namespace that was created | |
| 12020 */ | |
| 12021 Namespace createImportNamespace(ImportElement element) { | |
| 12022 LibraryElement importedLibrary = element.importedLibrary; | |
| 12023 if (importedLibrary == null) { | |
| 12024 return Namespace.EMPTY; | |
| 12025 } | |
| 12026 Map<String, Element> definedNames = createExportMapping(importedLibrary, new
Set<LibraryElement>()); | |
| 12027 definedNames = apply(definedNames, element.combinators); | |
| 12028 definedNames = apply2(definedNames, element.prefix); | |
| 12029 return new Namespace(definedNames); | |
| 12030 } | |
| 12031 | |
| 12032 /** | |
| 12033 * Create a namespace representing the public namespace of the given library. | |
| 12034 * | |
| 12035 * @param library the library whose public namespace is to be created | |
| 12036 * @return the public namespace that was created | |
| 12037 */ | |
| 12038 Namespace createPublicNamespace(LibraryElement library) { | |
| 12039 Map<String, Element> definedNames = new Map<String, Element>(); | |
| 12040 addPublicNames(definedNames, library.definingCompilationUnit); | |
| 12041 for (CompilationUnitElement compilationUnit in library.parts) { | |
| 12042 addPublicNames(definedNames, compilationUnit); | |
| 12043 } | |
| 12044 return new Namespace(definedNames); | |
| 12045 } | |
| 12046 | |
| 12047 /** | |
| 12048 * Add all of the names in the given namespace to the given mapping table. | |
| 12049 * | |
| 12050 * @param definedNames the mapping table to which the names in the given names
pace are to be added | |
| 12051 * @param namespace the namespace containing the names to be added to this nam
espace | |
| 12052 */ | |
| 12053 void addAll(Map<String, Element> definedNames, Map<String, Element> newNames)
{ | |
| 12054 for (MapEntry<String, Element> entry in getMapEntrySet(newNames)) { | |
| 12055 definedNames[entry.getKey()] = entry.getValue(); | |
| 12056 } | |
| 12057 } | |
| 12058 | |
| 12059 /** | |
| 12060 * Add all of the names in the given namespace to the given mapping table. | |
| 12061 * | |
| 12062 * @param definedNames the mapping table to which the names in the given names
pace are to be added | |
| 12063 * @param namespace the namespace containing the names to be added to this nam
espace | |
| 12064 */ | |
| 12065 void addAll2(Map<String, Element> definedNames, Namespace namespace) { | |
| 12066 if (namespace != null) { | |
| 12067 addAll(definedNames, namespace.definedNames); | |
| 12068 } | |
| 12069 } | |
| 12070 | |
| 12071 /** | |
| 12072 * Add the given element to the given mapping table if it has a publicly visib
le name. | |
| 12073 * | |
| 12074 * @param definedNames the mapping table to which the public name is to be add
ed | |
| 12075 * @param element the element to be added | |
| 12076 */ | |
| 12077 void addIfPublic(Map<String, Element> definedNames, Element element) { | |
| 12078 String name = element.name; | |
| 12079 if (name != null && !Scope.isPrivateName(name)) { | |
| 12080 definedNames[name] = element; | |
| 12081 } | |
| 12082 } | |
| 12083 | |
| 12084 /** | |
| 12085 * Add to the given mapping table all of the public top-level names that are d
efined in the given | |
| 12086 * compilation unit. | |
| 12087 * | |
| 12088 * @param definedNames the mapping table to which the public names are to be a
dded | |
| 12089 * @param compilationUnit the compilation unit defining the top-level names to
be added to this | |
| 12090 * namespace | |
| 12091 */ | |
| 12092 void addPublicNames(Map<String, Element> definedNames, CompilationUnitElement
compilationUnit) { | |
| 12093 for (PropertyAccessorElement element in compilationUnit.accessors) { | |
| 12094 addIfPublic(definedNames, element); | |
| 12095 } | |
| 12096 for (FunctionElement element in compilationUnit.functions) { | |
| 12097 addIfPublic(definedNames, element); | |
| 12098 } | |
| 12099 for (FunctionTypeAliasElement element in compilationUnit.functionTypeAliases
) { | |
| 12100 addIfPublic(definedNames, element); | |
| 12101 } | |
| 12102 for (ClassElement element in compilationUnit.types) { | |
| 12103 addIfPublic(definedNames, element); | |
| 12104 } | |
| 12105 } | |
| 12106 | |
| 12107 /** | |
| 12108 * Apply the given combinators to all of the names in the given mapping table. | |
| 12109 * | |
| 12110 * @param definedNames the mapping table to which the namespace operations are
to be applied | |
| 12111 * @param combinators the combinators to be applied | |
| 12112 */ | |
| 12113 Map<String, Element> apply(Map<String, Element> definedNames, List<NamespaceCo
mbinator> combinators) { | |
| 12114 for (NamespaceCombinator combinator in combinators) { | |
| 12115 if (combinator is HideElementCombinator) { | |
| 12116 hide(definedNames, ((combinator as HideElementCombinator)).hiddenNames); | |
| 12117 } else if (combinator is ShowElementCombinator) { | |
| 12118 definedNames = show(definedNames, ((combinator as ShowElementCombinator)
).shownNames); | |
| 12119 } else { | |
| 12120 AnalysisEngine.instance.logger.logError("Unknown type of combinator: ${c
ombinator.runtimeType.toString()}"); | |
| 12121 } | |
| 12122 } | |
| 12123 return definedNames; | |
| 12124 } | |
| 12125 | |
| 12126 /** | |
| 12127 * Apply the given prefix to all of the names in the table of defined names. | |
| 12128 * | |
| 12129 * @param definedNames the names that were defined before this operation | |
| 12130 * @param prefixElement the element defining the prefix to be added to the nam
es | |
| 12131 */ | |
| 12132 Map<String, Element> apply2(Map<String, Element> definedNames, PrefixElement p
refixElement) { | |
| 12133 if (prefixElement != null) { | |
| 12134 String prefix = prefixElement.name; | |
| 12135 Map<String, Element> newNames = new Map<String, Element>(); | |
| 12136 for (MapEntry<String, Element> entry in getMapEntrySet(definedNames)) { | |
| 12137 newNames["${prefix}.${entry.getKey()}"] = entry.getValue(); | |
| 12138 } | |
| 12139 return newNames; | |
| 12140 } else { | |
| 12141 return definedNames; | |
| 12142 } | |
| 12143 } | |
| 12144 | |
| 12145 /** | |
| 12146 * Create a mapping table representing the export namespace of the given libra
ry. | |
| 12147 * | |
| 12148 * @param library the library whose public namespace is to be created | |
| 12149 * @param visitedElements a set of libraries that do not need to be visited wh
en processing the | |
| 12150 * export directives of the given library because all of the names de
fined by them will | |
| 12151 * be added by another library | |
| 12152 * @return the mapping table that was created | |
| 12153 */ | |
| 12154 Map<String, Element> createExportMapping(LibraryElement library, Set<LibraryEl
ement> visitedElements) { | |
| 12155 javaSetAdd(visitedElements, library); | |
| 12156 try { | |
| 12157 Map<String, Element> definedNames = new Map<String, Element>(); | |
| 12158 for (ExportElement element in library.exports) { | |
| 12159 LibraryElement exportedLibrary = element.exportedLibrary; | |
| 12160 if (exportedLibrary != null && !visitedElements.contains(exportedLibrary
)) { | |
| 12161 Map<String, Element> exportedNames = createExportMapping(exportedLibra
ry, visitedElements); | |
| 12162 exportedNames = apply(exportedNames, element.combinators); | |
| 12163 addAll(definedNames, exportedNames); | |
| 12164 } | |
| 12165 } | |
| 12166 addAll2(definedNames, ((library.context as InternalAnalysisContext)).getPu
blicNamespace(library)); | |
| 12167 return definedNames; | |
| 12168 } finally { | |
| 12169 visitedElements.remove(library); | |
| 12170 } | |
| 12171 } | |
| 12172 | |
| 12173 /** | |
| 12174 * Hide all of the given names by removing them from the given collection of d
efined names. | |
| 12175 * | |
| 12176 * @param definedNames the names that were defined before this operation | |
| 12177 * @param hiddenNames the names to be hidden | |
| 12178 */ | |
| 12179 void hide(Map<String, Element> definedNames, List<String> hiddenNames) { | |
| 12180 for (String name in hiddenNames) { | |
| 12181 definedNames.remove(name); | |
| 12182 definedNames.remove("${name}="); | |
| 12183 } | |
| 12184 } | |
| 12185 | |
| 12186 /** | |
| 12187 * Show only the given names by removing all other names from the given collec
tion of defined | |
| 12188 * names. | |
| 12189 * | |
| 12190 * @param definedNames the names that were defined before this operation | |
| 12191 * @param shownNames the names to be shown | |
| 12192 */ | |
| 12193 Map<String, Element> show(Map<String, Element> definedNames, List<String> show
nNames) { | |
| 12194 Map<String, Element> newNames = new Map<String, Element>(); | |
| 12195 for (String name in shownNames) { | |
| 12196 Element element = definedNames[name]; | |
| 12197 if (element != null) { | |
| 12198 newNames[name] = element; | |
| 12199 } | |
| 12200 String setterName = "${name}="; | |
| 12201 element = definedNames[setterName]; | |
| 12202 if (element != null) { | |
| 12203 newNames[setterName] = element; | |
| 12204 } | |
| 12205 } | |
| 12206 return newNames; | |
| 12207 } | |
| 12208 } | |
| 12209 /** | |
| 12210 * The abstract class `Scope` defines the behavior common to name scopes used by
the resolver | |
| 12211 * to determine which names are visible at any given point in the code. | |
| 12212 * | |
| 12213 * @coverage dart.engine.resolver | |
| 12214 */ | |
| 12215 abstract class Scope { | |
| 12216 | |
| 12217 /** | |
| 12218 * The prefix used to mark an identifier as being private to its library. | |
| 12219 */ | |
| 12220 static String PRIVATE_NAME_PREFIX = "_"; | |
| 12221 | |
| 12222 /** | |
| 12223 * The suffix added to the declared name of a setter when looking up the sette
r. Used to | |
| 12224 * disambiguate between a getter and a setter that have the same name. | |
| 12225 */ | |
| 12226 static String SETTER_SUFFIX = "="; | |
| 12227 | |
| 12228 /** | |
| 12229 * The name used to look up the method used to implement the unary minus opera
tor. Used to | |
| 12230 * disambiguate between the unary and binary operators. | |
| 12231 */ | |
| 12232 static String UNARY_MINUS = "unary-"; | |
| 12233 | |
| 12234 /** | |
| 12235 * Return `true` if the given name is a library-private name. | |
| 12236 * | |
| 12237 * @param name the name being tested | |
| 12238 * @return `true` if the given name is a library-private name | |
| 12239 */ | |
| 12240 static bool isPrivateName(String name) => name != null && name.startsWith(PRIV
ATE_NAME_PREFIX); | |
| 12241 | |
| 12242 /** | |
| 12243 * A table mapping names that are defined in this scope to the element represe
nting the thing | |
| 12244 * declared with that name. | |
| 12245 */ | |
| 12246 Map<String, Element> _definedNames = new Map<String, Element>(); | |
| 12247 | |
| 12248 /** | |
| 12249 * Add the given element to this scope. If there is already an element with th
e given name defined | |
| 12250 * in this scope, then an error will be generated and the original element wil
l continue to be | |
| 12251 * mapped to the name. If there is an element with the given name in an enclos
ing scope, then a | |
| 12252 * warning will be generated but the given element will hide the inherited ele
ment. | |
| 12253 * | |
| 12254 * @param element the element to be added to this scope | |
| 12255 */ | |
| 12256 void define(Element element) { | |
| 12257 String name = getName(element); | |
| 12258 if (name != null && !name.isEmpty) { | |
| 12259 if (_definedNames.containsKey(name)) { | |
| 12260 errorListener.onError(getErrorForDuplicate(_definedNames[name], element)
); | |
| 12261 } else { | |
| 12262 _definedNames[name] = element; | |
| 12263 } | |
| 12264 } | |
| 12265 } | |
| 12266 | |
| 12267 /** | |
| 12268 * Return the element with which the given identifier is associated, or `null`
if the name | |
| 12269 * is not defined within this scope. | |
| 12270 * | |
| 12271 * @param identifier the identifier associated with the element to be returned | |
| 12272 * @param referencingLibrary the library that contains the reference to the na
me, used to | |
| 12273 * implement library-level privacy | |
| 12274 * @return the element with which the given identifier is associated | |
| 12275 */ | |
| 12276 Element lookup(Identifier identifier, LibraryElement referencingLibrary) => lo
okup3(identifier, identifier.name, referencingLibrary); | |
| 12277 | |
| 12278 /** | |
| 12279 * Add the given element to this scope without checking for duplication or hid
ing. | |
| 12280 * | |
| 12281 * @param element the element to be added to this scope | |
| 12282 */ | |
| 12283 void defineWithoutChecking(Element element) { | |
| 12284 _definedNames[getName(element)] = element; | |
| 12285 } | |
| 12286 | |
| 12287 /** | |
| 12288 * Add the given element to this scope without checking for duplication or hid
ing. | |
| 12289 * | |
| 12290 * @param name the name of the element to be added | |
| 12291 * @param element the element to be added to this scope | |
| 12292 */ | |
| 12293 void defineWithoutChecking2(String name, Element element) { | |
| 12294 _definedNames[name] = element; | |
| 12295 } | |
| 12296 | |
| 12297 /** | |
| 12298 * Return the element representing the library in which this scope is enclosed
. | |
| 12299 * | |
| 12300 * @return the element representing the library in which this scope is enclose
d | |
| 12301 */ | |
| 12302 LibraryElement get definingLibrary; | |
| 12303 | |
| 12304 /** | |
| 12305 * Return the error code to be used when reporting that a name being defined l
ocally conflicts | |
| 12306 * with another element of the same name in the local scope. | |
| 12307 * | |
| 12308 * @param existing the first element to be declared with the conflicting name | |
| 12309 * @param duplicate another element declared with the conflicting name | |
| 12310 * @return the error code used to report duplicate names within a scope | |
| 12311 */ | |
| 12312 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { | |
| 12313 Source source = duplicate.source; | |
| 12314 if (source == null) { | |
| 12315 source = this.source; | |
| 12316 } | |
| 12317 return new AnalysisError.con2(source, duplicate.nameOffset, duplicate.displa
yName.length, CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName])
; | |
| 12318 } | |
| 12319 | |
| 12320 /** | |
| 12321 * Return the listener that is to be informed when an error is encountered. | |
| 12322 * | |
| 12323 * @return the listener that is to be informed when an error is encountered | |
| 12324 */ | |
| 12325 AnalysisErrorListener get errorListener; | |
| 12326 | |
| 12327 /** | |
| 12328 * Return the source object representing the compilation unit with which error
s related to this | |
| 12329 * scope should be associated. | |
| 12330 * | |
| 12331 * @return the source object with which errors should be associated | |
| 12332 */ | |
| 12333 Source get source => definingLibrary.definingCompilationUnit.source; | |
| 12334 | |
| 12335 /** | |
| 12336 * Return the element with which the given name is associated, or `null` if th
e name is not | |
| 12337 * defined within this scope. This method only returns elements that are direc
tly defined within | |
| 12338 * this scope, not elements that are defined in an enclosing scope. | |
| 12339 * | |
| 12340 * @param name the name associated with the element to be returned | |
| 12341 * @param referencingLibrary the library that contains the reference to the na
me, used to | |
| 12342 * implement library-level privacy | |
| 12343 * @return the element with which the given name is associated | |
| 12344 */ | |
| 12345 Element localLookup(String name, LibraryElement referencingLibrary) => _define
dNames[name]; | |
| 12346 | |
| 12347 /** | |
| 12348 * Return the element with which the given name is associated, or `null` if th
e name is not | |
| 12349 * defined within this scope. | |
| 12350 * | |
| 12351 * @param identifier the identifier node to lookup element for, used to report
correct kind of a | |
| 12352 * problem and associate problem with | |
| 12353 * @param name the name associated with the element to be returned | |
| 12354 * @param referencingLibrary the library that contains the reference to the na
me, used to | |
| 12355 * implement library-level privacy | |
| 12356 * @return the element with which the given name is associated | |
| 12357 */ | |
| 12358 Element lookup3(Identifier identifier, String name, LibraryElement referencing
Library); | |
| 12359 | |
| 12360 /** | |
| 12361 * Return the name that will be used to look up the given element. | |
| 12362 * | |
| 12363 * @param element the element whose look-up name is to be returned | |
| 12364 * @return the name that will be used to look up the given element | |
| 12365 */ | |
| 12366 String getName(Element element) { | |
| 12367 if (element is MethodElement) { | |
| 12368 MethodElement method = element as MethodElement; | |
| 12369 if (method.name == "-" && method.parameters.length == 0) { | |
| 12370 return UNARY_MINUS; | |
| 12371 } | |
| 12372 } | |
| 12373 return element.name; | |
| 12374 } | |
| 12375 } | |
| 12376 /** | |
| 12377 * Instances of the class `ConstantVerifier` traverse an AST structure looking f
or additional | |
| 12378 * errors and warnings not covered by the parser and resolver. In particular, it
looks for errors | |
| 12379 * and warnings related to constant expressions. | |
| 12380 * | |
| 12381 * @coverage dart.engine.resolver | |
| 12382 */ | |
| 12383 class ConstantVerifier extends RecursiveASTVisitor<Object> { | |
| 12384 | |
| 12385 /** | |
| 12386 * The error reporter by which errors will be reported. | |
| 12387 */ | |
| 12388 ErrorReporter _errorReporter; | |
| 12389 | |
| 12390 /** | |
| 12391 * The type representing the type 'bool'. | |
| 12392 */ | |
| 12393 InterfaceType _boolType; | |
| 12394 | |
| 12395 /** | |
| 12396 * The type representing the type 'int'. | |
| 12397 */ | |
| 12398 InterfaceType _intType; | |
| 12399 | |
| 12400 /** | |
| 12401 * The type representing the type 'num'. | |
| 12402 */ | |
| 12403 InterfaceType _numType; | |
| 12404 | |
| 12405 /** | |
| 12406 * The type representing the type 'string'. | |
| 12407 */ | |
| 12408 InterfaceType _stringType; | |
| 12409 | |
| 12410 /** | |
| 12411 * Initialize a newly created constant verifier. | |
| 12412 * | |
| 12413 * @param errorReporter the error reporter by which errors will be reported | |
| 12414 */ | |
| 12415 ConstantVerifier(ErrorReporter errorReporter, TypeProvider typeProvider) { | |
| 12416 this._errorReporter = errorReporter; | |
| 12417 this._boolType = typeProvider.boolType; | |
| 12418 this._intType = typeProvider.intType; | |
| 12419 this._numType = typeProvider.numType; | |
| 12420 this._stringType = typeProvider.stringType; | |
| 12421 } | |
| 12422 Object visitAnnotation(Annotation node) { | |
| 12423 super.visitAnnotation(node); | |
| 12424 Element element = node.element; | |
| 12425 if (element is ConstructorElement) { | |
| 12426 ConstructorElement constructorElement = element as ConstructorElement; | |
| 12427 if (!constructorElement.isConst) { | |
| 12428 _errorReporter.reportError2(CompileTimeErrorCode.NON_CONSTANT_ANNOTATION
_CONSTRUCTOR, node, []); | |
| 12429 return null; | |
| 12430 } | |
| 12431 ArgumentList argumentList = node.arguments; | |
| 12432 if (argumentList == null) { | |
| 12433 _errorReporter.reportError2(CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCT
OR_ARGUMENTS, node, []); | |
| 12434 return null; | |
| 12435 } | |
| 12436 validateConstantArguments(argumentList); | |
| 12437 } | |
| 12438 return null; | |
| 12439 } | |
| 12440 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 12441 if (node.constKeyword != null) { | |
| 12442 validateInitializers(node); | |
| 12443 } | |
| 12444 validateDefaultValues(node.parameters); | |
| 12445 return super.visitConstructorDeclaration(node); | |
| 12446 } | |
| 12447 Object visitFunctionExpression(FunctionExpression node) { | |
| 12448 super.visitFunctionExpression(node); | |
| 12449 validateDefaultValues(node.parameters); | |
| 12450 return null; | |
| 12451 } | |
| 12452 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 12453 validateConstantArguments2(node); | |
| 12454 return super.visitInstanceCreationExpression(node); | |
| 12455 } | |
| 12456 Object visitListLiteral(ListLiteral node) { | |
| 12457 super.visitListLiteral(node); | |
| 12458 if (node.constKeyword != null) { | |
| 12459 for (Expression element in node.elements) { | |
| 12460 validate(element, CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT); | |
| 12461 } | |
| 12462 } | |
| 12463 return null; | |
| 12464 } | |
| 12465 Object visitMapLiteral(MapLiteral node) { | |
| 12466 super.visitMapLiteral(node); | |
| 12467 bool isConst = node.constKeyword != null; | |
| 12468 bool reportEqualKeys = true; | |
| 12469 Set<Object> keys = new Set<Object>(); | |
| 12470 List<Expression> invalidKeys = new List<Expression>(); | |
| 12471 for (MapLiteralEntry entry in node.entries) { | |
| 12472 Expression key = entry.key; | |
| 12473 if (isConst) { | |
| 12474 EvaluationResultImpl result = validate(key, CompileTimeErrorCode.NON_CON
STANT_MAP_KEY); | |
| 12475 validate(entry.value, CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE); | |
| 12476 if (result is ValidResult) { | |
| 12477 Object value = ((result as ValidResult)).value; | |
| 12478 if (keys.contains(value)) { | |
| 12479 invalidKeys.add(key); | |
| 12480 } else { | |
| 12481 javaSetAdd(keys, value); | |
| 12482 } | |
| 12483 } | |
| 12484 } else { | |
| 12485 EvaluationResultImpl result = key.accept(new ConstantVisitor()); | |
| 12486 if (result is ValidResult) { | |
| 12487 Object value = ((result as ValidResult)).value; | |
| 12488 if (keys.contains(value)) { | |
| 12489 invalidKeys.add(key); | |
| 12490 } else { | |
| 12491 javaSetAdd(keys, value); | |
| 12492 } | |
| 12493 } else { | |
| 12494 reportEqualKeys = false; | |
| 12495 } | |
| 12496 } | |
| 12497 } | |
| 12498 if (reportEqualKeys) { | |
| 12499 for (Expression key in invalidKeys) { | |
| 12500 _errorReporter.reportError2(StaticWarningCode.EQUAL_KEYS_IN_MAP, key, []
); | |
| 12501 } | |
| 12502 } | |
| 12503 return null; | |
| 12504 } | |
| 12505 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 12506 super.visitMethodDeclaration(node); | |
| 12507 validateDefaultValues(node.parameters); | |
| 12508 return null; | |
| 12509 } | |
| 12510 Object visitSwitchCase(SwitchCase node) { | |
| 12511 super.visitSwitchCase(node); | |
| 12512 validate(node.expression, CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION)
; | |
| 12513 return null; | |
| 12514 } | |
| 12515 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 12516 super.visitVariableDeclaration(node); | |
| 12517 Expression initializer = node.initializer; | |
| 12518 if (initializer != null && node.isConst) { | |
| 12519 VariableElementImpl element = node.element as VariableElementImpl; | |
| 12520 EvaluationResultImpl result = element.evaluationResult; | |
| 12521 if (result == null) { | |
| 12522 result = validate(initializer, CompileTimeErrorCode.CONST_INITIALIZED_WI
TH_NON_CONSTANT_VALUE); | |
| 12523 element.evaluationResult = result; | |
| 12524 } else if (result is ErrorResult) { | |
| 12525 reportErrors(result, CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CON
STANT_VALUE); | |
| 12526 } | |
| 12527 } | |
| 12528 return null; | |
| 12529 } | |
| 12530 | |
| 12531 /** | |
| 12532 * If the given result represents one or more errors, report those errors. Exc
ept for special | |
| 12533 * cases, use the given error code rather than the one reported in the error. | |
| 12534 * | |
| 12535 * @param result the result containing any errors that need to be reported | |
| 12536 * @param errorCode the error code to be used if the result represents an erro
r | |
| 12537 */ | |
| 12538 void reportErrors(EvaluationResultImpl result, ErrorCode errorCode) { | |
| 12539 if (result is ErrorResult) { | |
| 12540 for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) { | |
| 12541 ErrorCode dataErrorCode = data.errorCode; | |
| 12542 if (identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCE
PTION) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE)
|| identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRIN
G) || identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) || ide
ntical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) || identical(dat
aErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM)) { | |
| 12543 _errorReporter.reportError2(dataErrorCode, data.node, []); | |
| 12544 } else { | |
| 12545 _errorReporter.reportError2(errorCode, data.node, []); | |
| 12546 } | |
| 12547 } | |
| 12548 } | |
| 12549 } | |
| 12550 | |
| 12551 /** | |
| 12552 * Validate that the given expression is a compile time constant. Return the v
alue of the compile | |
| 12553 * time constant, or `null` if the expression is not a compile time constant. | |
| 12554 * | |
| 12555 * @param expression the expression to be validated | |
| 12556 * @param errorCode the error code to be used if the expression is not a compi
le time constant | |
| 12557 * @return the value of the compile time constant | |
| 12558 */ | |
| 12559 EvaluationResultImpl validate(Expression expression, ErrorCode errorCode) { | |
| 12560 EvaluationResultImpl result = expression.accept(new ConstantVisitor()); | |
| 12561 reportErrors(result, errorCode); | |
| 12562 return result; | |
| 12563 } | |
| 12564 | |
| 12565 /** | |
| 12566 * Validate that if the passed arguments are constant expressions. | |
| 12567 * | |
| 12568 * @param argumentList the argument list to evaluate | |
| 12569 */ | |
| 12570 void validateConstantArguments(ArgumentList argumentList) { | |
| 12571 for (Expression argument in argumentList.arguments) { | |
| 12572 if (argument is NamedExpression) { | |
| 12573 argument = ((argument as NamedExpression)).expression; | |
| 12574 } | |
| 12575 validate(argument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT); | |
| 12576 } | |
| 12577 } | |
| 12578 | |
| 12579 /** | |
| 12580 * Validate that if the passed instance creation is 'const' then all its argum
ents are constant | |
| 12581 * expressions. | |
| 12582 * | |
| 12583 * @param node the instance creation evaluate | |
| 12584 */ | |
| 12585 void validateConstantArguments2(InstanceCreationExpression node) { | |
| 12586 if (!node.isConst) { | |
| 12587 return; | |
| 12588 } | |
| 12589 ArgumentList argumentList = node.argumentList; | |
| 12590 if (argumentList == null) { | |
| 12591 return; | |
| 12592 } | |
| 12593 validateConstantArguments(argumentList); | |
| 12594 } | |
| 12595 | |
| 12596 /** | |
| 12597 * Validate that the default value associated with each of the parameters in t
he given list is a | |
| 12598 * compile time constant. | |
| 12599 * | |
| 12600 * @param parameters the list of parameters to be validated | |
| 12601 */ | |
| 12602 void validateDefaultValues(FormalParameterList parameters) { | |
| 12603 if (parameters == null) { | |
| 12604 return; | |
| 12605 } | |
| 12606 for (FormalParameter parameter in parameters.parameters) { | |
| 12607 if (parameter is DefaultFormalParameter) { | |
| 12608 DefaultFormalParameter defaultParameter = parameter as DefaultFormalPara
meter; | |
| 12609 Expression defaultValue = defaultParameter.defaultValue; | |
| 12610 if (defaultValue != null) { | |
| 12611 EvaluationResultImpl result = validate(defaultValue, CompileTimeErrorC
ode.NON_CONSTANT_DEFAULT_VALUE); | |
| 12612 VariableElementImpl element = parameter.element as VariableElementImpl
; | |
| 12613 element.evaluationResult = result; | |
| 12614 } | |
| 12615 } | |
| 12616 } | |
| 12617 } | |
| 12618 | |
| 12619 /** | |
| 12620 * Validates that the given expression is a compile time constant. | |
| 12621 * | |
| 12622 * @param parameterElements the elements of parameters of constant constructor
, they are | |
| 12623 * considered as a valid potentially constant expressions | |
| 12624 * @param expression the expression to validate | |
| 12625 */ | |
| 12626 void validateInitializerExpression(List<ParameterElement> parameterElements, E
xpression expression) { | |
| 12627 EvaluationResultImpl result = expression.accept(new ConstantVisitor_13(this,
parameterElements)); | |
| 12628 reportErrors(result, CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER)
; | |
| 12629 } | |
| 12630 | |
| 12631 /** | |
| 12632 * Validates that all of the arguments of a constructor initializer are compil
e time constants. | |
| 12633 * | |
| 12634 * @param parameterElements the elements of parameters of constant constructor
, they are | |
| 12635 * considered as a valid potentially constant expressions | |
| 12636 * @param argumentList the argument list to validate | |
| 12637 */ | |
| 12638 void validateInitializerInvocationArguments(List<ParameterElement> parameterEl
ements, ArgumentList argumentList) { | |
| 12639 if (argumentList == null) { | |
| 12640 return; | |
| 12641 } | |
| 12642 for (Expression argument in argumentList.arguments) { | |
| 12643 validateInitializerExpression(parameterElements, argument); | |
| 12644 } | |
| 12645 } | |
| 12646 | |
| 12647 /** | |
| 12648 * Validates that the expressions of the given initializers (of a constant con
structor) are all | |
| 12649 * compile time constants. | |
| 12650 * | |
| 12651 * @param constructor the constant constructor declaration to validate | |
| 12652 */ | |
| 12653 void validateInitializers(ConstructorDeclaration constructor) { | |
| 12654 List<ParameterElement> parameterElements = constructor.parameters.parameterE
lements; | |
| 12655 NodeList<ConstructorInitializer> initializers = constructor.initializers; | |
| 12656 for (ConstructorInitializer initializer in initializers) { | |
| 12657 if (initializer is ConstructorFieldInitializer) { | |
| 12658 ConstructorFieldInitializer fieldInitializer = initializer as Constructo
rFieldInitializer; | |
| 12659 validateInitializerExpression(parameterElements, fieldInitializer.expres
sion); | |
| 12660 } | |
| 12661 if (initializer is RedirectingConstructorInvocation) { | |
| 12662 RedirectingConstructorInvocation invocation = initializer as Redirecting
ConstructorInvocation; | |
| 12663 validateInitializerInvocationArguments(parameterElements, invocation.arg
umentList); | |
| 12664 } | |
| 12665 if (initializer is SuperConstructorInvocation) { | |
| 12666 SuperConstructorInvocation invocation = initializer as SuperConstructorI
nvocation; | |
| 12667 validateInitializerInvocationArguments(parameterElements, invocation.arg
umentList); | |
| 12668 } | |
| 12669 } | |
| 12670 } | |
| 12671 } | |
| 12672 class ConstantVisitor_13 extends ConstantVisitor { | |
| 12673 final ConstantVerifier ConstantVerifier_this; | |
| 12674 List<ParameterElement> parameterElements; | |
| 12675 ConstantVisitor_13(this.ConstantVerifier_this, this.parameterElements) : super
(); | |
| 12676 EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) { | |
| 12677 Element element = node.staticElement; | |
| 12678 for (ParameterElement parameterElement in parameterElements) { | |
| 12679 if (identical(parameterElement, element) && parameterElement != null) { | |
| 12680 Type2 type = parameterElement.type; | |
| 12681 if (type != null) { | |
| 12682 if (type.isDynamic) { | |
| 12683 return ValidResult.RESULT_DYNAMIC; | |
| 12684 } | |
| 12685 if (type.isSubtypeOf(ConstantVerifier_this._boolType)) { | |
| 12686 return ValidResult.RESULT_BOOL; | |
| 12687 } | |
| 12688 if (type.isSubtypeOf(ConstantVerifier_this._intType)) { | |
| 12689 return ValidResult.RESULT_INT; | |
| 12690 } | |
| 12691 if (type.isSubtypeOf(ConstantVerifier_this._numType)) { | |
| 12692 return ValidResult.RESULT_NUM; | |
| 12693 } | |
| 12694 if (type.isSubtypeOf(ConstantVerifier_this._stringType)) { | |
| 12695 return ValidResult.RESULT_STRING; | |
| 12696 } | |
| 12697 } | |
| 12698 return ValidResult.RESULT_OBJECT; | |
| 12699 } | |
| 12700 } | |
| 12701 return super.visitSimpleIdentifier(node); | |
| 12702 } | |
| 12703 } | |
| 12704 /** | |
| 12705 * Instances of the class `ErrorVerifier` traverse an AST structure looking for
additional | |
| 12706 * errors and warnings not covered by the parser and resolver. | |
| 12707 * | |
| 12708 * @coverage dart.engine.resolver | |
| 12709 */ | |
| 12710 class ErrorVerifier extends RecursiveASTVisitor<Object> { | |
| 12711 | |
| 12712 /** | |
| 12713 * Checks if the given expression is the reference to the type. | |
| 12714 * | |
| 12715 * @param expr the expression to evaluate | |
| 12716 * @return `true` if the given expression is the reference to the type | |
| 12717 */ | |
| 12718 static bool isTypeReference(Expression expr) { | |
| 12719 if (expr is Identifier) { | |
| 12720 Identifier identifier = expr as Identifier; | |
| 12721 return identifier.staticElement is ClassElement; | |
| 12722 } | |
| 12723 return false; | |
| 12724 } | |
| 12725 | |
| 12726 /** | |
| 12727 * The error reporter by which errors will be reported. | |
| 12728 */ | |
| 12729 ErrorReporter _errorReporter; | |
| 12730 | |
| 12731 /** | |
| 12732 * The current library that is being analyzed. | |
| 12733 */ | |
| 12734 LibraryElement _currentLibrary; | |
| 12735 | |
| 12736 /** | |
| 12737 * The type representing the type 'dynamic'. | |
| 12738 */ | |
| 12739 Type2 _dynamicType; | |
| 12740 | |
| 12741 /** | |
| 12742 * The object providing access to the types defined by the language. | |
| 12743 */ | |
| 12744 TypeProvider _typeProvider; | |
| 12745 | |
| 12746 /** | |
| 12747 * The manager for the inheritance mappings. | |
| 12748 */ | |
| 12749 InheritanceManager _inheritanceManager; | |
| 12750 | |
| 12751 /** | |
| 12752 * A flag indicating whether we are running in strict mode. In strict mode, er
ror reporting is | |
| 12753 * based exclusively on the static type information. | |
| 12754 */ | |
| 12755 bool _strictMode = false; | |
| 12756 | |
| 12757 /** | |
| 12758 * This is set to `true` iff the visitor is currently visiting children nodes
of a | |
| 12759 * [ConstructorDeclaration] and the constructor is 'const'. | |
| 12760 * | |
| 12761 * @see #visitConstructorDeclaration(ConstructorDeclaration) | |
| 12762 */ | |
| 12763 bool _isEnclosingConstructorConst = false; | |
| 12764 | |
| 12765 /** | |
| 12766 * This is set to `true` iff the visitor is currently visiting children nodes
of a | |
| 12767 * [CatchClause]. | |
| 12768 * | |
| 12769 * @see #visitCatchClause(CatchClause) | |
| 12770 */ | |
| 12771 bool _isInCatchClause = false; | |
| 12772 | |
| 12773 /** | |
| 12774 * This is set to `true` iff the visitor is currently visiting children nodes
of an | |
| 12775 * [Comment]. | |
| 12776 */ | |
| 12777 bool _isInComment = false; | |
| 12778 | |
| 12779 /** | |
| 12780 * This is set to `true` iff the visitor is currently visiting children nodes
of an | |
| 12781 * [InstanceCreationExpression]. | |
| 12782 */ | |
| 12783 bool _isInConstInstanceCreation = false; | |
| 12784 | |
| 12785 /** | |
| 12786 * This is set to `true` iff the visitor is currently visiting children nodes
of a native | |
| 12787 * [ClassDeclaration]. | |
| 12788 */ | |
| 12789 bool _isInNativeClass = false; | |
| 12790 | |
| 12791 /** | |
| 12792 * This is set to `true` iff the visitor is currently visiting a static variab
le | |
| 12793 * declaration. | |
| 12794 */ | |
| 12795 bool _isInStaticVariableDeclaration = false; | |
| 12796 | |
| 12797 /** | |
| 12798 * This is set to `true` iff the visitor is currently visiting an instance var
iable | |
| 12799 * declaration. | |
| 12800 */ | |
| 12801 bool _isInInstanceVariableDeclaration = false; | |
| 12802 | |
| 12803 /** | |
| 12804 * This is set to `true` iff the visitor is currently visiting an instance var
iable | |
| 12805 * initializer. | |
| 12806 */ | |
| 12807 bool _isInInstanceVariableInitializer = false; | |
| 12808 | |
| 12809 /** | |
| 12810 * This is set to `true` iff the visitor is currently visiting a | |
| 12811 * [ConstructorInitializer]. | |
| 12812 */ | |
| 12813 bool _isInConstructorInitializer = false; | |
| 12814 | |
| 12815 /** | |
| 12816 * This is set to `true` iff the visitor is currently visiting a | |
| 12817 * [FunctionTypedFormalParameter]. | |
| 12818 */ | |
| 12819 bool _isInFunctionTypedFormalParameter = false; | |
| 12820 | |
| 12821 /** | |
| 12822 * This is set to `true` iff the visitor is currently visiting a static method
. By "method" | |
| 12823 * here getter, setter and operator declarations are also implied since they a
re all represented | |
| 12824 * with a [MethodDeclaration] in the AST structure. | |
| 12825 */ | |
| 12826 bool _isInStaticMethod = false; | |
| 12827 | |
| 12828 /** | |
| 12829 * This is set to `true` iff the visitor is currently visiting code in the SDK
. | |
| 12830 */ | |
| 12831 bool _isInSystemLibrary = false; | |
| 12832 | |
| 12833 /** | |
| 12834 * The class containing the AST nodes being visited, or `null` if we are not i
n the scope of | |
| 12835 * a class. | |
| 12836 */ | |
| 12837 ClassElement _enclosingClass; | |
| 12838 | |
| 12839 /** | |
| 12840 * The method or function that we are currently visiting, or `null` if we are
not inside a | |
| 12841 * method or function. | |
| 12842 */ | |
| 12843 ExecutableElement _enclosingFunction; | |
| 12844 | |
| 12845 /** | |
| 12846 * The number of return statements found in the method or function that we are
currently visiting | |
| 12847 * that have a return value. | |
| 12848 */ | |
| 12849 int _returnWithCount = 0; | |
| 12850 | |
| 12851 /** | |
| 12852 * The number of return statements found in the method or function that we are
currently visiting | |
| 12853 * that do not have a return value. | |
| 12854 */ | |
| 12855 int _returnWithoutCount = 0; | |
| 12856 | |
| 12857 /** | |
| 12858 * This map is initialized when visiting the contents of a class declaration.
If the visitor is | |
| 12859 * not in an enclosing class declaration, then the map is set to `null`. | |
| 12860 * | |
| 12861 * When set the map maps the set of [FieldElement]s in the class to an | |
| 12862 * [INIT_STATE#NOT_INIT] or [INIT_STATE#INIT_IN_DECLARATION]. <code>checkFor*<
/code> | |
| 12863 * methods, specifically [checkForAllFinalInitializedErrorCodes], | |
| 12864 * can make a copy of the map to compute error code states. <code>checkFor*</c
ode> methods should | |
| 12865 * only ever make a copy, or read from this map after it has been set in | |
| 12866 * [visitClassDeclaration]. | |
| 12867 * | |
| 12868 * @see #visitClassDeclaration(ClassDeclaration) | |
| 12869 * @see #checkForAllFinalInitializedErrorCodes(ConstructorDeclaration) | |
| 12870 */ | |
| 12871 Map<FieldElement, INIT_STATE> _initialFieldElementsMap; | |
| 12872 | |
| 12873 /** | |
| 12874 * A table mapping name of the library to the export directive which export th
is library. | |
| 12875 */ | |
| 12876 Map<String, LibraryElement> _nameToExportElement = new Map<String, LibraryElem
ent>(); | |
| 12877 | |
| 12878 /** | |
| 12879 * A table mapping name of the library to the import directive which import th
is library. | |
| 12880 */ | |
| 12881 Map<String, LibraryElement> _nameToImportElement = new Map<String, LibraryElem
ent>(); | |
| 12882 | |
| 12883 /** | |
| 12884 * A table mapping names to the export elements exported them. | |
| 12885 */ | |
| 12886 Map<String, ExportElement> _exportedNames = new Map<String, ExportElement>(); | |
| 12887 | |
| 12888 /** | |
| 12889 * A set of the names of the variable initializers we are visiting now. | |
| 12890 */ | |
| 12891 Set<String> _namesForReferenceToDeclaredVariableInInitializer = new Set<String
>(); | |
| 12892 | |
| 12893 /** | |
| 12894 * A list of types used by the [CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS]
and | |
| 12895 * [CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS] error codes. | |
| 12896 */ | |
| 12897 List<InterfaceType> _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT; | |
| 12898 ErrorVerifier(ErrorReporter errorReporter, LibraryElement currentLibrary, Type
Provider typeProvider, InheritanceManager inheritanceManager) { | |
| 12899 this._errorReporter = errorReporter; | |
| 12900 this._currentLibrary = currentLibrary; | |
| 12901 this._isInSystemLibrary = currentLibrary.source.isInSystemLibrary; | |
| 12902 this._typeProvider = typeProvider; | |
| 12903 this._inheritanceManager = inheritanceManager; | |
| 12904 _strictMode = currentLibrary.context.analysisOptions.strictMode; | |
| 12905 _isEnclosingConstructorConst = false; | |
| 12906 _isInCatchClause = false; | |
| 12907 _isInStaticVariableDeclaration = false; | |
| 12908 _isInInstanceVariableDeclaration = false; | |
| 12909 _isInInstanceVariableInitializer = false; | |
| 12910 _isInConstructorInitializer = false; | |
| 12911 _isInStaticMethod = false; | |
| 12912 _dynamicType = typeProvider.dynamicType; | |
| 12913 _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT = <InterfaceType> [ | |
| 12914 typeProvider.nullType, | |
| 12915 typeProvider.numType, | |
| 12916 typeProvider.intType, | |
| 12917 typeProvider.doubleType, | |
| 12918 typeProvider.boolType, | |
| 12919 typeProvider.stringType]; | |
| 12920 } | |
| 12921 Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) { | |
| 12922 checkForArgumentDefinitionTestNonParameter(node); | |
| 12923 return super.visitArgumentDefinitionTest(node); | |
| 12924 } | |
| 12925 Object visitArgumentList(ArgumentList node) { | |
| 12926 checkForArgumentTypeNotAssignable(node); | |
| 12927 return super.visitArgumentList(node); | |
| 12928 } | |
| 12929 Object visitAssertStatement(AssertStatement node) { | |
| 12930 checkForNonBoolExpression(node); | |
| 12931 return super.visitAssertStatement(node); | |
| 12932 } | |
| 12933 Object visitAssignmentExpression(AssignmentExpression node) { | |
| 12934 sc.Token operator = node.operator; | |
| 12935 sc.TokenType operatorType = operator.type; | |
| 12936 if (identical(operatorType, sc.TokenType.EQ)) { | |
| 12937 checkForInvalidAssignment2(node.leftHandSide, node.rightHandSide); | |
| 12938 } else { | |
| 12939 checkForInvalidAssignment(node); | |
| 12940 } | |
| 12941 checkForAssignmentToFinal(node); | |
| 12942 checkForArgumentTypeNotAssignable2(node.rightHandSide); | |
| 12943 return super.visitAssignmentExpression(node); | |
| 12944 } | |
| 12945 Object visitBinaryExpression(BinaryExpression node) { | |
| 12946 checkForArgumentTypeNotAssignable2(node.rightOperand); | |
| 12947 return super.visitBinaryExpression(node); | |
| 12948 } | |
| 12949 Object visitBlockFunctionBody(BlockFunctionBody node) { | |
| 12950 int previousReturnWithCount = _returnWithCount; | |
| 12951 int previousReturnWithoutCount = _returnWithoutCount; | |
| 12952 try { | |
| 12953 _returnWithCount = 0; | |
| 12954 _returnWithoutCount = 0; | |
| 12955 super.visitBlockFunctionBody(node); | |
| 12956 checkForMixedReturns(node); | |
| 12957 } finally { | |
| 12958 _returnWithCount = previousReturnWithCount; | |
| 12959 _returnWithoutCount = previousReturnWithoutCount; | |
| 12960 } | |
| 12961 return null; | |
| 12962 } | |
| 12963 Object visitCatchClause(CatchClause node) { | |
| 12964 bool previousIsInCatchClause = _isInCatchClause; | |
| 12965 try { | |
| 12966 _isInCatchClause = true; | |
| 12967 return super.visitCatchClause(node); | |
| 12968 } finally { | |
| 12969 _isInCatchClause = previousIsInCatchClause; | |
| 12970 } | |
| 12971 } | |
| 12972 Object visitClassDeclaration(ClassDeclaration node) { | |
| 12973 ClassElement outerClass = _enclosingClass; | |
| 12974 try { | |
| 12975 _isInNativeClass = node.nativeClause != null; | |
| 12976 _enclosingClass = node.element; | |
| 12977 WithClause withClause = node.withClause; | |
| 12978 ImplementsClause implementsClause = node.implementsClause; | |
| 12979 ExtendsClause extendsClause = node.extendsClause; | |
| 12980 checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_I
DENTIFIER_AS_TYPE_NAME); | |
| 12981 checkForMemberWithClassName(); | |
| 12982 checkForNoDefaultSuperConstructorImplicit(node); | |
| 12983 checkForAllMixinErrorCodes(withClause); | |
| 12984 checkForConflictingTypeVariableErrorCodes(node); | |
| 12985 if (implementsClause != null || extendsClause != null) { | |
| 12986 if (!checkForImplementsDisallowedClass(implementsClause) && !checkForExt
endsDisallowedClass(extendsClause)) { | |
| 12987 checkForNonAbstractClassInheritsAbstractMember(node); | |
| 12988 checkForInconsistentMethodInheritance(); | |
| 12989 checkForRecursiveInterfaceInheritance(_enclosingClass); | |
| 12990 } | |
| 12991 } | |
| 12992 ClassElement classElement = node.element; | |
| 12993 if (classElement != null) { | |
| 12994 List<FieldElement> fieldElements = classElement.fields; | |
| 12995 _initialFieldElementsMap = new Map<FieldElement, INIT_STATE>(); | |
| 12996 for (FieldElement fieldElement in fieldElements) { | |
| 12997 if (!fieldElement.isSynthetic) { | |
| 12998 _initialFieldElementsMap[fieldElement] = fieldElement.initializer ==
null ? INIT_STATE.NOT_INIT : INIT_STATE.INIT_IN_DECLARATION; | |
| 12999 } | |
| 13000 } | |
| 13001 } | |
| 13002 checkForFinalNotInitialized(node); | |
| 13003 checkForDuplicateDefinitionInheritance(); | |
| 13004 checkForConflictingGetterAndMethod(); | |
| 13005 checkImplementsSuperClass(node); | |
| 13006 checkImplementsFunctionWithoutCall(node); | |
| 13007 return super.visitClassDeclaration(node); | |
| 13008 } finally { | |
| 13009 _isInNativeClass = false; | |
| 13010 _initialFieldElementsMap = null; | |
| 13011 _enclosingClass = outerClass; | |
| 13012 } | |
| 13013 } | |
| 13014 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 13015 checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDE
NTIFIER_AS_TYPEDEF_NAME); | |
| 13016 checkForAllMixinErrorCodes(node.withClause); | |
| 13017 ClassElement outerClassElement = _enclosingClass; | |
| 13018 try { | |
| 13019 _enclosingClass = node.element; | |
| 13020 checkForRecursiveInterfaceInheritance(node.element); | |
| 13021 checkForTypeAliasCannotReferenceItself_mixin(node); | |
| 13022 } finally { | |
| 13023 _enclosingClass = outerClassElement; | |
| 13024 } | |
| 13025 return super.visitClassTypeAlias(node); | |
| 13026 } | |
| 13027 Object visitComment(Comment node) { | |
| 13028 _isInComment = true; | |
| 13029 try { | |
| 13030 return super.visitComment(node); | |
| 13031 } finally { | |
| 13032 _isInComment = false; | |
| 13033 } | |
| 13034 } | |
| 13035 Object visitConditionalExpression(ConditionalExpression node) { | |
| 13036 checkForNonBoolCondition(node.condition); | |
| 13037 return super.visitConditionalExpression(node); | |
| 13038 } | |
| 13039 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 13040 ExecutableElement outerFunction = _enclosingFunction; | |
| 13041 try { | |
| 13042 _enclosingFunction = node.element; | |
| 13043 _isEnclosingConstructorConst = node.constKeyword != null; | |
| 13044 checkForConstConstructorWithNonFinalField(node); | |
| 13045 checkForConstConstructorWithNonConstSuper(node); | |
| 13046 checkForConflictingConstructorNameAndMember(node); | |
| 13047 checkForAllFinalInitializedErrorCodes(node); | |
| 13048 checkForRedirectingConstructorErrorCodes(node); | |
| 13049 checkForMultipleSuperInitializers(node); | |
| 13050 checkForRecursiveConstructorRedirect(node); | |
| 13051 if (!checkForRecursiveFactoryRedirect(node)) { | |
| 13052 checkForAllRedirectConstructorErrorCodes(node); | |
| 13053 } | |
| 13054 checkForUndefinedConstructorInInitializerImplicit(node); | |
| 13055 checkForRedirectToNonConstConstructor(node); | |
| 13056 checkForReturnInGenerativeConstructor(node); | |
| 13057 return super.visitConstructorDeclaration(node); | |
| 13058 } finally { | |
| 13059 _isEnclosingConstructorConst = false; | |
| 13060 _enclosingFunction = outerFunction; | |
| 13061 } | |
| 13062 } | |
| 13063 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 13064 _isInConstructorInitializer = true; | |
| 13065 try { | |
| 13066 checkForFieldInitializerNotAssignable(node); | |
| 13067 return super.visitConstructorFieldInitializer(node); | |
| 13068 } finally { | |
| 13069 _isInConstructorInitializer = false; | |
| 13070 } | |
| 13071 } | |
| 13072 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 13073 checkForInvalidAssignment2(node.identifier, node.defaultValue); | |
| 13074 checkForDefaultValueInFunctionTypedParameter(node); | |
| 13075 return super.visitDefaultFormalParameter(node); | |
| 13076 } | |
| 13077 Object visitDoStatement(DoStatement node) { | |
| 13078 checkForNonBoolCondition(node.condition); | |
| 13079 return super.visitDoStatement(node); | |
| 13080 } | |
| 13081 Object visitExportDirective(ExportDirective node) { | |
| 13082 checkForAmbiguousExport(node); | |
| 13083 checkForExportDuplicateLibraryName(node); | |
| 13084 checkForExportInternalLibrary(node); | |
| 13085 return super.visitExportDirective(node); | |
| 13086 } | |
| 13087 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { | |
| 13088 FunctionType functionType = _enclosingFunction == null ? null : _enclosingFu
nction.type; | |
| 13089 Type2 expectedReturnType = functionType == null ? DynamicTypeImpl.instance :
functionType.returnType; | |
| 13090 checkForReturnOfInvalidType(node.expression, expectedReturnType); | |
| 13091 return super.visitExpressionFunctionBody(node); | |
| 13092 } | |
| 13093 Object visitFieldDeclaration(FieldDeclaration node) { | |
| 13094 if (!node.isStatic) { | |
| 13095 VariableDeclarationList variables = node.fields; | |
| 13096 if (variables.isConst) { | |
| 13097 _errorReporter.reportError4(CompileTimeErrorCode.CONST_INSTANCE_FIELD, v
ariables.keyword, []); | |
| 13098 } | |
| 13099 } | |
| 13100 _isInStaticVariableDeclaration = node.isStatic; | |
| 13101 _isInInstanceVariableDeclaration = !_isInStaticVariableDeclaration; | |
| 13102 try { | |
| 13103 checkForAllInvalidOverrideErrorCodes2(node); | |
| 13104 return super.visitFieldDeclaration(node); | |
| 13105 } finally { | |
| 13106 _isInStaticVariableDeclaration = false; | |
| 13107 _isInInstanceVariableDeclaration = false; | |
| 13108 } | |
| 13109 } | |
| 13110 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 13111 checkForConstFormalParameter(node); | |
| 13112 checkForPrivateOptionalParameter(node); | |
| 13113 checkForFieldInitializingFormalRedirectingConstructor(node); | |
| 13114 return super.visitFieldFormalParameter(node); | |
| 13115 } | |
| 13116 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 13117 ExecutableElement outerFunction = _enclosingFunction; | |
| 13118 try { | |
| 13119 SimpleIdentifier identifier = node.name; | |
| 13120 String methodName = ""; | |
| 13121 if (identifier != null) { | |
| 13122 methodName = identifier.name; | |
| 13123 } | |
| 13124 _enclosingFunction = node.element; | |
| 13125 if (node.isSetter || node.isGetter) { | |
| 13126 checkForMismatchedAccessorTypes(node, methodName); | |
| 13127 if (node.isSetter) { | |
| 13128 FunctionExpression functionExpression = node.functionExpression; | |
| 13129 if (functionExpression != null) { | |
| 13130 checkForWrongNumberOfParametersForSetter(node.name, functionExpressi
on.parameters); | |
| 13131 } | |
| 13132 TypeName returnType = node.returnType; | |
| 13133 checkForNonVoidReturnTypeForSetter(returnType); | |
| 13134 } | |
| 13135 } | |
| 13136 return super.visitFunctionDeclaration(node); | |
| 13137 } finally { | |
| 13138 _enclosingFunction = outerFunction; | |
| 13139 } | |
| 13140 } | |
| 13141 Object visitFunctionExpression(FunctionExpression node) { | |
| 13142 if (node.parent is! FunctionDeclaration) { | |
| 13143 ExecutableElement outerFunction = _enclosingFunction; | |
| 13144 try { | |
| 13145 _enclosingFunction = node.element; | |
| 13146 return super.visitFunctionExpression(node); | |
| 13147 } finally { | |
| 13148 _enclosingFunction = outerFunction; | |
| 13149 } | |
| 13150 } else { | |
| 13151 return super.visitFunctionExpression(node); | |
| 13152 } | |
| 13153 } | |
| 13154 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 13155 Expression functionExpression = node.function; | |
| 13156 Type2 expressionType = functionExpression.staticType; | |
| 13157 if (!isFunctionType(expressionType)) { | |
| 13158 _errorReporter.reportError2(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTI
ON_EXPRESSION, functionExpression, []); | |
| 13159 } | |
| 13160 return super.visitFunctionExpressionInvocation(node); | |
| 13161 } | |
| 13162 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 13163 checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDE
NTIFIER_AS_TYPEDEF_NAME); | |
| 13164 checkForDefaultValueInFunctionTypeAlias(node); | |
| 13165 checkForTypeAliasCannotReferenceItself_function(node); | |
| 13166 return super.visitFunctionTypeAlias(node); | |
| 13167 } | |
| 13168 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 13169 bool old = _isInFunctionTypedFormalParameter; | |
| 13170 _isInFunctionTypedFormalParameter = true; | |
| 13171 try { | |
| 13172 return super.visitFunctionTypedFormalParameter(node); | |
| 13173 } finally { | |
| 13174 _isInFunctionTypedFormalParameter = old; | |
| 13175 } | |
| 13176 } | |
| 13177 Object visitIfStatement(IfStatement node) { | |
| 13178 checkForNonBoolCondition(node.condition); | |
| 13179 return super.visitIfStatement(node); | |
| 13180 } | |
| 13181 Object visitImportDirective(ImportDirective node) { | |
| 13182 checkForImportDuplicateLibraryName(node); | |
| 13183 checkForImportInternalLibrary(node); | |
| 13184 return super.visitImportDirective(node); | |
| 13185 } | |
| 13186 Object visitIndexExpression(IndexExpression node) { | |
| 13187 checkForArgumentTypeNotAssignable2(node.index); | |
| 13188 return super.visitIndexExpression(node); | |
| 13189 } | |
| 13190 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 13191 _isInConstInstanceCreation = node.isConst; | |
| 13192 try { | |
| 13193 ConstructorName constructorName = node.constructorName; | |
| 13194 TypeName typeName = constructorName.type; | |
| 13195 Type2 type = typeName.type; | |
| 13196 if (type is InterfaceType) { | |
| 13197 InterfaceType interfaceType = type as InterfaceType; | |
| 13198 checkForConstOrNewWithAbstractClass(node, typeName, interfaceType); | |
| 13199 if (_isInConstInstanceCreation) { | |
| 13200 checkForConstWithNonConst(node); | |
| 13201 checkForConstWithUndefinedConstructor(node); | |
| 13202 checkForConstWithTypeParameters(node); | |
| 13203 } else { | |
| 13204 checkForNewWithUndefinedConstructor(node); | |
| 13205 } | |
| 13206 } | |
| 13207 return super.visitInstanceCreationExpression(node); | |
| 13208 } finally { | |
| 13209 _isInConstInstanceCreation = false; | |
| 13210 } | |
| 13211 } | |
| 13212 Object visitListLiteral(ListLiteral node) { | |
| 13213 if (node.constKeyword != null) { | |
| 13214 TypeArgumentList typeArguments = node.typeArguments; | |
| 13215 if (typeArguments != null) { | |
| 13216 NodeList<TypeName> arguments = typeArguments.arguments; | |
| 13217 if (arguments.length != 0) { | |
| 13218 checkForInvalidTypeArgumentInConstTypedLiteral(arguments, CompileTimeE
rrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_LIST); | |
| 13219 } | |
| 13220 } | |
| 13221 } | |
| 13222 checkForExpectedOneListTypeArgument(node); | |
| 13223 checkForListElementTypeNotAssignable(node); | |
| 13224 return super.visitListLiteral(node); | |
| 13225 } | |
| 13226 Object visitMapLiteral(MapLiteral node) { | |
| 13227 TypeArgumentList typeArguments = node.typeArguments; | |
| 13228 if (typeArguments != null) { | |
| 13229 NodeList<TypeName> arguments = typeArguments.arguments; | |
| 13230 if (arguments.length != 0) { | |
| 13231 if (node.constKeyword != null) { | |
| 13232 checkForInvalidTypeArgumentInConstTypedLiteral(arguments, CompileTimeE
rrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_MAP); | |
| 13233 } | |
| 13234 } | |
| 13235 } | |
| 13236 checkExpectedTwoMapTypeArguments(typeArguments); | |
| 13237 checkForNonConstMapAsExpressionStatement(node); | |
| 13238 checkForMapTypeNotAssignable(node); | |
| 13239 checkForConstMapKeyExpressionTypeImplementsEquals2(node); | |
| 13240 return super.visitMapLiteral(node); | |
| 13241 } | |
| 13242 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 13243 ExecutableElement previousFunction = _enclosingFunction; | |
| 13244 try { | |
| 13245 _isInStaticMethod = node.isStatic; | |
| 13246 _enclosingFunction = node.element; | |
| 13247 SimpleIdentifier identifier = node.name; | |
| 13248 String methodName = ""; | |
| 13249 if (identifier != null) { | |
| 13250 methodName = identifier.name; | |
| 13251 } | |
| 13252 if (node.isSetter || node.isGetter) { | |
| 13253 checkForMismatchedAccessorTypes(node, methodName); | |
| 13254 checkForConflictingInstanceGetterAndSuperclassMember(node); | |
| 13255 } | |
| 13256 if (node.isGetter) { | |
| 13257 checkForConflictingStaticGetterAndInstanceSetter(node); | |
| 13258 } else if (node.isSetter) { | |
| 13259 checkForWrongNumberOfParametersForSetter(node.name, node.parameters); | |
| 13260 checkForNonVoidReturnTypeForSetter(node.returnType); | |
| 13261 checkForConflictingStaticSetterAndInstanceMember(node); | |
| 13262 } else if (node.isOperator) { | |
| 13263 checkForOptionalParameterInOperator(node); | |
| 13264 checkForWrongNumberOfParametersForOperator(node); | |
| 13265 checkForNonVoidReturnTypeForOperator(node); | |
| 13266 } | |
| 13267 checkForConcreteClassWithAbstractMember(node); | |
| 13268 checkForAllInvalidOverrideErrorCodes3(node); | |
| 13269 return super.visitMethodDeclaration(node); | |
| 13270 } finally { | |
| 13271 _enclosingFunction = previousFunction; | |
| 13272 _isInStaticMethod = false; | |
| 13273 } | |
| 13274 } | |
| 13275 Object visitMethodInvocation(MethodInvocation node) { | |
| 13276 Expression target = node.realTarget; | |
| 13277 SimpleIdentifier methodName = node.methodName; | |
| 13278 checkForStaticAccessToInstanceMember(target, methodName); | |
| 13279 checkForInstanceAccessToStaticMember(target, methodName); | |
| 13280 if (target == null) { | |
| 13281 checkForUnqualifiedReferenceToNonLocalStaticMember(methodName); | |
| 13282 } | |
| 13283 return super.visitMethodInvocation(node); | |
| 13284 } | |
| 13285 Object visitNativeClause(NativeClause node) { | |
| 13286 if (!_isInSystemLibrary) { | |
| 13287 _errorReporter.reportError2(ParserErrorCode.NATIVE_CLAUSE_IN_NON_SDK_CODE,
node, []); | |
| 13288 } | |
| 13289 return super.visitNativeClause(node); | |
| 13290 } | |
| 13291 Object visitNativeFunctionBody(NativeFunctionBody node) { | |
| 13292 checkForNativeFunctionBodyInNonSDKCode(node); | |
| 13293 return super.visitNativeFunctionBody(node); | |
| 13294 } | |
| 13295 Object visitPostfixExpression(PostfixExpression node) { | |
| 13296 checkForAssignmentToFinal2(node.operand); | |
| 13297 checkForIntNotAssignable(node.operand); | |
| 13298 return super.visitPostfixExpression(node); | |
| 13299 } | |
| 13300 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 13301 if (node.parent is! Annotation) { | |
| 13302 checkForStaticAccessToInstanceMember(node.prefix, node.identifier); | |
| 13303 checkForInstanceAccessToStaticMember(node.prefix, node.identifier); | |
| 13304 } | |
| 13305 return super.visitPrefixedIdentifier(node); | |
| 13306 } | |
| 13307 Object visitPrefixExpression(PrefixExpression node) { | |
| 13308 if (node.operator.type.isIncrementOperator) { | |
| 13309 checkForAssignmentToFinal2(node.operand); | |
| 13310 } | |
| 13311 checkForIntNotAssignable(node.operand); | |
| 13312 return super.visitPrefixExpression(node); | |
| 13313 } | |
| 13314 Object visitPropertyAccess(PropertyAccess node) { | |
| 13315 Expression target = node.realTarget; | |
| 13316 SimpleIdentifier propertyName = node.propertyName; | |
| 13317 checkForStaticAccessToInstanceMember(target, propertyName); | |
| 13318 checkForInstanceAccessToStaticMember(target, propertyName); | |
| 13319 return super.visitPropertyAccess(node); | |
| 13320 } | |
| 13321 Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation
node) { | |
| 13322 _isInConstructorInitializer = true; | |
| 13323 try { | |
| 13324 return super.visitRedirectingConstructorInvocation(node); | |
| 13325 } finally { | |
| 13326 _isInConstructorInitializer = false; | |
| 13327 } | |
| 13328 } | |
| 13329 Object visitRethrowExpression(RethrowExpression node) { | |
| 13330 checkForRethrowOutsideCatch(node); | |
| 13331 return super.visitRethrowExpression(node); | |
| 13332 } | |
| 13333 Object visitReturnStatement(ReturnStatement node) { | |
| 13334 if (node.expression == null) { | |
| 13335 _returnWithoutCount++; | |
| 13336 } else { | |
| 13337 _returnWithCount++; | |
| 13338 } | |
| 13339 checkForAllReturnStatementErrorCodes(node); | |
| 13340 return super.visitReturnStatement(node); | |
| 13341 } | |
| 13342 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 13343 checkForConstFormalParameter(node); | |
| 13344 checkForPrivateOptionalParameter(node); | |
| 13345 return super.visitSimpleFormalParameter(node); | |
| 13346 } | |
| 13347 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 13348 checkForReferenceToDeclaredVariableInInitializer(node); | |
| 13349 checkForImplicitThisReferenceInInitializer(node); | |
| 13350 if (!isUnqualifiedReferenceToNonLocalStaticMemberAllowed(node)) { | |
| 13351 checkForUnqualifiedReferenceToNonLocalStaticMember(node); | |
| 13352 } | |
| 13353 return super.visitSimpleIdentifier(node); | |
| 13354 } | |
| 13355 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 13356 _isInConstructorInitializer = true; | |
| 13357 try { | |
| 13358 return super.visitSuperConstructorInvocation(node); | |
| 13359 } finally { | |
| 13360 _isInConstructorInitializer = false; | |
| 13361 } | |
| 13362 } | |
| 13363 Object visitSwitchStatement(SwitchStatement node) { | |
| 13364 checkForInconsistentCaseExpressionTypes(node); | |
| 13365 checkForSwitchExpressionNotAssignable(node); | |
| 13366 checkForCaseBlocksNotTerminated(node); | |
| 13367 return super.visitSwitchStatement(node); | |
| 13368 } | |
| 13369 Object visitThisExpression(ThisExpression node) { | |
| 13370 checkForInvalidReferenceToThis(node); | |
| 13371 return super.visitThisExpression(node); | |
| 13372 } | |
| 13373 Object visitThrowExpression(ThrowExpression node) { | |
| 13374 checkForConstEvalThrowsException(node); | |
| 13375 return super.visitThrowExpression(node); | |
| 13376 } | |
| 13377 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| 13378 checkForFinalNotInitialized2(node.variables); | |
| 13379 return super.visitTopLevelVariableDeclaration(node); | |
| 13380 } | |
| 13381 Object visitTypeName(TypeName node) { | |
| 13382 checkForTypeArgumentNotMatchingBounds(node); | |
| 13383 checkForTypeParameterReferencedByStatic(node); | |
| 13384 return super.visitTypeName(node); | |
| 13385 } | |
| 13386 Object visitTypeParameter(TypeParameter node) { | |
| 13387 checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDE
NTIFIER_AS_TYPE_PARAMETER_NAME); | |
| 13388 checkForTypeParameterSupertypeOfItsBound(node); | |
| 13389 return super.visitTypeParameter(node); | |
| 13390 } | |
| 13391 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 13392 SimpleIdentifier nameNode = node.name; | |
| 13393 Expression initializerNode = node.initializer; | |
| 13394 checkForInvalidAssignment2(nameNode, initializerNode); | |
| 13395 nameNode.accept(this); | |
| 13396 String name = nameNode.name; | |
| 13397 javaSetAdd(_namesForReferenceToDeclaredVariableInInitializer, name); | |
| 13398 _isInInstanceVariableInitializer = _isInInstanceVariableDeclaration; | |
| 13399 try { | |
| 13400 if (initializerNode != null) { | |
| 13401 initializerNode.accept(this); | |
| 13402 } | |
| 13403 } finally { | |
| 13404 _isInInstanceVariableInitializer = false; | |
| 13405 _namesForReferenceToDeclaredVariableInInitializer.remove(name); | |
| 13406 } | |
| 13407 return null; | |
| 13408 } | |
| 13409 Object visitVariableDeclarationList(VariableDeclarationList node) => super.vis
itVariableDeclarationList(node); | |
| 13410 Object visitVariableDeclarationStatement(VariableDeclarationStatement node) { | |
| 13411 checkForFinalNotInitialized2(node.variables); | |
| 13412 return super.visitVariableDeclarationStatement(node); | |
| 13413 } | |
| 13414 Object visitWhileStatement(WhileStatement node) { | |
| 13415 checkForNonBoolCondition(node.condition); | |
| 13416 return super.visitWhileStatement(node); | |
| 13417 } | |
| 13418 | |
| 13419 /** | |
| 13420 * This verifies if the passed map literal has type arguments then there is ex
actly two. | |
| 13421 * | |
| 13422 * @param node the map literal to evaluate | |
| 13423 * @return `true` if and only if an error code is generated on the passed node | |
| 13424 * @see StaticTypeWarningCode#EXPECTED_TWO_MAP_TYPE_ARGUMENTS | |
| 13425 */ | |
| 13426 bool checkExpectedTwoMapTypeArguments(TypeArgumentList typeArguments) { | |
| 13427 if (typeArguments == null) { | |
| 13428 return false; | |
| 13429 } | |
| 13430 int num = typeArguments.arguments.length; | |
| 13431 if (num == 2) { | |
| 13432 return false; | |
| 13433 } | |
| 13434 _errorReporter.reportError2(StaticTypeWarningCode.EXPECTED_TWO_MAP_TYPE_ARGU
MENTS, typeArguments, [num]); | |
| 13435 return true; | |
| 13436 } | |
| 13437 | |
| 13438 /** | |
| 13439 * This verifies that the passed constructor declaration does not violate any
of the error codes | |
| 13440 * relating to the initialization of fields in the enclosing class. | |
| 13441 * | |
| 13442 * @param node the [ConstructorDeclaration] to evaluate | |
| 13443 * @return `true` if and only if an error code is generated on the passed node | |
| 13444 * @see #initialFieldElementsMap | |
| 13445 * @see CompileTimeErrorCode#FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR | |
| 13446 * @see CompileTimeErrorCode#FINAL_INITIALIZED_MULTIPLE_TIMES | |
| 13447 */ | |
| 13448 bool checkForAllFinalInitializedErrorCodes(ConstructorDeclaration node) { | |
| 13449 if (node.factoryKeyword != null || node.redirectedConstructor != null || nod
e.externalKeyword != null) { | |
| 13450 return false; | |
| 13451 } | |
| 13452 if (_isInNativeClass) { | |
| 13453 return false; | |
| 13454 } | |
| 13455 bool foundError = false; | |
| 13456 Map<FieldElement, INIT_STATE> fieldElementsMap = new Map<FieldElement, INIT_
STATE>.from(_initialFieldElementsMap); | |
| 13457 NodeList<FormalParameter> formalParameters = node.parameters.parameters; | |
| 13458 for (FormalParameter formalParameter in formalParameters) { | |
| 13459 FormalParameter parameter = formalParameter; | |
| 13460 if (parameter is DefaultFormalParameter) { | |
| 13461 parameter = ((parameter as DefaultFormalParameter)).parameter; | |
| 13462 } | |
| 13463 if (parameter is FieldFormalParameter) { | |
| 13464 FieldElement fieldElement = ((parameter.element as FieldFormalParameterE
lementImpl)).field; | |
| 13465 INIT_STATE state = fieldElementsMap[fieldElement]; | |
| 13466 if (identical(state, INIT_STATE.NOT_INIT)) { | |
| 13467 fieldElementsMap[fieldElement] = INIT_STATE.INIT_IN_FIELD_FORMAL; | |
| 13468 } else if (identical(state, INIT_STATE.INIT_IN_DECLARATION)) { | |
| 13469 if (fieldElement.isFinal || fieldElement.isConst) { | |
| 13470 _errorReporter.reportError2(StaticWarningCode.FINAL_INITIALIZED_IN_D
ECLARATION_AND_CONSTRUCTOR, formalParameter.identifier, [fieldElement.displayNam
e]); | |
| 13471 foundError = true; | |
| 13472 } | |
| 13473 } else if (identical(state, INIT_STATE.INIT_IN_FIELD_FORMAL)) { | |
| 13474 if (fieldElement.isFinal || fieldElement.isConst) { | |
| 13475 _errorReporter.reportError2(CompileTimeErrorCode.FINAL_INITIALIZED_M
ULTIPLE_TIMES, formalParameter.identifier, [fieldElement.displayName]); | |
| 13476 foundError = true; | |
| 13477 } | |
| 13478 } | |
| 13479 } | |
| 13480 } | |
| 13481 NodeList<ConstructorInitializer> initializers = node.initializers; | |
| 13482 for (ConstructorInitializer constructorInitializer in initializers) { | |
| 13483 if (constructorInitializer is RedirectingConstructorInvocation) { | |
| 13484 return false; | |
| 13485 } | |
| 13486 if (constructorInitializer is ConstructorFieldInitializer) { | |
| 13487 ConstructorFieldInitializer constructorFieldInitializer = constructorIni
tializer as ConstructorFieldInitializer; | |
| 13488 SimpleIdentifier fieldName = constructorFieldInitializer.fieldName; | |
| 13489 Element element = fieldName.staticElement; | |
| 13490 if (element is FieldElement) { | |
| 13491 FieldElement fieldElement = element as FieldElement; | |
| 13492 INIT_STATE state = fieldElementsMap[fieldElement]; | |
| 13493 if (identical(state, INIT_STATE.NOT_INIT)) { | |
| 13494 fieldElementsMap[fieldElement] = INIT_STATE.INIT_IN_INITIALIZERS; | |
| 13495 } else if (identical(state, INIT_STATE.INIT_IN_DECLARATION)) { | |
| 13496 if (fieldElement.isFinal || fieldElement.isConst) { | |
| 13497 _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZED_IN
_INITIALIZER_AND_DECLARATION, fieldName, []); | |
| 13498 foundError = true; | |
| 13499 } | |
| 13500 } else if (identical(state, INIT_STATE.INIT_IN_FIELD_FORMAL)) { | |
| 13501 _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZED_I
N_PARAMETER_AND_INITIALIZER, fieldName, []); | |
| 13502 foundError = true; | |
| 13503 } else if (identical(state, INIT_STATE.INIT_IN_INITIALIZERS)) { | |
| 13504 _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZED_B
Y_MULTIPLE_INITIALIZERS, fieldName, [fieldElement.displayName]); | |
| 13505 foundError = true; | |
| 13506 } | |
| 13507 } | |
| 13508 } | |
| 13509 } | |
| 13510 for (MapEntry<FieldElement, INIT_STATE> entry in getMapEntrySet(fieldElement
sMap)) { | |
| 13511 if (identical(entry.getValue(), INIT_STATE.NOT_INIT)) { | |
| 13512 FieldElement fieldElement = entry.getKey(); | |
| 13513 if (fieldElement.isConst) { | |
| 13514 _errorReporter.reportError2(CompileTimeErrorCode.CONST_NOT_INITIALIZED
, node.returnType, [fieldElement.name]); | |
| 13515 foundError = true; | |
| 13516 } else if (fieldElement.isFinal) { | |
| 13517 _errorReporter.reportError2(StaticWarningCode.FINAL_NOT_INITIALIZED, n
ode.returnType, [fieldElement.name]); | |
| 13518 foundError = true; | |
| 13519 } | |
| 13520 } | |
| 13521 } | |
| 13522 return foundError; | |
| 13523 } | |
| 13524 | |
| 13525 /** | |
| 13526 * This checks the passed executable element against override-error codes. | |
| 13527 * | |
| 13528 * @param executableElement a non-null [ExecutableElement] to evaluate | |
| 13529 * @param parameters the parameters of the executable element | |
| 13530 * @param errorNameTarget the node to report problems on | |
| 13531 * @return `true` if and only if an error code is generated on the passed node | |
| 13532 * @see StaticWarningCode#INSTANCE_METHOD_NAME_COLLIDES_WITH_SUPERCLASS_STATIC | |
| 13533 * @see CompileTimeErrorCode#INVALID_OVERRIDE_REQUIRED | |
| 13534 * @see CompileTimeErrorCode#INVALID_OVERRIDE_POSITIONAL | |
| 13535 * @see CompileTimeErrorCode#INVALID_OVERRIDE_NAMED | |
| 13536 * @see StaticWarningCode#INVALID_GETTER_OVERRIDE_RETURN_TYPE | |
| 13537 * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_RETURN_TYPE | |
| 13538 * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE | |
| 13539 * @see StaticWarningCode#INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE | |
| 13540 * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_OPTIONAL_PARAM_TYPE | |
| 13541 * @see StaticWarningCode#INVALID_METHOD_OVERRIDE_NAMED_PARAM_TYPE | |
| 13542 * @see StaticWarningCode#INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES | |
| 13543 */ | |
| 13544 bool checkForAllInvalidOverrideErrorCodes(ExecutableElement executableElement,
List<ParameterElement> parameters, List<ASTNode> parameterLocations, SimpleIden
tifier errorNameTarget) { | |
| 13545 String executableElementName = executableElement.name; | |
| 13546 bool executableElementPrivate = Identifier.isPrivateName(executableElementNa
me); | |
| 13547 ExecutableElement overriddenExecutable = _inheritanceManager.lookupInheritan
ce(_enclosingClass, executableElementName); | |
| 13548 bool isGetter = false; | |
| 13549 bool isSetter = false; | |
| 13550 if (executableElement is PropertyAccessorElement) { | |
| 13551 PropertyAccessorElement accessorElement = executableElement as PropertyAcc
essorElement; | |
| 13552 isGetter = accessorElement.isGetter; | |
| 13553 isSetter = accessorElement.isSetter; | |
| 13554 } | |
| 13555 if (overriddenExecutable == null) { | |
| 13556 if (!isGetter && !isSetter && !executableElement.isOperator) { | |
| 13557 Set<ClassElement> visitedClasses = new Set<ClassElement>(); | |
| 13558 InterfaceType superclassType = _enclosingClass.supertype; | |
| 13559 ClassElement superclassElement = superclassType == null ? null : supercl
assType.element; | |
| 13560 while (superclassElement != null && !visitedClasses.contains(superclassE
lement)) { | |
| 13561 javaSetAdd(visitedClasses, superclassElement); | |
| 13562 LibraryElement superclassLibrary = superclassElement.library; | |
| 13563 List<FieldElement> fieldElts = superclassElement.fields; | |
| 13564 for (FieldElement fieldElt in fieldElts) { | |
| 13565 if (fieldElt.name != executableElementName) { | |
| 13566 continue; | |
| 13567 } | |
| 13568 if (executableElementPrivate && _currentLibrary != superclassLibrary
) { | |
| 13569 continue; | |
| 13570 } | |
| 13571 if (fieldElt.isStatic) { | |
| 13572 _errorReporter.reportError2(StaticWarningCode.INSTANCE_METHOD_NAME
_COLLIDES_WITH_SUPERCLASS_STATIC, errorNameTarget, [ | |
| 13573 executableElementName, | |
| 13574 fieldElt.enclosingElement.displayName]); | |
| 13575 return true; | |
| 13576 } | |
| 13577 } | |
| 13578 List<MethodElement> methodElements = superclassElement.methods; | |
| 13579 for (MethodElement methodElement in methodElements) { | |
| 13580 if (methodElement.name != executableElementName) { | |
| 13581 continue; | |
| 13582 } | |
| 13583 if (executableElementPrivate && _currentLibrary != superclassLibrary
) { | |
| 13584 continue; | |
| 13585 } | |
| 13586 if (methodElement.isStatic) { | |
| 13587 _errorReporter.reportError2(StaticWarningCode.INSTANCE_METHOD_NAME
_COLLIDES_WITH_SUPERCLASS_STATIC, errorNameTarget, [ | |
| 13588 executableElementName, | |
| 13589 methodElement.enclosingElement.displayName]); | |
| 13590 return true; | |
| 13591 } | |
| 13592 } | |
| 13593 superclassType = superclassElement.supertype; | |
| 13594 superclassElement = superclassType == null ? null : superclassType.ele
ment; | |
| 13595 } | |
| 13596 } | |
| 13597 return false; | |
| 13598 } | |
| 13599 FunctionType overridingFT = executableElement.type; | |
| 13600 FunctionType overriddenFT = overriddenExecutable.type; | |
| 13601 InterfaceType enclosingType = _enclosingClass.type; | |
| 13602 overriddenFT = _inheritanceManager.substituteTypeArgumentsInMemberFromInheri
tance(overriddenFT, executableElementName, enclosingType); | |
| 13603 if (overridingFT == null || overriddenFT == null) { | |
| 13604 return false; | |
| 13605 } | |
| 13606 Type2 overridingFTReturnType = overridingFT.returnType; | |
| 13607 Type2 overriddenFTReturnType = overriddenFT.returnType; | |
| 13608 List<Type2> overridingNormalPT = overridingFT.normalParameterTypes; | |
| 13609 List<Type2> overriddenNormalPT = overriddenFT.normalParameterTypes; | |
| 13610 List<Type2> overridingPositionalPT = overridingFT.optionalParameterTypes; | |
| 13611 List<Type2> overriddenPositionalPT = overriddenFT.optionalParameterTypes; | |
| 13612 Map<String, Type2> overridingNamedPT = overridingFT.namedParameterTypes; | |
| 13613 Map<String, Type2> overriddenNamedPT = overriddenFT.namedParameterTypes; | |
| 13614 if (overridingNormalPT.length > overriddenNormalPT.length) { | |
| 13615 _errorReporter.reportError2(StaticWarningCode.INVALID_OVERRIDE_REQUIRED, e
rrorNameTarget, [ | |
| 13616 overriddenNormalPT.length, | |
| 13617 overriddenExecutable.enclosingElement.displayName]); | |
| 13618 return true; | |
| 13619 } | |
| 13620 if (overridingNormalPT.length + overridingPositionalPT.length < overriddenPo
sitionalPT.length + overriddenNormalPT.length) { | |
| 13621 _errorReporter.reportError2(StaticWarningCode.INVALID_OVERRIDE_POSITIONAL,
errorNameTarget, [ | |
| 13622 overriddenPositionalPT.length + overriddenNormalPT.length, | |
| 13623 overriddenExecutable.enclosingElement.displayName]); | |
| 13624 return true; | |
| 13625 } | |
| 13626 Set<String> overridingParameterNameSet = overridingNamedPT.keys.toSet(); | |
| 13627 JavaIterator<String> overriddenParameterNameIterator = new JavaIterator(over
riddenNamedPT.keys.toSet()); | |
| 13628 while (overriddenParameterNameIterator.hasNext) { | |
| 13629 String overriddenParamName = overriddenParameterNameIterator.next(); | |
| 13630 if (!overridingParameterNameSet.contains(overriddenParamName)) { | |
| 13631 _errorReporter.reportError2(StaticWarningCode.INVALID_OVERRIDE_NAMED, er
rorNameTarget, [ | |
| 13632 overriddenParamName, | |
| 13633 overriddenExecutable.enclosingElement.displayName]); | |
| 13634 return true; | |
| 13635 } | |
| 13636 } | |
| 13637 if (overriddenFTReturnType != VoidTypeImpl.instance && !overridingFTReturnTy
pe.isAssignableTo(overriddenFTReturnType)) { | |
| 13638 _errorReporter.reportError2(!isGetter ? StaticWarningCode.INVALID_METHOD_O
VERRIDE_RETURN_TYPE : StaticWarningCode.INVALID_GETTER_OVERRIDE_RETURN_TYPE, err
orNameTarget, [ | |
| 13639 overridingFTReturnType.displayName, | |
| 13640 overriddenFTReturnType.displayName, | |
| 13641 overriddenExecutable.enclosingElement.displayName]); | |
| 13642 return true; | |
| 13643 } | |
| 13644 if (parameterLocations == null) { | |
| 13645 return false; | |
| 13646 } | |
| 13647 int parameterIndex = 0; | |
| 13648 for (int i = 0; i < overridingNormalPT.length; i++) { | |
| 13649 if (!overridingNormalPT[i].isAssignableTo(overriddenNormalPT[i])) { | |
| 13650 _errorReporter.reportError2(!isSetter ? StaticWarningCode.INVALID_METHOD
_OVERRIDE_NORMAL_PARAM_TYPE : StaticWarningCode.INVALID_SETTER_OVERRIDE_NORMAL_P
ARAM_TYPE, parameterLocations[parameterIndex], [ | |
| 13651 overridingNormalPT[i].displayName, | |
| 13652 overriddenNormalPT[i].displayName, | |
| 13653 overriddenExecutable.enclosingElement.displayName]); | |
| 13654 return true; | |
| 13655 } | |
| 13656 parameterIndex++; | |
| 13657 } | |
| 13658 for (int i = 0; i < overriddenPositionalPT.length; i++) { | |
| 13659 if (!overridingPositionalPT[i].isAssignableTo(overriddenPositionalPT[i]))
{ | |
| 13660 _errorReporter.reportError2(StaticWarningCode.INVALID_METHOD_OVERRIDE_OP
TIONAL_PARAM_TYPE, parameterLocations[parameterIndex], [ | |
| 13661 overridingPositionalPT[i].displayName, | |
| 13662 overriddenPositionalPT[i].displayName, | |
| 13663 overriddenExecutable.enclosingElement.displayName]); | |
| 13664 return true; | |
| 13665 } | |
| 13666 parameterIndex++; | |
| 13667 } | |
| 13668 JavaIterator<MapEntry<String, Type2>> overriddenNamedPTIterator = new JavaIt
erator(getMapEntrySet(overriddenNamedPT)); | |
| 13669 while (overriddenNamedPTIterator.hasNext) { | |
| 13670 MapEntry<String, Type2> overriddenNamedPTEntry = overriddenNamedPTIterator
.next(); | |
| 13671 Type2 overridingType = overridingNamedPT[overriddenNamedPTEntry.getKey()]; | |
| 13672 if (overridingType == null) { | |
| 13673 continue; | |
| 13674 } | |
| 13675 if (!overriddenNamedPTEntry.getValue().isAssignableTo(overridingType)) { | |
| 13676 ParameterElement parameterToSelect = null; | |
| 13677 ASTNode parameterLocationToSelect = null; | |
| 13678 for (int i = 0; i < parameters.length; i++) { | |
| 13679 ParameterElement parameter = parameters[i]; | |
| 13680 if (identical(parameter.parameterKind, ParameterKind.NAMED) && overrid
denNamedPTEntry.getKey() == parameter.name) { | |
| 13681 parameterToSelect = parameter; | |
| 13682 parameterLocationToSelect = parameterLocations[i]; | |
| 13683 break; | |
| 13684 } | |
| 13685 } | |
| 13686 if (parameterToSelect != null) { | |
| 13687 _errorReporter.reportError2(StaticWarningCode.INVALID_METHOD_OVERRIDE_
NAMED_PARAM_TYPE, parameterLocationToSelect, [ | |
| 13688 overridingType.displayName, | |
| 13689 overriddenNamedPTEntry.getValue().displayName, | |
| 13690 overriddenExecutable.enclosingElement.displayName]); | |
| 13691 return true; | |
| 13692 } | |
| 13693 } | |
| 13694 } | |
| 13695 bool foundError = false; | |
| 13696 List<ASTNode> formalParameters = new List<ASTNode>(); | |
| 13697 List<ParameterElementImpl> parameterElts = new List<ParameterElementImpl>(); | |
| 13698 List<ParameterElementImpl> overriddenParameterElts = new List<ParameterEleme
ntImpl>(); | |
| 13699 List<ParameterElement> overriddenPEs = overriddenExecutable.parameters; | |
| 13700 for (int i = 0; i < parameters.length; i++) { | |
| 13701 ParameterElement parameter = parameters[i]; | |
| 13702 if (parameter.parameterKind.isOptional) { | |
| 13703 formalParameters.add(parameterLocations[i]); | |
| 13704 parameterElts.add(parameter as ParameterElementImpl); | |
| 13705 } | |
| 13706 } | |
| 13707 for (ParameterElement parameterElt in overriddenPEs) { | |
| 13708 if (parameterElt.parameterKind.isOptional) { | |
| 13709 if (parameterElt is ParameterElementImpl) { | |
| 13710 overriddenParameterElts.add(parameterElt as ParameterElementImpl); | |
| 13711 } | |
| 13712 } | |
| 13713 } | |
| 13714 if (parameterElts.length > 0) { | |
| 13715 if (identical(parameterElts[0].parameterKind, ParameterKind.NAMED)) { | |
| 13716 for (int i = 0; i < parameterElts.length; i++) { | |
| 13717 ParameterElementImpl parameterElt = parameterElts[i]; | |
| 13718 EvaluationResultImpl result = parameterElt.evaluationResult; | |
| 13719 if (result == null || identical(result, ValidResult.RESULT_OBJECT)) { | |
| 13720 continue; | |
| 13721 } | |
| 13722 String parameterName = parameterElt.name; | |
| 13723 for (int j = 0; j < overriddenParameterElts.length; j++) { | |
| 13724 ParameterElementImpl overriddenParameterElt = overriddenParameterElt
s[j]; | |
| 13725 String overriddenParameterName = overriddenParameterElt.name; | |
| 13726 if (parameterName != null && parameterName == overriddenParameterNam
e) { | |
| 13727 EvaluationResultImpl overriddenResult = overriddenParameterElt.eva
luationResult; | |
| 13728 if (overriddenResult == null || identical(result, ValidResult.RESU
LT_OBJECT)) { | |
| 13729 break; | |
| 13730 } | |
| 13731 if (!result.equalValues(overriddenResult)) { | |
| 13732 _errorReporter.reportError2(StaticWarningCode.INVALID_OVERRIDE_D
IFFERENT_DEFAULT_VALUES_NAMED, formalParameters[i], [ | |
| 13733 overriddenExecutable.enclosingElement.displayName, | |
| 13734 overriddenExecutable.displayName, | |
| 13735 parameterName]); | |
| 13736 foundError = true; | |
| 13737 } | |
| 13738 } | |
| 13739 } | |
| 13740 } | |
| 13741 } else { | |
| 13742 for (int i = 0; i < parameterElts.length && i < overriddenParameterElts.
length; i++) { | |
| 13743 ParameterElementImpl parameterElt = parameterElts[i]; | |
| 13744 EvaluationResultImpl result = parameterElt.evaluationResult; | |
| 13745 if (result == null || identical(result, ValidResult.RESULT_OBJECT)) { | |
| 13746 continue; | |
| 13747 } | |
| 13748 ParameterElementImpl overriddenParameterElt = overriddenParameterElts[
i]; | |
| 13749 EvaluationResultImpl overriddenResult = overriddenParameterElt.evaluat
ionResult; | |
| 13750 if (overriddenResult == null || identical(result, ValidResult.RESULT_O
BJECT)) { | |
| 13751 continue; | |
| 13752 } | |
| 13753 if (!result.equalValues(overriddenResult)) { | |
| 13754 _errorReporter.reportError2(StaticWarningCode.INVALID_OVERRIDE_DIFFE
RENT_DEFAULT_VALUES_POSITIONAL, formalParameters[i], [ | |
| 13755 overriddenExecutable.enclosingElement.displayName, | |
| 13756 overriddenExecutable.displayName]); | |
| 13757 foundError = true; | |
| 13758 } | |
| 13759 } | |
| 13760 } | |
| 13761 } | |
| 13762 return foundError; | |
| 13763 } | |
| 13764 | |
| 13765 /** | |
| 13766 * This checks the passed field declaration against override-error codes. | |
| 13767 * | |
| 13768 * @param node the [MethodDeclaration] to evaluate | |
| 13769 * @return `true` if and only if an error code is generated on the passed node | |
| 13770 * @see #checkForAllInvalidOverrideErrorCodes(ExecutableElement) | |
| 13771 */ | |
| 13772 bool checkForAllInvalidOverrideErrorCodes2(FieldDeclaration node) { | |
| 13773 if (_enclosingClass == null || node.isStatic) { | |
| 13774 return false; | |
| 13775 } | |
| 13776 bool hasProblems = false; | |
| 13777 VariableDeclarationList fields = node.fields; | |
| 13778 for (VariableDeclaration field in fields.variables) { | |
| 13779 FieldElement element = field.element as FieldElement; | |
| 13780 if (element == null) { | |
| 13781 continue; | |
| 13782 } | |
| 13783 PropertyAccessorElement getter = element.getter; | |
| 13784 PropertyAccessorElement setter = element.setter; | |
| 13785 SimpleIdentifier fieldName = field.name; | |
| 13786 if (getter != null) { | |
| 13787 hasProblems = javaBooleanOr(hasProblems, checkForAllInvalidOverrideError
Codes(getter, ParameterElementImpl.EMPTY_ARRAY, ASTNode.EMPTY_ARRAY, fieldName))
; | |
| 13788 } | |
| 13789 if (setter != null) { | |
| 13790 hasProblems = javaBooleanOr(hasProblems, checkForAllInvalidOverrideError
Codes(setter, setter.parameters, <ASTNode> [fieldName], fieldName)); | |
| 13791 } | |
| 13792 } | |
| 13793 return hasProblems; | |
| 13794 } | |
| 13795 | |
| 13796 /** | |
| 13797 * This checks the passed method declaration against override-error codes. | |
| 13798 * | |
| 13799 * @param node the [MethodDeclaration] to evaluate | |
| 13800 * @return `true` if and only if an error code is generated on the passed node | |
| 13801 * @see #checkForAllInvalidOverrideErrorCodes(ExecutableElement) | |
| 13802 */ | |
| 13803 bool checkForAllInvalidOverrideErrorCodes3(MethodDeclaration node) { | |
| 13804 if (_enclosingClass == null || node.isStatic || node.body is NativeFunctionB
ody) { | |
| 13805 return false; | |
| 13806 } | |
| 13807 ExecutableElement executableElement = node.element; | |
| 13808 if (executableElement == null) { | |
| 13809 return false; | |
| 13810 } | |
| 13811 SimpleIdentifier methodName = node.name; | |
| 13812 if (methodName.isSynthetic) { | |
| 13813 return false; | |
| 13814 } | |
| 13815 FormalParameterList formalParameterList = node.parameters; | |
| 13816 NodeList<FormalParameter> parameterList = formalParameterList != null ? form
alParameterList.parameters : null; | |
| 13817 List<ASTNode> parameters = parameterList != null ? new List.from(parameterLi
st) : null; | |
| 13818 return checkForAllInvalidOverrideErrorCodes(executableElement, executableEle
ment.parameters, parameters, methodName); | |
| 13819 } | |
| 13820 | |
| 13821 /** | |
| 13822 * This verifies that all classes of the passed 'with' clause are valid. | |
| 13823 * | |
| 13824 * @param node the 'with' clause to evaluate | |
| 13825 * @return `true` if and only if an error code is generated on the passed node | |
| 13826 * @see CompileTimeErrorCode#MIXIN_DECLARES_CONSTRUCTOR | |
| 13827 * @see CompileTimeErrorCode#MIXIN_INHERITS_FROM_NOT_OBJECT | |
| 13828 * @see CompileTimeErrorCode#MIXIN_REFERENCES_SUPER | |
| 13829 */ | |
| 13830 bool checkForAllMixinErrorCodes(WithClause withClause) { | |
| 13831 if (withClause == null) { | |
| 13832 return false; | |
| 13833 } | |
| 13834 bool problemReported = false; | |
| 13835 for (TypeName mixinName in withClause.mixinTypes) { | |
| 13836 Type2 mixinType = mixinName.type; | |
| 13837 if (mixinType is! InterfaceType) { | |
| 13838 continue; | |
| 13839 } | |
| 13840 if (checkForExtendsOrImplementsDisallowedClass(mixinName, CompileTimeError
Code.MIXIN_OF_DISALLOWED_CLASS)) { | |
| 13841 problemReported = true; | |
| 13842 } else { | |
| 13843 ClassElement mixinElement = ((mixinType as InterfaceType)).element; | |
| 13844 problemReported = javaBooleanOr(problemReported, checkForMixinDeclaresCo
nstructor(mixinName, mixinElement)); | |
| 13845 problemReported = javaBooleanOr(problemReported, checkForMixinInheritsNo
tFromObject(mixinName, mixinElement)); | |
| 13846 problemReported = javaBooleanOr(problemReported, checkForMixinReferences
Super(mixinName, mixinElement)); | |
| 13847 } | |
| 13848 } | |
| 13849 return problemReported; | |
| 13850 } | |
| 13851 | |
| 13852 /** | |
| 13853 * This checks error related to the redirected constructors. | |
| 13854 * | |
| 13855 * @param node the constructor declaration to evaluate | |
| 13856 * @return `true` if and only if an error code is generated on the passed node | |
| 13857 * @see StaticWarningCode#REDIRECT_TO_INVALID_RETURN_TYPE | |
| 13858 * @see StaticWarningCode#REDIRECT_TO_INVALID_FUNCTION_TYPE | |
| 13859 * @see StaticWarningCode#REDIRECT_TO_MISSING_CONSTRUCTOR | |
| 13860 */ | |
| 13861 bool checkForAllRedirectConstructorErrorCodes(ConstructorDeclaration node) { | |
| 13862 ConstructorName redirectedConstructor = node.redirectedConstructor; | |
| 13863 if (redirectedConstructor == null) { | |
| 13864 return false; | |
| 13865 } | |
| 13866 ConstructorElement redirectedElement = redirectedConstructor.staticElement; | |
| 13867 if (redirectedElement == null) { | |
| 13868 TypeName constructorTypeName = redirectedConstructor.type; | |
| 13869 Type2 redirectedType = constructorTypeName.type; | |
| 13870 if (redirectedType != null && redirectedType.element != null && !redirecte
dType.isDynamic) { | |
| 13871 String constructorStrName = constructorTypeName.name.name; | |
| 13872 if (redirectedConstructor.name != null) { | |
| 13873 constructorStrName += ".${redirectedConstructor.name.name}"; | |
| 13874 } | |
| 13875 _errorReporter.reportError2(StaticWarningCode.REDIRECT_TO_MISSING_CONSTR
UCTOR, redirectedConstructor, [constructorStrName, redirectedType.displayName]); | |
| 13876 return true; | |
| 13877 } | |
| 13878 return false; | |
| 13879 } | |
| 13880 FunctionType redirectedType = redirectedElement.type; | |
| 13881 Type2 redirectedReturnType = redirectedType.returnType; | |
| 13882 FunctionType constructorType = node.element.type; | |
| 13883 Type2 constructorReturnType = constructorType.returnType; | |
| 13884 if (!redirectedReturnType.isAssignableTo(constructorReturnType)) { | |
| 13885 _errorReporter.reportError2(StaticWarningCode.REDIRECT_TO_INVALID_RETURN_T
YPE, redirectedConstructor, [redirectedReturnType, constructorReturnType]); | |
| 13886 return true; | |
| 13887 } | |
| 13888 if (!redirectedType.isSubtypeOf(constructorType)) { | |
| 13889 _errorReporter.reportError2(StaticWarningCode.REDIRECT_TO_INVALID_FUNCTION
_TYPE, redirectedConstructor, [redirectedType, constructorType]); | |
| 13890 return true; | |
| 13891 } | |
| 13892 return false; | |
| 13893 } | |
| 13894 | |
| 13895 /** | |
| 13896 * This checks that the return statement of the form <i>return e;</i> is not i
n a generative | |
| 13897 * constructor. | |
| 13898 * | |
| 13899 * This checks that return statements without expressions are not in a generat
ive constructor and | |
| 13900 * the return type is not assignable to `null`; that is, we don't have `return
;` if | |
| 13901 * the enclosing method has a return type. | |
| 13902 * | |
| 13903 * This checks that the return type matches the type of the declared return ty
pe in the enclosing | |
| 13904 * method or function. | |
| 13905 * | |
| 13906 * @param node the return statement to evaluate | |
| 13907 * @return `true` if and only if an error code is generated on the passed node | |
| 13908 * @see CompileTimeErrorCode#RETURN_IN_GENERATIVE_CONSTRUCTOR | |
| 13909 * @see StaticWarningCode#RETURN_WITHOUT_VALUE | |
| 13910 * @see StaticTypeWarningCode#RETURN_OF_INVALID_TYPE | |
| 13911 */ | |
| 13912 bool checkForAllReturnStatementErrorCodes(ReturnStatement node) { | |
| 13913 FunctionType functionType = _enclosingFunction == null ? null : _enclosingFu
nction.type; | |
| 13914 Type2 expectedReturnType = functionType == null ? DynamicTypeImpl.instance :
functionType.returnType; | |
| 13915 Expression returnExpression = node.expression; | |
| 13916 bool isGenerativeConstructor = _enclosingFunction is ConstructorElement && !
((_enclosingFunction as ConstructorElement)).isFactory; | |
| 13917 if (isGenerativeConstructor) { | |
| 13918 if (returnExpression == null) { | |
| 13919 return false; | |
| 13920 } | |
| 13921 _errorReporter.reportError2(CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONS
TRUCTOR, returnExpression, []); | |
| 13922 return true; | |
| 13923 } | |
| 13924 if (returnExpression == null) { | |
| 13925 if (VoidTypeImpl.instance.isAssignableTo(expectedReturnType)) { | |
| 13926 return false; | |
| 13927 } | |
| 13928 _errorReporter.reportError2(StaticWarningCode.RETURN_WITHOUT_VALUE, node,
[]); | |
| 13929 return true; | |
| 13930 } | |
| 13931 return checkForReturnOfInvalidType(returnExpression, expectedReturnType); | |
| 13932 } | |
| 13933 | |
| 13934 /** | |
| 13935 * This verifies that the export namespace of the passed export directive does
not export any name | |
| 13936 * already exported by other export directive. | |
| 13937 * | |
| 13938 * @param node the export directive node to report problem on | |
| 13939 * @return `true` if and only if an error code is generated on the passed node | |
| 13940 * @see CompileTimeErrorCode#AMBIGUOUS_EXPORT | |
| 13941 */ | |
| 13942 bool checkForAmbiguousExport(ExportDirective node) { | |
| 13943 if (node.element is! ExportElement) { | |
| 13944 return false; | |
| 13945 } | |
| 13946 ExportElement exportElement = node.element as ExportElement; | |
| 13947 LibraryElement exportedLibrary = exportElement.exportedLibrary; | |
| 13948 if (exportedLibrary == null) { | |
| 13949 return false; | |
| 13950 } | |
| 13951 Namespace namespace = new NamespaceBuilder().createExportNamespace(exportEle
ment); | |
| 13952 Set<String> newNames = namespace.definedNames.keys.toSet(); | |
| 13953 for (String name in newNames) { | |
| 13954 ExportElement prevElement = _exportedNames[name]; | |
| 13955 if (prevElement != null && prevElement != exportElement) { | |
| 13956 _errorReporter.reportError2(CompileTimeErrorCode.AMBIGUOUS_EXPORT, node,
[ | |
| 13957 name, | |
| 13958 prevElement.exportedLibrary.definingCompilationUnit.displayName, | |
| 13959 exportedLibrary.definingCompilationUnit.displayName]); | |
| 13960 return true; | |
| 13961 } else { | |
| 13962 _exportedNames[name] = exportElement; | |
| 13963 } | |
| 13964 } | |
| 13965 return false; | |
| 13966 } | |
| 13967 | |
| 13968 /** | |
| 13969 * This verifies that the passed argument definition test identifier is a para
meter. | |
| 13970 * | |
| 13971 * @param node the [ArgumentDefinitionTest] to evaluate | |
| 13972 * @return `true` if and only if an error code is generated on the passed node | |
| 13973 * @see CompileTimeErrorCode#ARGUMENT_DEFINITION_TEST_NON_PARAMETER | |
| 13974 */ | |
| 13975 bool checkForArgumentDefinitionTestNonParameter(ArgumentDefinitionTest node) { | |
| 13976 SimpleIdentifier identifier = node.identifier; | |
| 13977 Element element = identifier.staticElement; | |
| 13978 if (element != null && element is! ParameterElement) { | |
| 13979 _errorReporter.reportError2(CompileTimeErrorCode.ARGUMENT_DEFINITION_TEST_
NON_PARAMETER, identifier, [identifier.name]); | |
| 13980 return true; | |
| 13981 } | |
| 13982 return false; | |
| 13983 } | |
| 13984 | |
| 13985 /** | |
| 13986 * This verifies that the passed arguments can be assigned to their correspond
ing parameters. | |
| 13987 * | |
| 13988 * @param node the arguments to evaluate | |
| 13989 * @return `true` if and only if an error code is generated on the passed node | |
| 13990 * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE | |
| 13991 */ | |
| 13992 bool checkForArgumentTypeNotAssignable(ArgumentList argumentList) { | |
| 13993 if (argumentList == null) { | |
| 13994 return false; | |
| 13995 } | |
| 13996 bool problemReported = false; | |
| 13997 for (Expression argument in argumentList.arguments) { | |
| 13998 problemReported = javaBooleanOr(problemReported, checkForArgumentTypeNotAs
signable2(argument)); | |
| 13999 } | |
| 14000 return problemReported; | |
| 14001 } | |
| 14002 | |
| 14003 /** | |
| 14004 * This verifies that the passed argument can be assigned to its corresponding
parameter. | |
| 14005 * | |
| 14006 * @param argument the argument to evaluate | |
| 14007 * @return `true` if and only if an error code is generated on the passed node | |
| 14008 * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE | |
| 14009 */ | |
| 14010 bool checkForArgumentTypeNotAssignable2(Expression argument) { | |
| 14011 if (argument == null) { | |
| 14012 return false; | |
| 14013 } | |
| 14014 ParameterElement staticParameterElement = argument.staticParameterElement; | |
| 14015 Type2 staticParameterType = staticParameterElement == null ? null : staticPa
rameterElement.type; | |
| 14016 ParameterElement propagatedParameterElement = argument.propagatedParameterEl
ement; | |
| 14017 Type2 propagatedParameterType = propagatedParameterElement == null ? null :
propagatedParameterElement.type; | |
| 14018 return checkForArgumentTypeNotAssignable3(argument, staticParameterType, pro
pagatedParameterType, StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); | |
| 14019 } | |
| 14020 | |
| 14021 /** | |
| 14022 * This verifies that the passed expression can be assigned to its correspondi
ng parameters. | |
| 14023 * | |
| 14024 * @param expression the expression to evaluate | |
| 14025 * @param expectedStaticType the expected static type | |
| 14026 * @param expectedPropagatedType the expected propagated type, may be `null` | |
| 14027 * @return `true` if and only if an error code is generated on the passed node | |
| 14028 * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE | |
| 14029 */ | |
| 14030 bool checkForArgumentTypeNotAssignable3(Expression expression, Type2 expectedS
taticType, Type2 expectedPropagatedType, ErrorCode errorCode) => checkForArgumen
tTypeNotAssignable4(expression, expectedStaticType, getStaticType(expression), e
xpectedPropagatedType, expression.propagatedType, errorCode); | |
| 14031 | |
| 14032 /** | |
| 14033 * This verifies that the passed expression can be assigned to its correspondi
ng parameters. | |
| 14034 * | |
| 14035 * @param expression the expression to evaluate | |
| 14036 * @param expectedStaticType the expected static type of the parameter | |
| 14037 * @param actualStaticType the actual static type of the argument | |
| 14038 * @param expectedPropagatedType the expected propagated type of the parameter
, may be | |
| 14039 * `null` | |
| 14040 * @param actualPropagatedType the expected propagated type of the parameter,
may be `null` | |
| 14041 * @return `true` if and only if an error code is generated on the passed node | |
| 14042 * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE | |
| 14043 */ | |
| 14044 bool checkForArgumentTypeNotAssignable4(Expression expression, Type2 expectedS
taticType, Type2 actualStaticType, Type2 expectedPropagatedType, Type2 actualPro
pagatedType, ErrorCode errorCode) { | |
| 14045 if (actualStaticType == null || expectedStaticType == null) { | |
| 14046 return false; | |
| 14047 } | |
| 14048 if (_strictMode) { | |
| 14049 if (actualStaticType.isAssignableTo(expectedStaticType)) { | |
| 14050 return false; | |
| 14051 } | |
| 14052 _errorReporter.reportError2(errorCode, expression, [ | |
| 14053 actualStaticType.displayName, | |
| 14054 expectedStaticType.displayName]); | |
| 14055 return true; | |
| 14056 } | |
| 14057 if (actualPropagatedType == null || expectedPropagatedType == null) { | |
| 14058 if (actualStaticType.isAssignableTo(expectedStaticType)) { | |
| 14059 return false; | |
| 14060 } | |
| 14061 _errorReporter.reportError2(errorCode, expression, [ | |
| 14062 actualStaticType.displayName, | |
| 14063 expectedStaticType.displayName]); | |
| 14064 return true; | |
| 14065 } | |
| 14066 if (actualStaticType.isAssignableTo(expectedStaticType) || actualStaticType.
isAssignableTo(expectedPropagatedType) || actualPropagatedType.isAssignableTo(ex
pectedStaticType) || actualPropagatedType.isAssignableTo(expectedPropagatedType)
) { | |
| 14067 return false; | |
| 14068 } | |
| 14069 _errorReporter.reportError2(errorCode, expression, [ | |
| 14070 (actualPropagatedType == null ? actualStaticType : actualPropagatedType)
.displayName, | |
| 14071 (expectedPropagatedType == null ? expectedStaticType : expectedPropagate
dType).displayName]); | |
| 14072 return true; | |
| 14073 } | |
| 14074 | |
| 14075 /** | |
| 14076 * This verifies that left hand side of the passed assignment expression is no
t final. | |
| 14077 * | |
| 14078 * @param node the assignment expression to evaluate | |
| 14079 * @return `true` if and only if an error code is generated on the passed node | |
| 14080 * @see StaticWarningCode#ASSIGNMENT_TO_FINAL | |
| 14081 */ | |
| 14082 bool checkForAssignmentToFinal(AssignmentExpression node) { | |
| 14083 Expression leftExpression = node.leftHandSide; | |
| 14084 return checkForAssignmentToFinal2(leftExpression); | |
| 14085 } | |
| 14086 | |
| 14087 /** | |
| 14088 * This verifies that the passed expression is not final. | |
| 14089 * | |
| 14090 * @param node the expression to evaluate | |
| 14091 * @return `true` if and only if an error code is generated on the passed node | |
| 14092 * @see StaticWarningCode#ASSIGNMENT_TO_CONST | |
| 14093 * @see StaticWarningCode#ASSIGNMENT_TO_FINAL | |
| 14094 * @see StaticWarningCode#ASSIGNMENT_TO_METHOD | |
| 14095 */ | |
| 14096 bool checkForAssignmentToFinal2(Expression expression) { | |
| 14097 Element element = null; | |
| 14098 if (expression is Identifier) { | |
| 14099 element = ((expression as Identifier)).staticElement; | |
| 14100 } | |
| 14101 if (expression is PropertyAccess) { | |
| 14102 element = ((expression as PropertyAccess)).propertyName.staticElement; | |
| 14103 } | |
| 14104 if (element is PropertyAccessorElement) { | |
| 14105 PropertyAccessorElement accessor = element as PropertyAccessorElement; | |
| 14106 element = accessor.variable; | |
| 14107 } | |
| 14108 if (element is VariableElement) { | |
| 14109 VariableElement variable = element as VariableElement; | |
| 14110 if (variable.isConst) { | |
| 14111 _errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_CONST, expre
ssion, []); | |
| 14112 return true; | |
| 14113 } | |
| 14114 if (variable.isFinal) { | |
| 14115 _errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_FINAL, expre
ssion, []); | |
| 14116 return true; | |
| 14117 } | |
| 14118 return false; | |
| 14119 } | |
| 14120 if (element is MethodElement) { | |
| 14121 _errorReporter.reportError2(StaticWarningCode.ASSIGNMENT_TO_METHOD, expres
sion, []); | |
| 14122 return true; | |
| 14123 } | |
| 14124 return false; | |
| 14125 } | |
| 14126 | |
| 14127 /** | |
| 14128 * This verifies that the passed identifier is not a keyword, and generates th
e passed error code | |
| 14129 * on the identifier if it is a keyword. | |
| 14130 * | |
| 14131 * @param identifier the identifier to check to ensure that it is not a keywor
d | |
| 14132 * @param errorCode if the passed identifier is a keyword then this error code
is created on the | |
| 14133 * identifier, the error code will be one of | |
| 14134 * [CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_NAME], | |
| 14135 * [CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME]
or | |
| 14136 * [CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME] | |
| 14137 * @return `true` if and only if an error code is generated on the passed node | |
| 14138 * @see CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_NAME | |
| 14139 * @see CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME | |
| 14140 * @see CompileTimeErrorCode#BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME | |
| 14141 */ | |
| 14142 bool checkForBuiltInIdentifierAsName(SimpleIdentifier identifier, ErrorCode er
rorCode) { | |
| 14143 sc.Token token = identifier.token; | |
| 14144 if (identical(token.type, sc.TokenType.KEYWORD)) { | |
| 14145 _errorReporter.reportError2(errorCode, identifier, [identifier.name]); | |
| 14146 return true; | |
| 14147 } | |
| 14148 return false; | |
| 14149 } | |
| 14150 | |
| 14151 /** | |
| 14152 * This verifies that the given switch case is terminated with 'break', 'conti
nue', 'return' or | |
| 14153 * 'throw'. | |
| 14154 * | |
| 14155 * @param node the switch case to evaluate | |
| 14156 * @return `true` if and only if an error code is generated on the passed node | |
| 14157 * @see StaticWarningCode#CASE_BLOCK_NOT_TERMINATED | |
| 14158 */ | |
| 14159 bool checkForCaseBlockNotTerminated(SwitchCase node) { | |
| 14160 NodeList<Statement> statements = node.statements; | |
| 14161 if (statements.isEmpty) { | |
| 14162 ASTNode parent = node.parent; | |
| 14163 if (parent is SwitchStatement) { | |
| 14164 SwitchStatement switchStatement = parent as SwitchStatement; | |
| 14165 NodeList<SwitchMember> members = switchStatement.members; | |
| 14166 int index = members.indexOf(node); | |
| 14167 if (index != -1 && index < members.length - 1) { | |
| 14168 return false; | |
| 14169 } | |
| 14170 } | |
| 14171 } else { | |
| 14172 Statement statement = statements[statements.length - 1]; | |
| 14173 if (statement is BreakStatement || statement is ContinueStatement || state
ment is ReturnStatement) { | |
| 14174 return false; | |
| 14175 } | |
| 14176 if (statement is ExpressionStatement) { | |
| 14177 Expression expression = ((statement as ExpressionStatement)).expression; | |
| 14178 if (expression is ThrowExpression) { | |
| 14179 return false; | |
| 14180 } | |
| 14181 } | |
| 14182 } | |
| 14183 _errorReporter.reportError4(StaticWarningCode.CASE_BLOCK_NOT_TERMINATED, nod
e.keyword, []); | |
| 14184 return true; | |
| 14185 } | |
| 14186 | |
| 14187 /** | |
| 14188 * This verifies that the switch cases in the given switch statement is termin
ated with 'break', | |
| 14189 * 'continue', 'return' or 'throw'. | |
| 14190 * | |
| 14191 * @param node the switch statement containing the cases to be checked | |
| 14192 * @return `true` if and only if an error code is generated on the passed node | |
| 14193 * @see StaticWarningCode#CASE_BLOCK_NOT_TERMINATED | |
| 14194 */ | |
| 14195 bool checkForCaseBlocksNotTerminated(SwitchStatement node) { | |
| 14196 bool foundError = false; | |
| 14197 NodeList<SwitchMember> members = node.members; | |
| 14198 int lastMember = members.length - 1; | |
| 14199 for (int i = 0; i < lastMember; i++) { | |
| 14200 SwitchMember member = members[i]; | |
| 14201 if (member is SwitchCase) { | |
| 14202 foundError = javaBooleanOr(foundError, checkForCaseBlockNotTerminated(me
mber as SwitchCase)); | |
| 14203 } | |
| 14204 } | |
| 14205 return foundError; | |
| 14206 } | |
| 14207 | |
| 14208 /** | |
| 14209 * This verifies that the passed switch statement does not have a case express
ion with the | |
| 14210 * operator '==' overridden. | |
| 14211 * | |
| 14212 * @param node the switch statement to evaluate | |
| 14213 * @param type the common type of all 'case' expressions | |
| 14214 * @return `true` if and only if an error code is generated on the passed node | |
| 14215 * @see CompileTimeErrorCode#CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS | |
| 14216 */ | |
| 14217 bool checkForCaseExpressionTypeImplementsEquals(SwitchStatement node, Type2 ty
pe) { | |
| 14218 if (!implementsEqualsWhenNotAllowed(type)) { | |
| 14219 return false; | |
| 14220 } | |
| 14221 _errorReporter.reportError4(CompileTimeErrorCode.CASE_EXPRESSION_TYPE_IMPLEM
ENTS_EQUALS, node.keyword, [type.displayName]); | |
| 14222 return true; | |
| 14223 } | |
| 14224 | |
| 14225 /** | |
| 14226 * This verifies that the passed method declaration is abstract only if the en
closing class is | |
| 14227 * also abstract. | |
| 14228 * | |
| 14229 * @param node the method declaration to evaluate | |
| 14230 * @return `true` if and only if an error code is generated on the passed node | |
| 14231 * @see StaticWarningCode#CONCRETE_CLASS_WITH_ABSTRACT_MEMBER | |
| 14232 */ | |
| 14233 bool checkForConcreteClassWithAbstractMember(MethodDeclaration node) { | |
| 14234 if (node.isAbstract && _enclosingClass != null && !_enclosingClass.isAbstrac
t) { | |
| 14235 SimpleIdentifier methodName = node.name; | |
| 14236 _errorReporter.reportError2(StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT
_MEMBER, methodName, [methodName.name, _enclosingClass.displayName]); | |
| 14237 return true; | |
| 14238 } | |
| 14239 return false; | |
| 14240 } | |
| 14241 | |
| 14242 /** | |
| 14243 * This verifies all possible conflicts of the constructor name with other con
structors and | |
| 14244 * members of the same class. | |
| 14245 * | |
| 14246 * @param node the constructor declaration to evaluate | |
| 14247 * @return `true` if and only if an error code is generated on the passed node | |
| 14248 * @see CompileTimeErrorCode#DUPLICATE_CONSTRUCTOR_DEFAULT | |
| 14249 * @see CompileTimeErrorCode#DUPLICATE_CONSTRUCTOR_NAME | |
| 14250 * @see CompileTimeErrorCode#CONFLICTING_CONSTRUCTOR_NAME_AND_FIELD | |
| 14251 * @see CompileTimeErrorCode#CONFLICTING_CONSTRUCTOR_NAME_AND_METHOD | |
| 14252 */ | |
| 14253 bool checkForConflictingConstructorNameAndMember(ConstructorDeclaration node)
{ | |
| 14254 ConstructorElement constructorElement = node.element; | |
| 14255 SimpleIdentifier constructorName = node.name; | |
| 14256 String name = constructorElement.name; | |
| 14257 ClassElement classElement = constructorElement.enclosingElement; | |
| 14258 List<ConstructorElement> constructors = classElement.constructors; | |
| 14259 for (ConstructorElement otherConstructor in constructors) { | |
| 14260 if (identical(otherConstructor, constructorElement)) { | |
| 14261 continue; | |
| 14262 } | |
| 14263 if (name == otherConstructor.name) { | |
| 14264 if (name == null || name.length == 0) { | |
| 14265 _errorReporter.reportError2(CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR
_DEFAULT, node, []); | |
| 14266 } else { | |
| 14267 _errorReporter.reportError2(CompileTimeErrorCode.DUPLICATE_CONSTRUCTOR
_NAME, node, [name]); | |
| 14268 } | |
| 14269 return true; | |
| 14270 } | |
| 14271 } | |
| 14272 if (constructorName != null && constructorElement != null && !constructorNam
e.isSynthetic) { | |
| 14273 List<FieldElement> fields = classElement.fields; | |
| 14274 for (FieldElement field in fields) { | |
| 14275 if (field.name == name) { | |
| 14276 _errorReporter.reportError2(CompileTimeErrorCode.CONFLICTING_CONSTRUCT
OR_NAME_AND_FIELD, node, [name]); | |
| 14277 return true; | |
| 14278 } | |
| 14279 } | |
| 14280 List<MethodElement> methods = classElement.methods; | |
| 14281 for (MethodElement method in methods) { | |
| 14282 if (method.name == name) { | |
| 14283 _errorReporter.reportError2(CompileTimeErrorCode.CONFLICTING_CONSTRUCT
OR_NAME_AND_METHOD, node, [name]); | |
| 14284 return true; | |
| 14285 } | |
| 14286 } | |
| 14287 } | |
| 14288 return false; | |
| 14289 } | |
| 14290 | |
| 14291 /** | |
| 14292 * This verifies that the [enclosingClass] does not have method and getter wit
h the same | |
| 14293 * names. | |
| 14294 * | |
| 14295 * @return `true` if and only if an error code is generated on the passed node | |
| 14296 * @see CompileTimeErrorCode#CONFLICTING_GETTER_AND_METHOD | |
| 14297 * @see CompileTimeErrorCode#CONFLICTING_METHOD_AND_GETTER | |
| 14298 */ | |
| 14299 bool checkForConflictingGetterAndMethod() { | |
| 14300 if (_enclosingClass == null) { | |
| 14301 return false; | |
| 14302 } | |
| 14303 bool hasProblem = false; | |
| 14304 for (MethodElement method in _enclosingClass.methods) { | |
| 14305 String name = method.name; | |
| 14306 ExecutableElement inherited = _inheritanceManager.lookupInheritance(_enclo
singClass, name); | |
| 14307 if (inherited is! PropertyAccessorElement) { | |
| 14308 continue; | |
| 14309 } | |
| 14310 hasProblem = true; | |
| 14311 _errorReporter.reportError3(CompileTimeErrorCode.CONFLICTING_GETTER_AND_ME
THOD, method.nameOffset, name.length, [ | |
| 14312 _enclosingClass.displayName, | |
| 14313 inherited.enclosingElement.displayName, | |
| 14314 name]); | |
| 14315 } | |
| 14316 for (PropertyAccessorElement accessor in _enclosingClass.accessors) { | |
| 14317 if (!accessor.isGetter) { | |
| 14318 continue; | |
| 14319 } | |
| 14320 String name = accessor.name; | |
| 14321 ExecutableElement inherited = _inheritanceManager.lookupInheritance(_enclo
singClass, name); | |
| 14322 if (inherited is! MethodElement) { | |
| 14323 continue; | |
| 14324 } | |
| 14325 hasProblem = true; | |
| 14326 _errorReporter.reportError3(CompileTimeErrorCode.CONFLICTING_METHOD_AND_GE
TTER, accessor.nameOffset, name.length, [ | |
| 14327 _enclosingClass.displayName, | |
| 14328 inherited.enclosingElement.displayName, | |
| 14329 name]); | |
| 14330 } | |
| 14331 return hasProblem; | |
| 14332 } | |
| 14333 | |
| 14334 /** | |
| 14335 * This verifies that the superclass of the enclosing class does not declare a
ccessible static | |
| 14336 * member with the same name as the passed instance getter/setter method decla
ration. | |
| 14337 * | |
| 14338 * @param node the method declaration to evaluate | |
| 14339 * @return `true` if and only if an error code is generated on the passed node | |
| 14340 * @see StaticWarningCode#CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER | |
| 14341 * @see StaticWarningCode#CONFLICTING_INSTANCE_SETTER_AND_SUPERCLASS_MEMBER | |
| 14342 */ | |
| 14343 bool checkForConflictingInstanceGetterAndSuperclassMember(MethodDeclaration no
de) { | |
| 14344 if (node.isStatic) { | |
| 14345 return false; | |
| 14346 } | |
| 14347 SimpleIdentifier nameNode = node.name; | |
| 14348 if (nameNode == null) { | |
| 14349 return false; | |
| 14350 } | |
| 14351 String name = nameNode.name; | |
| 14352 if (_enclosingClass == null) { | |
| 14353 return false; | |
| 14354 } | |
| 14355 InterfaceType enclosingType = _enclosingClass.type; | |
| 14356 ExecutableElement superElement; | |
| 14357 superElement = enclosingType.lookUpGetterInSuperclass(name, _currentLibrary)
; | |
| 14358 if (superElement == null) { | |
| 14359 superElement = enclosingType.lookUpSetterInSuperclass(name, _currentLibrar
y); | |
| 14360 } | |
| 14361 if (superElement == null) { | |
| 14362 superElement = enclosingType.lookUpMethodInSuperclass(name, _currentLibrar
y); | |
| 14363 } | |
| 14364 if (superElement == null) { | |
| 14365 return false; | |
| 14366 } | |
| 14367 if (!superElement.isStatic) { | |
| 14368 return false; | |
| 14369 } | |
| 14370 ClassElement superElementClass = superElement.enclosingElement as ClassEleme
nt; | |
| 14371 InterfaceType superElementType = superElementClass.type; | |
| 14372 if (node.isGetter) { | |
| 14373 _errorReporter.reportError2(StaticWarningCode.CONFLICTING_INSTANCE_GETTER_
AND_SUPERCLASS_MEMBER, nameNode, [superElementType.displayName]); | |
| 14374 } else { | |
| 14375 _errorReporter.reportError2(StaticWarningCode.CONFLICTING_INSTANCE_SETTER_
AND_SUPERCLASS_MEMBER, nameNode, [superElementType.displayName]); | |
| 14376 } | |
| 14377 return true; | |
| 14378 } | |
| 14379 | |
| 14380 /** | |
| 14381 * This verifies that the enclosing class does not have an instance member wit
h the same name as | |
| 14382 * the passed static getter method declaration. | |
| 14383 * | |
| 14384 * @param node the method declaration to evaluate | |
| 14385 * @return `true` if and only if an error code is generated on the passed node | |
| 14386 * @see StaticWarningCode#CONFLICTING_STATIC_GETTER_AND_INSTANCE_SETTER | |
| 14387 */ | |
| 14388 bool checkForConflictingStaticGetterAndInstanceSetter(MethodDeclaration node)
{ | |
| 14389 if (!node.isStatic) { | |
| 14390 return false; | |
| 14391 } | |
| 14392 SimpleIdentifier nameNode = node.name; | |
| 14393 if (nameNode == null) { | |
| 14394 return false; | |
| 14395 } | |
| 14396 String name = nameNode.name; | |
| 14397 if (_enclosingClass == null) { | |
| 14398 return false; | |
| 14399 } | |
| 14400 InterfaceType enclosingType = _enclosingClass.type; | |
| 14401 ExecutableElement setter = enclosingType.lookUpSetter(name, _currentLibrary)
; | |
| 14402 if (setter == null) { | |
| 14403 return false; | |
| 14404 } | |
| 14405 if (setter.isStatic) { | |
| 14406 return false; | |
| 14407 } | |
| 14408 ClassElement setterClass = setter.enclosingElement as ClassElement; | |
| 14409 InterfaceType setterType = setterClass.type; | |
| 14410 _errorReporter.reportError2(StaticWarningCode.CONFLICTING_STATIC_GETTER_AND_
INSTANCE_SETTER, nameNode, [setterType.displayName]); | |
| 14411 return true; | |
| 14412 } | |
| 14413 | |
| 14414 /** | |
| 14415 * This verifies that the enclosing class does not have an instance member wit
h the same name as | |
| 14416 * the passed static getter method declaration. | |
| 14417 * | |
| 14418 * @param node the method declaration to evaluate | |
| 14419 * @return `true` if and only if an error code is generated on the passed node | |
| 14420 * @see StaticWarningCode#CONFLICTING_STATIC_SETTER_AND_INSTANCE_MEMBER | |
| 14421 */ | |
| 14422 bool checkForConflictingStaticSetterAndInstanceMember(MethodDeclaration node)
{ | |
| 14423 if (!node.isStatic) { | |
| 14424 return false; | |
| 14425 } | |
| 14426 SimpleIdentifier nameNode = node.name; | |
| 14427 if (nameNode == null) { | |
| 14428 return false; | |
| 14429 } | |
| 14430 String name = nameNode.name; | |
| 14431 if (_enclosingClass == null) { | |
| 14432 return false; | |
| 14433 } | |
| 14434 InterfaceType enclosingType = _enclosingClass.type; | |
| 14435 ExecutableElement member; | |
| 14436 member = enclosingType.lookUpMethod(name, _currentLibrary); | |
| 14437 if (member == null) { | |
| 14438 member = enclosingType.lookUpGetter(name, _currentLibrary); | |
| 14439 } | |
| 14440 if (member == null) { | |
| 14441 member = enclosingType.lookUpSetter(name, _currentLibrary); | |
| 14442 } | |
| 14443 if (member == null) { | |
| 14444 return false; | |
| 14445 } | |
| 14446 if (member.isStatic) { | |
| 14447 return false; | |
| 14448 } | |
| 14449 ClassElement memberClass = member.enclosingElement as ClassElement; | |
| 14450 InterfaceType memberType = memberClass.type; | |
| 14451 _errorReporter.reportError2(StaticWarningCode.CONFLICTING_STATIC_SETTER_AND_
INSTANCE_MEMBER, nameNode, [memberType.displayName]); | |
| 14452 return true; | |
| 14453 } | |
| 14454 | |
| 14455 /** | |
| 14456 * This verifies all conflicts between type variable and enclosing class. TODO
(scheglov) | |
| 14457 * | |
| 14458 * @param node the class declaration to evaluate | |
| 14459 * @return `true` if and only if an error code is generated on the passed node | |
| 14460 * @see CompileTimeErrorCode#CONFLICTING_TYPE_VARIABLE_AND_CLASS | |
| 14461 * @see CompileTimeErrorCode#CONFLICTING_TYPE_VARIABLE_AND_MEMBER | |
| 14462 */ | |
| 14463 bool checkForConflictingTypeVariableErrorCodes(ClassDeclaration node) { | |
| 14464 bool problemReported = false; | |
| 14465 for (TypeParameterElement typeParameter in _enclosingClass.typeParameters) { | |
| 14466 String name = typeParameter.name; | |
| 14467 if (_enclosingClass.name == name) { | |
| 14468 _errorReporter.reportError3(CompileTimeErrorCode.CONFLICTING_TYPE_VARIAB
LE_AND_CLASS, typeParameter.nameOffset, name.length, [name]); | |
| 14469 problemReported = true; | |
| 14470 } | |
| 14471 if (_enclosingClass.getMethod(name) != null || _enclosingClass.getGetter(n
ame) != null || _enclosingClass.getSetter(name) != null) { | |
| 14472 _errorReporter.reportError3(CompileTimeErrorCode.CONFLICTING_TYPE_VARIAB
LE_AND_MEMBER, typeParameter.nameOffset, name.length, [name]); | |
| 14473 problemReported = true; | |
| 14474 } | |
| 14475 } | |
| 14476 return problemReported; | |
| 14477 } | |
| 14478 | |
| 14479 /** | |
| 14480 * This verifies that if the passed constructor declaration is 'const' then th
ere are no | |
| 14481 * invocations of non-'const' super constructors. | |
| 14482 * | |
| 14483 * @param node the constructor declaration to evaluate | |
| 14484 * @return `true` if and only if an error code is generated on the passed node | |
| 14485 * @see CompileTimeErrorCode#CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER | |
| 14486 */ | |
| 14487 bool checkForConstConstructorWithNonConstSuper(ConstructorDeclaration node) { | |
| 14488 if (!_isEnclosingConstructorConst) { | |
| 14489 return false; | |
| 14490 } | |
| 14491 if (node.factoryKeyword != null) { | |
| 14492 return false; | |
| 14493 } | |
| 14494 for (ConstructorInitializer initializer in node.initializers) { | |
| 14495 if (initializer is SuperConstructorInvocation) { | |
| 14496 SuperConstructorInvocation superInvocation = initializer as SuperConstru
ctorInvocation; | |
| 14497 ConstructorElement element = superInvocation.staticElement; | |
| 14498 if (element.isConst) { | |
| 14499 return false; | |
| 14500 } | |
| 14501 _errorReporter.reportError2(CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_
NON_CONST_SUPER, superInvocation, []); | |
| 14502 return true; | |
| 14503 } | |
| 14504 } | |
| 14505 InterfaceType supertype = _enclosingClass.supertype; | |
| 14506 if (supertype == null) { | |
| 14507 return false; | |
| 14508 } | |
| 14509 if (supertype.isObject) { | |
| 14510 return false; | |
| 14511 } | |
| 14512 ConstructorElement unnamedConstructor = supertype.element.unnamedConstructor
; | |
| 14513 if (unnamedConstructor == null) { | |
| 14514 return false; | |
| 14515 } | |
| 14516 if (unnamedConstructor.isConst) { | |
| 14517 return false; | |
| 14518 } | |
| 14519 _errorReporter.reportError2(CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_
CONST_SUPER, node, []); | |
| 14520 return true; | |
| 14521 } | |
| 14522 | |
| 14523 /** | |
| 14524 * This verifies that if the passed constructor declaration is 'const' then th
ere are no non-final | |
| 14525 * instance variable. | |
| 14526 * | |
| 14527 * @param node the constructor declaration to evaluate | |
| 14528 * @return `true` if and only if an error code is generated on the passed node | |
| 14529 * @see CompileTimeErrorCode#CONST_CONSTRUCTOR_WITH_NON_FINAL_FIELD | |
| 14530 */ | |
| 14531 bool checkForConstConstructorWithNonFinalField(ConstructorDeclaration node) { | |
| 14532 if (!_isEnclosingConstructorConst) { | |
| 14533 return false; | |
| 14534 } | |
| 14535 ConstructorElement constructorElement = node.element; | |
| 14536 ClassElement classElement = constructorElement.enclosingElement; | |
| 14537 if (!classElement.hasNonFinalField()) { | |
| 14538 return false; | |
| 14539 } | |
| 14540 _errorReporter.reportError2(CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_NON_
FINAL_FIELD, node, []); | |
| 14541 return true; | |
| 14542 } | |
| 14543 | |
| 14544 /** | |
| 14545 * This verifies that the passed throw expression is not enclosed in a 'const'
constructor | |
| 14546 * declaration. | |
| 14547 * | |
| 14548 * @param node the throw expression expression to evaluate | |
| 14549 * @return `true` if and only if an error code is generated on the passed node | |
| 14550 * @see CompileTimeErrorCode#CONST_CONSTRUCTOR_THROWS_EXCEPTION | |
| 14551 */ | |
| 14552 bool checkForConstEvalThrowsException(ThrowExpression node) { | |
| 14553 if (_isEnclosingConstructorConst) { | |
| 14554 _errorReporter.reportError2(CompileTimeErrorCode.CONST_CONSTRUCTOR_THROWS_
EXCEPTION, node, []); | |
| 14555 return true; | |
| 14556 } | |
| 14557 return false; | |
| 14558 } | |
| 14559 | |
| 14560 /** | |
| 14561 * This verifies that the passed normal formal parameter is not 'const'. | |
| 14562 * | |
| 14563 * @param node the normal formal parameter to evaluate | |
| 14564 * @return `true` if and only if an error code is generated on the passed node | |
| 14565 * @see CompileTimeErrorCode#CONST_FORMAL_PARAMETER | |
| 14566 */ | |
| 14567 bool checkForConstFormalParameter(NormalFormalParameter node) { | |
| 14568 if (node.isConst) { | |
| 14569 _errorReporter.reportError2(CompileTimeErrorCode.CONST_FORMAL_PARAMETER, n
ode, []); | |
| 14570 return true; | |
| 14571 } | |
| 14572 return false; | |
| 14573 } | |
| 14574 | |
| 14575 /** | |
| 14576 * This verifies that the passed expression (used as a key in constant map) ha
s class type that | |
| 14577 * does not declare operator <i>==<i>. | |
| 14578 * | |
| 14579 * @param key the expression to evaluate | |
| 14580 * @return `true` if and only if an error code is generated on the passed node | |
| 14581 * @see CompileTimeErrorCode#CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS | |
| 14582 */ | |
| 14583 bool checkForConstMapKeyExpressionTypeImplementsEquals(Expression key) { | |
| 14584 Type2 type = key.staticType; | |
| 14585 if (!implementsEqualsWhenNotAllowed(type)) { | |
| 14586 return false; | |
| 14587 } | |
| 14588 _errorReporter.reportError2(CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TY
PE_IMPLEMENTS_EQUALS, key, [type.displayName]); | |
| 14589 return true; | |
| 14590 } | |
| 14591 | |
| 14592 /** | |
| 14593 * This verifies that the all keys of the passed map literal have class type t
hat does not declare | |
| 14594 * operator <i>==<i>. | |
| 14595 * | |
| 14596 * @param key the map literal to evaluate | |
| 14597 * @return `true` if and only if an error code is generated on the passed node | |
| 14598 * @see CompileTimeErrorCode#CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS | |
| 14599 */ | |
| 14600 bool checkForConstMapKeyExpressionTypeImplementsEquals2(MapLiteral node) { | |
| 14601 if (node.constKeyword == null) { | |
| 14602 return false; | |
| 14603 } | |
| 14604 bool hasProblems = false; | |
| 14605 for (MapLiteralEntry entry in node.entries) { | |
| 14606 Expression key = entry.key; | |
| 14607 hasProblems = javaBooleanOr(hasProblems, checkForConstMapKeyExpressionType
ImplementsEquals(key)); | |
| 14608 } | |
| 14609 return hasProblems; | |
| 14610 } | |
| 14611 | |
| 14612 /** | |
| 14613 * This verifies that the passed instance creation expression is not being inv
oked on an abstract | |
| 14614 * class. | |
| 14615 * | |
| 14616 * @param node the instance creation expression to evaluate | |
| 14617 * @param typeName the [TypeName] of the [ConstructorName] from the | |
| 14618 * [InstanceCreationExpression], this is the AST node that the error
is attached to | |
| 14619 * @param type the type being constructed with this [InstanceCreationExpressio
n] | |
| 14620 * @return `true` if and only if an error code is generated on the passed node | |
| 14621 * @see StaticWarningCode#CONST_WITH_ABSTRACT_CLASS | |
| 14622 * @see StaticWarningCode#NEW_WITH_ABSTRACT_CLASS | |
| 14623 */ | |
| 14624 bool checkForConstOrNewWithAbstractClass(InstanceCreationExpression node, Type
Name typeName, InterfaceType type) { | |
| 14625 if (type.element.isAbstract) { | |
| 14626 ConstructorElement element = node.staticElement; | |
| 14627 if (element != null && !element.isFactory) { | |
| 14628 if (identical(((node.keyword as sc.KeywordToken)).keyword, sc.Keyword.CO
NST)) { | |
| 14629 _errorReporter.reportError2(StaticWarningCode.CONST_WITH_ABSTRACT_CLAS
S, typeName, []); | |
| 14630 } else { | |
| 14631 _errorReporter.reportError2(StaticWarningCode.NEW_WITH_ABSTRACT_CLASS,
typeName, []); | |
| 14632 } | |
| 14633 return true; | |
| 14634 } | |
| 14635 } | |
| 14636 return false; | |
| 14637 } | |
| 14638 | |
| 14639 /** | |
| 14640 * This verifies that the passed 'const' instance creation expression is not b
eing invoked on a | |
| 14641 * constructor that is not 'const'. | |
| 14642 * | |
| 14643 * This method assumes that the instance creation was tested to be 'const' bef
ore being called. | |
| 14644 * | |
| 14645 * @param node the instance creation expression to evaluate | |
| 14646 * @return `true` if and only if an error code is generated on the passed node | |
| 14647 * @see CompileTimeErrorCode#CONST_WITH_NON_CONST | |
| 14648 */ | |
| 14649 bool checkForConstWithNonConst(InstanceCreationExpression node) { | |
| 14650 ConstructorElement constructorElement = node.staticElement; | |
| 14651 if (constructorElement != null && !constructorElement.isConst) { | |
| 14652 _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_NON_CONST, nod
e, []); | |
| 14653 return true; | |
| 14654 } | |
| 14655 return false; | |
| 14656 } | |
| 14657 | |
| 14658 /** | |
| 14659 * This verifies that the passed 'const' instance creation expression does not
reference any type | |
| 14660 * parameters. | |
| 14661 * | |
| 14662 * This method assumes that the instance creation was tested to be 'const' bef
ore being called. | |
| 14663 * | |
| 14664 * @param node the instance creation expression to evaluate | |
| 14665 * @return `true` if and only if an error code is generated on the passed node | |
| 14666 * @see CompileTimeErrorCode#CONST_WITH_TYPE_PARAMETERS | |
| 14667 */ | |
| 14668 bool checkForConstWithTypeParameters(InstanceCreationExpression node) { | |
| 14669 ConstructorName constructorName = node.constructorName; | |
| 14670 if (constructorName == null) { | |
| 14671 return false; | |
| 14672 } | |
| 14673 TypeName typeName = constructorName.type; | |
| 14674 return checkForConstWithTypeParameters2(typeName); | |
| 14675 } | |
| 14676 | |
| 14677 /** | |
| 14678 * This verifies that the passed type name does not reference any type paramet
ers. | |
| 14679 * | |
| 14680 * @param typeName the type name to evaluate | |
| 14681 * @return `true` if and only if an error code is generated on the passed node | |
| 14682 * @see CompileTimeErrorCode#CONST_WITH_TYPE_PARAMETERS | |
| 14683 */ | |
| 14684 bool checkForConstWithTypeParameters2(TypeName typeName) { | |
| 14685 if (typeName == null) { | |
| 14686 return false; | |
| 14687 } | |
| 14688 Identifier name = typeName.name; | |
| 14689 if (name == null) { | |
| 14690 return false; | |
| 14691 } | |
| 14692 if (name.staticElement is TypeParameterElement) { | |
| 14693 _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETER
S, name, []); | |
| 14694 } | |
| 14695 TypeArgumentList typeArguments = typeName.typeArguments; | |
| 14696 if (typeArguments != null) { | |
| 14697 bool hasError = false; | |
| 14698 for (TypeName argument in typeArguments.arguments) { | |
| 14699 hasError = javaBooleanOr(hasError, checkForConstWithTypeParameters2(argu
ment)); | |
| 14700 } | |
| 14701 return hasError; | |
| 14702 } | |
| 14703 return false; | |
| 14704 } | |
| 14705 | |
| 14706 /** | |
| 14707 * This verifies that if the passed 'const' instance creation expression is be
ing invoked on the | |
| 14708 * resolved constructor. | |
| 14709 * | |
| 14710 * This method assumes that the instance creation was tested to be 'const' bef
ore being called. | |
| 14711 * | |
| 14712 * @param node the instance creation expression to evaluate | |
| 14713 * @return `true` if and only if an error code is generated on the passed node | |
| 14714 * @see CompileTimeErrorCode#CONST_WITH_UNDEFINED_CONSTRUCTOR | |
| 14715 * @see CompileTimeErrorCode#CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT | |
| 14716 */ | |
| 14717 bool checkForConstWithUndefinedConstructor(InstanceCreationExpression node) { | |
| 14718 if (node.staticElement != null) { | |
| 14719 return false; | |
| 14720 } | |
| 14721 ConstructorName constructorName = node.constructorName; | |
| 14722 if (constructorName == null) { | |
| 14723 return false; | |
| 14724 } | |
| 14725 TypeName type = constructorName.type; | |
| 14726 if (type == null) { | |
| 14727 return false; | |
| 14728 } | |
| 14729 Identifier className = type.name; | |
| 14730 SimpleIdentifier name = constructorName.name; | |
| 14731 if (name != null) { | |
| 14732 _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONS
TRUCTOR, name, [className, name]); | |
| 14733 } else { | |
| 14734 _errorReporter.reportError2(CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONS
TRUCTOR_DEFAULT, constructorName, [className]); | |
| 14735 } | |
| 14736 return true; | |
| 14737 } | |
| 14738 | |
| 14739 /** | |
| 14740 * This verifies that there are no default parameters in the passed function t
ype alias. | |
| 14741 * | |
| 14742 * @param node the function type alias to evaluate | |
| 14743 * @return `true` if and only if an error code is generated on the passed node | |
| 14744 * @see CompileTimeErrorCode#DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS | |
| 14745 */ | |
| 14746 bool checkForDefaultValueInFunctionTypeAlias(FunctionTypeAlias node) { | |
| 14747 bool result = false; | |
| 14748 FormalParameterList formalParameterList = node.parameters; | |
| 14749 NodeList<FormalParameter> parameters = formalParameterList.parameters; | |
| 14750 for (FormalParameter formalParameter in parameters) { | |
| 14751 if (formalParameter is DefaultFormalParameter) { | |
| 14752 DefaultFormalParameter defaultFormalParameter = formalParameter as Defau
ltFormalParameter; | |
| 14753 if (defaultFormalParameter.defaultValue != null) { | |
| 14754 _errorReporter.reportError2(CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNC
TION_TYPE_ALIAS, node, []); | |
| 14755 result = true; | |
| 14756 } | |
| 14757 } | |
| 14758 } | |
| 14759 return result; | |
| 14760 } | |
| 14761 | |
| 14762 /** | |
| 14763 * This verifies that the given default formal parameter is not part of a func
tion typed | |
| 14764 * parameter. | |
| 14765 * | |
| 14766 * @param node the default formal parameter to evaluate | |
| 14767 * @return `true` if and only if an error code is generated on the passed node | |
| 14768 * @see CompileTimeErrorCode#DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER | |
| 14769 */ | |
| 14770 bool checkForDefaultValueInFunctionTypedParameter(DefaultFormalParameter node)
{ | |
| 14771 if (!_isInFunctionTypedFormalParameter) { | |
| 14772 return false; | |
| 14773 } | |
| 14774 if (node.defaultValue == null) { | |
| 14775 return false; | |
| 14776 } | |
| 14777 _errorReporter.reportError2(CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_T
YPED_PARAMETER, node, []); | |
| 14778 return true; | |
| 14779 } | |
| 14780 | |
| 14781 /** | |
| 14782 * This verifies that the enclosing class does not have an instance member wit
h the given name of | |
| 14783 * the static member. | |
| 14784 * | |
| 14785 * @return `true` if and only if an error code is generated on the passed node | |
| 14786 * @see CompileTimeErrorCode#DUPLICATE_DEFINITION_INHERITANCE | |
| 14787 */ | |
| 14788 bool checkForDuplicateDefinitionInheritance() { | |
| 14789 if (_enclosingClass == null) { | |
| 14790 return false; | |
| 14791 } | |
| 14792 bool hasProblem = false; | |
| 14793 for (ExecutableElement member in _enclosingClass.methods) { | |
| 14794 if (!member.isStatic) { | |
| 14795 continue; | |
| 14796 } | |
| 14797 hasProblem = javaBooleanOr(hasProblem, checkForDuplicateDefinitionInherita
nce2(member)); | |
| 14798 } | |
| 14799 for (ExecutableElement member in _enclosingClass.accessors) { | |
| 14800 if (!member.isStatic) { | |
| 14801 continue; | |
| 14802 } | |
| 14803 hasProblem = javaBooleanOr(hasProblem, checkForDuplicateDefinitionInherita
nce2(member)); | |
| 14804 } | |
| 14805 return hasProblem; | |
| 14806 } | |
| 14807 | |
| 14808 /** | |
| 14809 * This verifies that the enclosing class does not have an instance member wit
h the given name of | |
| 14810 * the static member. | |
| 14811 * | |
| 14812 * @param staticMember the static member to check conflict for | |
| 14813 * @return `true` if and only if an error code is generated on the passed node | |
| 14814 * @see CompileTimeErrorCode#DUPLICATE_DEFINITION_INHERITANCE | |
| 14815 */ | |
| 14816 bool checkForDuplicateDefinitionInheritance2(ExecutableElement staticMember) { | |
| 14817 String name = staticMember.name; | |
| 14818 if (name == null) { | |
| 14819 return false; | |
| 14820 } | |
| 14821 ExecutableElement inheritedMember = _inheritanceManager.lookupInheritance(_e
nclosingClass, name); | |
| 14822 if (inheritedMember == null) { | |
| 14823 return false; | |
| 14824 } | |
| 14825 if (inheritedMember.isStatic) { | |
| 14826 return false; | |
| 14827 } | |
| 14828 _errorReporter.reportError3(CompileTimeErrorCode.DUPLICATE_DEFINITION_INHERI
TANCE, staticMember.nameOffset, name.length, [name, inheritedMember.enclosingEle
ment.displayName]); | |
| 14829 return true; | |
| 14830 } | |
| 14831 | |
| 14832 /** | |
| 14833 * This verifies if the passed list literal has type arguments then there is e
xactly one. | |
| 14834 * | |
| 14835 * @param node the list literal to evaluate | |
| 14836 * @return `true` if and only if an error code is generated on the passed node | |
| 14837 * @see StaticTypeWarningCode#EXPECTED_ONE_LIST_TYPE_ARGUMENTS | |
| 14838 */ | |
| 14839 bool checkForExpectedOneListTypeArgument(ListLiteral node) { | |
| 14840 TypeArgumentList typeArguments = node.typeArguments; | |
| 14841 if (typeArguments == null) { | |
| 14842 return false; | |
| 14843 } | |
| 14844 int num = typeArguments.arguments.length; | |
| 14845 if (num == 1) { | |
| 14846 return false; | |
| 14847 } | |
| 14848 _errorReporter.reportError2(StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARG
UMENTS, typeArguments, [num]); | |
| 14849 return true; | |
| 14850 } | |
| 14851 | |
| 14852 /** | |
| 14853 * This verifies the passed import has unique name among other exported librar
ies. | |
| 14854 * | |
| 14855 * @param node the export directive to evaluate | |
| 14856 * @return `true` if and only if an error code is generated on the passed node | |
| 14857 * @see CompileTimeErrorCode#EXPORT_DUPLICATED_LIBRARY_NAME | |
| 14858 */ | |
| 14859 bool checkForExportDuplicateLibraryName(ExportDirective node) { | |
| 14860 Element nodeElement = node.element; | |
| 14861 if (nodeElement is! ExportElement) { | |
| 14862 return false; | |
| 14863 } | |
| 14864 ExportElement nodeExportElement = nodeElement as ExportElement; | |
| 14865 LibraryElement nodeLibrary = nodeExportElement.exportedLibrary; | |
| 14866 if (nodeLibrary == null) { | |
| 14867 return false; | |
| 14868 } | |
| 14869 String name = nodeLibrary.name; | |
| 14870 LibraryElement prevLibrary = _nameToExportElement[name]; | |
| 14871 if (prevLibrary != null) { | |
| 14872 if (prevLibrary != nodeLibrary) { | |
| 14873 _errorReporter.reportError2(StaticWarningCode.EXPORT_DUPLICATED_LIBRARY_
NAME, node, [ | |
| 14874 prevLibrary.definingCompilationUnit.displayName, | |
| 14875 nodeLibrary.definingCompilationUnit.displayName, | |
| 14876 name]); | |
| 14877 return true; | |
| 14878 } | |
| 14879 } else { | |
| 14880 _nameToExportElement[name] = nodeLibrary; | |
| 14881 } | |
| 14882 return false; | |
| 14883 } | |
| 14884 | |
| 14885 /** | |
| 14886 * Check that if the visiting library is not system, then any passed library s
hould not be SDK | |
| 14887 * internal library. | |
| 14888 * | |
| 14889 * @param node the export directive to evaluate | |
| 14890 * @return `true` if and only if an error code is generated on the passed node | |
| 14891 * @see CompileTimeErrorCode#EXPORT_INTERNAL_LIBRARY | |
| 14892 */ | |
| 14893 bool checkForExportInternalLibrary(ExportDirective node) { | |
| 14894 if (_isInSystemLibrary) { | |
| 14895 return false; | |
| 14896 } | |
| 14897 Element element = node.element; | |
| 14898 if (element is! ExportElement) { | |
| 14899 return false; | |
| 14900 } | |
| 14901 ExportElement exportElement = element as ExportElement; | |
| 14902 DartSdk sdk = _currentLibrary.context.sourceFactory.dartSdk; | |
| 14903 String uri = exportElement.uri; | |
| 14904 SdkLibrary sdkLibrary = sdk.getSdkLibrary(uri); | |
| 14905 if (sdkLibrary == null) { | |
| 14906 return false; | |
| 14907 } | |
| 14908 if (!sdkLibrary.isInternal) { | |
| 14909 return false; | |
| 14910 } | |
| 14911 _errorReporter.reportError2(CompileTimeErrorCode.EXPORT_INTERNAL_LIBRARY, no
de, [node.uri]); | |
| 14912 return true; | |
| 14913 } | |
| 14914 | |
| 14915 /** | |
| 14916 * This verifies that the passed extends clause does not extend classes such a
s num or String. | |
| 14917 * | |
| 14918 * @param node the extends clause to test | |
| 14919 * @return `true` if and only if an error code is generated on the passed node | |
| 14920 * @see CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS | |
| 14921 */ | |
| 14922 bool checkForExtendsDisallowedClass(ExtendsClause extendsClause) { | |
| 14923 if (extendsClause == null) { | |
| 14924 return false; | |
| 14925 } | |
| 14926 return checkForExtendsOrImplementsDisallowedClass(extendsClause.superclass,
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS); | |
| 14927 } | |
| 14928 | |
| 14929 /** | |
| 14930 * This verifies that the passed type name does not extend or implement classe
s such as 'num' or | |
| 14931 * 'String'. | |
| 14932 * | |
| 14933 * @param node the type name to test | |
| 14934 * @return `true` if and only if an error code is generated on the passed node | |
| 14935 * @see #checkForExtendsDisallowedClass(ExtendsClause) | |
| 14936 * @see #checkForImplementsDisallowedClass(ImplementsClause) | |
| 14937 * @see CompileTimeErrorCode#EXTENDS_DISALLOWED_CLASS | |
| 14938 * @see CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS | |
| 14939 */ | |
| 14940 bool checkForExtendsOrImplementsDisallowedClass(TypeName typeName, ErrorCode e
rrorCode) { | |
| 14941 if (typeName.isSynthetic) { | |
| 14942 return false; | |
| 14943 } | |
| 14944 Type2 superType = typeName.type; | |
| 14945 for (InterfaceType disallowedType in _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMEN
T) { | |
| 14946 if (superType != null && superType == disallowedType) { | |
| 14947 if (superType == _typeProvider.numType) { | |
| 14948 ASTNode grandParent = typeName.parent.parent; | |
| 14949 if (grandParent is ClassDeclaration) { | |
| 14950 ClassElement classElement = ((grandParent as ClassDeclaration)).elem
ent; | |
| 14951 Type2 classType = classElement.type; | |
| 14952 if (classType != null && (classType == _typeProvider.intType || clas
sType == _typeProvider.doubleType)) { | |
| 14953 return false; | |
| 14954 } | |
| 14955 } | |
| 14956 } | |
| 14957 _errorReporter.reportError2(errorCode, typeName, [disallowedType.display
Name]); | |
| 14958 return true; | |
| 14959 } | |
| 14960 } | |
| 14961 return false; | |
| 14962 } | |
| 14963 | |
| 14964 /** | |
| 14965 * This verifies that the passed constructor field initializer has compatible
field and | |
| 14966 * initializer expression types. | |
| 14967 * | |
| 14968 * @param node the constructor field initializer to test | |
| 14969 * @return `true` if and only if an error code is generated on the passed node | |
| 14970 * @see CompileTimeErrorCode#CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE | |
| 14971 * @see StaticWarningCode#FIELD_INITIALIZER_NOT_ASSIGNABLE | |
| 14972 */ | |
| 14973 bool checkForFieldInitializerNotAssignable(ConstructorFieldInitializer node) { | |
| 14974 Element fieldNameElement = node.fieldName.staticElement; | |
| 14975 if (fieldNameElement is! FieldElement) { | |
| 14976 return false; | |
| 14977 } | |
| 14978 FieldElement fieldElement = fieldNameElement as FieldElement; | |
| 14979 Type2 fieldType = fieldElement.type; | |
| 14980 Expression expression = node.expression; | |
| 14981 if (expression == null) { | |
| 14982 return false; | |
| 14983 } | |
| 14984 Type2 staticType = getStaticType(expression); | |
| 14985 if (staticType == null) { | |
| 14986 return false; | |
| 14987 } | |
| 14988 if (staticType.isAssignableTo(fieldType)) { | |
| 14989 return false; | |
| 14990 } else if (_strictMode) { | |
| 14991 if (_isEnclosingConstructorConst) { | |
| 14992 _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER
_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]); | |
| 14993 } else { | |
| 14994 _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSI
GNABLE, expression, [staticType.displayName, fieldType.displayName]); | |
| 14995 } | |
| 14996 return true; | |
| 14997 } | |
| 14998 Type2 propagatedType = expression.propagatedType; | |
| 14999 if (propagatedType != null && propagatedType.isAssignableTo(fieldType)) { | |
| 15000 return false; | |
| 15001 } | |
| 15002 if (_isEnclosingConstructorConst) { | |
| 15003 _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_N
OT_ASSIGNABLE, expression, [ | |
| 15004 (propagatedType == null ? staticType : propagatedType).displayName, | |
| 15005 fieldType.displayName]); | |
| 15006 } else { | |
| 15007 _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGN
ABLE, expression, [ | |
| 15008 (propagatedType == null ? staticType : propagatedType).displayName, | |
| 15009 fieldType.displayName]); | |
| 15010 } | |
| 15011 return true; | |
| 15012 } | |
| 15013 | |
| 15014 /** | |
| 15015 * This verifies that the passed field formal parameter is in a constructor de
claration. | |
| 15016 * | |
| 15017 * @param node the field formal parameter to test | |
| 15018 * @return `true` if and only if an error code is generated on the passed node | |
| 15019 * @see CompileTimeErrorCode#FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR | |
| 15020 */ | |
| 15021 bool checkForFieldInitializingFormalRedirectingConstructor(FieldFormalParamete
r node) { | |
| 15022 ConstructorDeclaration constructor = node.getAncestor(ConstructorDeclaration
); | |
| 15023 if (constructor == null) { | |
| 15024 _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE
_CONSTRUCTOR, node, []); | |
| 15025 return true; | |
| 15026 } | |
| 15027 if (constructor.factoryKeyword != null) { | |
| 15028 _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_FACTORY
_CONSTRUCTOR, node, []); | |
| 15029 return true; | |
| 15030 } | |
| 15031 for (ConstructorInitializer initializer in constructor.initializers) { | |
| 15032 if (initializer is RedirectingConstructorInvocation) { | |
| 15033 _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_REDIR
ECTING_CONSTRUCTOR, node, []); | |
| 15034 return true; | |
| 15035 } | |
| 15036 } | |
| 15037 return false; | |
| 15038 } | |
| 15039 | |
| 15040 /** | |
| 15041 * This verifies that final fields that are declared, without any constructors
in the enclosing | |
| 15042 * class, are initialized. Cases in which there is at least one constructor ar
e handled at the end | |
| 15043 * of [checkForAllFinalInitializedErrorCodes]. | |
| 15044 * | |
| 15045 * @param node the class declaration to test | |
| 15046 * @return `true` if and only if an error code is generated on the passed node | |
| 15047 * @see CompileTimeErrorCode#CONST_NOT_INITIALIZED | |
| 15048 * @see StaticWarningCode#FINAL_NOT_INITIALIZED | |
| 15049 */ | |
| 15050 bool checkForFinalNotInitialized(ClassDeclaration node) { | |
| 15051 NodeList<ClassMember> classMembers = node.members; | |
| 15052 for (ClassMember classMember in classMembers) { | |
| 15053 if (classMember is ConstructorDeclaration) { | |
| 15054 return false; | |
| 15055 } | |
| 15056 } | |
| 15057 bool foundError = false; | |
| 15058 for (ClassMember classMember in classMembers) { | |
| 15059 if (classMember is FieldDeclaration) { | |
| 15060 FieldDeclaration field = classMember as FieldDeclaration; | |
| 15061 foundError = javaBooleanOr(foundError, checkForFinalNotInitialized2(fiel
d.fields)); | |
| 15062 } | |
| 15063 } | |
| 15064 return foundError; | |
| 15065 } | |
| 15066 | |
| 15067 /** | |
| 15068 * This verifies that the passed variable declaration list has only initialize
d variables if the | |
| 15069 * list is final or const. This method is called by | |
| 15070 * [checkForFinalNotInitialized], | |
| 15071 * [visitTopLevelVariableDeclaration] and | |
| 15072 * [visitVariableDeclarationStatement]. | |
| 15073 * | |
| 15074 * @param node the class declaration to test | |
| 15075 * @return `true` if and only if an error code is generated on the passed node | |
| 15076 * @see CompileTimeErrorCode#CONST_NOT_INITIALIZED | |
| 15077 * @see StaticWarningCode#FINAL_NOT_INITIALIZED | |
| 15078 */ | |
| 15079 bool checkForFinalNotInitialized2(VariableDeclarationList node) { | |
| 15080 if (_isInNativeClass) { | |
| 15081 return false; | |
| 15082 } | |
| 15083 bool foundError = false; | |
| 15084 if (!node.isSynthetic) { | |
| 15085 NodeList<VariableDeclaration> variables = node.variables; | |
| 15086 for (VariableDeclaration variable in variables) { | |
| 15087 if (variable.initializer == null) { | |
| 15088 if (node.isConst) { | |
| 15089 _errorReporter.reportError2(CompileTimeErrorCode.CONST_NOT_INITIALIZ
ED, variable.name, [variable.name.name]); | |
| 15090 } else if (node.isFinal) { | |
| 15091 _errorReporter.reportError2(StaticWarningCode.FINAL_NOT_INITIALIZED,
variable.name, [variable.name.name]); | |
| 15092 } | |
| 15093 foundError = true; | |
| 15094 } | |
| 15095 } | |
| 15096 } | |
| 15097 return foundError; | |
| 15098 } | |
| 15099 | |
| 15100 /** | |
| 15101 * This verifies that the passed implements clause does not implement classes
such as 'num' or | |
| 15102 * 'String'. | |
| 15103 * | |
| 15104 * @param node the implements clause to test | |
| 15105 * @return `true` if and only if an error code is generated on the passed node | |
| 15106 * @see CompileTimeErrorCode#IMPLEMENTS_DISALLOWED_CLASS | |
| 15107 */ | |
| 15108 bool checkForImplementsDisallowedClass(ImplementsClause implementsClause) { | |
| 15109 if (implementsClause == null) { | |
| 15110 return false; | |
| 15111 } | |
| 15112 bool foundError = false; | |
| 15113 for (TypeName type in implementsClause.interfaces) { | |
| 15114 foundError = javaBooleanOr(foundError, checkForExtendsOrImplementsDisallow
edClass(type, CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS)); | |
| 15115 } | |
| 15116 return foundError; | |
| 15117 } | |
| 15118 | |
| 15119 /** | |
| 15120 * This verifies that if the passed identifier is part of constructor initiali
zer, then it does | |
| 15121 * not reference implicitly 'this' expression. | |
| 15122 * | |
| 15123 * @param node the simple identifier to test | |
| 15124 * @return `true` if and only if an error code is generated on the passed node | |
| 15125 * @see CompileTimeErrorCode#IMPLICIT_THIS_REFERENCE_IN_INITIALIZER | |
| 15126 * @see CompileTimeErrorCode#INSTANCE_MEMBER_ACCESS_FROM_STATIC TODO(scheglov)
rename thid method | |
| 15127 */ | |
| 15128 bool checkForImplicitThisReferenceInInitializer(SimpleIdentifier node) { | |
| 15129 if (!_isInConstructorInitializer && !_isInStaticMethod && !_isInInstanceVari
ableInitializer && !_isInStaticVariableDeclaration) { | |
| 15130 return false; | |
| 15131 } | |
| 15132 Element element = node.staticElement; | |
| 15133 if (!(element is MethodElement || element is PropertyAccessorElement)) { | |
| 15134 return false; | |
| 15135 } | |
| 15136 ExecutableElement executableElement = element as ExecutableElement; | |
| 15137 if (executableElement.isStatic) { | |
| 15138 return false; | |
| 15139 } | |
| 15140 Element enclosingElement = element.enclosingElement; | |
| 15141 if (enclosingElement is! ClassElement) { | |
| 15142 return false; | |
| 15143 } | |
| 15144 ASTNode parent = node.parent; | |
| 15145 if (parent is CommentReference) { | |
| 15146 return false; | |
| 15147 } | |
| 15148 if (parent is MethodInvocation) { | |
| 15149 MethodInvocation invocation = parent as MethodInvocation; | |
| 15150 if (identical(invocation.methodName, node) && invocation.realTarget != nul
l) { | |
| 15151 return false; | |
| 15152 } | |
| 15153 } | |
| 15154 if (parent is PropertyAccess) { | |
| 15155 PropertyAccess access = parent as PropertyAccess; | |
| 15156 if (identical(access.propertyName, node) && access.realTarget != null) { | |
| 15157 return false; | |
| 15158 } | |
| 15159 } | |
| 15160 if (parent is PrefixedIdentifier) { | |
| 15161 PrefixedIdentifier prefixed = parent as PrefixedIdentifier; | |
| 15162 if (identical(prefixed.identifier, node)) { | |
| 15163 return false; | |
| 15164 } | |
| 15165 } | |
| 15166 if (_isInStaticMethod) { | |
| 15167 _errorReporter.reportError2(CompileTimeErrorCode.INSTANCE_MEMBER_ACCESS_FR
OM_STATIC, node, []); | |
| 15168 } else { | |
| 15169 _errorReporter.reportError2(CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_I
N_INITIALIZER, node, []); | |
| 15170 } | |
| 15171 return true; | |
| 15172 } | |
| 15173 | |
| 15174 /** | |
| 15175 * This verifies the passed import has unique name among other imported librar
ies. | |
| 15176 * | |
| 15177 * @param node the import directive to evaluate | |
| 15178 * @return `true` if and only if an error code is generated on the passed node | |
| 15179 * @see CompileTimeErrorCode#IMPORT_DUPLICATED_LIBRARY_NAME | |
| 15180 */ | |
| 15181 bool checkForImportDuplicateLibraryName(ImportDirective node) { | |
| 15182 ImportElement nodeImportElement = node.element; | |
| 15183 if (nodeImportElement == null) { | |
| 15184 return false; | |
| 15185 } | |
| 15186 LibraryElement nodeLibrary = nodeImportElement.importedLibrary; | |
| 15187 if (nodeLibrary == null) { | |
| 15188 return false; | |
| 15189 } | |
| 15190 String name = nodeLibrary.name; | |
| 15191 LibraryElement prevLibrary = _nameToImportElement[name]; | |
| 15192 if (prevLibrary != null) { | |
| 15193 if (prevLibrary != nodeLibrary) { | |
| 15194 _errorReporter.reportError2(StaticWarningCode.IMPORT_DUPLICATED_LIBRARY_
NAME, node, [ | |
| 15195 prevLibrary.definingCompilationUnit.displayName, | |
| 15196 nodeLibrary.definingCompilationUnit.displayName, | |
| 15197 name]); | |
| 15198 return true; | |
| 15199 } | |
| 15200 } else { | |
| 15201 _nameToImportElement[name] = nodeLibrary; | |
| 15202 } | |
| 15203 return false; | |
| 15204 } | |
| 15205 | |
| 15206 /** | |
| 15207 * Check that if the visiting library is not system, then any passed library s
hould not be SDK | |
| 15208 * internal library. | |
| 15209 * | |
| 15210 * @param node the import directive to evaluate | |
| 15211 * @return `true` if and only if an error code is generated on the passed node | |
| 15212 * @see CompileTimeErrorCode#IMPORT_INTERNAL_LIBRARY | |
| 15213 */ | |
| 15214 bool checkForImportInternalLibrary(ImportDirective node) { | |
| 15215 if (_isInSystemLibrary) { | |
| 15216 return false; | |
| 15217 } | |
| 15218 ImportElement importElement = node.element; | |
| 15219 if (importElement == null) { | |
| 15220 return false; | |
| 15221 } | |
| 15222 DartSdk sdk = _currentLibrary.context.sourceFactory.dartSdk; | |
| 15223 String uri = importElement.uri; | |
| 15224 SdkLibrary sdkLibrary = sdk.getSdkLibrary(uri); | |
| 15225 if (sdkLibrary == null) { | |
| 15226 return false; | |
| 15227 } | |
| 15228 if (!sdkLibrary.isInternal) { | |
| 15229 return false; | |
| 15230 } | |
| 15231 _errorReporter.reportError2(CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY, no
de, [node.uri]); | |
| 15232 return true; | |
| 15233 } | |
| 15234 | |
| 15235 /** | |
| 15236 * This verifies that the passed switch statement case expressions all have th
e same type. | |
| 15237 * | |
| 15238 * @param node the switch statement to evaluate | |
| 15239 * @return `true` if and only if an error code is generated on the passed node | |
| 15240 * @see CompileTimeErrorCode#INCONSISTENT_CASE_EXPRESSION_TYPES | |
| 15241 */ | |
| 15242 bool checkForInconsistentCaseExpressionTypes(SwitchStatement node) { | |
| 15243 NodeList<SwitchMember> switchMembers = node.members; | |
| 15244 bool foundError = false; | |
| 15245 Type2 firstType = null; | |
| 15246 for (SwitchMember switchMember in switchMembers) { | |
| 15247 if (switchMember is SwitchCase) { | |
| 15248 SwitchCase switchCase = switchMember as SwitchCase; | |
| 15249 Expression expression = switchCase.expression; | |
| 15250 if (firstType == null) { | |
| 15251 firstType = expression.bestType; | |
| 15252 } else { | |
| 15253 Type2 nType = expression.bestType; | |
| 15254 if (firstType != nType) { | |
| 15255 _errorReporter.reportError2(CompileTimeErrorCode.INCONSISTENT_CASE_E
XPRESSION_TYPES, expression, [expression.toSource(), firstType.displayName]); | |
| 15256 foundError = true; | |
| 15257 } | |
| 15258 } | |
| 15259 } | |
| 15260 } | |
| 15261 if (!foundError) { | |
| 15262 checkForCaseExpressionTypeImplementsEquals(node, firstType); | |
| 15263 } | |
| 15264 return foundError; | |
| 15265 } | |
| 15266 | |
| 15267 /** | |
| 15268 * For each class declaration, this method is called which verifies that all i
nherited members are | |
| 15269 * inherited consistently. | |
| 15270 * | |
| 15271 * @return `true` if and only if an error code is generated on the passed node | |
| 15272 * @see StaticTypeWarningCode#INCONSISTENT_METHOD_INHERITANCE | |
| 15273 */ | |
| 15274 bool checkForInconsistentMethodInheritance() { | |
| 15275 _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass); | |
| 15276 Set<AnalysisError> errors = _inheritanceManager.getErrors(_enclosingClass); | |
| 15277 if (errors == null || errors.isEmpty) { | |
| 15278 return false; | |
| 15279 } | |
| 15280 for (AnalysisError error in errors) { | |
| 15281 _errorReporter.reportError(error); | |
| 15282 } | |
| 15283 return true; | |
| 15284 } | |
| 15285 | |
| 15286 /** | |
| 15287 * This checks that if the given "target" is not a type reference then the "na
me" is reference to | |
| 15288 * an instance member. | |
| 15289 * | |
| 15290 * @param target the target of the name access to evaluate | |
| 15291 * @param name the accessed name to evaluate | |
| 15292 * @return `true` if and only if an error code is generated on the passed node | |
| 15293 * @see StaticTypeWarningCode#INSTANCE_ACCESS_TO_STATIC_MEMBER | |
| 15294 */ | |
| 15295 bool checkForInstanceAccessToStaticMember(Expression target, SimpleIdentifier
name) { | |
| 15296 if (target == null) { | |
| 15297 return false; | |
| 15298 } | |
| 15299 if (_isInComment) { | |
| 15300 return false; | |
| 15301 } | |
| 15302 Element element = name.staticElement; | |
| 15303 if (element is! ExecutableElement) { | |
| 15304 return false; | |
| 15305 } | |
| 15306 ExecutableElement executableElement = element as ExecutableElement; | |
| 15307 if (executableElement.enclosingElement is! ClassElement) { | |
| 15308 return false; | |
| 15309 } | |
| 15310 if (!executableElement.isStatic) { | |
| 15311 return false; | |
| 15312 } | |
| 15313 if (isTypeReference(target)) { | |
| 15314 return false; | |
| 15315 } | |
| 15316 _errorReporter.reportError2(StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_
MEMBER, name, [name.name]); | |
| 15317 return true; | |
| 15318 } | |
| 15319 | |
| 15320 /** | |
| 15321 * This verifies that an 'int' can be assigned to the parameter corresponding
to the given | |
| 15322 * expression. This is used for prefix and postfix expressions where the argum
ent value is | |
| 15323 * implicit. | |
| 15324 * | |
| 15325 * @param argument the expression to which the operator is being applied | |
| 15326 * @return `true` if and only if an error code is generated on the passed node | |
| 15327 * @see StaticWarningCode#ARGUMENT_TYPE_NOT_ASSIGNABLE | |
| 15328 */ | |
| 15329 bool checkForIntNotAssignable(Expression argument) { | |
| 15330 if (argument == null) { | |
| 15331 return false; | |
| 15332 } | |
| 15333 ParameterElement staticParameterElement = argument.staticParameterElement; | |
| 15334 Type2 staticParameterType = staticParameterElement == null ? null : staticPa
rameterElement.type; | |
| 15335 ParameterElement propagatedParameterElement = argument.propagatedParameterEl
ement; | |
| 15336 Type2 propagatedParameterType = propagatedParameterElement == null ? null :
propagatedParameterElement.type; | |
| 15337 return checkForArgumentTypeNotAssignable4(argument, staticParameterType, _ty
peProvider.intType, propagatedParameterType, _typeProvider.intType, StaticWarnin
gCode.ARGUMENT_TYPE_NOT_ASSIGNABLE); | |
| 15338 } | |
| 15339 | |
| 15340 /** | |
| 15341 * Given an assignment using a compound assignment operator, this verifies tha
t the given | |
| 15342 * assignment is valid. | |
| 15343 * | |
| 15344 * @param node the assignment expression being tested | |
| 15345 * @return `true` if and only if an error code is generated on the passed node | |
| 15346 * @see StaticTypeWarningCode#INVALID_ASSIGNMENT | |
| 15347 */ | |
| 15348 bool checkForInvalidAssignment(AssignmentExpression node) { | |
| 15349 Expression lhs = node.leftHandSide; | |
| 15350 if (lhs == null) { | |
| 15351 return false; | |
| 15352 } | |
| 15353 VariableElement leftElement = getVariableElement(lhs); | |
| 15354 Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.ty
pe; | |
| 15355 MethodElement invokedMethod = node.staticElement; | |
| 15356 if (invokedMethod == null) { | |
| 15357 return false; | |
| 15358 } | |
| 15359 Type2 rightType = invokedMethod.type.returnType; | |
| 15360 if (leftType == null || rightType == null) { | |
| 15361 return false; | |
| 15362 } | |
| 15363 if (!rightType.isAssignableTo(leftType)) { | |
| 15364 _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, node
.rightHandSide, [rightType.displayName, leftType.displayName]); | |
| 15365 return true; | |
| 15366 } | |
| 15367 return false; | |
| 15368 } | |
| 15369 | |
| 15370 /** | |
| 15371 * This verifies that the passed left hand side and right hand side represent
a valid assignment. | |
| 15372 * | |
| 15373 * @param lhs the left hand side expression | |
| 15374 * @param rhs the right hand side expression | |
| 15375 * @return `true` if and only if an error code is generated on the passed node | |
| 15376 * @see StaticTypeWarningCode#INVALID_ASSIGNMENT | |
| 15377 */ | |
| 15378 bool checkForInvalidAssignment2(Expression lhs, Expression rhs) { | |
| 15379 if (lhs == null || rhs == null) { | |
| 15380 return false; | |
| 15381 } | |
| 15382 VariableElement leftElement = getVariableElement(lhs); | |
| 15383 Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.ty
pe; | |
| 15384 Type2 staticRightType = getStaticType(rhs); | |
| 15385 bool isStaticAssignable = staticRightType.isAssignableTo(leftType); | |
| 15386 Type2 propagatedRightType = rhs.propagatedType; | |
| 15387 if (_strictMode || propagatedRightType == null) { | |
| 15388 if (!isStaticAssignable) { | |
| 15389 _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rh
s, [staticRightType.displayName, leftType.displayName]); | |
| 15390 return true; | |
| 15391 } | |
| 15392 } else { | |
| 15393 bool isPropagatedAssignable = propagatedRightType.isAssignableTo(leftType)
; | |
| 15394 if (!isStaticAssignable && !isPropagatedAssignable) { | |
| 15395 _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rh
s, [staticRightType.displayName, leftType.displayName]); | |
| 15396 return true; | |
| 15397 } | |
| 15398 } | |
| 15399 return false; | |
| 15400 } | |
| 15401 | |
| 15402 /** | |
| 15403 * This verifies that the usage of the passed 'this' is valid. | |
| 15404 * | |
| 15405 * @param node the 'this' expression to evaluate | |
| 15406 * @return `true` if and only if an error code is generated on the passed node | |
| 15407 * @see CompileTimeErrorCode#INVALID_REFERENCE_TO_THIS | |
| 15408 */ | |
| 15409 bool checkForInvalidReferenceToThis(ThisExpression node) { | |
| 15410 if (!isThisInValidContext(node)) { | |
| 15411 _errorReporter.reportError2(CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS
, node, []); | |
| 15412 return true; | |
| 15413 } | |
| 15414 return false; | |
| 15415 } | |
| 15416 | |
| 15417 /** | |
| 15418 * Checks to ensure that the passed [ListLiteral] or [MapLiteral] does not hav
e a type | |
| 15419 * parameter as a type argument. | |
| 15420 * | |
| 15421 * @param arguments a non-`null`, non-empty [TypeName] node list from the resp
ective | |
| 15422 * [ListLiteral] or [MapLiteral] | |
| 15423 * @param errorCode either [CompileTimeErrorCode#INVALID_TYPE_ARGUMENT_IN_CONS
T_LIST] or | |
| 15424 * [CompileTimeErrorCode#INVALID_TYPE_ARGUMENT_IN_CONST_MAP] | |
| 15425 * @return `true` if and only if an error code is generated on the passed node | |
| 15426 */ | |
| 15427 bool checkForInvalidTypeArgumentInConstTypedLiteral(NodeList<TypeName> argumen
ts, ErrorCode errorCode) { | |
| 15428 bool foundError = false; | |
| 15429 for (TypeName typeName in arguments) { | |
| 15430 if (typeName.type is TypeParameterType) { | |
| 15431 _errorReporter.reportError2(errorCode, typeName, [typeName.name]); | |
| 15432 foundError = true; | |
| 15433 } | |
| 15434 } | |
| 15435 return foundError; | |
| 15436 } | |
| 15437 | |
| 15438 /** | |
| 15439 * This verifies that the elements given [ListLiteral] are subtypes of the spe
cified element | |
| 15440 * type. | |
| 15441 * | |
| 15442 * @param node the list literal to evaluate | |
| 15443 * @return `true` if and only if an error code is generated on the passed node | |
| 15444 * @see CompileTimeErrorCode#LIST_ELEMENT_TYPE_NOT_ASSIGNABLE | |
| 15445 * @see StaticWarningCode#LIST_ELEMENT_TYPE_NOT_ASSIGNABLE | |
| 15446 */ | |
| 15447 bool checkForListElementTypeNotAssignable(ListLiteral node) { | |
| 15448 TypeArgumentList typeArgumentList = node.typeArguments; | |
| 15449 if (typeArgumentList == null) { | |
| 15450 return false; | |
| 15451 } | |
| 15452 NodeList<TypeName> typeArguments = typeArgumentList.arguments; | |
| 15453 if (typeArguments.length < 1) { | |
| 15454 return false; | |
| 15455 } | |
| 15456 Type2 listElementType = typeArguments[0].type; | |
| 15457 ErrorCode errorCode; | |
| 15458 if (node.constKeyword != null) { | |
| 15459 errorCode = CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE; | |
| 15460 } else { | |
| 15461 errorCode = StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE; | |
| 15462 } | |
| 15463 bool hasProblems = false; | |
| 15464 for (Expression element in node.elements) { | |
| 15465 hasProblems = javaBooleanOr(hasProblems, checkForArgumentTypeNotAssignable
3(element, listElementType, null, errorCode)); | |
| 15466 } | |
| 15467 return hasProblems; | |
| 15468 } | |
| 15469 | |
| 15470 /** | |
| 15471 * This verifies that the key/value of entries of the given [MapLiteral] are s
ubtypes of the | |
| 15472 * key/value types specified in the type arguments. | |
| 15473 * | |
| 15474 * @param node the map literal to evaluate | |
| 15475 * @return `true` if and only if an error code is generated on the passed node | |
| 15476 * @see CompileTimeErrorCode#MAP_KEY_TYPE_NOT_ASSIGNABLE | |
| 15477 * @see CompileTimeErrorCode#MAP_VALUE_TYPE_NOT_ASSIGNABLE | |
| 15478 * @see StaticWarningCode#MAP_KEY_TYPE_NOT_ASSIGNABLE | |
| 15479 * @see StaticWarningCode#MAP_VALUE_TYPE_NOT_ASSIGNABLE | |
| 15480 */ | |
| 15481 bool checkForMapTypeNotAssignable(MapLiteral node) { | |
| 15482 TypeArgumentList typeArgumentList = node.typeArguments; | |
| 15483 if (typeArgumentList == null) { | |
| 15484 return false; | |
| 15485 } | |
| 15486 NodeList<TypeName> typeArguments = typeArgumentList.arguments; | |
| 15487 if (typeArguments.length < 2) { | |
| 15488 return false; | |
| 15489 } | |
| 15490 Type2 keyType = typeArguments[0].type; | |
| 15491 Type2 valueType = typeArguments[1].type; | |
| 15492 ErrorCode keyErrorCode; | |
| 15493 ErrorCode valueErrorCode; | |
| 15494 if (node.constKeyword != null) { | |
| 15495 keyErrorCode = CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE; | |
| 15496 valueErrorCode = CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE; | |
| 15497 } else { | |
| 15498 keyErrorCode = StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE; | |
| 15499 valueErrorCode = StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE; | |
| 15500 } | |
| 15501 bool hasProblems = false; | |
| 15502 NodeList<MapLiteralEntry> entries = node.entries; | |
| 15503 for (MapLiteralEntry entry in entries) { | |
| 15504 Expression key = entry.key; | |
| 15505 Expression value = entry.value; | |
| 15506 hasProblems = javaBooleanOr(hasProblems, checkForArgumentTypeNotAssignable
3(key, keyType, null, keyErrorCode)); | |
| 15507 hasProblems = javaBooleanOr(hasProblems, checkForArgumentTypeNotAssignable
3(value, valueType, null, valueErrorCode)); | |
| 15508 } | |
| 15509 return hasProblems; | |
| 15510 } | |
| 15511 | |
| 15512 /** | |
| 15513 * This verifies that the [enclosingClass] does not define members with the sa
me name as | |
| 15514 * the enclosing class. | |
| 15515 * | |
| 15516 * @return `true` if and only if an error code is generated on the passed node | |
| 15517 * @see CompileTimeErrorCode#MEMBER_WITH_CLASS_NAME | |
| 15518 */ | |
| 15519 bool checkForMemberWithClassName() { | |
| 15520 if (_enclosingClass == null) { | |
| 15521 return false; | |
| 15522 } | |
| 15523 String className = _enclosingClass.name; | |
| 15524 if (className == null) { | |
| 15525 return false; | |
| 15526 } | |
| 15527 bool problemReported = false; | |
| 15528 for (PropertyAccessorElement accessor in _enclosingClass.accessors) { | |
| 15529 if (className == accessor.name) { | |
| 15530 _errorReporter.reportError3(CompileTimeErrorCode.MEMBER_WITH_CLASS_NAME,
accessor.nameOffset, className.length, []); | |
| 15531 problemReported = true; | |
| 15532 } | |
| 15533 } | |
| 15534 return problemReported; | |
| 15535 } | |
| 15536 | |
| 15537 /** | |
| 15538 * Check to make sure that all similarly typed accessors are of the same type
(including inherited | |
| 15539 * accessors). | |
| 15540 * | |
| 15541 * @param node the accessor currently being visited | |
| 15542 * @return `true` if and only if an error code is generated on the passed node | |
| 15543 * @see StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES | |
| 15544 * @see StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE | |
| 15545 */ | |
| 15546 bool checkForMismatchedAccessorTypes(Declaration accessorDeclaration, String a
ccessorTextName) { | |
| 15547 ExecutableElement accessorElement = accessorDeclaration.element as Executabl
eElement; | |
| 15548 if (accessorElement is! PropertyAccessorElement) { | |
| 15549 return false; | |
| 15550 } | |
| 15551 PropertyAccessorElement propertyAccessorElement = accessorElement as Propert
yAccessorElement; | |
| 15552 PropertyAccessorElement counterpartAccessor = null; | |
| 15553 ClassElement enclosingClassForCounterpart = null; | |
| 15554 if (propertyAccessorElement.isGetter) { | |
| 15555 counterpartAccessor = propertyAccessorElement.correspondingSetter; | |
| 15556 } else { | |
| 15557 counterpartAccessor = propertyAccessorElement.correspondingGetter; | |
| 15558 if (counterpartAccessor != null && identical(counterpartAccessor.enclosing
Element, propertyAccessorElement.enclosingElement)) { | |
| 15559 return false; | |
| 15560 } | |
| 15561 } | |
| 15562 if (counterpartAccessor == null) { | |
| 15563 if (_enclosingClass != null) { | |
| 15564 String lookupIdentifier = propertyAccessorElement.name; | |
| 15565 if (lookupIdentifier.endsWith("=")) { | |
| 15566 lookupIdentifier = lookupIdentifier.substring(0, lookupIdentifier.leng
th - 1); | |
| 15567 } else { | |
| 15568 lookupIdentifier += "="; | |
| 15569 } | |
| 15570 ExecutableElement elementFromInheritance = _inheritanceManager.lookupInh
eritance(_enclosingClass, lookupIdentifier); | |
| 15571 if (elementFromInheritance != null && elementFromInheritance is Property
AccessorElement) { | |
| 15572 enclosingClassForCounterpart = elementFromInheritance.enclosingElement
as ClassElement; | |
| 15573 counterpartAccessor = elementFromInheritance as PropertyAccessorElemen
t; | |
| 15574 } | |
| 15575 } | |
| 15576 if (counterpartAccessor == null) { | |
| 15577 return false; | |
| 15578 } | |
| 15579 } | |
| 15580 Type2 getterType = null; | |
| 15581 Type2 setterType = null; | |
| 15582 if (propertyAccessorElement.isGetter) { | |
| 15583 getterType = getGetterType(propertyAccessorElement); | |
| 15584 setterType = getSetterType(counterpartAccessor); | |
| 15585 } else if (propertyAccessorElement.isSetter) { | |
| 15586 setterType = getSetterType(propertyAccessorElement); | |
| 15587 getterType = getGetterType(counterpartAccessor); | |
| 15588 } | |
| 15589 if (setterType != null && getterType != null && !getterType.isAssignableTo(s
etterType)) { | |
| 15590 if (enclosingClassForCounterpart == null) { | |
| 15591 _errorReporter.reportError2(StaticWarningCode.MISMATCHED_GETTER_AND_SETT
ER_TYPES, accessorDeclaration, [ | |
| 15592 accessorTextName, | |
| 15593 setterType.displayName, | |
| 15594 getterType.displayName]); | |
| 15595 return true; | |
| 15596 } else { | |
| 15597 _errorReporter.reportError2(StaticWarningCode.MISMATCHED_GETTER_AND_SETT
ER_TYPES_FROM_SUPERTYPE, accessorDeclaration, [ | |
| 15598 accessorTextName, | |
| 15599 setterType.displayName, | |
| 15600 getterType.displayName, | |
| 15601 enclosingClassForCounterpart.displayName]); | |
| 15602 } | |
| 15603 } | |
| 15604 return false; | |
| 15605 } | |
| 15606 | |
| 15607 /** | |
| 15608 * This verifies that the given function body does not contain return statemen
ts that both have | |
| 15609 * and do not have return values. | |
| 15610 * | |
| 15611 * @param node the function body being tested | |
| 15612 * @return `true` if and only if an error code is generated on the passed node | |
| 15613 * @see StaticWarningCode#MIXED_RETURN_TYPES | |
| 15614 */ | |
| 15615 bool checkForMixedReturns(BlockFunctionBody node) { | |
| 15616 if (_returnWithCount > 0 && _returnWithoutCount > 0) { | |
| 15617 _errorReporter.reportError2(StaticWarningCode.MIXED_RETURN_TYPES, node, []
); | |
| 15618 return true; | |
| 15619 } | |
| 15620 return false; | |
| 15621 } | |
| 15622 | |
| 15623 /** | |
| 15624 * This verifies that the passed mixin does not have an explicitly declared co
nstructor. | |
| 15625 * | |
| 15626 * @param mixinName the node to report problem on | |
| 15627 * @param mixinElement the mixing to evaluate | |
| 15628 * @return `true` if and only if an error code is generated on the passed node | |
| 15629 * @see CompileTimeErrorCode#MIXIN_DECLARES_CONSTRUCTOR | |
| 15630 */ | |
| 15631 bool checkForMixinDeclaresConstructor(TypeName mixinName, ClassElement mixinEl
ement) { | |
| 15632 for (ConstructorElement constructor in mixinElement.constructors) { | |
| 15633 if (!constructor.isSynthetic && !constructor.isFactory) { | |
| 15634 _errorReporter.reportError2(CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUC
TOR, mixinName, [mixinElement.name]); | |
| 15635 return true; | |
| 15636 } | |
| 15637 } | |
| 15638 return false; | |
| 15639 } | |
| 15640 | |
| 15641 /** | |
| 15642 * This verifies that the passed mixin has the 'Object' superclass. | |
| 15643 * | |
| 15644 * @param mixinName the node to report problem on | |
| 15645 * @param mixinElement the mixing to evaluate | |
| 15646 * @return `true` if and only if an error code is generated on the passed node | |
| 15647 * @see CompileTimeErrorCode#MIXIN_INHERITS_FROM_NOT_OBJECT | |
| 15648 */ | |
| 15649 bool checkForMixinInheritsNotFromObject(TypeName mixinName, ClassElement mixin
Element) { | |
| 15650 InterfaceType mixinSupertype = mixinElement.supertype; | |
| 15651 if (mixinSupertype != null) { | |
| 15652 if (!mixinSupertype.isObject || !mixinElement.isTypedef && mixinElement.mi
xins.length != 0) { | |
| 15653 _errorReporter.reportError2(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT
_OBJECT, mixinName, [mixinElement.name]); | |
| 15654 return true; | |
| 15655 } | |
| 15656 } | |
| 15657 return false; | |
| 15658 } | |
| 15659 | |
| 15660 /** | |
| 15661 * This verifies that the passed mixin does not reference 'super'. | |
| 15662 * | |
| 15663 * @param mixinName the node to report problem on | |
| 15664 * @param mixinElement the mixing to evaluate | |
| 15665 * @return `true` if and only if an error code is generated on the passed node | |
| 15666 * @see CompileTimeErrorCode#MIXIN_REFERENCES_SUPER | |
| 15667 */ | |
| 15668 bool checkForMixinReferencesSuper(TypeName mixinName, ClassElement mixinElemen
t) { | |
| 15669 if (mixinElement.hasReferenceToSuper()) { | |
| 15670 _errorReporter.reportError2(CompileTimeErrorCode.MIXIN_REFERENCES_SUPER, m
ixinName, [mixinElement.name]); | |
| 15671 } | |
| 15672 return false; | |
| 15673 } | |
| 15674 | |
| 15675 /** | |
| 15676 * This verifies that the passed constructor has at most one 'super' initializ
er. | |
| 15677 * | |
| 15678 * @param node the constructor declaration to evaluate | |
| 15679 * @return `true` if and only if an error code is generated on the passed node | |
| 15680 * @see CompileTimeErrorCode#MULTIPLE_SUPER_INITIALIZERS | |
| 15681 */ | |
| 15682 bool checkForMultipleSuperInitializers(ConstructorDeclaration node) { | |
| 15683 int numSuperInitializers = 0; | |
| 15684 for (ConstructorInitializer initializer in node.initializers) { | |
| 15685 if (initializer is SuperConstructorInvocation) { | |
| 15686 numSuperInitializers++; | |
| 15687 if (numSuperInitializers > 1) { | |
| 15688 _errorReporter.reportError2(CompileTimeErrorCode.MULTIPLE_SUPER_INITIA
LIZERS, initializer, []); | |
| 15689 } | |
| 15690 } | |
| 15691 } | |
| 15692 return numSuperInitializers > 0; | |
| 15693 } | |
| 15694 | |
| 15695 /** | |
| 15696 * Checks to ensure that native function bodies can only in SDK code. | |
| 15697 * | |
| 15698 * @param node the native function body to test | |
| 15699 * @return `true` if and only if an error code is generated on the passed node | |
| 15700 * @see ParserErrorCode#NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE | |
| 15701 */ | |
| 15702 bool checkForNativeFunctionBodyInNonSDKCode(NativeFunctionBody node) { | |
| 15703 if (!_isInSystemLibrary) { | |
| 15704 _errorReporter.reportError2(ParserErrorCode.NATIVE_FUNCTION_BODY_IN_NON_SD
K_CODE, node, []); | |
| 15705 return true; | |
| 15706 } | |
| 15707 return false; | |
| 15708 } | |
| 15709 | |
| 15710 /** | |
| 15711 * This verifies that the passed 'new' instance creation expression invokes ex
isting constructor. | |
| 15712 * | |
| 15713 * This method assumes that the instance creation was tested to be 'new' befor
e being called. | |
| 15714 * | |
| 15715 * @param node the instance creation expression to evaluate | |
| 15716 * @return `true` if and only if an error code is generated on the passed node | |
| 15717 * @see StaticWarningCode#NEW_WITH_UNDEFINED_CONSTRUCTOR | |
| 15718 */ | |
| 15719 bool checkForNewWithUndefinedConstructor(InstanceCreationExpression node) { | |
| 15720 if (node.staticElement != null) { | |
| 15721 return false; | |
| 15722 } | |
| 15723 ConstructorName constructorName = node.constructorName; | |
| 15724 if (constructorName == null) { | |
| 15725 return false; | |
| 15726 } | |
| 15727 TypeName type = constructorName.type; | |
| 15728 if (type == null) { | |
| 15729 return false; | |
| 15730 } | |
| 15731 Identifier className = type.name; | |
| 15732 SimpleIdentifier name = constructorName.name; | |
| 15733 if (name != null) { | |
| 15734 _errorReporter.reportError2(StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCT
OR, name, [className, name]); | |
| 15735 } else { | |
| 15736 _errorReporter.reportError2(StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCT
OR_DEFAULT, constructorName, [className]); | |
| 15737 } | |
| 15738 return true; | |
| 15739 } | |
| 15740 | |
| 15741 /** | |
| 15742 * This checks that if the passed class declaration implicitly calls default c
onstructor of its | |
| 15743 * superclass, there should be such default constructor - implicit or explicit
. | |
| 15744 * | |
| 15745 * @param node the [ClassDeclaration] to evaluate | |
| 15746 * @return `true` if and only if an error code is generated on the passed node | |
| 15747 * @see CompileTimeErrorCode#NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT | |
| 15748 */ | |
| 15749 bool checkForNoDefaultSuperConstructorImplicit(ClassDeclaration node) { | |
| 15750 List<ConstructorElement> constructors = _enclosingClass.constructors; | |
| 15751 if (!constructors[0].isSynthetic) { | |
| 15752 return false; | |
| 15753 } | |
| 15754 InterfaceType superType = _enclosingClass.supertype; | |
| 15755 if (superType == null) { | |
| 15756 return false; | |
| 15757 } | |
| 15758 ClassElement superElement = superType.element; | |
| 15759 ConstructorElement superUnnamedConstructor = superElement.unnamedConstructor
; | |
| 15760 if (superUnnamedConstructor != null) { | |
| 15761 if (superUnnamedConstructor.isFactory) { | |
| 15762 _errorReporter.reportError2(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUC
TOR, node.name, [superUnnamedConstructor]); | |
| 15763 return true; | |
| 15764 } | |
| 15765 if (superUnnamedConstructor.isDefaultConstructor) { | |
| 15766 return true; | |
| 15767 } | |
| 15768 } | |
| 15769 _errorReporter.reportError2(CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTO
R_IMPLICIT, node.name, [superType.displayName]); | |
| 15770 return true; | |
| 15771 } | |
| 15772 | |
| 15773 /** | |
| 15774 * This checks that passed class declaration overrides all members required by
its superclasses | |
| 15775 * and interfaces. | |
| 15776 * | |
| 15777 * @param node the [ClassDeclaration] to evaluate | |
| 15778 * @return `true` if and only if an error code is generated on the passed node | |
| 15779 * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE | |
| 15780 * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO | |
| 15781 * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE | |
| 15782 * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR | |
| 15783 * @see StaticWarningCode#NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLU
S | |
| 15784 */ | |
| 15785 bool checkForNonAbstractClassInheritsAbstractMember(ClassDeclaration node) { | |
| 15786 if (_enclosingClass.isAbstract) { | |
| 15787 return false; | |
| 15788 } | |
| 15789 List<MethodElement> methods = _enclosingClass.methods; | |
| 15790 List<PropertyAccessorElement> accessors = _enclosingClass.accessors; | |
| 15791 Set<String> methodsInEnclosingClass = new Set<String>(); | |
| 15792 for (MethodElement method in methods) { | |
| 15793 String methodName = method.name; | |
| 15794 if (methodName == ElementResolver.NO_SUCH_METHOD_METHOD_NAME) { | |
| 15795 return false; | |
| 15796 } | |
| 15797 javaSetAdd(methodsInEnclosingClass, methodName); | |
| 15798 } | |
| 15799 Set<String> accessorsInEnclosingClass = new Set<String>(); | |
| 15800 for (PropertyAccessorElement accessor in accessors) { | |
| 15801 javaSetAdd(accessorsInEnclosingClass, accessor.name); | |
| 15802 } | |
| 15803 Set<ExecutableElement> missingOverrides = new Set<ExecutableElement>(); | |
| 15804 MemberMap membersInheritedFromInterfaces = _inheritanceManager.getMapOfMembe
rsInheritedFromInterfaces(_enclosingClass); | |
| 15805 MemberMap membersInheritedFromSuperclasses = _inheritanceManager.getMapOfMem
bersInheritedFromClasses(_enclosingClass); | |
| 15806 for (int i = 0; i < membersInheritedFromInterfaces.size; i++) { | |
| 15807 String memberName = membersInheritedFromInterfaces.getKey(i); | |
| 15808 ExecutableElement executableElt = membersInheritedFromInterfaces.getValue(
i); | |
| 15809 if (memberName == null) { | |
| 15810 break; | |
| 15811 } | |
| 15812 ExecutableElement elt = membersInheritedFromSuperclasses.get(executableElt
.name); | |
| 15813 if (elt != null) { | |
| 15814 if (elt is MethodElement && !((elt as MethodElement)).isAbstract) { | |
| 15815 continue; | |
| 15816 } else if (elt is PropertyAccessorElement && !((elt as PropertyAccessorE
lement)).isAbstract) { | |
| 15817 continue; | |
| 15818 } | |
| 15819 } | |
| 15820 if (executableElt is MethodElement) { | |
| 15821 if (!methodsInEnclosingClass.contains(memberName) && !memberHasConcreteM
ethodImplementationInSuperclassChain(_enclosingClass, memberName, new List<Class
Element>())) { | |
| 15822 javaSetAdd(missingOverrides, executableElt); | |
| 15823 } | |
| 15824 } else if (executableElt is PropertyAccessorElement) { | |
| 15825 if (!accessorsInEnclosingClass.contains(memberName) && !memberHasConcret
eAccessorImplementationInSuperclassChain(_enclosingClass, memberName, new List<C
lassElement>())) { | |
| 15826 javaSetAdd(missingOverrides, executableElt); | |
| 15827 } | |
| 15828 } | |
| 15829 } | |
| 15830 int missingOverridesSize = missingOverrides.length; | |
| 15831 if (missingOverridesSize == 0) { | |
| 15832 return false; | |
| 15833 } | |
| 15834 List<ExecutableElement> missingOverridesArray = new List.from(missingOverrid
es); | |
| 15835 List<String> stringMembersArrayListSet = new List<String>(); | |
| 15836 for (int i = 0; i < missingOverridesArray.length; i++) { | |
| 15837 String newStrMember = "${missingOverridesArray[i].enclosingElement.display
Name}.${missingOverridesArray[i].displayName}"; | |
| 15838 if (!stringMembersArrayListSet.contains(newStrMember)) { | |
| 15839 stringMembersArrayListSet.add(newStrMember); | |
| 15840 } | |
| 15841 } | |
| 15842 List<String> stringMembersArray = new List.from(stringMembersArrayListSet); | |
| 15843 AnalysisErrorWithProperties analysisError; | |
| 15844 if (stringMembersArray.length == 1) { | |
| 15845 analysisError = _errorReporter.newErrorWithProperties(StaticWarningCode.NO
N_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE, node.name, [stringMembersArray[0]
]); | |
| 15846 } else if (stringMembersArray.length == 2) { | |
| 15847 analysisError = _errorReporter.newErrorWithProperties(StaticWarningCode.NO
N_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO, node.name, [stringMembersArray[0]
, stringMembersArray[1]]); | |
| 15848 } else if (stringMembersArray.length == 3) { | |
| 15849 analysisError = _errorReporter.newErrorWithProperties(StaticWarningCode.NO
N_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE, node.name, [ | |
| 15850 stringMembersArray[0], | |
| 15851 stringMembersArray[1], | |
| 15852 stringMembersArray[2]]); | |
| 15853 } else if (stringMembersArray.length == 4) { | |
| 15854 analysisError = _errorReporter.newErrorWithProperties(StaticWarningCode.NO
N_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR, node.name, [ | |
| 15855 stringMembersArray[0], | |
| 15856 stringMembersArray[1], | |
| 15857 stringMembersArray[2], | |
| 15858 stringMembersArray[3]]); | |
| 15859 } else { | |
| 15860 analysisError = _errorReporter.newErrorWithProperties(StaticWarningCode.NO
N_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS, node.name, [ | |
| 15861 stringMembersArray[0], | |
| 15862 stringMembersArray[1], | |
| 15863 stringMembersArray[2], | |
| 15864 stringMembersArray[3], | |
| 15865 stringMembersArray.length - 4]); | |
| 15866 } | |
| 15867 analysisError.setProperty(ErrorProperty.UNIMPLEMENTED_METHODS, missingOverri
desArray); | |
| 15868 _errorReporter.reportError(analysisError); | |
| 15869 return true; | |
| 15870 } | |
| 15871 | |
| 15872 /** | |
| 15873 * Checks to ensure that the expressions that need to be of type bool, are. Ot
herwise an error is | |
| 15874 * reported on the expression. | |
| 15875 * | |
| 15876 * @param condition the conditional expression to test | |
| 15877 * @return `true` if and only if an error code is generated on the passed node | |
| 15878 * @see StaticTypeWarningCode#NON_BOOL_CONDITION | |
| 15879 */ | |
| 15880 bool checkForNonBoolCondition(Expression condition) { | |
| 15881 Type2 conditionType = getStaticType(condition); | |
| 15882 if (conditionType != null && !conditionType.isAssignableTo(_typeProvider.boo
lType)) { | |
| 15883 _errorReporter.reportError2(StaticTypeWarningCode.NON_BOOL_CONDITION, cond
ition, []); | |
| 15884 return true; | |
| 15885 } | |
| 15886 return false; | |
| 15887 } | |
| 15888 | |
| 15889 /** | |
| 15890 * This verifies that the passed assert statement has either a 'bool' or '() -
> bool' input. | |
| 15891 * | |
| 15892 * @param node the assert statement to evaluate | |
| 15893 * @return `true` if and only if an error code is generated on the passed node | |
| 15894 * @see StaticTypeWarningCode#NON_BOOL_EXPRESSION | |
| 15895 */ | |
| 15896 bool checkForNonBoolExpression(AssertStatement node) { | |
| 15897 Expression expression = node.condition; | |
| 15898 Type2 type = getStaticType(expression); | |
| 15899 if (type is InterfaceType) { | |
| 15900 if (!type.isAssignableTo(_typeProvider.boolType)) { | |
| 15901 _errorReporter.reportError2(StaticTypeWarningCode.NON_BOOL_EXPRESSION, e
xpression, []); | |
| 15902 return true; | |
| 15903 } | |
| 15904 } else if (type is FunctionType) { | |
| 15905 FunctionType functionType = type as FunctionType; | |
| 15906 if (functionType.typeArguments.length == 0 && !functionType.returnType.isA
ssignableTo(_typeProvider.boolType)) { | |
| 15907 _errorReporter.reportError2(StaticTypeWarningCode.NON_BOOL_EXPRESSION, e
xpression, []); | |
| 15908 return true; | |
| 15909 } | |
| 15910 } | |
| 15911 return false; | |
| 15912 } | |
| 15913 | |
| 15914 /** | |
| 15915 * This verifies the passed map literal either: | |
| 15916 * | |
| 15917 * * has `const modifier` | |
| 15918 * * has explicit type arguments | |
| 15919 * * is not start of the statement | |
| 15920 * | |
| 15921 * | |
| 15922 * @param node the map literal to evaluate | |
| 15923 * @return `true` if and only if an error code is generated on the passed node | |
| 15924 * @see CompileTimeErrorCode#NON_CONST_MAP_AS_EXPRESSION_STATEMENT | |
| 15925 */ | |
| 15926 bool checkForNonConstMapAsExpressionStatement(MapLiteral node) { | |
| 15927 if (node.constKeyword != null) { | |
| 15928 return false; | |
| 15929 } | |
| 15930 if (node.typeArguments != null) { | |
| 15931 return false; | |
| 15932 } | |
| 15933 Statement statement = node.getAncestor(ExpressionStatement); | |
| 15934 if (statement == null) { | |
| 15935 return false; | |
| 15936 } | |
| 15937 if (statement.beginToken != node.beginToken) { | |
| 15938 return false; | |
| 15939 } | |
| 15940 _errorReporter.reportError2(CompileTimeErrorCode.NON_CONST_MAP_AS_EXPRESSION
_STATEMENT, node, []); | |
| 15941 return true; | |
| 15942 } | |
| 15943 | |
| 15944 /** | |
| 15945 * This verifies the passed method declaration of operator `[]=`, has `void` r
eturn | |
| 15946 * type. | |
| 15947 * | |
| 15948 * @param node the method declaration to evaluate | |
| 15949 * @return `true` if and only if an error code is generated on the passed node | |
| 15950 * @see StaticWarningCode#NON_VOID_RETURN_FOR_OPERATOR | |
| 15951 */ | |
| 15952 bool checkForNonVoidReturnTypeForOperator(MethodDeclaration node) { | |
| 15953 SimpleIdentifier name = node.name; | |
| 15954 if (name.name != "[]=") { | |
| 15955 return false; | |
| 15956 } | |
| 15957 TypeName typeName = node.returnType; | |
| 15958 if (typeName != null) { | |
| 15959 Type2 type = typeName.type; | |
| 15960 if (type != null && !type.isVoid) { | |
| 15961 _errorReporter.reportError2(StaticWarningCode.NON_VOID_RETURN_FOR_OPERAT
OR, typeName, []); | |
| 15962 } | |
| 15963 } | |
| 15964 return false; | |
| 15965 } | |
| 15966 | |
| 15967 /** | |
| 15968 * This verifies the passed setter has no return type or the `void` return typ
e. | |
| 15969 * | |
| 15970 * @param typeName the type name to evaluate | |
| 15971 * @return `true` if and only if an error code is generated on the passed node | |
| 15972 * @see StaticWarningCode#NON_VOID_RETURN_FOR_SETTER | |
| 15973 */ | |
| 15974 bool checkForNonVoidReturnTypeForSetter(TypeName typeName) { | |
| 15975 if (typeName != null) { | |
| 15976 Type2 type = typeName.type; | |
| 15977 if (type != null && !type.isVoid) { | |
| 15978 _errorReporter.reportError2(StaticWarningCode.NON_VOID_RETURN_FOR_SETTER
, typeName, []); | |
| 15979 } | |
| 15980 } | |
| 15981 return false; | |
| 15982 } | |
| 15983 | |
| 15984 /** | |
| 15985 * This verifies the passed operator-method declaration, does not have an opti
onal parameter. | |
| 15986 * | |
| 15987 * This method assumes that the method declaration was tested to be an operato
r declaration before | |
| 15988 * being called. | |
| 15989 * | |
| 15990 * @param node the method declaration to evaluate | |
| 15991 * @return `true` if and only if an error code is generated on the passed node | |
| 15992 * @see CompileTimeErrorCode#OPTIONAL_PARAMETER_IN_OPERATOR | |
| 15993 */ | |
| 15994 bool checkForOptionalParameterInOperator(MethodDeclaration node) { | |
| 15995 FormalParameterList parameterList = node.parameters; | |
| 15996 if (parameterList == null) { | |
| 15997 return false; | |
| 15998 } | |
| 15999 bool foundError = false; | |
| 16000 NodeList<FormalParameter> formalParameters = parameterList.parameters; | |
| 16001 for (FormalParameter formalParameter in formalParameters) { | |
| 16002 if (formalParameter.kind.isOptional) { | |
| 16003 _errorReporter.reportError2(CompileTimeErrorCode.OPTIONAL_PARAMETER_IN_O
PERATOR, formalParameter, []); | |
| 16004 foundError = true; | |
| 16005 } | |
| 16006 } | |
| 16007 return foundError; | |
| 16008 } | |
| 16009 | |
| 16010 /** | |
| 16011 * This checks for named optional parameters that begin with '_'. | |
| 16012 * | |
| 16013 * @param node the default formal parameter to evaluate | |
| 16014 * @return `true` if and only if an error code is generated on the passed node | |
| 16015 * @see CompileTimeErrorCode#PRIVATE_OPTIONAL_PARAMETER | |
| 16016 */ | |
| 16017 bool checkForPrivateOptionalParameter(FormalParameter node) { | |
| 16018 if (node.kind != ParameterKind.NAMED) { | |
| 16019 return false; | |
| 16020 } | |
| 16021 SimpleIdentifier name = node.identifier; | |
| 16022 if (name.isSynthetic || !name.name.startsWith("_")) { | |
| 16023 return false; | |
| 16024 } | |
| 16025 _errorReporter.reportError2(CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER,
node, []); | |
| 16026 return true; | |
| 16027 } | |
| 16028 | |
| 16029 /** | |
| 16030 * This checks if the passed constructor declaration is the redirecting genera
tive constructor and | |
| 16031 * references itself directly or indirectly. | |
| 16032 * | |
| 16033 * @param node the constructor declaration to evaluate | |
| 16034 * @return `true` if and only if an error code is generated on the passed node | |
| 16035 * @see CompileTimeErrorCode#RECURSIVE_CONSTRUCTOR_REDIRECT | |
| 16036 */ | |
| 16037 bool checkForRecursiveConstructorRedirect(ConstructorDeclaration node) { | |
| 16038 if (node.factoryKeyword != null) { | |
| 16039 return false; | |
| 16040 } | |
| 16041 for (ConstructorInitializer initializer in node.initializers) { | |
| 16042 if (initializer is RedirectingConstructorInvocation) { | |
| 16043 ConstructorElement element = node.element; | |
| 16044 if (!hasRedirectingFactoryConstructorCycle(element)) { | |
| 16045 return false; | |
| 16046 } | |
| 16047 _errorReporter.reportError2(CompileTimeErrorCode.RECURSIVE_CONSTRUCTOR_R
EDIRECT, initializer, []); | |
| 16048 return true; | |
| 16049 } | |
| 16050 } | |
| 16051 return false; | |
| 16052 } | |
| 16053 | |
| 16054 /** | |
| 16055 * This checks if the passed constructor declaration has redirected constructo
r and references | |
| 16056 * itself directly or indirectly. | |
| 16057 * | |
| 16058 * @param node the constructor declaration to evaluate | |
| 16059 * @return `true` if and only if an error code is generated on the passed node | |
| 16060 * @see CompileTimeErrorCode#RECURSIVE_FACTORY_REDIRECT | |
| 16061 */ | |
| 16062 bool checkForRecursiveFactoryRedirect(ConstructorDeclaration node) { | |
| 16063 ConstructorName redirectedConstructorNode = node.redirectedConstructor; | |
| 16064 if (redirectedConstructorNode == null) { | |
| 16065 return false; | |
| 16066 } | |
| 16067 ConstructorElement element = node.element; | |
| 16068 if (!hasRedirectingFactoryConstructorCycle(element)) { | |
| 16069 return false; | |
| 16070 } | |
| 16071 _errorReporter.reportError2(CompileTimeErrorCode.RECURSIVE_FACTORY_REDIRECT,
redirectedConstructorNode, []); | |
| 16072 return true; | |
| 16073 } | |
| 16074 | |
| 16075 /** | |
| 16076 * This checks the class declaration is not a superinterface to itself. | |
| 16077 * | |
| 16078 * @param classElt the class element to test | |
| 16079 * @return `true` if and only if an error code is generated on the passed elem
ent | |
| 16080 * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE | |
| 16081 * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS | |
| 16082 * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEME
NTS | |
| 16083 */ | |
| 16084 bool checkForRecursiveInterfaceInheritance(ClassElement classElt) { | |
| 16085 if (classElt == null) { | |
| 16086 return false; | |
| 16087 } | |
| 16088 return checkForRecursiveInterfaceInheritance2(classElt, new List<ClassElemen
t>()); | |
| 16089 } | |
| 16090 | |
| 16091 /** | |
| 16092 * This checks the class declaration is not a superinterface to itself. | |
| 16093 * | |
| 16094 * @param classElt the class element to test | |
| 16095 * @param path a list containing the potentially cyclic implements path | |
| 16096 * @return `true` if and only if an error code is generated on the passed elem
ent | |
| 16097 * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE | |
| 16098 * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS | |
| 16099 * @see CompileTimeErrorCode#RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEME
NTS | |
| 16100 */ | |
| 16101 bool checkForRecursiveInterfaceInheritance2(ClassElement classElt, List<ClassE
lement> path) { | |
| 16102 int size = path.length; | |
| 16103 if (size > 0 && _enclosingClass == classElt) { | |
| 16104 String enclosingClassName = _enclosingClass.displayName; | |
| 16105 if (size > 1) { | |
| 16106 String separator = ", "; | |
| 16107 JavaStringBuilder builder = new JavaStringBuilder(); | |
| 16108 for (int i = 0; i < size; i++) { | |
| 16109 builder.append(path[i].displayName); | |
| 16110 builder.append(separator); | |
| 16111 } | |
| 16112 builder.append(classElt.displayName); | |
| 16113 _errorReporter.reportError3(CompileTimeErrorCode.RECURSIVE_INTERFACE_INH
ERITANCE, _enclosingClass.nameOffset, enclosingClassName.length, [enclosingClass
Name, builder.toString()]); | |
| 16114 return true; | |
| 16115 } else { | |
| 16116 InterfaceType supertype = classElt.supertype; | |
| 16117 ErrorCode errorCode = (supertype != null && _enclosingClass == supertype
.element ? CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTEND
S : CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS) a
s ErrorCode; | |
| 16118 _errorReporter.reportError3(errorCode, _enclosingClass.nameOffset, enclo
singClassName.length, [enclosingClassName]); | |
| 16119 return true; | |
| 16120 } | |
| 16121 } | |
| 16122 if (path.indexOf(classElt) > 0) { | |
| 16123 return false; | |
| 16124 } | |
| 16125 path.add(classElt); | |
| 16126 InterfaceType supertype = classElt.supertype; | |
| 16127 if (supertype != null && checkForRecursiveInterfaceInheritance2(supertype.el
ement, path)) { | |
| 16128 return true; | |
| 16129 } | |
| 16130 List<InterfaceType> interfaceTypes = classElt.interfaces; | |
| 16131 for (InterfaceType interfaceType in interfaceTypes) { | |
| 16132 if (checkForRecursiveInterfaceInheritance2(interfaceType.element, path)) { | |
| 16133 return true; | |
| 16134 } | |
| 16135 } | |
| 16136 path.removeAt(path.length - 1); | |
| 16137 return false; | |
| 16138 } | |
| 16139 | |
| 16140 /** | |
| 16141 * This checks the passed constructor declaration has a valid combination of r
edirected | |
| 16142 * constructor invocation(s), super constructor invocations and field initiali
zers. | |
| 16143 * | |
| 16144 * @param node the constructor declaration to evaluate | |
| 16145 * @return `true` if and only if an error code is generated on the passed node | |
| 16146 * @see CompileTimeErrorCode#DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR | |
| 16147 * @see CompileTimeErrorCode#FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR | |
| 16148 * @see CompileTimeErrorCode#MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS | |
| 16149 * @see CompileTimeErrorCode#SUPER_IN_REDIRECTING_CONSTRUCTOR | |
| 16150 */ | |
| 16151 bool checkForRedirectingConstructorErrorCodes(ConstructorDeclaration node) { | |
| 16152 bool errorReported = false; | |
| 16153 ConstructorName redirectedConstructor = node.redirectedConstructor; | |
| 16154 if (redirectedConstructor != null) { | |
| 16155 for (FormalParameter parameter in node.parameters.parameters) { | |
| 16156 if (parameter is DefaultFormalParameter && ((parameter as DefaultFormalP
arameter)).defaultValue != null) { | |
| 16157 _errorReporter.reportError2(CompileTimeErrorCode.DEFAULT_VALUE_IN_REDI
RECTING_FACTORY_CONSTRUCTOR, parameter.identifier, []); | |
| 16158 errorReported = true; | |
| 16159 } | |
| 16160 } | |
| 16161 } | |
| 16162 int numRedirections = 0; | |
| 16163 for (ConstructorInitializer initializer in node.initializers) { | |
| 16164 if (initializer is RedirectingConstructorInvocation) { | |
| 16165 if (numRedirections > 0) { | |
| 16166 _errorReporter.reportError2(CompileTimeErrorCode.MULTIPLE_REDIRECTING_
CONSTRUCTOR_INVOCATIONS, initializer, []); | |
| 16167 errorReported = true; | |
| 16168 } | |
| 16169 numRedirections++; | |
| 16170 } | |
| 16171 } | |
| 16172 if (numRedirections > 0) { | |
| 16173 for (ConstructorInitializer initializer in node.initializers) { | |
| 16174 if (initializer is SuperConstructorInvocation) { | |
| 16175 _errorReporter.reportError2(CompileTimeErrorCode.SUPER_IN_REDIRECTING_
CONSTRUCTOR, initializer, []); | |
| 16176 errorReported = true; | |
| 16177 } | |
| 16178 if (initializer is ConstructorFieldInitializer) { | |
| 16179 _errorReporter.reportError2(CompileTimeErrorCode.FIELD_INITIALIZER_RED
IRECTING_CONSTRUCTOR, initializer, []); | |
| 16180 errorReported = true; | |
| 16181 } | |
| 16182 } | |
| 16183 } | |
| 16184 return errorReported; | |
| 16185 } | |
| 16186 | |
| 16187 /** | |
| 16188 * This checks if the passed constructor declaration has redirected constructo
r and references | |
| 16189 * itself directly or indirectly. | |
| 16190 * | |
| 16191 * @param node the constructor declaration to evaluate | |
| 16192 * @return `true` if and only if an error code is generated on the passed node | |
| 16193 * @see CompileTimeErrorCode#REDIRECT_TO_NON_CONST_CONSTRUCTOR | |
| 16194 */ | |
| 16195 bool checkForRedirectToNonConstConstructor(ConstructorDeclaration node) { | |
| 16196 ConstructorName redirectedConstructorNode = node.redirectedConstructor; | |
| 16197 if (redirectedConstructorNode == null) { | |
| 16198 return false; | |
| 16199 } | |
| 16200 ConstructorElement element = node.element; | |
| 16201 if (element == null) { | |
| 16202 return false; | |
| 16203 } | |
| 16204 if (!element.isConst) { | |
| 16205 return false; | |
| 16206 } | |
| 16207 ConstructorElement redirectedConstructor = element.redirectedConstructor; | |
| 16208 if (redirectedConstructor == null) { | |
| 16209 return false; | |
| 16210 } | |
| 16211 if (redirectedConstructor.isConst) { | |
| 16212 return false; | |
| 16213 } | |
| 16214 _errorReporter.reportError2(CompileTimeErrorCode.REDIRECT_TO_NON_CONST_CONST
RUCTOR, redirectedConstructorNode, []); | |
| 16215 return true; | |
| 16216 } | |
| 16217 | |
| 16218 /** | |
| 16219 * This checks if the passed identifier is banned because it is part of the va
riable declaration | |
| 16220 * with the same name. | |
| 16221 * | |
| 16222 * @param node the identifier to evaluate | |
| 16223 * @return `true` if and only if an error code is generated on the passed node | |
| 16224 * @see CompileTimeErrorCode#REFERENCE_TO_DECLARED_VARIABLE_IN_INITIALIZER | |
| 16225 */ | |
| 16226 bool checkForReferenceToDeclaredVariableInInitializer(SimpleIdentifier node) { | |
| 16227 ASTNode parent = node.parent; | |
| 16228 if (parent is PrefixedIdentifier) { | |
| 16229 PrefixedIdentifier prefixedIdentifier = parent as PrefixedIdentifier; | |
| 16230 if (identical(prefixedIdentifier.identifier, node)) { | |
| 16231 return false; | |
| 16232 } | |
| 16233 } | |
| 16234 if (parent is PropertyAccess) { | |
| 16235 PropertyAccess propertyAccess = parent as PropertyAccess; | |
| 16236 if (identical(propertyAccess.propertyName, node)) { | |
| 16237 return false; | |
| 16238 } | |
| 16239 } | |
| 16240 if (parent is MethodInvocation) { | |
| 16241 MethodInvocation methodInvocation = parent as MethodInvocation; | |
| 16242 if (methodInvocation.target != null && identical(methodInvocation.methodNa
me, node)) { | |
| 16243 return false; | |
| 16244 } | |
| 16245 } | |
| 16246 if (parent is ConstructorName) { | |
| 16247 ConstructorName constructorName = parent as ConstructorName; | |
| 16248 if (identical(constructorName.name, node)) { | |
| 16249 return false; | |
| 16250 } | |
| 16251 } | |
| 16252 if (parent is Label) { | |
| 16253 Label label = parent as Label; | |
| 16254 if (identical(label.label, node)) { | |
| 16255 return false; | |
| 16256 } | |
| 16257 } | |
| 16258 String name = node.name; | |
| 16259 if (!_namesForReferenceToDeclaredVariableInInitializer.contains(name)) { | |
| 16260 return false; | |
| 16261 } | |
| 16262 _errorReporter.reportError2(CompileTimeErrorCode.REFERENCE_TO_DECLARED_VARIA
BLE_IN_INITIALIZER, node, [name]); | |
| 16263 return true; | |
| 16264 } | |
| 16265 | |
| 16266 /** | |
| 16267 * This checks that the rethrow is inside of a catch clause. | |
| 16268 * | |
| 16269 * @param node the rethrow expression to evaluate | |
| 16270 * @return `true` if and only if an error code is generated on the passed node | |
| 16271 * @see CompileTimeErrorCode#RETHROW_OUTSIDE_CATCH | |
| 16272 */ | |
| 16273 bool checkForRethrowOutsideCatch(RethrowExpression node) { | |
| 16274 if (!_isInCatchClause) { | |
| 16275 _errorReporter.reportError2(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, no
de, []); | |
| 16276 return true; | |
| 16277 } | |
| 16278 return false; | |
| 16279 } | |
| 16280 | |
| 16281 /** | |
| 16282 * This checks that if the the given constructor declaration is generative, th
en it does not have | |
| 16283 * an expression function body. | |
| 16284 * | |
| 16285 * @param node the constructor to evaluate | |
| 16286 * @return `true` if and only if an error code is generated on the passed node | |
| 16287 * @see CompileTimeErrorCode#RETURN_IN_GENERATIVE_CONSTRUCTOR | |
| 16288 */ | |
| 16289 bool checkForReturnInGenerativeConstructor(ConstructorDeclaration node) { | |
| 16290 if (node.factoryKeyword != null) { | |
| 16291 return false; | |
| 16292 } | |
| 16293 FunctionBody body = node.body; | |
| 16294 if (body is! ExpressionFunctionBody) { | |
| 16295 return false; | |
| 16296 } | |
| 16297 _errorReporter.reportError2(CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTR
UCTOR, body, []); | |
| 16298 return true; | |
| 16299 } | |
| 16300 | |
| 16301 /** | |
| 16302 * This checks that a type mis-match between the return type and the expressed
return type by the | |
| 16303 * enclosing method or function. | |
| 16304 * | |
| 16305 * This method is called both by [checkForAllReturnStatementErrorCodes] | |
| 16306 * and [visitExpressionFunctionBody]. | |
| 16307 * | |
| 16308 * @param returnExpression the returned expression to evaluate | |
| 16309 * @param expectedReturnType the expressed return type by the enclosing method
or function | |
| 16310 * @return `true` if and only if an error code is generated on the passed node | |
| 16311 * @see StaticTypeWarningCode#RETURN_OF_INVALID_TYPE | |
| 16312 */ | |
| 16313 bool checkForReturnOfInvalidType(Expression returnExpression, Type2 expectedRe
turnType) { | |
| 16314 Type2 staticReturnType = getStaticType(returnExpression); | |
| 16315 if (expectedReturnType.isVoid) { | |
| 16316 if (staticReturnType.isVoid || staticReturnType.isDynamic || staticReturnT
ype.isBottom) { | |
| 16317 return false; | |
| 16318 } | |
| 16319 _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
returnExpression, [ | |
| 16320 staticReturnType.displayName, | |
| 16321 expectedReturnType.displayName, | |
| 16322 _enclosingFunction.displayName]); | |
| 16323 return true; | |
| 16324 } | |
| 16325 bool isStaticAssignable = staticReturnType.isAssignableTo(expectedReturnType
); | |
| 16326 Type2 propagatedReturnType = returnExpression.propagatedType; | |
| 16327 if (_strictMode || propagatedReturnType == null) { | |
| 16328 if (isStaticAssignable) { | |
| 16329 return false; | |
| 16330 } | |
| 16331 _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
returnExpression, [ | |
| 16332 staticReturnType.displayName, | |
| 16333 expectedReturnType.displayName, | |
| 16334 _enclosingFunction.displayName]); | |
| 16335 return true; | |
| 16336 } else { | |
| 16337 bool isPropagatedAssignable = propagatedReturnType.isAssignableTo(expected
ReturnType); | |
| 16338 if (isStaticAssignable || isPropagatedAssignable) { | |
| 16339 return false; | |
| 16340 } | |
| 16341 _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
returnExpression, [ | |
| 16342 staticReturnType.displayName, | |
| 16343 expectedReturnType.displayName, | |
| 16344 _enclosingFunction.displayName]); | |
| 16345 return true; | |
| 16346 } | |
| 16347 } | |
| 16348 | |
| 16349 /** | |
| 16350 * This checks that if the given "target" is the type reference then the "name
" is not the | |
| 16351 * reference to a instance member. | |
| 16352 * | |
| 16353 * @param target the target of the name access to evaluate | |
| 16354 * @param name the accessed name to evaluate | |
| 16355 * @return `true` if and only if an error code is generated on the passed node | |
| 16356 * @see StaticWarningCode#STATIC_ACCESS_TO_INSTANCE_MEMBER | |
| 16357 */ | |
| 16358 bool checkForStaticAccessToInstanceMember(Expression target, SimpleIdentifier
name) { | |
| 16359 Element element = name.staticElement; | |
| 16360 if (element is! ExecutableElement) { | |
| 16361 return false; | |
| 16362 } | |
| 16363 ExecutableElement memberElement = element as ExecutableElement; | |
| 16364 if (memberElement.isStatic) { | |
| 16365 return false; | |
| 16366 } | |
| 16367 if (!isTypeReference(target)) { | |
| 16368 return false; | |
| 16369 } | |
| 16370 _errorReporter.reportError2(StaticWarningCode.STATIC_ACCESS_TO_INSTANCE_MEMB
ER, name, [name.name]); | |
| 16371 return true; | |
| 16372 } | |
| 16373 | |
| 16374 /** | |
| 16375 * This checks that the type of the passed 'switch' expression is assignable t
o the type of the | |
| 16376 * 'case' members. | |
| 16377 * | |
| 16378 * @param node the 'switch' statement to evaluate | |
| 16379 * @return `true` if and only if an error code is generated on the passed node | |
| 16380 * @see StaticWarningCode#SWITCH_EXPRESSION_NOT_ASSIGNABLE | |
| 16381 */ | |
| 16382 bool checkForSwitchExpressionNotAssignable(SwitchStatement node) { | |
| 16383 Expression expression = node.expression; | |
| 16384 Type2 expressionType = getStaticType(expression); | |
| 16385 if (expressionType == null) { | |
| 16386 return false; | |
| 16387 } | |
| 16388 NodeList<SwitchMember> members = node.members; | |
| 16389 for (SwitchMember switchMember in members) { | |
| 16390 if (switchMember is! SwitchCase) { | |
| 16391 continue; | |
| 16392 } | |
| 16393 SwitchCase switchCase = switchMember as SwitchCase; | |
| 16394 Expression caseExpression = switchCase.expression; | |
| 16395 Type2 caseType = getStaticType(caseExpression); | |
| 16396 if (expressionType.isAssignableTo(caseType)) { | |
| 16397 return false; | |
| 16398 } | |
| 16399 _errorReporter.reportError2(StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGN
ABLE, expression, [expressionType, caseType]); | |
| 16400 return true; | |
| 16401 } | |
| 16402 return false; | |
| 16403 } | |
| 16404 | |
| 16405 /** | |
| 16406 * This verifies that the passed function type alias does not reference itself
directly. | |
| 16407 * | |
| 16408 * @param node the function type alias to evaluate | |
| 16409 * @return `true` if and only if an error code is generated on the passed node | |
| 16410 * @see CompileTimeErrorCode#TYPE_ALIAS_CANNOT_REFERENCE_ITSELF | |
| 16411 */ | |
| 16412 bool checkForTypeAliasCannotReferenceItself_function(FunctionTypeAlias node) { | |
| 16413 FunctionTypeAliasElement element = node.element; | |
| 16414 if (!hasTypedefSelfReference(element)) { | |
| 16415 return false; | |
| 16416 } | |
| 16417 _errorReporter.reportError2(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE
_ITSELF, node, []); | |
| 16418 return true; | |
| 16419 } | |
| 16420 | |
| 16421 /** | |
| 16422 * This verifies that the given class type alias does not reference itself. | |
| 16423 * | |
| 16424 * @return `true` if and only if an error code is generated on the passed node | |
| 16425 * @see CompileTimeErrorCode#TYPE_ALIAS_CANNOT_REFERENCE_ITSELF | |
| 16426 */ | |
| 16427 bool checkForTypeAliasCannotReferenceItself_mixin(ClassTypeAlias node) { | |
| 16428 ClassElement element = node.element; | |
| 16429 if (!hasTypedefSelfReference(element)) { | |
| 16430 return false; | |
| 16431 } | |
| 16432 _errorReporter.reportError2(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE
_ITSELF, node, []); | |
| 16433 return true; | |
| 16434 } | |
| 16435 | |
| 16436 /** | |
| 16437 * This verifies that the type arguments in the passed type name are all withi
n their bounds. | |
| 16438 * | |
| 16439 * @param node the [TypeName] to evaluate | |
| 16440 * @return `true` if and only if an error code is generated on the passed node | |
| 16441 * @see StaticTypeWarningCode#TYPE_ARGUMENT_NOT_MATCHING_BOUNDS | |
| 16442 */ | |
| 16443 bool checkForTypeArgumentNotMatchingBounds(TypeName node) { | |
| 16444 if (node.typeArguments == null) { | |
| 16445 return false; | |
| 16446 } | |
| 16447 Type2 type = node.type; | |
| 16448 if (type == null) { | |
| 16449 return false; | |
| 16450 } | |
| 16451 Element element = type.element; | |
| 16452 if (element is! ClassElement) { | |
| 16453 return false; | |
| 16454 } | |
| 16455 ClassElement classElement = element as ClassElement; | |
| 16456 List<Type2> typeParameters = classElement.type.typeArguments; | |
| 16457 List<TypeParameterElement> boundingElts = classElement.typeParameters; | |
| 16458 NodeList<TypeName> typeNameArgList = node.typeArguments.arguments; | |
| 16459 List<Type2> typeArguments = ((type as InterfaceType)).typeArguments; | |
| 16460 int loopThroughIndex = Math.min(typeNameArgList.length, boundingElts.length)
; | |
| 16461 bool foundError = false; | |
| 16462 for (int i = 0; i < loopThroughIndex; i++) { | |
| 16463 TypeName argTypeName = typeNameArgList[i]; | |
| 16464 Type2 argType = argTypeName.type; | |
| 16465 Type2 boundType = boundingElts[i].bound; | |
| 16466 if (argType != null && boundType != null) { | |
| 16467 boundType = boundType.substitute2(typeArguments, typeParameters); | |
| 16468 if (!argType.isSubtypeOf(boundType)) { | |
| 16469 ErrorCode errorCode; | |
| 16470 if (isInConstConstructorInvocation(node)) { | |
| 16471 errorCode = CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; | |
| 16472 } else { | |
| 16473 errorCode = StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS; | |
| 16474 } | |
| 16475 _errorReporter.reportError2(errorCode, argTypeName, [argType.displayNa
me, boundType.displayName]); | |
| 16476 foundError = true; | |
| 16477 } | |
| 16478 } | |
| 16479 } | |
| 16480 return foundError; | |
| 16481 } | |
| 16482 | |
| 16483 /** | |
| 16484 * This checks that if the passed type name is a type parameter being used to
define a static | |
| 16485 * member. | |
| 16486 * | |
| 16487 * @param node the type name to evaluate | |
| 16488 * @return `true` if and only if an error code is generated on the passed node | |
| 16489 * @see StaticWarningCode#TYPE_PARAMETER_REFERENCED_BY_STATIC | |
| 16490 */ | |
| 16491 bool checkForTypeParameterReferencedByStatic(TypeName node) { | |
| 16492 if (_isInStaticMethod || _isInStaticVariableDeclaration) { | |
| 16493 Type2 type = node.type; | |
| 16494 if (type is TypeParameterType) { | |
| 16495 _errorReporter.reportError2(StaticWarningCode.TYPE_PARAMETER_REFERENCED_
BY_STATIC, node, []); | |
| 16496 return true; | |
| 16497 } | |
| 16498 } | |
| 16499 return false; | |
| 16500 } | |
| 16501 | |
| 16502 /** | |
| 16503 * This checks that if the passed type parameter is a supertype of its bound. | |
| 16504 * | |
| 16505 * @param node the type parameter to evaluate | |
| 16506 * @return `true` if and only if an error code is generated on the passed node | |
| 16507 * @see StaticTypeWarningCode#TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND | |
| 16508 */ | |
| 16509 bool checkForTypeParameterSupertypeOfItsBound(TypeParameter node) { | |
| 16510 TypeParameterElement element = node.element; | |
| 16511 Type2 bound = element.bound; | |
| 16512 if (bound == null) { | |
| 16513 return false; | |
| 16514 } | |
| 16515 if (!bound.isMoreSpecificThan(element.type)) { | |
| 16516 return false; | |
| 16517 } | |
| 16518 _errorReporter.reportError2(StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_O
F_ITS_BOUND, node, [element.displayName]); | |
| 16519 return true; | |
| 16520 } | |
| 16521 | |
| 16522 /** | |
| 16523 * This checks that if the passed generative constructor has neither an explic
it super constructor | |
| 16524 * invocation nor a redirecting constructor invocation, that the superclass ha
s a default | |
| 16525 * generative constructor. | |
| 16526 * | |
| 16527 * @param node the constructor declaration to evaluate | |
| 16528 * @return `true` if and only if an error code is generated on the passed node | |
| 16529 * @see CompileTimeErrorCode#UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT | |
| 16530 * @see CompileTimeErrorCode#NON_GENERATIVE_CONSTRUCTOR | |
| 16531 * @see StaticWarningCode#NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT | |
| 16532 */ | |
| 16533 bool checkForUndefinedConstructorInInitializerImplicit(ConstructorDeclaration
node) { | |
| 16534 if (node.factoryKeyword != null) { | |
| 16535 return false; | |
| 16536 } | |
| 16537 for (ConstructorInitializer constructorInitializer in node.initializers) { | |
| 16538 if (constructorInitializer is SuperConstructorInvocation || constructorIni
tializer is RedirectingConstructorInvocation) { | |
| 16539 return false; | |
| 16540 } | |
| 16541 } | |
| 16542 if (_enclosingClass == null) { | |
| 16543 return false; | |
| 16544 } | |
| 16545 InterfaceType superType = _enclosingClass.supertype; | |
| 16546 if (superType == null) { | |
| 16547 return false; | |
| 16548 } | |
| 16549 ClassElement superElement = superType.element; | |
| 16550 ConstructorElement superUnnamedConstructor = superElement.unnamedConstructor
; | |
| 16551 if (superUnnamedConstructor != null) { | |
| 16552 if (superUnnamedConstructor.isFactory) { | |
| 16553 _errorReporter.reportError2(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUC
TOR, node.returnType, [superUnnamedConstructor]); | |
| 16554 return true; | |
| 16555 } | |
| 16556 if (!superUnnamedConstructor.isDefaultConstructor) { | |
| 16557 int offset; | |
| 16558 int length; | |
| 16559 { | |
| 16560 Identifier returnType = node.returnType; | |
| 16561 SimpleIdentifier name = node.name; | |
| 16562 offset = returnType.offset; | |
| 16563 length = (name != null ? name.end : returnType.end) - offset; | |
| 16564 } | |
| 16565 _errorReporter.reportError3(CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTR
UCTOR_EXPLICIT, offset, length, [superType.displayName]); | |
| 16566 } | |
| 16567 return false; | |
| 16568 } | |
| 16569 _errorReporter.reportError2(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_IN
ITIALIZER_DEFAULT, node.returnType, [superElement.name]); | |
| 16570 return true; | |
| 16571 } | |
| 16572 | |
| 16573 /** | |
| 16574 * This checks that if the given name is a reference to a static member it is
defined in the | |
| 16575 * enclosing class rather than in a superclass. | |
| 16576 * | |
| 16577 * @param name the name to be evaluated | |
| 16578 * @return `true` if and only if an error code is generated on the passed node | |
| 16579 * @see StaticTypeWarningCode#UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER | |
| 16580 */ | |
| 16581 bool checkForUnqualifiedReferenceToNonLocalStaticMember(SimpleIdentifier name)
{ | |
| 16582 Element element = name.staticElement; | |
| 16583 if (element == null || element is TypeParameterElement) { | |
| 16584 return false; | |
| 16585 } | |
| 16586 Element enclosingElement = element.enclosingElement; | |
| 16587 if (enclosingElement is! ClassElement) { | |
| 16588 return false; | |
| 16589 } | |
| 16590 if ((element is MethodElement && !((element as MethodElement)).isStatic) ||
(element is PropertyAccessorElement && !((element as PropertyAccessorElement)).i
sStatic)) { | |
| 16591 return false; | |
| 16592 } | |
| 16593 if (identical(enclosingElement, _enclosingClass)) { | |
| 16594 return false; | |
| 16595 } | |
| 16596 _errorReporter.reportError2(StaticTypeWarningCode.UNQUALIFIED_REFERENCE_TO_N
ON_LOCAL_STATIC_MEMBER, name, [name.name]); | |
| 16597 return true; | |
| 16598 } | |
| 16599 | |
| 16600 /** | |
| 16601 * This verifies the passed operator-method declaration, has correct number of
parameters. | |
| 16602 * | |
| 16603 * This method assumes that the method declaration was tested to be an operato
r declaration before | |
| 16604 * being called. | |
| 16605 * | |
| 16606 * @param node the method declaration to evaluate | |
| 16607 * @return `true` if and only if an error code is generated on the passed node | |
| 16608 * @see CompileTimeErrorCode#WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR | |
| 16609 */ | |
| 16610 bool checkForWrongNumberOfParametersForOperator(MethodDeclaration node) { | |
| 16611 FormalParameterList parameterList = node.parameters; | |
| 16612 if (parameterList == null) { | |
| 16613 return false; | |
| 16614 } | |
| 16615 int numParameters = parameterList.parameters.length; | |
| 16616 SimpleIdentifier nameNode = node.name; | |
| 16617 if (nameNode == null) { | |
| 16618 return false; | |
| 16619 } | |
| 16620 String name = nameNode.name; | |
| 16621 int expected = -1; | |
| 16622 if ("[]=" == name) { | |
| 16623 expected = 2; | |
| 16624 } else if ("<" == name || ">" == name || "<=" == name || ">=" == name || "==
" == name || "+" == name || "/" == name || "~/" == name || "*" == name || "%" ==
name || "|" == name || "^" == name || "&" == name || "<<" == name || ">>" == na
me || "[]" == name) { | |
| 16625 expected = 1; | |
| 16626 } else if ("~" == name) { | |
| 16627 expected = 0; | |
| 16628 } | |
| 16629 if (expected != -1 && numParameters != expected) { | |
| 16630 _errorReporter.reportError2(CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETER
S_FOR_OPERATOR, nameNode, [name, expected, numParameters]); | |
| 16631 return true; | |
| 16632 } | |
| 16633 if ("-" == name && numParameters > 1) { | |
| 16634 _errorReporter.reportError2(CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETER
S_FOR_OPERATOR_MINUS, nameNode, [numParameters]); | |
| 16635 return true; | |
| 16636 } | |
| 16637 return false; | |
| 16638 } | |
| 16639 | |
| 16640 /** | |
| 16641 * This verifies if the passed setter parameter list have only one required pa
rameter. | |
| 16642 * | |
| 16643 * This method assumes that the method declaration was tested to be a setter b
efore being called. | |
| 16644 * | |
| 16645 * @param setterName the name of the setter to report problems on | |
| 16646 * @param parameterList the parameter list to evaluate | |
| 16647 * @return `true` if and only if an error code is generated on the passed node | |
| 16648 * @see CompileTimeErrorCode#WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER | |
| 16649 */ | |
| 16650 bool checkForWrongNumberOfParametersForSetter(SimpleIdentifier setterName, For
malParameterList parameterList) { | |
| 16651 if (setterName == null) { | |
| 16652 return false; | |
| 16653 } | |
| 16654 if (parameterList == null) { | |
| 16655 return false; | |
| 16656 } | |
| 16657 NodeList<FormalParameter> parameters = parameterList.parameters; | |
| 16658 if (parameters.length != 1 || parameters[0].kind != ParameterKind.REQUIRED)
{ | |
| 16659 _errorReporter.reportError2(CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETER
S_FOR_SETTER, setterName, []); | |
| 16660 return true; | |
| 16661 } | |
| 16662 return false; | |
| 16663 } | |
| 16664 | |
| 16665 /** | |
| 16666 * This verifies that if the given class declaration implements the class Func
tion that it has a | |
| 16667 * concrete implementation of the call method. | |
| 16668 * | |
| 16669 * @return `true` if and only if an error code is generated on the passed node | |
| 16670 * @see StaticWarningCode#FUNCTION_WITHOUT_CALL | |
| 16671 */ | |
| 16672 bool checkImplementsFunctionWithoutCall(ClassDeclaration node) { | |
| 16673 if (node.abstractKeyword != null) { | |
| 16674 return false; | |
| 16675 } | |
| 16676 ClassElement classElement = node.element; | |
| 16677 if (classElement == null) { | |
| 16678 return false; | |
| 16679 } | |
| 16680 if (!classElement.type.isSubtypeOf(_typeProvider.functionType)) { | |
| 16681 return false; | |
| 16682 } | |
| 16683 ExecutableElement callMethod = _inheritanceManager.lookupMember(classElement
, "call"); | |
| 16684 if (callMethod == null || callMethod is! MethodElement || ((callMethod as Me
thodElement)).isAbstract) { | |
| 16685 _errorReporter.reportError2(StaticWarningCode.FUNCTION_WITHOUT_CALL, node.
name, []); | |
| 16686 return true; | |
| 16687 } | |
| 16688 return false; | |
| 16689 } | |
| 16690 | |
| 16691 /** | |
| 16692 * This verifies that the given class declaration does not have the same class
in the 'extends' | |
| 16693 * and 'implements' clauses. | |
| 16694 * | |
| 16695 * @return `true` if and only if an error code is generated on the passed node | |
| 16696 * @see CompileTimeErrorCode#IMPLEMENTS_SUPER_CLASS | |
| 16697 */ | |
| 16698 bool checkImplementsSuperClass(ClassDeclaration node) { | |
| 16699 InterfaceType superType = _enclosingClass.supertype; | |
| 16700 if (superType == null) { | |
| 16701 return false; | |
| 16702 } | |
| 16703 ImplementsClause implementsClause = node.implementsClause; | |
| 16704 if (implementsClause == null) { | |
| 16705 return false; | |
| 16706 } | |
| 16707 bool hasProblem = false; | |
| 16708 for (TypeName interfaceNode in implementsClause.interfaces) { | |
| 16709 if (interfaceNode.type == superType) { | |
| 16710 hasProblem = true; | |
| 16711 _errorReporter.reportError2(CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS,
interfaceNode, [superType.displayName]); | |
| 16712 } | |
| 16713 } | |
| 16714 return hasProblem; | |
| 16715 } | |
| 16716 | |
| 16717 /** | |
| 16718 * Returns the Type (return type) for a given getter. | |
| 16719 * | |
| 16720 * @param propertyAccessorElement | |
| 16721 * @return The type of the given getter. | |
| 16722 */ | |
| 16723 Type2 getGetterType(PropertyAccessorElement propertyAccessorElement) { | |
| 16724 FunctionType functionType = propertyAccessorElement.type; | |
| 16725 if (functionType != null) { | |
| 16726 return functionType.returnType; | |
| 16727 } else { | |
| 16728 return null; | |
| 16729 } | |
| 16730 } | |
| 16731 | |
| 16732 /** | |
| 16733 * Returns the Type (first and only parameter) for a given setter. | |
| 16734 * | |
| 16735 * @param propertyAccessorElement | |
| 16736 * @return The type of the given setter. | |
| 16737 */ | |
| 16738 Type2 getSetterType(PropertyAccessorElement propertyAccessorElement) { | |
| 16739 List<ParameterElement> setterParameters = propertyAccessorElement.parameters
; | |
| 16740 if (setterParameters.length == 0) { | |
| 16741 return null; | |
| 16742 } | |
| 16743 return setterParameters[0].type; | |
| 16744 } | |
| 16745 | |
| 16746 /** | |
| 16747 * Return the static type of the given expression that is to be used for type
analysis. | |
| 16748 * | |
| 16749 * @param expression the expression whose type is to be returned | |
| 16750 * @return the static type of the given expression | |
| 16751 */ | |
| 16752 Type2 getStaticType(Expression expression) { | |
| 16753 Type2 type = expression.staticType; | |
| 16754 if (type == null) { | |
| 16755 return _dynamicType; | |
| 16756 } | |
| 16757 return type; | |
| 16758 } | |
| 16759 | |
| 16760 /** | |
| 16761 * Return the variable element represented by the given expression, or `null`
if there is no | |
| 16762 * such element. | |
| 16763 * | |
| 16764 * @param expression the expression whose element is to be returned | |
| 16765 * @return the variable element represented by the expression | |
| 16766 */ | |
| 16767 VariableElement getVariableElement(Expression expression) { | |
| 16768 if (expression is Identifier) { | |
| 16769 Element element = ((expression as Identifier)).staticElement; | |
| 16770 if (element is VariableElement) { | |
| 16771 return element as VariableElement; | |
| 16772 } | |
| 16773 } | |
| 16774 return null; | |
| 16775 } | |
| 16776 | |
| 16777 /** | |
| 16778 * @return `true` if the given constructor redirects to itself, directly or in
directly | |
| 16779 */ | |
| 16780 bool hasRedirectingFactoryConstructorCycle(ConstructorElement element) { | |
| 16781 Set<ConstructorElement> constructors = new Set<ConstructorElement>(); | |
| 16782 ConstructorElement current = element; | |
| 16783 while (current != null) { | |
| 16784 if (constructors.contains(current)) { | |
| 16785 return identical(current, element); | |
| 16786 } | |
| 16787 javaSetAdd(constructors, current); | |
| 16788 current = current.redirectedConstructor; | |
| 16789 if (current is ConstructorMember) { | |
| 16790 current = ((current as ConstructorMember)).baseElement; | |
| 16791 } | |
| 16792 } | |
| 16793 return false; | |
| 16794 } | |
| 16795 | |
| 16796 /** | |
| 16797 * @return <code>true</code> if given [Element] has direct or indirect referen
ce to itself | |
| 16798 * from anywhere except [ClassElement] or type parameter bounds. | |
| 16799 */ | |
| 16800 bool hasTypedefSelfReference(Element target) { | |
| 16801 Set<Element> checked = new Set<Element>(); | |
| 16802 List<Element> toCheck = new List<Element>(); | |
| 16803 toCheck.add(target); | |
| 16804 bool firstIteration = true; | |
| 16805 while (true) { | |
| 16806 Element current; | |
| 16807 while (true) { | |
| 16808 if (toCheck.isEmpty) { | |
| 16809 return false; | |
| 16810 } | |
| 16811 current = toCheck.removeAt(toCheck.length - 1); | |
| 16812 if (target == current) { | |
| 16813 if (firstIteration) { | |
| 16814 firstIteration = false; | |
| 16815 break; | |
| 16816 } else { | |
| 16817 return true; | |
| 16818 } | |
| 16819 } | |
| 16820 if (current != null && !checked.contains(current)) { | |
| 16821 break; | |
| 16822 } | |
| 16823 } | |
| 16824 current.accept(new GeneralizingElementVisitor_14(target, toCheck)); | |
| 16825 javaSetAdd(checked, current); | |
| 16826 } | |
| 16827 } | |
| 16828 | |
| 16829 /** | |
| 16830 * @return `true` if given [Type] implements operator <i>==</i>, and it is not | |
| 16831 * <i>int</i> or <i>String</i>. | |
| 16832 */ | |
| 16833 bool implementsEqualsWhenNotAllowed(Type2 type) { | |
| 16834 if (type == null || type == _typeProvider.intType || type == _typeProvider.s
tringType) { | |
| 16835 return false; | |
| 16836 } | |
| 16837 Element element = type.element; | |
| 16838 if (element is! ClassElement) { | |
| 16839 return false; | |
| 16840 } | |
| 16841 ClassElement classElement = element as ClassElement; | |
| 16842 MethodElement method = classElement.lookUpMethod("==", _currentLibrary); | |
| 16843 if (method == null || method.enclosingElement.type.isObject) { | |
| 16844 return false; | |
| 16845 } | |
| 16846 return true; | |
| 16847 } | |
| 16848 bool isFunctionType(Type2 type) { | |
| 16849 if (type.isDynamic || type.isBottom) { | |
| 16850 return true; | |
| 16851 } else if (type is FunctionType || type.isDartCoreFunction) { | |
| 16852 return true; | |
| 16853 } else if (type is InterfaceType) { | |
| 16854 MethodElement callMethod = ((type as InterfaceType)).lookUpMethod(ElementR
esolver.CALL_METHOD_NAME, _currentLibrary); | |
| 16855 return callMethod != null; | |
| 16856 } | |
| 16857 return false; | |
| 16858 } | |
| 16859 | |
| 16860 /** | |
| 16861 * @return `true` if the given [ASTNode] is the part of constant constructor | |
| 16862 * invocation. | |
| 16863 */ | |
| 16864 bool isInConstConstructorInvocation(ASTNode node) { | |
| 16865 InstanceCreationExpression creation = node.getAncestor(InstanceCreationExpre
ssion); | |
| 16866 if (creation == null) { | |
| 16867 return false; | |
| 16868 } | |
| 16869 return creation.isConst; | |
| 16870 } | |
| 16871 | |
| 16872 /** | |
| 16873 * @param node the 'this' expression to analyze | |
| 16874 * @return `true` if the given 'this' expression is in the valid context | |
| 16875 */ | |
| 16876 bool isThisInValidContext(ThisExpression node) { | |
| 16877 for (ASTNode n = node; n != null; n = n.parent) { | |
| 16878 if (n is CompilationUnit) { | |
| 16879 return false; | |
| 16880 } | |
| 16881 if (n is ConstructorDeclaration) { | |
| 16882 ConstructorDeclaration constructor = n as ConstructorDeclaration; | |
| 16883 return constructor.factoryKeyword == null; | |
| 16884 } | |
| 16885 if (n is ConstructorInitializer) { | |
| 16886 return false; | |
| 16887 } | |
| 16888 if (n is MethodDeclaration) { | |
| 16889 MethodDeclaration method = n as MethodDeclaration; | |
| 16890 return !method.isStatic; | |
| 16891 } | |
| 16892 } | |
| 16893 return false; | |
| 16894 } | |
| 16895 | |
| 16896 /** | |
| 16897 * Return `true` if the given identifier is in a location where it is allowed
to resolve to | |
| 16898 * a static member of a supertype. | |
| 16899 * | |
| 16900 * @param node the node being tested | |
| 16901 * @return `true` if the given identifier is in a location where it is allowed
to resolve to | |
| 16902 * a static member of a supertype | |
| 16903 */ | |
| 16904 bool isUnqualifiedReferenceToNonLocalStaticMemberAllowed(SimpleIdentifier node
) { | |
| 16905 if (node.inDeclarationContext()) { | |
| 16906 return true; | |
| 16907 } | |
| 16908 ASTNode parent = node.parent; | |
| 16909 if (parent is ConstructorName || parent is MethodInvocation || parent is Pro
pertyAccess || parent is SuperConstructorInvocation) { | |
| 16910 return true; | |
| 16911 } | |
| 16912 if (parent is PrefixedIdentifier && identical(((parent as PrefixedIdentifier
)).identifier, node)) { | |
| 16913 return true; | |
| 16914 } | |
| 16915 if (parent is Annotation && identical(((parent as Annotation)).constructorNa
me, node)) { | |
| 16916 return true; | |
| 16917 } | |
| 16918 return false; | |
| 16919 } | |
| 16920 | |
| 16921 /** | |
| 16922 * Return `true` iff the passed [ClassElement] has a concrete implementation o
f the | |
| 16923 * passed accessor name in the superclass chain. | |
| 16924 */ | |
| 16925 bool memberHasConcreteAccessorImplementationInSuperclassChain(ClassElement cla
ssElement, String accessorName, List<ClassElement> superclassChain) { | |
| 16926 if (superclassChain.contains(classElement)) { | |
| 16927 return false; | |
| 16928 } else { | |
| 16929 superclassChain.add(classElement); | |
| 16930 } | |
| 16931 for (PropertyAccessorElement accessor in classElement.accessors) { | |
| 16932 if (accessor.name == accessorName) { | |
| 16933 if (!accessor.isAbstract) { | |
| 16934 return true; | |
| 16935 } | |
| 16936 } | |
| 16937 } | |
| 16938 for (InterfaceType mixinType in classElement.mixins) { | |
| 16939 if (mixinType != null) { | |
| 16940 ClassElement mixinElement = mixinType.element; | |
| 16941 if (mixinElement != null) { | |
| 16942 for (PropertyAccessorElement accessor in mixinElement.accessors) { | |
| 16943 if (accessor.name == accessorName) { | |
| 16944 if (!accessor.isAbstract) { | |
| 16945 return true; | |
| 16946 } | |
| 16947 } | |
| 16948 } | |
| 16949 } | |
| 16950 } | |
| 16951 } | |
| 16952 InterfaceType superType = classElement.supertype; | |
| 16953 if (superType != null) { | |
| 16954 ClassElement superClassElt = superType.element; | |
| 16955 if (superClassElt != null) { | |
| 16956 return memberHasConcreteAccessorImplementationInSuperclassChain(superCla
ssElt, accessorName, superclassChain); | |
| 16957 } | |
| 16958 } | |
| 16959 return false; | |
| 16960 } | |
| 16961 | |
| 16962 /** | |
| 16963 * Return `true` iff the passed [ClassElement] has a concrete implementation o
f the | |
| 16964 * passed method name in the superclass chain. | |
| 16965 */ | |
| 16966 bool memberHasConcreteMethodImplementationInSuperclassChain(ClassElement class
Element, String methodName, List<ClassElement> superclassChain) { | |
| 16967 if (superclassChain.contains(classElement)) { | |
| 16968 return false; | |
| 16969 } else { | |
| 16970 superclassChain.add(classElement); | |
| 16971 } | |
| 16972 for (MethodElement method in classElement.methods) { | |
| 16973 if (method.name == methodName) { | |
| 16974 if (!method.isAbstract) { | |
| 16975 return true; | |
| 16976 } | |
| 16977 } | |
| 16978 } | |
| 16979 for (InterfaceType mixinType in classElement.mixins) { | |
| 16980 if (mixinType != null) { | |
| 16981 ClassElement mixinElement = mixinType.element; | |
| 16982 if (mixinElement != null) { | |
| 16983 for (MethodElement method in mixinElement.methods) { | |
| 16984 if (method.name == methodName) { | |
| 16985 if (!method.isAbstract) { | |
| 16986 return true; | |
| 16987 } | |
| 16988 } | |
| 16989 } | |
| 16990 } | |
| 16991 } | |
| 16992 } | |
| 16993 InterfaceType superType = classElement.supertype; | |
| 16994 if (superType != null) { | |
| 16995 ClassElement superClassElt = superType.element; | |
| 16996 if (superClassElt != null) { | |
| 16997 return memberHasConcreteMethodImplementationInSuperclassChain(superClass
Elt, methodName, superclassChain); | |
| 16998 } | |
| 16999 } | |
| 17000 return false; | |
| 17001 } | |
| 17002 } | |
| 17003 /** | |
| 17004 * This enum holds one of four states of a field initialization state through a
constructor | |
| 17005 * signature, not initialized, initialized in the field declaration, initialized
in the field | |
| 17006 * formal, and finally, initialized in the initializers list. | |
| 17007 */ | |
| 17008 class INIT_STATE extends Enum<INIT_STATE> { | |
| 17009 static final INIT_STATE NOT_INIT = new INIT_STATE('NOT_INIT', 0); | |
| 17010 static final INIT_STATE INIT_IN_DECLARATION = new INIT_STATE('INIT_IN_DECLARAT
ION', 1); | |
| 17011 static final INIT_STATE INIT_IN_FIELD_FORMAL = new INIT_STATE('INIT_IN_FIELD_F
ORMAL', 2); | |
| 17012 static final INIT_STATE INIT_IN_INITIALIZERS = new INIT_STATE('INIT_IN_INITIAL
IZERS', 3); | |
| 17013 static final List<INIT_STATE> values = [ | |
| 17014 NOT_INIT, | |
| 17015 INIT_IN_DECLARATION, | |
| 17016 INIT_IN_FIELD_FORMAL, | |
| 17017 INIT_IN_INITIALIZERS]; | |
| 17018 INIT_STATE(String name, int ordinal) : super(name, ordinal); | |
| 17019 } | |
| 17020 class GeneralizingElementVisitor_14 extends GeneralizingElementVisitor<Object> { | |
| 17021 Element target; | |
| 17022 List<Element> toCheck; | |
| 17023 GeneralizingElementVisitor_14(this.target, this.toCheck) : super(); | |
| 17024 bool _inClass = false; | |
| 17025 Object visitClassElement(ClassElement element) { | |
| 17026 addTypeToCheck(element.supertype); | |
| 17027 for (InterfaceType mixin in element.mixins) { | |
| 17028 addTypeToCheck(mixin); | |
| 17029 } | |
| 17030 _inClass = !element.isTypedef; | |
| 17031 try { | |
| 17032 return super.visitClassElement(element); | |
| 17033 } finally { | |
| 17034 _inClass = false; | |
| 17035 } | |
| 17036 } | |
| 17037 Object visitExecutableElement(ExecutableElement element) { | |
| 17038 if (element.isSynthetic) { | |
| 17039 return null; | |
| 17040 } | |
| 17041 addTypeToCheck(element.returnType); | |
| 17042 return super.visitExecutableElement(element); | |
| 17043 } | |
| 17044 Object visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { | |
| 17045 addTypeToCheck(element.returnType); | |
| 17046 return super.visitFunctionTypeAliasElement(element); | |
| 17047 } | |
| 17048 Object visitParameterElement(ParameterElement element) { | |
| 17049 addTypeToCheck(element.type); | |
| 17050 return super.visitParameterElement(element); | |
| 17051 } | |
| 17052 Object visitTypeParameterElement(TypeParameterElement element) { | |
| 17053 addTypeToCheck(element.bound); | |
| 17054 return super.visitTypeParameterElement(element); | |
| 17055 } | |
| 17056 Object visitVariableElement(VariableElement element) { | |
| 17057 addTypeToCheck(element.type); | |
| 17058 return super.visitVariableElement(element); | |
| 17059 } | |
| 17060 void addTypeToCheck(Type2 type) { | |
| 17061 if (type == null) { | |
| 17062 return; | |
| 17063 } | |
| 17064 Element element = type.element; | |
| 17065 if (_inClass && target == element) { | |
| 17066 return; | |
| 17067 } | |
| 17068 toCheck.add(element); | |
| 17069 if (type is InterfaceType) { | |
| 17070 InterfaceType interfaceType = type as InterfaceType; | |
| 17071 for (Type2 typeArgument in interfaceType.typeArguments) { | |
| 17072 addTypeToCheck(typeArgument); | |
| 17073 } | |
| 17074 } | |
| 17075 } | |
| 17076 } | |
| 17077 /** | |
| 17078 * The enumeration `ResolverErrorCode` defines the error codes used for errors d
etected by the | |
| 17079 * resolver. The convention for this class is for the name of the error code to
indicate the problem | |
| 17080 * that caused the error to be generated and for the error message to explain wh
at is wrong and, | |
| 17081 * when appropriate, how the problem can be corrected. | |
| 17082 * | |
| 17083 * @coverage dart.engine.resolver | |
| 17084 */ | |
| 17085 class ResolverErrorCode extends Enum<ResolverErrorCode> implements ErrorCode { | |
| 17086 static final ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER = new ResolverErro
rCode.con1('BREAK_LABEL_ON_SWITCH_MEMBER', 0, ErrorType.COMPILE_TIME_ERROR, "Bre
ak label resolves to case or default statement"); | |
| 17087 static final ResolverErrorCode CONTINUE_LABEL_ON_SWITCH = new ResolverErrorCod
e.con1('CONTINUE_LABEL_ON_SWITCH', 1, ErrorType.COMPILE_TIME_ERROR, "A continue
label resolves to switch, must be loop or switch member"); | |
| 17088 static final ResolverErrorCode MISSING_LIBRARY_DIRECTIVE_WITH_PART = new Resol
verErrorCode.con1('MISSING_LIBRARY_DIRECTIVE_WITH_PART', 2, ErrorType.COMPILE_TI
ME_ERROR, "Libraries that have parts must have a library directive"); | |
| 17089 static final List<ResolverErrorCode> values = [ | |
| 17090 BREAK_LABEL_ON_SWITCH_MEMBER, | |
| 17091 CONTINUE_LABEL_ON_SWITCH, | |
| 17092 MISSING_LIBRARY_DIRECTIVE_WITH_PART]; | |
| 17093 | |
| 17094 /** | |
| 17095 * The type of this error. | |
| 17096 */ | |
| 17097 ErrorType _type; | |
| 17098 | |
| 17099 /** | |
| 17100 * The template used to create the message to be displayed for this error. | |
| 17101 */ | |
| 17102 String _message; | |
| 17103 | |
| 17104 /** | |
| 17105 * The template used to create the correction to be displayed for this error,
or `null` if | |
| 17106 * there is no correction information for this error. | |
| 17107 */ | |
| 17108 String correction9; | |
| 17109 | |
| 17110 /** | |
| 17111 * Initialize a newly created error code to have the given type and message. | |
| 17112 * | |
| 17113 * @param type the type of this error | |
| 17114 * @param message the message template used to create the message to be displa
yed for the error | |
| 17115 */ | |
| 17116 ResolverErrorCode.con1(String name, int ordinal, ErrorType type, String messag
e) : super(name, ordinal) { | |
| 17117 this._type = type; | |
| 17118 this._message = message; | |
| 17119 } | |
| 17120 | |
| 17121 /** | |
| 17122 * Initialize a newly created error code to have the given type, message and c
orrection. | |
| 17123 * | |
| 17124 * @param type the type of this error | |
| 17125 * @param message the template used to create the message to be displayed for
the error | |
| 17126 * @param correction the template used to create the correction to be displaye
d for the error | |
| 17127 */ | |
| 17128 ResolverErrorCode.con2(String name, int ordinal, ErrorType type, String messag
e, String correction) : super(name, ordinal) { | |
| 17129 this._type = type; | |
| 17130 this._message = message; | |
| 17131 this.correction9 = correction; | |
| 17132 } | |
| 17133 String get correction => correction9; | |
| 17134 ErrorSeverity get errorSeverity => _type.severity; | |
| 17135 String get message => _message; | |
| 17136 ErrorType get type => _type; | |
| 17137 } | |
| OLD | NEW |