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 |
| 4 library engine.resolver; |
| 5 |
| 6 import 'dart:collection'; |
| 7 import 'java_core.dart'; |
| 8 import 'java_engine.dart'; |
| 9 import 'source.dart'; |
| 10 import 'error.dart'; |
| 11 import 'scanner.dart' show Keyword, TokenType, Token, KeywordToken, StringToken; |
| 12 import 'utilities_dart.dart'; |
| 13 import 'ast.dart'; |
| 14 import 'element.dart' hide HideCombinator, ShowCombinator; |
| 15 import 'engine.dart'; |
| 16 import 'element.dart' as __imp_combi show HideCombinator, ShowCombinator; |
| 17 |
| 18 /** |
| 19 * Instances of the class {@code CompilationUnitBuilder} build an element model
for a single |
| 20 * compilation unit. |
| 21 */ |
| 22 class CompilationUnitBuilder { |
| 23 /** |
| 24 * The analysis context in which the element model will be built. |
| 25 */ |
| 26 AnalysisContextImpl _analysisContext; |
| 27 /** |
| 28 * The listener to which errors will be reported. |
| 29 */ |
| 30 AnalysisErrorListener _errorListener; |
| 31 /** |
| 32 * Initialize a newly created compilation unit element builder. |
| 33 * @param analysisContext the analysis context in which the element model will
be built |
| 34 * @param errorListener the listener to which errors will be reported |
| 35 */ |
| 36 CompilationUnitBuilder(AnalysisContextImpl analysisContext, AnalysisErrorListe
ner errorListener) { |
| 37 this._analysisContext = analysisContext; |
| 38 this._errorListener = errorListener; |
| 39 } |
| 40 /** |
| 41 * Build the compilation unit element for the given source. |
| 42 * @param source the source describing the compilation unit |
| 43 * @return the compilation unit element that was built |
| 44 * @throws AnalysisException if the analysis could not be performed |
| 45 */ |
| 46 CompilationUnitElementImpl buildCompilationUnit(Source source) => buildCompila
tionUnit2(source, _analysisContext.parse2(source, _errorListener)); |
| 47 /** |
| 48 * Build the compilation unit element for the given source. |
| 49 * @param source the source describing the compilation unit |
| 50 * @param unit the AST structure representing the compilation unit |
| 51 * @return the compilation unit element that was built |
| 52 * @throws AnalysisException if the analysis could not be performed |
| 53 */ |
| 54 CompilationUnitElementImpl buildCompilationUnit2(Source source11, CompilationU
nit unit) { |
| 55 ElementHolder holder = new ElementHolder(); |
| 56 ElementBuilder builder = new ElementBuilder(holder); |
| 57 unit.accept(builder); |
| 58 CompilationUnitElementImpl element = new CompilationUnitElementImpl(source11
.shortName); |
| 59 element.accessors = holder.accessors; |
| 60 element.functions = holder.functions; |
| 61 element.source = source11; |
| 62 element.typeAliases = holder.typeAliases; |
| 63 element.types = holder.types; |
| 64 element.variables = holder.variables; |
| 65 unit.element = element; |
| 66 return element; |
| 67 } |
| 68 } |
| 69 /** |
| 70 * Instances of the class {@code ElementBuilder} traverse an AST structure and b
uild the element |
| 71 * model representing the AST structure. |
| 72 */ |
| 73 class ElementBuilder extends RecursiveASTVisitor<Object> { |
| 74 /** |
| 75 * The element holder associated with the element that is currently being buil
t. |
| 76 */ |
| 77 ElementHolder _currentHolder; |
| 78 /** |
| 79 * A flag indicating whether a variable declaration is in the context of a fie
ld declaration. |
| 80 */ |
| 81 bool _inFieldContext = false; |
| 82 /** |
| 83 * Initialize a newly created element builder to build the elements for a comp
ilation unit. |
| 84 * @param initialHolder the element holder associated with the compilation uni
t being built |
| 85 */ |
| 86 ElementBuilder(ElementHolder initialHolder) { |
| 87 _currentHolder = initialHolder; |
| 88 } |
| 89 Object visitCatchClause(CatchClause node) { |
| 90 SimpleIdentifier exceptionParameter2 = node.exceptionParameter; |
| 91 if (exceptionParameter2 != null) { |
| 92 VariableElementImpl exception = new VariableElementImpl.con1(exceptionPara
meter2); |
| 93 _currentHolder.addVariable(exception); |
| 94 exceptionParameter2.element = exception; |
| 95 SimpleIdentifier stackTraceParameter2 = node.stackTraceParameter; |
| 96 if (stackTraceParameter2 != null) { |
| 97 VariableElementImpl stackTrace = new VariableElementImpl.con1(stackTrace
Parameter2); |
| 98 _currentHolder.addVariable(stackTrace); |
| 99 stackTraceParameter2.element = stackTrace; |
| 100 } |
| 101 } |
| 102 node.visitChildren(this); |
| 103 return null; |
| 104 } |
| 105 Object visitClassDeclaration(ClassDeclaration node) { |
| 106 ElementHolder holder = new ElementHolder(); |
| 107 visitChildren(holder, node); |
| 108 SimpleIdentifier className = node.name; |
| 109 ClassElementImpl element = new ClassElementImpl(className); |
| 110 List<ConstructorElement> constructors3 = holder.constructors; |
| 111 if (constructors3.length == 0) { |
| 112 ConstructorElementImpl constructor = new ConstructorElementImpl(null); |
| 113 constructor.synthetic = true; |
| 114 FunctionTypeImpl type = new FunctionTypeImpl.con1(constructor); |
| 115 type.returnType = element.type; |
| 116 constructor.type = type; |
| 117 constructors3 = <ConstructorElement> [constructor]; |
| 118 } |
| 119 element.abstract = node.abstractKeyword != null; |
| 120 element.accessors = holder.accessors; |
| 121 element.constructors = constructors3; |
| 122 element.fields = holder.fields; |
| 123 element.methods = holder.methods; |
| 124 List<TypeVariableElement> typeVariables4 = holder.typeVariables; |
| 125 element.typeVariables = typeVariables4; |
| 126 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl.con1(element); |
| 127 int typeVariableCount = typeVariables4.length; |
| 128 List<Type2> typeArguments = new List<Type2>.fixedLength(typeVariableCount); |
| 129 for (int i = 0; i < typeVariableCount; i++) { |
| 130 TypeVariableElementImpl typeVariable = (typeVariables4[i] as TypeVariableE
lementImpl); |
| 131 TypeVariableTypeImpl typeArgument = new TypeVariableTypeImpl(typeVariable)
; |
| 132 typeVariable.type = typeArgument; |
| 133 typeArguments[i] = typeArgument; |
| 134 } |
| 135 interfaceType.typeArguments = typeArguments; |
| 136 element.type = interfaceType; |
| 137 _currentHolder.addType(element); |
| 138 className.element = element; |
| 139 return null; |
| 140 } |
| 141 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 142 ElementHolder holder = new ElementHolder(); |
| 143 visitChildren(holder, node); |
| 144 SimpleIdentifier className = node.name; |
| 145 ClassElementImpl element = new ClassElementImpl(className); |
| 146 element.abstract = node.abstractKeyword != null; |
| 147 List<TypeVariableElement> typeVariables5 = holder.typeVariables; |
| 148 element.typeVariables = typeVariables5; |
| 149 InterfaceTypeImpl interfaceType = new InterfaceTypeImpl.con1(element); |
| 150 int typeVariableCount = typeVariables5.length; |
| 151 List<Type2> typeArguments = new List<Type2>.fixedLength(typeVariableCount); |
| 152 for (int i = 0; i < typeVariableCount; i++) { |
| 153 TypeVariableElementImpl typeVariable = (typeVariables5[i] as TypeVariableE
lementImpl); |
| 154 TypeVariableTypeImpl typeArgument = new TypeVariableTypeImpl(typeVariable)
; |
| 155 typeVariable.type = typeArgument; |
| 156 typeArguments[i] = typeArgument; |
| 157 } |
| 158 interfaceType.typeArguments = typeArguments; |
| 159 element.type = interfaceType; |
| 160 _currentHolder.addType(element); |
| 161 className.element = element; |
| 162 return null; |
| 163 } |
| 164 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 165 ElementHolder holder = new ElementHolder(); |
| 166 visitChildren(holder, node); |
| 167 SimpleIdentifier constructorName = node.name; |
| 168 ConstructorElementImpl element = new ConstructorElementImpl(constructorName)
; |
| 169 if (node.factoryKeyword != null) { |
| 170 element.factory = true; |
| 171 } |
| 172 element.functions = holder.functions; |
| 173 element.labels = holder.labels; |
| 174 element.localVariables = holder.variables; |
| 175 element.parameters = holder.parameters; |
| 176 _currentHolder.addConstructor(element); |
| 177 node.element = element; |
| 178 if (constructorName != null) { |
| 179 constructorName.element = element; |
| 180 } |
| 181 return null; |
| 182 } |
| 183 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 184 ElementHolder holder = new ElementHolder(); |
| 185 visitChildren(holder, node.defaultValue); |
| 186 FunctionElementImpl initializer = new FunctionElementImpl(); |
| 187 initializer.functions = holder.functions; |
| 188 initializer.labels = holder.labels; |
| 189 initializer.localVariables = holder.variables; |
| 190 initializer.parameters = holder.parameters; |
| 191 SimpleIdentifier parameterName = node.parameter.identifier; |
| 192 ParameterElementImpl parameter = new ParameterElementImpl(parameterName); |
| 193 parameter.const2 = node.isConst(); |
| 194 parameter.final2 = node.isFinal(); |
| 195 parameter.initializer = initializer; |
| 196 parameter.parameterKind = node.kind; |
| 197 _currentHolder.addParameter(parameter); |
| 198 parameterName.element = parameter; |
| 199 node.parameter.accept(this); |
| 200 return null; |
| 201 } |
| 202 Object visitFieldDeclaration(FieldDeclaration node) { |
| 203 bool wasInField = _inFieldContext; |
| 204 _inFieldContext = true; |
| 205 try { |
| 206 node.visitChildren(this); |
| 207 } finally { |
| 208 _inFieldContext = wasInField; |
| 209 } |
| 210 return null; |
| 211 } |
| 212 Object visitFieldFormalParameter(FieldFormalParameter node) { |
| 213 if (node.parent is! DefaultFormalParameter) { |
| 214 SimpleIdentifier parameterName = node.identifier; |
| 215 ParameterElementImpl parameter = new ParameterElementImpl(parameterName); |
| 216 parameter.const2 = node.isConst(); |
| 217 parameter.initializingFormal = true; |
| 218 parameter.final2 = node.isFinal(); |
| 219 parameter.parameterKind = node.kind; |
| 220 _currentHolder.addParameter(parameter); |
| 221 parameterName.element = parameter; |
| 222 } |
| 223 node.visitChildren(this); |
| 224 return null; |
| 225 } |
| 226 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 227 ElementHolder holder = new ElementHolder(); |
| 228 visitChildren(holder, node); |
| 229 SimpleIdentifier functionName = node.name; |
| 230 FunctionElementImpl element = new FunctionElementImpl.con1(functionName); |
| 231 element.functions = holder.functions; |
| 232 element.labels = holder.labels; |
| 233 element.localVariables = holder.variables; |
| 234 element.parameters = holder.parameters; |
| 235 _currentHolder.addFunction(element); |
| 236 functionName.element = element; |
| 237 return null; |
| 238 } |
| 239 Object visitFunctionExpression(FunctionExpression node) { |
| 240 ElementHolder holder = new ElementHolder(); |
| 241 visitChildren(holder, node); |
| 242 SimpleIdentifier functionName = null; |
| 243 FunctionElementImpl element = new FunctionElementImpl.con1(functionName); |
| 244 element.functions = holder.functions; |
| 245 element.labels = holder.labels; |
| 246 element.localVariables = holder.variables; |
| 247 element.parameters = holder.parameters; |
| 248 FunctionTypeImpl type = new FunctionTypeImpl.con1(element); |
| 249 element.type = type; |
| 250 _currentHolder.addFunction(element); |
| 251 node.element = element; |
| 252 return null; |
| 253 } |
| 254 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 255 ElementHolder holder = new ElementHolder(); |
| 256 visitChildren(holder, node); |
| 257 SimpleIdentifier aliasName = node.name; |
| 258 List<ParameterElement> parameters10 = holder.parameters; |
| 259 TypeAliasElementImpl element = new TypeAliasElementImpl(aliasName); |
| 260 element.parameters = parameters10; |
| 261 element.typeVariables = holder.typeVariables; |
| 262 FunctionTypeImpl type = new FunctionTypeImpl.con2(element); |
| 263 element.type = type; |
| 264 _currentHolder.addTypeAlias(element); |
| 265 aliasName.element = element; |
| 266 return null; |
| 267 } |
| 268 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 269 if (node.parent is! DefaultFormalParameter) { |
| 270 SimpleIdentifier parameterName = node.identifier; |
| 271 ParameterElementImpl parameter = new ParameterElementImpl(parameterName); |
| 272 parameter.parameterKind = node.kind; |
| 273 _currentHolder.addParameter(parameter); |
| 274 parameterName.element = parameter; |
| 275 } |
| 276 visitChildren(new ElementHolder(), node); |
| 277 return null; |
| 278 } |
| 279 Object visitLabeledStatement(LabeledStatement node) { |
| 280 bool onSwitchStatement = node.statement is SwitchStatement; |
| 281 for (Label label in node.labels) { |
| 282 SimpleIdentifier labelName = label.label; |
| 283 LabelElementImpl element = new LabelElementImpl(labelName, onSwitchStateme
nt, false); |
| 284 _currentHolder.addLabel(element); |
| 285 labelName.element = element; |
| 286 } |
| 287 node.visitChildren(this); |
| 288 return null; |
| 289 } |
| 290 Object visitMethodDeclaration(MethodDeclaration node) { |
| 291 ElementHolder holder = new ElementHolder(); |
| 292 visitChildren(holder, node); |
| 293 Token property = node.propertyKeyword; |
| 294 if (property == null) { |
| 295 Identifier methodName = node.name; |
| 296 String nameOfMethod = methodName.name; |
| 297 if (nameOfMethod == TokenType.MINUS.lexeme && node.parameters.parameters.l
ength == 0) { |
| 298 nameOfMethod = "unary-"; |
| 299 } |
| 300 MethodElementImpl element = new MethodElementImpl.con2(nameOfMethod, metho
dName.offset); |
| 301 Token keyword = node.modifierKeyword; |
| 302 element.abstract = matches(keyword, Keyword.ABSTRACT); |
| 303 element.functions = holder.functions; |
| 304 element.labels = holder.labels; |
| 305 element.localVariables = holder.variables; |
| 306 element.parameters = holder.parameters; |
| 307 element.static = matches(keyword, Keyword.STATIC); |
| 308 _currentHolder.addMethod(element); |
| 309 methodName.element = element; |
| 310 } else { |
| 311 Identifier propertyNameNode = node.name; |
| 312 String propertyName = propertyNameNode.name; |
| 313 FieldElementImpl field = (_currentHolder.getField(propertyName) as FieldEl
ementImpl); |
| 314 if (field == null) { |
| 315 field = new FieldElementImpl.con2(node.name.name); |
| 316 field.final2 = true; |
| 317 field.static = matches(node.modifierKeyword, Keyword.STATIC); |
| 318 _currentHolder.addField(field); |
| 319 } |
| 320 if (matches(property, Keyword.GET)) { |
| 321 PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.con
2(propertyNameNode); |
| 322 getter.functions = holder.functions; |
| 323 getter.labels = holder.labels; |
| 324 getter.localVariables = holder.variables; |
| 325 getter.field = field; |
| 326 getter.getter = true; |
| 327 field.getter = getter; |
| 328 _currentHolder.addAccessor(getter); |
| 329 propertyNameNode.element = getter; |
| 330 } else { |
| 331 PropertyAccessorElementImpl setter = new PropertyAccessorElementImpl.con
2(propertyNameNode); |
| 332 setter.functions = holder.functions; |
| 333 setter.labels = holder.labels; |
| 334 setter.localVariables = holder.variables; |
| 335 setter.parameters = holder.parameters; |
| 336 setter.field = field; |
| 337 setter.setter = true; |
| 338 field.setter = setter; |
| 339 field.final2 = false; |
| 340 _currentHolder.addAccessor(setter); |
| 341 propertyNameNode.element = setter; |
| 342 } |
| 343 } |
| 344 return null; |
| 345 } |
| 346 Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 347 if (node.parent is! DefaultFormalParameter) { |
| 348 SimpleIdentifier parameterName = node.identifier; |
| 349 ParameterElementImpl parameter = new ParameterElementImpl(parameterName); |
| 350 parameter.const2 = node.isConst(); |
| 351 parameter.final2 = node.isFinal(); |
| 352 parameter.parameterKind = node.kind; |
| 353 _currentHolder.addParameter(parameter); |
| 354 parameterName.element = parameter; |
| 355 } |
| 356 node.visitChildren(this); |
| 357 return null; |
| 358 } |
| 359 Object visitSwitchCase(SwitchCase node) { |
| 360 for (Label label in node.labels) { |
| 361 SimpleIdentifier labelName = label.label; |
| 362 LabelElementImpl element = new LabelElementImpl(labelName, false, true); |
| 363 _currentHolder.addLabel(element); |
| 364 labelName.element = element; |
| 365 } |
| 366 node.visitChildren(this); |
| 367 return null; |
| 368 } |
| 369 Object visitSwitchDefault(SwitchDefault node) { |
| 370 for (Label label in node.labels) { |
| 371 SimpleIdentifier labelName = label.label; |
| 372 LabelElementImpl element = new LabelElementImpl(labelName, false, true); |
| 373 _currentHolder.addLabel(element); |
| 374 labelName.element = element; |
| 375 } |
| 376 node.visitChildren(this); |
| 377 return null; |
| 378 } |
| 379 Object visitTypeParameter(TypeParameter node) { |
| 380 SimpleIdentifier parameterName = node.name; |
| 381 TypeVariableElementImpl element = new TypeVariableElementImpl(parameterName)
; |
| 382 TypeVariableTypeImpl type = new TypeVariableTypeImpl(element); |
| 383 element.type = type; |
| 384 _currentHolder.addTypeVariable(element); |
| 385 parameterName.element = element; |
| 386 node.visitChildren(this); |
| 387 return null; |
| 388 } |
| 389 Object visitVariableDeclaration(VariableDeclaration node) { |
| 390 VariableElementImpl element; |
| 391 if (_inFieldContext) { |
| 392 SimpleIdentifier fieldName = node.name; |
| 393 FieldElementImpl field = new FieldElementImpl.con1(fieldName); |
| 394 element = field; |
| 395 _currentHolder.addField(field); |
| 396 fieldName.element = field; |
| 397 } else { |
| 398 SimpleIdentifier variableName = node.name; |
| 399 element = new VariableElementImpl.con1(variableName); |
| 400 _currentHolder.addVariable(element); |
| 401 variableName.element = element; |
| 402 } |
| 403 Token keyword26 = ((node.parent as VariableDeclarationList)).keyword; |
| 404 bool isFinal = matches(keyword26, Keyword.FINAL); |
| 405 element.const2 = matches(keyword26, Keyword.CONST); |
| 406 element.final2 = isFinal; |
| 407 if (node.initializer != null) { |
| 408 ElementHolder holder = new ElementHolder(); |
| 409 bool wasInFieldContext = _inFieldContext; |
| 410 _inFieldContext = false; |
| 411 try { |
| 412 visitChildren(holder, node.initializer); |
| 413 } finally { |
| 414 _inFieldContext = wasInFieldContext; |
| 415 } |
| 416 FunctionElementImpl initializer = new FunctionElementImpl(); |
| 417 initializer.functions = holder.functions; |
| 418 initializer.labels = holder.labels; |
| 419 initializer.localVariables = holder.variables; |
| 420 initializer.synthetic = true; |
| 421 element.initializer = initializer; |
| 422 } |
| 423 if (_inFieldContext) { |
| 424 FieldElementImpl field = (element as FieldElementImpl); |
| 425 PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.con1(
field); |
| 426 getter.getter = true; |
| 427 _currentHolder.addAccessor(getter); |
| 428 field.getter = getter; |
| 429 if (!isFinal) { |
| 430 PropertyAccessorElementImpl setter = new PropertyAccessorElementImpl.con
1(field); |
| 431 setter.setter = true; |
| 432 _currentHolder.addAccessor(setter); |
| 433 field.setter = setter; |
| 434 } |
| 435 field.static = matches(((node.parent.parent as FieldDeclaration)).keyword,
Keyword.STATIC); |
| 436 } |
| 437 node.visitChildren(this); |
| 438 return null; |
| 439 } |
| 440 /** |
| 441 * Return {@code true} if the given token is a token for the given keyword. |
| 442 * @param token the token being tested |
| 443 * @param keyword the keyword being tested for |
| 444 * @return {@code true} if the given token is a token for the given keyword |
| 445 */ |
| 446 bool matches(Token token, Keyword keyword34) => token != null && identical(tok
en.type, TokenType.KEYWORD) && identical(((token as KeywordToken)).keyword, keyw
ord34); |
| 447 /** |
| 448 * Make the given holder be the current holder while visiting the children of
the given node. |
| 449 * @param holder the holder that will gather elements that are built while vis
iting the children |
| 450 * @param node the node whose children are to be visited |
| 451 */ |
| 452 void visitChildren(ElementHolder holder, ASTNode node) { |
| 453 if (node != null) { |
| 454 ElementHolder previousHolder = _currentHolder; |
| 455 _currentHolder = holder; |
| 456 try { |
| 457 node.visitChildren(this); |
| 458 } finally { |
| 459 _currentHolder = previousHolder; |
| 460 } |
| 461 } |
| 462 } |
| 463 } |
| 464 /** |
| 465 * Instances of the class {@code ElementHolder} hold on to elements created whil
e traversing an AST |
| 466 * structure so that they can be accessed when creating their enclosing element. |
| 467 */ |
| 468 class ElementHolder { |
| 469 List<PropertyAccessorElement> _accessors = new List<PropertyAccessorElement>()
; |
| 470 List<ConstructorElement> _constructors = new List<ConstructorElement>(); |
| 471 List<FieldElement> _fields = new List<FieldElement>(); |
| 472 List<FunctionElement> _functions = new List<FunctionElement>(); |
| 473 List<LabelElement> _labels = new List<LabelElement>(); |
| 474 List<MethodElement> _methods = new List<MethodElement>(); |
| 475 List<TypeAliasElement> _typeAliases = new List<TypeAliasElement>(); |
| 476 List<ParameterElement> _parameters = new List<ParameterElement>(); |
| 477 List<ClassElement> _types = new List<ClassElement>(); |
| 478 List<TypeVariableElement> _typeVariables = new List<TypeVariableElement>(); |
| 479 List<VariableElement> _variables = new List<VariableElement>(); |
| 480 /** |
| 481 * Initialize a newly created element holder. |
| 482 */ |
| 483 ElementHolder() : super() { |
| 484 } |
| 485 void addAccessor(PropertyAccessorElement element) { |
| 486 _accessors.add(element); |
| 487 } |
| 488 void addConstructor(ConstructorElement element) { |
| 489 _constructors.add(element); |
| 490 } |
| 491 void addField(FieldElement element) { |
| 492 _fields.add(element); |
| 493 } |
| 494 void addFunction(FunctionElement element) { |
| 495 _functions.add(element); |
| 496 } |
| 497 void addLabel(LabelElement element) { |
| 498 _labels.add(element); |
| 499 } |
| 500 void addMethod(MethodElement element) { |
| 501 _methods.add(element); |
| 502 } |
| 503 void addParameter(ParameterElement element) { |
| 504 _parameters.add(element); |
| 505 } |
| 506 void addType(ClassElement element) { |
| 507 _types.add(element); |
| 508 } |
| 509 void addTypeAlias(TypeAliasElement element) { |
| 510 _typeAliases.add(element); |
| 511 } |
| 512 void addTypeVariable(TypeVariableElement element) { |
| 513 _typeVariables.add(element); |
| 514 } |
| 515 void addVariable(VariableElement element) { |
| 516 _variables.add(element); |
| 517 } |
| 518 List<PropertyAccessorElement> get accessors => new List.from(_accessors); |
| 519 List<ConstructorElement> get constructors => new List.from(_constructors); |
| 520 FieldElement getField(String fieldName) { |
| 521 for (FieldElement field in _fields) { |
| 522 if (field.name == fieldName) { |
| 523 return field; |
| 524 } |
| 525 } |
| 526 return null; |
| 527 } |
| 528 List<FieldElement> get fields => new List.from(_fields); |
| 529 List<FunctionElement> get functions => new List.from(_functions); |
| 530 List<LabelElement> get labels => new List.from(_labels); |
| 531 List<MethodElement> get methods => new List.from(_methods); |
| 532 List<ParameterElement> get parameters => new List.from(_parameters); |
| 533 List<TypeAliasElement> get typeAliases => new List.from(_typeAliases); |
| 534 List<ClassElement> get types => new List.from(_types); |
| 535 List<TypeVariableElement> get typeVariables => new List.from(_typeVariables); |
| 536 List<VariableElement> get variables => new List.from(_variables); |
| 537 } |
| 538 /** |
| 539 * Instances of the class {@code ElementResolver} are used by instances of {@lin
k ResolverVisitor}to resolve references within the AST structure to the elements
being referenced. The requirements |
| 540 * for the element resolver are: |
| 541 * <ol> |
| 542 * <li>Every {@link SimpleIdentifier} should be resolved to the element to which
it refers. |
| 543 * Specifically: |
| 544 * <ul> |
| 545 * <li>An identifier within the declaration of that name should resolve to the e
lement being |
| 546 * declared.</li> |
| 547 * <li>An identifier denoting a prefix should resolve to the element representin
g the import that |
| 548 * defines the prefix (an {@link ImportElement}).</li> |
| 549 * <li>An identifier denoting a variable should resolve to the element represent
ing the variable (a{@link VariableElement}).</li> |
| 550 * <li>An identifier denoting a parameter should resolve to the element represen
ting the parameter |
| 551 * (a {@link ParameterElement}).</li> |
| 552 * <li>An identifier denoting a field should resolve to the element representing
the getter or |
| 553 * setter being invoked (a {@link PropertyAccessorElement}).</li> |
| 554 * <li>An identifier denoting the name of a method or function being invoked sho
uld resolve to the |
| 555 * element representing the method or function (a {@link ExecutableElement}).</l
i> |
| 556 * <li>An identifier denoting a label should resolve to the element representing
the label (a{@link LabelElement}).</li> |
| 557 * </ul> |
| 558 * The identifiers within directives are exceptions to this rule and are covered
below.</li> |
| 559 * <li>Every node containing a token representing an operator that can be overri
dden ({@link BinaryExpression}, {@link PrefixExpression}, {@link PostfixExpressi
on}) should resolve to |
| 560 * the element representing the method invoked by that operator (a {@link Method
Element}).</li> |
| 561 * <li>Every {@link FunctionExpressionInvocation} should resolve to the element
representing the |
| 562 * function being invoked (a {@link FunctionElement}). This will be the same ele
ment as that to |
| 563 * which the name is resolved if the function has a name, but is provided for th
ose cases where an |
| 564 * unnamed function is being invoked.</li> |
| 565 * <li>Every {@link LibraryDirective} and {@link PartOfDirective} should resolve
to the element |
| 566 * representing the library being specified by the directive (a {@link LibraryEl
ement}) unless, in |
| 567 * the case of a part-of directive, the specified library does not exist.</li> |
| 568 * <li>Every {@link ImportDirective} and {@link ExportDirective} should resolve
to the element |
| 569 * representing the library being specified by the directive unless the specifie
d library does not |
| 570 * exist (a {@link LibraryElement}).</li> |
| 571 * <li>The identifier representing the prefix in an {@link ImportDirective} shou
ld resolve to the |
| 572 * element representing the prefix (a {@link PrefixElement}).</li> |
| 573 * <li>The identifiers in the hide and show combinators in {@link ImportDirectiv
e}s and{@link ExportDirective}s should resolve to the elements that are being hi
dden or shown, |
| 574 * respectively, unless those names are not defined in the specified library (or
the specified |
| 575 * library does not exist).</li> |
| 576 * <li>Every {@link PartDirective} should resolve to the element representing th
e compilation unit |
| 577 * being specified by the string unless the specified compilation unit does not
exist (a{@link CompilationUnitElement}).</li> |
| 578 * </ol> |
| 579 * Note that AST nodes that would represent elements that are not defined are no
t resolved to |
| 580 * anything. This includes such things as references to undeclared variables (wh
ich is an error) and |
| 581 * names in hide and show combinators that are not defined in the imported libra
ry (which is not an |
| 582 * error). |
| 583 */ |
| 584 class ElementResolver extends SimpleASTVisitor<Object> { |
| 585 /** |
| 586 * The resolver driving this participant. |
| 587 */ |
| 588 ResolverVisitor _resolver; |
| 589 /** |
| 590 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. |
| 591 * @param resolver the resolver driving this participant |
| 592 */ |
| 593 ElementResolver(ResolverVisitor resolver) { |
| 594 this._resolver = resolver; |
| 595 } |
| 596 Object visitAssignmentExpression(AssignmentExpression node) { |
| 597 TokenType operator7 = node.operator.type; |
| 598 if (operator7 != TokenType.EQ) { |
| 599 operator7 = operatorFromCompoundAssignment(operator7); |
| 600 Expression leftNode = node.leftHandSide; |
| 601 if (leftNode != null) { |
| 602 Type2 leftType = leftNode.staticType; |
| 603 if (leftType != null) { |
| 604 Element leftElement = leftType.element; |
| 605 if (leftElement != null) { |
| 606 MethodElement method = lookUpMethod(leftElement, operator7.lexeme, 1
, []); |
| 607 if (method != null) { |
| 608 node.element = method; |
| 609 } else { |
| 610 } |
| 611 } |
| 612 } |
| 613 } |
| 614 } |
| 615 return null; |
| 616 } |
| 617 Object visitBinaryExpression(BinaryExpression node) { |
| 618 Token operator8 = node.operator; |
| 619 if (operator8.isUserDefinableOperator()) { |
| 620 Type2 leftType = getType(node.leftOperand); |
| 621 Element leftTypeElement; |
| 622 if (leftType == null) { |
| 623 return null; |
| 624 } else if (leftType is FunctionType) { |
| 625 leftTypeElement = _resolver.typeProvider.functionType.element; |
| 626 } else { |
| 627 leftTypeElement = leftType.element; |
| 628 } |
| 629 String methodName = operator8.lexeme; |
| 630 MethodElement member = lookUpMethod(leftTypeElement, methodName, 1, []); |
| 631 if (member == null) { |
| 632 _resolver.reportError2(ResolverErrorCode.CANNOT_BE_RESOLVED, operator8,
[methodName]); |
| 633 } else { |
| 634 node.element = member; |
| 635 } |
| 636 } |
| 637 return null; |
| 638 } |
| 639 Object visitBreakStatement(BreakStatement node) { |
| 640 SimpleIdentifier labelNode = node.label; |
| 641 LabelElementImpl labelElement = lookupLabel(node, labelNode); |
| 642 if (labelElement != null && labelElement.isOnSwitchMember()) { |
| 643 _resolver.reportError(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labe
lNode, []); |
| 644 } |
| 645 return null; |
| 646 } |
| 647 Object visitConstructorName(ConstructorName node) { |
| 648 Type2 type10 = node.type.type; |
| 649 if (type10 is! InterfaceType) { |
| 650 return null; |
| 651 } |
| 652 ClassElement classElement = ((type10 as InterfaceType)).element; |
| 653 ConstructorElement constructor; |
| 654 SimpleIdentifier name14 = node.name; |
| 655 if (name14 == null) { |
| 656 constructor = classElement.unnamedConstructor; |
| 657 } else { |
| 658 constructor = classElement.getNamedConstructor(name14.name); |
| 659 name14.element = constructor; |
| 660 } |
| 661 node.element = constructor; |
| 662 return null; |
| 663 } |
| 664 Object visitContinueStatement(ContinueStatement node) { |
| 665 SimpleIdentifier labelNode = node.label; |
| 666 LabelElementImpl labelElement = lookupLabel(node, labelNode); |
| 667 if (labelElement != null && labelElement.isOnSwitchStatement()) { |
| 668 _resolver.reportError(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNod
e, []); |
| 669 } |
| 670 return null; |
| 671 } |
| 672 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) =>
null; |
| 673 Object visitImportDirective(ImportDirective node) { |
| 674 SimpleIdentifier prefixNode = node.prefix; |
| 675 if (prefixNode != null) { |
| 676 String prefixName = prefixNode.name; |
| 677 for (PrefixElement prefixElement in _resolver.definingLibrary.prefixes) { |
| 678 if (prefixElement.name == prefixName) { |
| 679 recordResolution(prefixNode, prefixElement); |
| 680 } |
| 681 return null; |
| 682 } |
| 683 } |
| 684 return null; |
| 685 } |
| 686 Object visitIndexExpression(IndexExpression node) { |
| 687 Type2 arrayType = getType(node.array); |
| 688 if (arrayType == null) { |
| 689 return null; |
| 690 } |
| 691 Element arrayTypeElement = arrayType.element; |
| 692 String operator; |
| 693 if (node.inSetterContext()) { |
| 694 operator = TokenType.INDEX_EQ.lexeme; |
| 695 } else { |
| 696 operator = TokenType.INDEX.lexeme; |
| 697 } |
| 698 MethodElement member = lookUpMethod(arrayTypeElement, operator, 1, []); |
| 699 if (member == null) { |
| 700 _resolver.reportError(ResolverErrorCode.CANNOT_BE_RESOLVED, node, [operato
r]); |
| 701 } else { |
| 702 node.element = member; |
| 703 } |
| 704 return null; |
| 705 } |
| 706 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 707 node.element = node.constructorName.element; |
| 708 return null; |
| 709 } |
| 710 Object visitLibraryIdentifier(LibraryIdentifier node) => null; |
| 711 Object visitMethodInvocation(MethodInvocation node) { |
| 712 SimpleIdentifier methodName2 = node.methodName; |
| 713 Expression target4 = node.target; |
| 714 Element element; |
| 715 if (target4 == null) { |
| 716 element = _resolver.nameScope.lookup(methodName2, _resolver.definingLibrar
y); |
| 717 if (element == null) { |
| 718 element = lookUpMethod(_resolver.enclosingClass, methodName2.name, -1, [
]); |
| 719 } |
| 720 } else { |
| 721 Type2 targetType = getType(target4); |
| 722 if (targetType is InterfaceType) { |
| 723 int parameterCount = 0; |
| 724 List<String> parameterNames = new List<String>(); |
| 725 ArgumentList argumentList10 = node.argumentList; |
| 726 for (Expression argument in argumentList10.arguments) { |
| 727 if (argument is NamedExpression) { |
| 728 parameterNames.add(((argument as NamedExpression)).name.label.name); |
| 729 } else { |
| 730 parameterCount++; |
| 731 } |
| 732 } |
| 733 element = lookUpMethod(targetType.element, methodName2.name, parameterCo
unt, new List.from(parameterNames)); |
| 734 } else if (target4 is SimpleIdentifier) { |
| 735 Element targetElement = ((target4 as SimpleIdentifier)).element; |
| 736 if (targetElement is PrefixElement) { |
| 737 String name9 = "${((target4 as SimpleIdentifier)).name}.${methodName2}
"; |
| 738 Identifier functionName = new Identifier_2(name9); |
| 739 element = _resolver.nameScope.lookup(functionName, _resolver.definingL
ibrary); |
| 740 } else { |
| 741 return null; |
| 742 } |
| 743 } else { |
| 744 return null; |
| 745 } |
| 746 } |
| 747 ExecutableElement invokedMethod = null; |
| 748 if (element is ExecutableElement) { |
| 749 invokedMethod = (element as ExecutableElement); |
| 750 } else if (element is FieldElement) { |
| 751 } else { |
| 752 return null; |
| 753 } |
| 754 if (invokedMethod == null) { |
| 755 return null; |
| 756 } |
| 757 recordResolution(methodName2, invokedMethod); |
| 758 return null; |
| 759 } |
| 760 Object visitPostfixExpression(PostfixExpression node) { |
| 761 Token operator9 = node.operator; |
| 762 if (operator9.isUserDefinableOperator()) { |
| 763 Type2 operandType = getType(node.operand); |
| 764 if (operandType == null) { |
| 765 return null; |
| 766 } |
| 767 Element operandTypeElement = operandType.element; |
| 768 String methodName; |
| 769 if (identical(operator9.type, TokenType.PLUS_PLUS)) { |
| 770 methodName = TokenType.PLUS.lexeme; |
| 771 } else { |
| 772 methodName = TokenType.MINUS.lexeme; |
| 773 } |
| 774 MethodElement member = lookUpMethod(operandTypeElement, methodName, 1, [])
; |
| 775 if (member == null) { |
| 776 _resolver.reportError2(ResolverErrorCode.CANNOT_BE_RESOLVED, operator9,
[methodName]); |
| 777 } else { |
| 778 node.element = member; |
| 779 } |
| 780 } |
| 781 return null; |
| 782 } |
| 783 Object visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 784 SimpleIdentifier prefix5 = node.prefix; |
| 785 SimpleIdentifier identifier10 = node.identifier; |
| 786 Element prefixElement = prefix5.element; |
| 787 if (prefixElement is PrefixElement) { |
| 788 Element element = _resolver.nameScope.lookup(node, _resolver.definingLibra
ry); |
| 789 if (element == null) { |
| 790 return null; |
| 791 } |
| 792 recordResolution(identifier10, element); |
| 793 recordResolution(node, element); |
| 794 return null; |
| 795 } |
| 796 if (prefixElement is ClassElement) { |
| 797 Element memberElement; |
| 798 if (node.identifier.inSetterContext()) { |
| 799 memberElement = lookUpSetterInType((prefixElement as ClassElement), iden
tifier10.name); |
| 800 } else { |
| 801 memberElement = lookUpGetterInType((prefixElement as ClassElement), iden
tifier10.name); |
| 802 } |
| 803 if (memberElement == null) { |
| 804 MethodElement methodElement = lookUpMethod(prefixElement, identifier10.n
ame, -1, []); |
| 805 if (methodElement != null) { |
| 806 recordResolution(identifier10, methodElement); |
| 807 recordResolution(node, methodElement); |
| 808 return null; |
| 809 } |
| 810 } |
| 811 if (memberElement == null) { |
| 812 _resolver.reportError(ResolverErrorCode.CANNOT_BE_RESOLVED, identifier10
, [identifier10.name]); |
| 813 } else { |
| 814 recordResolution(identifier10, memberElement); |
| 815 recordResolution(node, memberElement); |
| 816 } |
| 817 return null; |
| 818 } |
| 819 Element variableType; |
| 820 if (prefixElement is PropertyAccessorElement) { |
| 821 PropertyAccessorElement accessor = (prefixElement as PropertyAccessorEleme
nt); |
| 822 if (accessor.isGetter()) { |
| 823 variableType = accessor.type.returnType.element; |
| 824 } else { |
| 825 variableType = accessor.type.normalParameterTypes[0].element; |
| 826 } |
| 827 } else if (prefixElement is VariableElement) { |
| 828 variableType = ((prefixElement as VariableElement)).type.element; |
| 829 } else { |
| 830 return null; |
| 831 } |
| 832 PropertyAccessorElement memberElement; |
| 833 if (node.identifier.inGetterContext()) { |
| 834 memberElement = lookUpGetter(variableType, identifier10.name); |
| 835 } else { |
| 836 memberElement = lookUpSetter(variableType, identifier10.name); |
| 837 } |
| 838 if (memberElement == null) { |
| 839 MethodElement methodElement = lookUpMethod(variableType, identifier10.name
, -1, []); |
| 840 if (methodElement != null) { |
| 841 recordResolution(identifier10, methodElement); |
| 842 recordResolution(node, methodElement); |
| 843 return null; |
| 844 } |
| 845 } |
| 846 if (memberElement == null) { |
| 847 _resolver.reportError(ResolverErrorCode.CANNOT_BE_RESOLVED, identifier10,
[identifier10.name]); |
| 848 } else { |
| 849 recordResolution(identifier10, memberElement); |
| 850 recordResolution(node, memberElement); |
| 851 } |
| 852 return null; |
| 853 } |
| 854 Object visitPrefixExpression(PrefixExpression node) { |
| 855 Token operator10 = node.operator; |
| 856 TokenType operatorType = operator10.type; |
| 857 if (operatorType.isUserDefinableOperator() || identical(operatorType, TokenT
ype.PLUS_PLUS) || identical(operatorType, TokenType.MINUS_MINUS)) { |
| 858 Type2 operandType = getType(node.operand); |
| 859 if (operandType == null) { |
| 860 return null; |
| 861 } |
| 862 Element operandTypeElement = operandType.element; |
| 863 String methodName; |
| 864 if (identical(operatorType, TokenType.PLUS_PLUS)) { |
| 865 methodName = TokenType.PLUS.lexeme; |
| 866 } else if (identical(operatorType, TokenType.MINUS_MINUS)) { |
| 867 methodName = TokenType.MINUS.lexeme; |
| 868 } else if (identical(operatorType, TokenType.MINUS)) { |
| 869 methodName = "unary-"; |
| 870 } else { |
| 871 methodName = operator10.lexeme; |
| 872 } |
| 873 MethodElement member = lookUpMethod(operandTypeElement, methodName, 1, [])
; |
| 874 if (member == null) { |
| 875 _resolver.reportError2(ResolverErrorCode.CANNOT_BE_RESOLVED, operator10,
[methodName]); |
| 876 } else { |
| 877 node.element = member; |
| 878 } |
| 879 } |
| 880 return null; |
| 881 } |
| 882 Object visitPropertyAccess(PropertyAccess node) { |
| 883 Type2 targetType = getType(node.realTarget); |
| 884 if (targetType is! InterfaceType) { |
| 885 return null; |
| 886 } |
| 887 ClassElement targetElement = ((targetType as InterfaceType)).element; |
| 888 SimpleIdentifier identifier = node.propertyName; |
| 889 PropertyAccessorElement memberElement; |
| 890 if (identifier.inSetterContext()) { |
| 891 memberElement = lookUpSetter(targetElement, identifier.name); |
| 892 } else { |
| 893 memberElement = lookUpGetter(targetElement, identifier.name); |
| 894 } |
| 895 if (memberElement == null) { |
| 896 MethodElement methodElement = lookUpMethod(targetElement, identifier.name,
-1, []); |
| 897 if (methodElement != null) { |
| 898 recordResolution(identifier, methodElement); |
| 899 return null; |
| 900 } |
| 901 } |
| 902 if (memberElement == null) { |
| 903 _resolver.reportError(ResolverErrorCode.CANNOT_BE_RESOLVED, identifier, [i
dentifier.name]); |
| 904 } else { |
| 905 recordResolution(identifier, memberElement); |
| 906 } |
| 907 return null; |
| 908 } |
| 909 Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation
node) { |
| 910 ClassElement enclosingClass2 = _resolver.enclosingClass; |
| 911 if (enclosingClass2 == null) { |
| 912 return null; |
| 913 } |
| 914 SimpleIdentifier name = node.constructorName; |
| 915 ConstructorElement element; |
| 916 if (name == null) { |
| 917 element = enclosingClass2.unnamedConstructor; |
| 918 } else { |
| 919 element = enclosingClass2.getNamedConstructor(name.name); |
| 920 } |
| 921 if (element == null) { |
| 922 return null; |
| 923 } |
| 924 if (name != null) { |
| 925 recordResolution(name, element); |
| 926 } |
| 927 node.element = element; |
| 928 return null; |
| 929 } |
| 930 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 931 if (node.element != null) { |
| 932 return null; |
| 933 } |
| 934 Element element = _resolver.nameScope.lookup(node, _resolver.definingLibrary
); |
| 935 if (element == null) { |
| 936 if (node.inGetterContext()) { |
| 937 element = lookUpGetter(_resolver.enclosingClass, node.name); |
| 938 } else { |
| 939 element = lookUpSetter(_resolver.enclosingClass, node.name); |
| 940 } |
| 941 } |
| 942 if (element == null) { |
| 943 element = lookUpMethod(_resolver.enclosingClass, node.name, -1, []); |
| 944 } |
| 945 if (element == null) { |
| 946 } |
| 947 recordResolution(node, element); |
| 948 return null; |
| 949 } |
| 950 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 951 ClassElement enclosingClass3 = _resolver.enclosingClass; |
| 952 if (enclosingClass3 == null) { |
| 953 return null; |
| 954 } |
| 955 ClassElement superclass = getSuperclass(enclosingClass3); |
| 956 if (superclass == null) { |
| 957 return null; |
| 958 } |
| 959 SimpleIdentifier name = node.constructorName; |
| 960 ConstructorElement element; |
| 961 if (name == null) { |
| 962 element = superclass.unnamedConstructor; |
| 963 } else { |
| 964 element = superclass.getNamedConstructor(name.name); |
| 965 } |
| 966 if (element == null) { |
| 967 return null; |
| 968 } |
| 969 if (name != null) { |
| 970 recordResolution(name, element); |
| 971 } |
| 972 node.element = element; |
| 973 return null; |
| 974 } |
| 975 /** |
| 976 * Return the element representing the superclass of the given class. |
| 977 * @param targetClass the class whose superclass is to be returned |
| 978 * @return the element representing the superclass of the given class |
| 979 */ |
| 980 ClassElement getSuperclass(ClassElement targetClass) { |
| 981 InterfaceType superType = targetClass.supertype; |
| 982 if (superType == null) { |
| 983 return null; |
| 984 } |
| 985 return superType.element; |
| 986 } |
| 987 /** |
| 988 * Return the type of the given expression that is to be used for type analysi
s. |
| 989 * @param expression the expression whose type is to be returned |
| 990 * @return the type of the given expression |
| 991 */ |
| 992 Type2 getType(Expression expression) => expression.staticType; |
| 993 /** |
| 994 * Look up the getter with the given name in the given type. Return the elemen
t representing the |
| 995 * getter that was found, or {@code null} if there is no getter with the given
name. |
| 996 * @param element the element representing the type in which the getter is def
ined |
| 997 * @param getterName the name of the getter being looked up |
| 998 * @return the element representing the getter that was found |
| 999 */ |
| 1000 PropertyAccessorElement lookUpGetter(Element element, String getterName) { |
| 1001 if (identical(element, DynamicTypeImpl.instance)) { |
| 1002 return null; |
| 1003 } |
| 1004 element = resolveTypeVariable(element); |
| 1005 if (element is ClassElement) { |
| 1006 ClassElement classElement = (element as ClassElement); |
| 1007 PropertyAccessorElement member = classElement.lookUpGetter(getterName, _re
solver.definingLibrary); |
| 1008 if (member != null) { |
| 1009 return member; |
| 1010 } |
| 1011 return lookUpGetterInInterfaces((element as ClassElement), getterName, new
Set<ClassElement>()); |
| 1012 } |
| 1013 return null; |
| 1014 } |
| 1015 /** |
| 1016 * Look up the name of a getter in the interfaces implemented by the given typ
e, either directly |
| 1017 * or indirectly. Return the element representing the getter that was found, o
r {@code null} if |
| 1018 * there is no getter with the given name. |
| 1019 * @param element the element representing the type in which the getter is def
ined |
| 1020 * @param memberName the name of the getter being looked up |
| 1021 * @param visitedInterfaces a set containing all of the interfaces that have b
een examined, used |
| 1022 * to prevent infinite recursion and to optimize the search |
| 1023 * @return the element representing the getter that was found |
| 1024 */ |
| 1025 PropertyAccessorElement lookUpGetterInInterfaces(ClassElement targetClass, Str
ing memberName, Set<ClassElement> visitedInterfaces) { |
| 1026 if (visitedInterfaces.contains(targetClass)) { |
| 1027 return null; |
| 1028 } |
| 1029 javaSetAdd(visitedInterfaces, targetClass); |
| 1030 PropertyAccessorElement member = lookUpGetterInType(targetClass, memberName)
; |
| 1031 if (member != null) { |
| 1032 return member; |
| 1033 } |
| 1034 for (InterfaceType interfaceType in targetClass.interfaces) { |
| 1035 member = lookUpGetterInInterfaces(interfaceType.element, memberName, visit
edInterfaces); |
| 1036 if (member != null) { |
| 1037 return member; |
| 1038 } |
| 1039 } |
| 1040 ClassElement superclass = getSuperclass(targetClass); |
| 1041 if (superclass == null) { |
| 1042 return null; |
| 1043 } |
| 1044 return lookUpGetterInInterfaces(superclass, memberName, visitedInterfaces); |
| 1045 } |
| 1046 /** |
| 1047 * Look up the name of a getter in the given type. Return the element represen
ting the getter that |
| 1048 * was found, or {@code null} if there is no getter with the given name. |
| 1049 * @param element the element representing the type in which the getter is def
ined |
| 1050 * @param memberName the name of the getter being looked up |
| 1051 * @return the element representing the getter that was found |
| 1052 */ |
| 1053 PropertyAccessorElement lookUpGetterInType(ClassElement element, String member
Name) { |
| 1054 for (PropertyAccessorElement accessor in element.accessors) { |
| 1055 if (accessor.isGetter() && accessor.name == memberName) { |
| 1056 return accessor; |
| 1057 } |
| 1058 } |
| 1059 return null; |
| 1060 } |
| 1061 /** |
| 1062 * Find the element corresponding to the given label node in the current label
scope. |
| 1063 * @param parentNode the node containing the given label |
| 1064 * @param labelNode the node representing the label being looked up |
| 1065 * @return the element corresponding to the given label node in the current sc
ope |
| 1066 */ |
| 1067 LabelElementImpl lookupLabel(ASTNode parentNode, SimpleIdentifier labelNode) { |
| 1068 LabelScope labelScope2 = _resolver.labelScope; |
| 1069 LabelElementImpl labelElement = null; |
| 1070 if (labelNode == null) { |
| 1071 if (labelScope2 == null) { |
| 1072 } else { |
| 1073 labelElement = (labelScope2.lookup2(LabelScope.EMPTY_LABEL) as LabelElem
entImpl); |
| 1074 if (labelElement == null) { |
| 1075 } |
| 1076 } |
| 1077 } else { |
| 1078 if (labelScope2 == null) { |
| 1079 _resolver.reportError(ResolverErrorCode.UNDEFINED_LABEL, labelNode, [lab
elNode.name]); |
| 1080 } else { |
| 1081 labelElement = (labelScope2.lookup(labelNode) as LabelElementImpl); |
| 1082 if (labelElement == null) { |
| 1083 _resolver.reportError(ResolverErrorCode.UNDEFINED_LABEL, labelNode, [l
abelNode.name]); |
| 1084 } else { |
| 1085 recordResolution(labelNode, labelElement); |
| 1086 } |
| 1087 } |
| 1088 } |
| 1089 if (labelElement != null) { |
| 1090 ExecutableElement labelContainer = labelElement.getAncestor(ExecutableElem
ent); |
| 1091 if (labelContainer != _resolver.enclosingFunction) { |
| 1092 if (labelNode == null) { |
| 1093 _resolver.reportError(ResolverErrorCode.LABEL_IN_OUTER_SCOPE, parentNo
de, [""]); |
| 1094 } else { |
| 1095 _resolver.reportError(ResolverErrorCode.LABEL_IN_OUTER_SCOPE, labelNod
e, [labelNode.name]); |
| 1096 } |
| 1097 labelElement = null; |
| 1098 } |
| 1099 } |
| 1100 return labelElement; |
| 1101 } |
| 1102 /** |
| 1103 * Look up the method with the given name in the given type. Return the elemen
t representing the |
| 1104 * method that was found, or {@code null} if there is no method with the given
name. |
| 1105 * @param element the element representing the type in which the method is def
ined |
| 1106 * @param methodName the name of the method being looked up |
| 1107 * @return the element representing the method that was found |
| 1108 */ |
| 1109 MethodElement lookUpMethod(Element element, String methodName, int parameterCo
unt, List<String> parameterNames) { |
| 1110 if (identical(element, DynamicTypeImpl.instance)) { |
| 1111 return null; |
| 1112 } |
| 1113 element = resolveTypeVariable(element); |
| 1114 if (element is ClassElement) { |
| 1115 ClassElement classElement = (element as ClassElement); |
| 1116 MethodElement member = classElement.lookUpMethod(methodName, _resolver.def
iningLibrary); |
| 1117 if (member != null) { |
| 1118 return member; |
| 1119 } |
| 1120 return lookUpMethodInInterfaces((element as ClassElement), methodName, new
Set<ClassElement>()); |
| 1121 } |
| 1122 return null; |
| 1123 } |
| 1124 /** |
| 1125 * Look up the name of a member in the interfaces implemented by the given typ
e, either directly |
| 1126 * or indirectly. Return the element representing the member that was found, o
r {@code null} if |
| 1127 * there is no member with the given name. |
| 1128 * @param element the element representing the type in which the member is def
ined |
| 1129 * @param memberName the name of the member being looked up |
| 1130 * @param visitedInterfaces a set containing all of the interfaces that have b
een examined, used |
| 1131 * to prevent infinite recursion and to optimize the search |
| 1132 * @return the element representing the member that was found |
| 1133 */ |
| 1134 MethodElement lookUpMethodInInterfaces(ClassElement targetClass, String member
Name, Set<ClassElement> visitedInterfaces) { |
| 1135 if (visitedInterfaces.contains(targetClass)) { |
| 1136 return null; |
| 1137 } |
| 1138 javaSetAdd(visitedInterfaces, targetClass); |
| 1139 MethodElement member = lookUpMethodInType(targetClass, memberName); |
| 1140 if (member != null) { |
| 1141 return member; |
| 1142 } |
| 1143 for (InterfaceType interfaceType in targetClass.interfaces) { |
| 1144 member = lookUpMethodInInterfaces(interfaceType.element, memberName, visit
edInterfaces); |
| 1145 if (member != null) { |
| 1146 return member; |
| 1147 } |
| 1148 } |
| 1149 ClassElement superclass = getSuperclass(targetClass); |
| 1150 if (superclass == null) { |
| 1151 return null; |
| 1152 } |
| 1153 return lookUpMethodInInterfaces(superclass, memberName, visitedInterfaces); |
| 1154 } |
| 1155 /** |
| 1156 * Look up the name of a method in the given type. Return the element represen
ting the method that |
| 1157 * was found, or {@code null} if there is no method with the given name. |
| 1158 * @param element the element representing the type in which the method is def
ined |
| 1159 * @param memberName the name of the method being looked up |
| 1160 * @return the element representing the method that was found |
| 1161 */ |
| 1162 MethodElement lookUpMethodInType(ClassElement element, String memberName) { |
| 1163 for (MethodElement method in element.methods) { |
| 1164 if (method.name == memberName) { |
| 1165 return method; |
| 1166 } |
| 1167 } |
| 1168 return null; |
| 1169 } |
| 1170 /** |
| 1171 * Look up the setter with the given name in the given type. Return the elemen
t representing the |
| 1172 * setter that was found, or {@code null} if there is no setter with the given
name. |
| 1173 * @param element the element representing the type in which the setter is def
ined |
| 1174 * @param setterName the name of the setter being looked up |
| 1175 * @return the element representing the setter that was found |
| 1176 */ |
| 1177 PropertyAccessorElement lookUpSetter(Element element, String setterName) { |
| 1178 if (identical(element, DynamicTypeImpl.instance)) { |
| 1179 return null; |
| 1180 } |
| 1181 element = resolveTypeVariable(element); |
| 1182 if (element is ClassElement) { |
| 1183 ClassElement classElement = (element as ClassElement); |
| 1184 PropertyAccessorElement member = classElement.lookUpSetter(setterName, _re
solver.definingLibrary); |
| 1185 if (member != null) { |
| 1186 return member; |
| 1187 } |
| 1188 return lookUpSetterInInterfaces((element as ClassElement), setterName, new
Set<ClassElement>()); |
| 1189 } |
| 1190 return null; |
| 1191 } |
| 1192 /** |
| 1193 * Look up the name of a setter in the interfaces implemented by the given typ
e, either directly |
| 1194 * or indirectly. Return the element representing the setter that was found, o
r {@code null} if |
| 1195 * there is no setter with the given name. |
| 1196 * @param element the element representing the type in which the setter is def
ined |
| 1197 * @param memberName the name of the setter being looked up |
| 1198 * @param visitedInterfaces a set containing all of the interfaces that have b
een examined, used |
| 1199 * to prevent infinite recursion and to optimize the search |
| 1200 * @return the element representing the setter that was found |
| 1201 */ |
| 1202 PropertyAccessorElement lookUpSetterInInterfaces(ClassElement targetClass, Str
ing memberName, Set<ClassElement> visitedInterfaces) { |
| 1203 if (visitedInterfaces.contains(targetClass)) { |
| 1204 return null; |
| 1205 } |
| 1206 javaSetAdd(visitedInterfaces, targetClass); |
| 1207 PropertyAccessorElement member = lookUpSetterInType(targetClass, memberName)
; |
| 1208 if (member != null) { |
| 1209 return member; |
| 1210 } |
| 1211 for (InterfaceType interfaceType in targetClass.interfaces) { |
| 1212 member = lookUpSetterInInterfaces(interfaceType.element, memberName, visit
edInterfaces); |
| 1213 if (member != null) { |
| 1214 return member; |
| 1215 } |
| 1216 } |
| 1217 ClassElement superclass = getSuperclass(targetClass); |
| 1218 if (superclass == null) { |
| 1219 return null; |
| 1220 } |
| 1221 return lookUpSetterInInterfaces(superclass, memberName, visitedInterfaces); |
| 1222 } |
| 1223 /** |
| 1224 * Look up the name of a setter in the given type. Return the element represen
ting the setter that |
| 1225 * was found, or {@code null} if there is no setter with the given name. |
| 1226 * @param element the element representing the type in which the setter is def
ined |
| 1227 * @param memberName the name of the setter being looked up |
| 1228 * @return the element representing the setter that was found |
| 1229 */ |
| 1230 PropertyAccessorElement lookUpSetterInType(ClassElement element, String member
Name) { |
| 1231 for (PropertyAccessorElement accessor in element.accessors) { |
| 1232 if (accessor.isSetter() && accessor.name == memberName) { |
| 1233 return accessor; |
| 1234 } |
| 1235 } |
| 1236 return null; |
| 1237 } |
| 1238 /** |
| 1239 * Return the binary operator that is invoked by the given compound assignment
operator. |
| 1240 * @param operator the assignment operator being mapped |
| 1241 * @return the binary operator that invoked by the given assignment operator |
| 1242 */ |
| 1243 TokenType operatorFromCompoundAssignment(TokenType operator) { |
| 1244 if (operator == TokenType.AMPERSAND_EQ) { |
| 1245 return TokenType.AMPERSAND; |
| 1246 } else if (operator == TokenType.BAR_EQ) { |
| 1247 return TokenType.BAR; |
| 1248 } else if (operator == TokenType.CARET_EQ) { |
| 1249 return TokenType.CARET; |
| 1250 } else if (operator == TokenType.GT_GT_EQ) { |
| 1251 return TokenType.GT_GT; |
| 1252 } else if (operator == TokenType.LT_LT_EQ) { |
| 1253 return TokenType.LT_LT; |
| 1254 } else if (operator == TokenType.MINUS_EQ) { |
| 1255 return TokenType.MINUS; |
| 1256 } else if (operator == TokenType.PERCENT_EQ) { |
| 1257 return TokenType.PERCENT; |
| 1258 } else if (operator == TokenType.PLUS_EQ) { |
| 1259 return TokenType.PLUS; |
| 1260 } else if (operator == TokenType.SLASH_EQ) { |
| 1261 return TokenType.SLASH; |
| 1262 } else if (operator == TokenType.STAR_EQ) { |
| 1263 return TokenType.STAR; |
| 1264 } else if (operator == TokenType.TILDE_SLASH_EQ) { |
| 1265 return TokenType.TILDE_SLASH; |
| 1266 } |
| 1267 AnalysisEngine.instance.logger.logError("Failed to map ${operator.lexeme} to
it's corresponding operator"); |
| 1268 return operator; |
| 1269 } |
| 1270 /** |
| 1271 * Record the fact that the given AST node was resolved to the given element. |
| 1272 * @param node the AST node that was resolved |
| 1273 * @param element the element to which the AST node was resolved |
| 1274 */ |
| 1275 void recordResolution(Identifier node, Element element39) { |
| 1276 if (element39 != null) { |
| 1277 node.element = element39; |
| 1278 } |
| 1279 } |
| 1280 /** |
| 1281 * If the given element is a type variable, resolve it to the class that shoul
d be used when |
| 1282 * looking up members. Otherwise, return the original element. |
| 1283 * @param element the element that is to be resolved if it is a type variable |
| 1284 * @return the class that should be used in place of the argument if it is a t
ype variable, or the |
| 1285 * original argument if it isn't a type variable |
| 1286 */ |
| 1287 Element resolveTypeVariable(Element element40) { |
| 1288 if (element40 is TypeVariableElement) { |
| 1289 Type2 bound3 = ((element40 as TypeVariableElement)).bound; |
| 1290 if (bound3 == null) { |
| 1291 return _resolver.typeProvider.objectType.element; |
| 1292 } |
| 1293 return bound3.element; |
| 1294 } |
| 1295 return element40; |
| 1296 } |
| 1297 } |
| 1298 class Identifier_2 extends Identifier { |
| 1299 String name9; |
| 1300 Identifier_2(this.name9) : super(); |
| 1301 accept(ASTVisitor visitor) => null; |
| 1302 Token get beginToken => null; |
| 1303 Token get endToken => null; |
| 1304 String get name => name9; |
| 1305 void visitChildren(ASTVisitor<Object> visitor) { |
| 1306 } |
| 1307 } |
| 1308 /** |
| 1309 * Instances of the class {@code Library} represent the data about a single libr
ary during the |
| 1310 * resolution of some (possibly different) library. They are not intended to be
used except during |
| 1311 * the resolution process. |
| 1312 */ |
| 1313 class Library { |
| 1314 /** |
| 1315 * The analysis context in which this library is being analyzed. |
| 1316 */ |
| 1317 AnalysisContextImpl _analysisContext; |
| 1318 /** |
| 1319 * The listener to which analysis errors will be reported. |
| 1320 */ |
| 1321 AnalysisErrorListener _errorListener; |
| 1322 /** |
| 1323 * The source specifying the defining compilation unit of this library. |
| 1324 */ |
| 1325 Source _librarySource; |
| 1326 /** |
| 1327 * The library element representing this library. |
| 1328 */ |
| 1329 LibraryElementImpl _libraryElement; |
| 1330 /** |
| 1331 * A list containing all of the libraries that are imported into this library. |
| 1332 */ |
| 1333 Map<ImportDirective, Library> _importedLibraries = new Map<ImportDirective, Li
brary>(); |
| 1334 /** |
| 1335 * A flag indicating whether this library explicitly imports core. |
| 1336 */ |
| 1337 bool _explicitlyImportsCore = false; |
| 1338 /** |
| 1339 * A list containing all of the libraries that are exported from this library. |
| 1340 */ |
| 1341 Map<ExportDirective, Library> _exportedLibraries = new Map<ExportDirective, Li
brary>(); |
| 1342 /** |
| 1343 * A table mapping the sources for the compilation units in this library to th
eir corresponding |
| 1344 * AST structures. |
| 1345 */ |
| 1346 Map<Source, CompilationUnit> _astMap = new Map<Source, CompilationUnit>(); |
| 1347 /** |
| 1348 * The library scope used when resolving elements within this library's compil
ation units. |
| 1349 */ |
| 1350 LibraryScope _libraryScope; |
| 1351 /** |
| 1352 * Initialize a newly created data holder that can maintain the data associate
d with a library. |
| 1353 * @param analysisContext the analysis context in which this library is being
analyzed |
| 1354 * @param errorListener the listener to which analysis errors will be reported |
| 1355 * @param librarySource the source specifying the defining compilation unit of
this library |
| 1356 */ |
| 1357 Library(AnalysisContextImpl analysisContext, AnalysisErrorListener errorListen
er, Source librarySource) { |
| 1358 this._analysisContext = analysisContext; |
| 1359 this._errorListener = errorListener; |
| 1360 this._librarySource = librarySource; |
| 1361 this._libraryElement = (analysisContext.getLibraryElementOrNull(librarySourc
e) as LibraryElementImpl); |
| 1362 } |
| 1363 /** |
| 1364 * Record that the given library is exported from this library. |
| 1365 * @param importLibrary the library that is exported from this library |
| 1366 */ |
| 1367 void addExport(ExportDirective directive, Library exportLibrary) { |
| 1368 _exportedLibraries[directive] = exportLibrary; |
| 1369 } |
| 1370 /** |
| 1371 * Record that the given library is imported into this library. |
| 1372 * @param importLibrary the library that is imported into this library |
| 1373 */ |
| 1374 void addImport(ImportDirective directive, Library importLibrary) { |
| 1375 _importedLibraries[directive] = importLibrary; |
| 1376 } |
| 1377 /** |
| 1378 * Return the AST structure associated with the given source. |
| 1379 * @param source the source representing the compilation unit whose AST is to
be returned |
| 1380 * @return the AST structure associated with the given source |
| 1381 * @throws AnalysisException if an AST structure could not be created for the
compilation unit |
| 1382 */ |
| 1383 CompilationUnit getAST(Source source) { |
| 1384 CompilationUnit unit = _astMap[source]; |
| 1385 if (unit == null) { |
| 1386 unit = _analysisContext.parse2(source, _errorListener); |
| 1387 _astMap[source] = unit; |
| 1388 } |
| 1389 return unit; |
| 1390 } |
| 1391 /** |
| 1392 * Return a collection containing the sources for the compilation units in thi
s library. |
| 1393 * @return the sources for the compilation units in this library |
| 1394 */ |
| 1395 Set<Source> get compilationUnitSources => _astMap.keys.toSet(); |
| 1396 /** |
| 1397 * Return the AST structure associated with the defining compilation unit for
this library. |
| 1398 * @return the AST structure associated with the defining compilation unit for
this library |
| 1399 * @throws AnalysisException if an AST structure could not be created for the
defining compilation |
| 1400 * unit |
| 1401 */ |
| 1402 CompilationUnit get definingCompilationUnit => getAST(librarySource); |
| 1403 /** |
| 1404 * Return {@code true} if this library explicitly imports core. |
| 1405 * @return {@code true} if this library explicitly imports core |
| 1406 */ |
| 1407 bool get explicitlyImportsCore => _explicitlyImportsCore; |
| 1408 /** |
| 1409 * Return the library exported by the given directive. |
| 1410 * @param directive the directive that exports the library to be returned |
| 1411 * @return the library exported by the given directive |
| 1412 */ |
| 1413 Library getExport(ExportDirective directive) => _exportedLibraries[directive]; |
| 1414 /** |
| 1415 * Return an array containing the libraries that are exported from this librar
y. |
| 1416 * @return an array containing the libraries that are exported from this libra
ry |
| 1417 */ |
| 1418 List<Library> get exports { |
| 1419 Set<Library> libraries = new Set<Library>(); |
| 1420 libraries.addAll(_exportedLibraries.values); |
| 1421 return new List.from(libraries); |
| 1422 } |
| 1423 /** |
| 1424 * Return the library imported by the given directive. |
| 1425 * @param directive the directive that imports the library to be returned |
| 1426 * @return the library imported by the given directive |
| 1427 */ |
| 1428 Library getImport(ImportDirective directive) => _importedLibraries[directive]; |
| 1429 /** |
| 1430 * Return an array containing the libraries that are imported into this librar
y. |
| 1431 * @return an array containing the libraries that are imported into this libra
ry |
| 1432 */ |
| 1433 List<Library> get imports { |
| 1434 Set<Library> libraries = new Set<Library>(); |
| 1435 libraries.addAll(_importedLibraries.values); |
| 1436 return new List.from(libraries); |
| 1437 } |
| 1438 /** |
| 1439 * Return an array containing the libraries that are either imported or export
ed from this |
| 1440 * library. |
| 1441 * @return the libraries that are either imported or exported from this librar
y |
| 1442 */ |
| 1443 List<Library> get importsAndExports { |
| 1444 Set<Library> libraries = new Set<Library>(); |
| 1445 libraries.addAll(_importedLibraries.values); |
| 1446 libraries.addAll(_exportedLibraries.values); |
| 1447 return new List.from(libraries); |
| 1448 } |
| 1449 /** |
| 1450 * Return the library element representing this library, creating it if necess
ary. |
| 1451 * @return the library element representing this library |
| 1452 */ |
| 1453 LibraryElementImpl get libraryElement { |
| 1454 if (_libraryElement == null) { |
| 1455 _libraryElement = (_analysisContext.getLibraryElement(_librarySource) as L
ibraryElementImpl); |
| 1456 } |
| 1457 return _libraryElement; |
| 1458 } |
| 1459 /** |
| 1460 * Return the library scope used when resolving elements within this library's
compilation units. |
| 1461 * @return the library scope used when resolving elements within this library'
s compilation units |
| 1462 */ |
| 1463 LibraryScope get libraryScope { |
| 1464 if (_libraryScope == null) { |
| 1465 _libraryScope = new LibraryScope(_libraryElement, _errorListener); |
| 1466 } |
| 1467 return _libraryScope; |
| 1468 } |
| 1469 /** |
| 1470 * Return the source specifying the defining compilation unit of this library. |
| 1471 * @return the source specifying the defining compilation unit of this library |
| 1472 */ |
| 1473 Source get librarySource => _librarySource; |
| 1474 /** |
| 1475 * Return the result of resolving the given URI against the URI of the library
, or {@code null} if |
| 1476 * the URI is not valid. If the URI is not valid, report the error. |
| 1477 * @param uriLiteral the string literal specifying the URI to be resolved |
| 1478 * @return the result of resolving the given URI against the URI of the librar
y |
| 1479 */ |
| 1480 Source getSource(StringLiteral uriLiteral) => getSource2(getStringValue(uriLit
eral), uriLiteral.offset, uriLiteral.length); |
| 1481 /** |
| 1482 * Set whether this library explicitly imports core to match the given value. |
| 1483 * @param explicitlyImportsCore {@code true} if this library explicitly import
s core |
| 1484 */ |
| 1485 void set explicitlyImportsCore(bool explicitlyImportsCore2) { |
| 1486 this._explicitlyImportsCore = explicitlyImportsCore2; |
| 1487 } |
| 1488 /** |
| 1489 * Set the library element representing this library to the given library elem
ent. |
| 1490 * @param libraryElement the library element representing this library |
| 1491 */ |
| 1492 void set libraryElement(LibraryElementImpl libraryElement2) { |
| 1493 this._libraryElement = libraryElement2; |
| 1494 } |
| 1495 String toString() => _librarySource.shortName; |
| 1496 /** |
| 1497 * Append the value of the given string literal to the given string builder. |
| 1498 * @param builder the builder to which the string's value is to be appended |
| 1499 * @param literal the string literal whose value is to be appended to the buil
der |
| 1500 * @throws IllegalArgumentException if the string is not a constant string wit
hout any string |
| 1501 * interpolation |
| 1502 */ |
| 1503 void appendStringValue(StringBuffer builder, StringLiteral literal) { |
| 1504 if (literal is SimpleStringLiteral) { |
| 1505 builder.add(((literal as SimpleStringLiteral)).value); |
| 1506 } else if (literal is AdjacentStrings) { |
| 1507 for (StringLiteral stringLiteral in ((literal as AdjacentStrings)).strings
) { |
| 1508 appendStringValue(builder, stringLiteral); |
| 1509 } |
| 1510 } else { |
| 1511 throw new IllegalArgumentException(); |
| 1512 } |
| 1513 } |
| 1514 /** |
| 1515 * Return the result of resolving the given URI against the URI of the library
, or {@code null} if |
| 1516 * the URI is not valid. If the URI is not valid, report the error. |
| 1517 * @param uri the URI to be resolved |
| 1518 * @param uriOffset the offset of the string literal representing the URI |
| 1519 * @param uriLength the length of the string literal representing the URI |
| 1520 * @return the result of resolving the given URI against the URI of the librar
y |
| 1521 */ |
| 1522 Source getSource2(String uri, int uriOffset, int uriLength) { |
| 1523 if (uri == null) { |
| 1524 _errorListener.onError(new AnalysisError.con2(_librarySource, uriOffset, u
riLength, ResolverErrorCode.INVALID_URI, [])); |
| 1525 return null; |
| 1526 } |
| 1527 return _librarySource.resolve(uri); |
| 1528 } |
| 1529 /** |
| 1530 * Return the value of the given string literal, or {@code null} if the string
is not a constant |
| 1531 * string without any string interpolation. |
| 1532 * @param literal the string literal whose value is to be returned |
| 1533 * @return the value of the given string literal |
| 1534 */ |
| 1535 String getStringValue(StringLiteral literal) { |
| 1536 StringBuffer builder = new StringBuffer(); |
| 1537 try { |
| 1538 appendStringValue(builder, literal); |
| 1539 } on IllegalArgumentException catch (exception) { |
| 1540 return null; |
| 1541 } |
| 1542 return builder.toString(); |
| 1543 } |
| 1544 } |
| 1545 /** |
| 1546 * Instances of the class {@code LibraryElementBuilder} build an element model f
or a single library. |
| 1547 */ |
| 1548 class LibraryElementBuilder { |
| 1549 /** |
| 1550 * The analysis context in which the element model will be built. |
| 1551 */ |
| 1552 AnalysisContextImpl _analysisContext; |
| 1553 /** |
| 1554 * The listener to which errors will be reported. |
| 1555 */ |
| 1556 AnalysisErrorListener _errorListener; |
| 1557 /** |
| 1558 * The name of the core library. |
| 1559 */ |
| 1560 static String CORE_LIBRARY_URI = "dart:core"; |
| 1561 /** |
| 1562 * The name of the function used as an entry point. |
| 1563 */ |
| 1564 static String _ENTRY_POINT_NAME = "main"; |
| 1565 /** |
| 1566 * Initialize a newly created library element builder. |
| 1567 * @param resolver the resolver for which the element model is being built |
| 1568 */ |
| 1569 LibraryElementBuilder(LibraryResolver resolver) { |
| 1570 this._analysisContext = resolver.analysisContext; |
| 1571 this._errorListener = resolver.errorListener; |
| 1572 } |
| 1573 /** |
| 1574 * Build the library element for the given library. |
| 1575 * @param library the library for which an element model is to be built |
| 1576 * @return the library element that was built |
| 1577 * @throws AnalysisException if the analysis could not be performed |
| 1578 */ |
| 1579 LibraryElementImpl buildLibrary(Library library) { |
| 1580 CompilationUnitBuilder builder = new CompilationUnitBuilder(_analysisContext
, _errorListener); |
| 1581 Source librarySource2 = library.librarySource; |
| 1582 CompilationUnit definingCompilationUnit3 = library.definingCompilationUnit; |
| 1583 CompilationUnitElementImpl definingCompilationUnitElement = builder.buildCom
pilationUnit2(librarySource2, definingCompilationUnit3); |
| 1584 NodeList<Directive> directives3 = definingCompilationUnit3.directives; |
| 1585 LibraryIdentifier libraryNameNode = null; |
| 1586 bool hasPartDirective = false; |
| 1587 FunctionElement entryPoint = findEntryPoint(definingCompilationUnitElement); |
| 1588 List<ImportElement> imports = new List<ImportElement>(); |
| 1589 List<ExportElement> exports = new List<ExportElement>(); |
| 1590 List<Directive> directivesToResolve = new List<Directive>(); |
| 1591 List<CompilationUnitElementImpl> sourcedCompilationUnits = new List<Compilat
ionUnitElementImpl>(); |
| 1592 for (Directive directive in directives3) { |
| 1593 if (directive is LibraryDirective) { |
| 1594 if (libraryNameNode == null) { |
| 1595 libraryNameNode = ((directive as LibraryDirective)).name; |
| 1596 directivesToResolve.add(directive); |
| 1597 } |
| 1598 } else if (directive is PartDirective) { |
| 1599 hasPartDirective = true; |
| 1600 StringLiteral partUri = ((directive as PartDirective)).uri; |
| 1601 Source partSource = library.getSource(partUri); |
| 1602 if (partSource != null) { |
| 1603 CompilationUnitElementImpl part = builder.buildCompilationUnit(partSou
rce); |
| 1604 String partLibraryName = getPartLibraryName(library, partSource, direc
tivesToResolve); |
| 1605 if (partLibraryName == null) { |
| 1606 _errorListener.onError(new AnalysisError.con2(librarySource2, partUr
i.offset, partUri.length, ResolverErrorCode.MISSING_PART_OF_DIRECTIVE, [])); |
| 1607 } else if (libraryNameNode == null) { |
| 1608 } else if (libraryNameNode.name != partLibraryName) { |
| 1609 _errorListener.onError(new AnalysisError.con2(librarySource2, partUr
i.offset, partUri.length, ResolverErrorCode.PART_WITH_WRONG_LIBRARY_NAME, [partL
ibraryName])); |
| 1610 } |
| 1611 if (entryPoint == null) { |
| 1612 entryPoint = findEntryPoint(part); |
| 1613 } |
| 1614 directive.element = part; |
| 1615 sourcedCompilationUnits.add(part); |
| 1616 } |
| 1617 } |
| 1618 } |
| 1619 if (hasPartDirective && libraryNameNode == null) { |
| 1620 _errorListener.onError(new AnalysisError.con1(librarySource2, ResolverErro
rCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART, [])); |
| 1621 } |
| 1622 LibraryElementImpl libraryElement = new LibraryElementImpl(_analysisContext,
libraryNameNode); |
| 1623 libraryElement.definingCompilationUnit = definingCompilationUnitElement; |
| 1624 if (entryPoint != null) { |
| 1625 libraryElement.entryPoint = entryPoint; |
| 1626 } |
| 1627 libraryElement.imports = new List.from(imports); |
| 1628 libraryElement.exports = new List.from(exports); |
| 1629 libraryElement.parts = new List.from(sourcedCompilationUnits); |
| 1630 for (Directive directive in directivesToResolve) { |
| 1631 directive.element = libraryElement; |
| 1632 } |
| 1633 library.libraryElement = libraryElement; |
| 1634 return libraryElement; |
| 1635 } |
| 1636 /** |
| 1637 * Search the top-level functions defined in the given compilation unit for th
e entry point. |
| 1638 * @param element the compilation unit to be searched |
| 1639 * @return the entry point that was found, or {@code null} if the compilation
unit does not define |
| 1640 * an entry point |
| 1641 */ |
| 1642 FunctionElement findEntryPoint(CompilationUnitElementImpl element) { |
| 1643 for (FunctionElement function in element.functions) { |
| 1644 if (function.name == _ENTRY_POINT_NAME) { |
| 1645 return function; |
| 1646 } |
| 1647 } |
| 1648 return null; |
| 1649 } |
| 1650 /** |
| 1651 * Return the name of the library that the given part is declared to be a part
of, or {@code null}if the part does not contain a part-of directive. |
| 1652 * @param library the library containing the part |
| 1653 * @param partSource the source representing the part |
| 1654 * @param directivesToResolve a list of directives that should be resolved to
the library being |
| 1655 * built |
| 1656 * @return the name of the library that the given part is declared to be a par
t of |
| 1657 */ |
| 1658 String getPartLibraryName(Library library, Source partSource, List<Directive>
directivesToResolve) { |
| 1659 try { |
| 1660 CompilationUnit partUnit = library.getAST(partSource); |
| 1661 for (Directive directive in partUnit.directives) { |
| 1662 if (directive is PartOfDirective) { |
| 1663 directivesToResolve.add(directive); |
| 1664 LibraryIdentifier libraryName3 = ((directive as PartOfDirective)).libr
aryName; |
| 1665 if (libraryName3 != null) { |
| 1666 return libraryName3.name; |
| 1667 } |
| 1668 } |
| 1669 } |
| 1670 } on AnalysisException catch (exception) { |
| 1671 } |
| 1672 return null; |
| 1673 } |
| 1674 } |
| 1675 /** |
| 1676 * Instances of the class {@code LibraryResolver} are used to resolve one or mor
e mutually dependent |
| 1677 * libraries within a single context. |
| 1678 */ |
| 1679 class LibraryResolver { |
| 1680 /** |
| 1681 * The analysis context in which the libraries are being analyzed. |
| 1682 */ |
| 1683 AnalysisContextImpl _analysisContext; |
| 1684 /** |
| 1685 * The listener to which analysis errors will be reported. |
| 1686 */ |
| 1687 AnalysisErrorListener _errorListener; |
| 1688 /** |
| 1689 * A source object representing the core library (dart:core). |
| 1690 */ |
| 1691 Source _coreLibrarySource; |
| 1692 /** |
| 1693 * The object representing the core library. |
| 1694 */ |
| 1695 Library _coreLibrary; |
| 1696 /** |
| 1697 * The object used to access the types from the core library. |
| 1698 */ |
| 1699 TypeProvider _typeProvider; |
| 1700 /** |
| 1701 * A table mapping library sources to the information being maintained for tho
se libraries. |
| 1702 */ |
| 1703 Map<Source, Library> _libraryMap = new Map<Source, Library>(); |
| 1704 /** |
| 1705 * A collection containing the libraries that are being resolved together. |
| 1706 */ |
| 1707 Set<Library> _librariesInCycles; |
| 1708 /** |
| 1709 * Initialize a newly created library resolver to resolve libraries within the
given context. |
| 1710 * @param analysisContext the analysis context in which the library is being a
nalyzed |
| 1711 * @param errorListener the listener to which analysis errors will be reported |
| 1712 */ |
| 1713 LibraryResolver(AnalysisContextImpl analysisContext, AnalysisErrorListener err
orListener) { |
| 1714 this._analysisContext = analysisContext; |
| 1715 this._errorListener = errorListener; |
| 1716 _coreLibrarySource = analysisContext.sourceFactory.forUri(LibraryElementBuil
der.CORE_LIBRARY_URI); |
| 1717 } |
| 1718 /** |
| 1719 * Return the analysis context in which the libraries are being analyzed. |
| 1720 * @return the analysis context in which the libraries are being analyzed |
| 1721 */ |
| 1722 AnalysisContextImpl get analysisContext => _analysisContext; |
| 1723 /** |
| 1724 * Return the listener to which analysis errors will be reported. |
| 1725 * @return the listener to which analysis errors will be reported |
| 1726 */ |
| 1727 AnalysisErrorListener get errorListener => _errorListener; |
| 1728 /** |
| 1729 * Resolve the library specified by the given source in the given context. |
| 1730 * <p> |
| 1731 * Note that because Dart allows circular imports between libraries, it is pos
sible that more than |
| 1732 * one library will need to be resolved. In such cases the error listener can
receive errors from |
| 1733 * multiple libraries. |
| 1734 * @param librarySource the source specifying the defining compilation unit of
the library to be |
| 1735 * resolved |
| 1736 * @param fullAnalysis {@code true} if a full analysis should be performed |
| 1737 * @return the element representing the resolved library |
| 1738 * @throws AnalysisException if the library could not be resolved for some rea
son |
| 1739 */ |
| 1740 LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) { |
| 1741 Library targetLibrary = createLibrary(librarySource); |
| 1742 _coreLibrary = _libraryMap[_coreLibrarySource]; |
| 1743 if (_coreLibrary == null) { |
| 1744 _coreLibrary = createLibrary(_coreLibrarySource); |
| 1745 } |
| 1746 computeLibraryDependencies(targetLibrary); |
| 1747 _librariesInCycles = computeLibrariesInCycles(targetLibrary); |
| 1748 buildElementModels(); |
| 1749 buildDirectiveModels(); |
| 1750 _typeProvider = new TypeProviderImpl(_coreLibrary.libraryElement); |
| 1751 buildTypeHierarchies(); |
| 1752 resolveReferencesAndTypes(); |
| 1753 if (fullAnalysis) { |
| 1754 } |
| 1755 recordLibraryElements(); |
| 1756 return targetLibrary.libraryElement; |
| 1757 } |
| 1758 /** |
| 1759 * Add a dependency to the given map from the referencing library to the refer
enced library. |
| 1760 * @param dependencyMap the map to which the dependency is to be added |
| 1761 * @param referencingLibrary the library that references the referenced librar
y |
| 1762 * @param referencedLibrary the library referenced by the referencing library |
| 1763 */ |
| 1764 void addDependencyToMap(Map<Library, List<Library>> dependencyMap, Library ref
erencingLibrary, Library referencedLibrary) { |
| 1765 List<Library> dependentLibraries = dependencyMap[referencedLibrary]; |
| 1766 if (dependentLibraries == null) { |
| 1767 dependentLibraries = new List<Library>(); |
| 1768 dependencyMap[referencedLibrary] = dependentLibraries; |
| 1769 } |
| 1770 dependentLibraries.add(referencingLibrary); |
| 1771 } |
| 1772 /** |
| 1773 * Given a library that is part of a cycle that includes the root library, add
to the given set of |
| 1774 * libraries all of the libraries reachable from the root library that are als
o included in the |
| 1775 * cycle. |
| 1776 * @param library the library to be added to the collection of libraries in cy
cles |
| 1777 * @param librariesInCycle a collection of the libraries that are in the cycle |
| 1778 * @param dependencyMap a table mapping libraries to the collection of librari
es from which those |
| 1779 * libraries are referenced |
| 1780 */ |
| 1781 void addLibrariesInCycle(Library library, Set<Library> librariesInCycle, Map<L
ibrary, List<Library>> dependencyMap) { |
| 1782 if (javaSetAdd(librariesInCycle, library)) { |
| 1783 List<Library> dependentLibraries = dependencyMap[library]; |
| 1784 if (dependentLibraries != null) { |
| 1785 for (Library dependentLibrary in dependentLibraries) { |
| 1786 addLibrariesInCycle(dependentLibrary, librariesInCycle, dependencyMap)
; |
| 1787 } |
| 1788 } |
| 1789 } |
| 1790 } |
| 1791 /** |
| 1792 * Add the given library, and all libraries reachable from it that have not al
ready been visited, |
| 1793 * to the given dependency map. |
| 1794 * @param library the library currently being added to the dependency map |
| 1795 * @param dependencyMap the dependency map being computed |
| 1796 * @param visitedLibraries the libraries that have already been visited, used
to prevent infinite |
| 1797 * recursion |
| 1798 */ |
| 1799 void addToDependencyMap(Library library, Map<Library, List<Library>> dependenc
yMap, Set<Library> visitedLibraries) { |
| 1800 if (javaSetAdd(visitedLibraries, library)) { |
| 1801 for (Library referencedLibrary in library.importsAndExports) { |
| 1802 addDependencyToMap(dependencyMap, library, referencedLibrary); |
| 1803 addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries); |
| 1804 } |
| 1805 if (!library.explicitlyImportsCore && library != _coreLibrary) { |
| 1806 addDependencyToMap(dependencyMap, library, _coreLibrary); |
| 1807 } |
| 1808 } |
| 1809 } |
| 1810 /** |
| 1811 * Build the element model representing the combinators declared by the given
directive. |
| 1812 * @param directive the directive that declares the combinators |
| 1813 * @return an array containing the import combinators that were built |
| 1814 */ |
| 1815 List<NamespaceCombinator> buildCombinators(NamespaceDirective directive) { |
| 1816 List<NamespaceCombinator> combinators = new List<NamespaceCombinator>(); |
| 1817 for (Combinator combinator in directive.combinators) { |
| 1818 if (combinator is HideCombinator) { |
| 1819 HideCombinatorImpl hide = new HideCombinatorImpl(); |
| 1820 hide.hiddenNames = getIdentifiers(((combinator as HideCombinator)).hidde
nNames); |
| 1821 combinators.add(hide); |
| 1822 } else { |
| 1823 ShowCombinatorImpl show = new ShowCombinatorImpl(); |
| 1824 show.shownNames = getIdentifiers(((combinator as ShowCombinator)).shownN
ames); |
| 1825 combinators.add(show); |
| 1826 } |
| 1827 } |
| 1828 return new List.from(combinators); |
| 1829 } |
| 1830 /** |
| 1831 * Every library now has a corresponding {@link LibraryElement}, so it is now
possible to resolve |
| 1832 * the import and export directives. |
| 1833 * @throws AnalysisException if the defining compilation unit for any of the l
ibraries could not |
| 1834 * be accessed |
| 1835 */ |
| 1836 void buildDirectiveModels() { |
| 1837 for (Library library in _librariesInCycles) { |
| 1838 Map<String, PrefixElementImpl> nameToPrefixMap = new Map<String, PrefixEle
mentImpl>(); |
| 1839 List<ImportElement> imports = new List<ImportElement>(); |
| 1840 List<ExportElement> exports = new List<ExportElement>(); |
| 1841 for (Directive directive in library.definingCompilationUnit.directives) { |
| 1842 if (directive is ImportDirective) { |
| 1843 ImportDirective importDirective = (directive as ImportDirective); |
| 1844 Library importedLibrary = library.getImport(importDirective); |
| 1845 ImportElementImpl importElement = new ImportElementImpl(); |
| 1846 importElement.combinators = buildCombinators(importDirective); |
| 1847 LibraryElement importedLibraryElement = importedLibrary.libraryElement
; |
| 1848 if (importedLibraryElement != null) { |
| 1849 importElement.importedLibrary = importedLibraryElement; |
| 1850 directive.element = importedLibraryElement; |
| 1851 } |
| 1852 SimpleIdentifier prefixNode = ((directive as ImportDirective)).prefix; |
| 1853 if (prefixNode != null) { |
| 1854 String prefixName = prefixNode.name; |
| 1855 PrefixElementImpl prefix = nameToPrefixMap[prefixName]; |
| 1856 if (prefix == null) { |
| 1857 prefix = new PrefixElementImpl(prefixNode); |
| 1858 nameToPrefixMap[prefixName] = prefix; |
| 1859 } |
| 1860 importElement.prefix = prefix; |
| 1861 } |
| 1862 imports.add(importElement); |
| 1863 } else if (directive is ExportDirective) { |
| 1864 ExportDirective exportDirective = (directive as ExportDirective); |
| 1865 ExportElementImpl exportElement = new ExportElementImpl(); |
| 1866 exportElement.combinators = buildCombinators(exportDirective); |
| 1867 LibraryElement exportedLibrary = library.getExport(exportDirective).li
braryElement; |
| 1868 if (exportedLibrary != null) { |
| 1869 exportElement.exportedLibrary = exportedLibrary; |
| 1870 directive.element = exportedLibrary; |
| 1871 } |
| 1872 exports.add(exportElement); |
| 1873 } |
| 1874 } |
| 1875 Source librarySource3 = library.librarySource; |
| 1876 if (!library.explicitlyImportsCore && _coreLibrarySource != librarySource3
) { |
| 1877 ImportElementImpl importElement = new ImportElementImpl(); |
| 1878 importElement.importedLibrary = _coreLibrary.libraryElement; |
| 1879 importElement.synthetic = true; |
| 1880 imports.add(importElement); |
| 1881 } |
| 1882 LibraryElementImpl libraryElement3 = library.libraryElement; |
| 1883 libraryElement3.imports = new List.from(imports); |
| 1884 libraryElement3.exports = new List.from(exports); |
| 1885 } |
| 1886 } |
| 1887 /** |
| 1888 * Build element models for all of the libraries in the current cycle. |
| 1889 * @throws AnalysisException if any of the element models cannot be built |
| 1890 */ |
| 1891 void buildElementModels() { |
| 1892 for (Library library in _librariesInCycles) { |
| 1893 LibraryElementBuilder builder = new LibraryElementBuilder(this); |
| 1894 LibraryElementImpl libraryElement = builder.buildLibrary(library); |
| 1895 library.libraryElement = libraryElement; |
| 1896 } |
| 1897 } |
| 1898 /** |
| 1899 * Resolve the type hierarchy across all of the types declared in the librarie
s in the current |
| 1900 * cycle. |
| 1901 * @throws AnalysisException if any of the type hierarchies could not be resol
ved |
| 1902 */ |
| 1903 void buildTypeHierarchies() { |
| 1904 for (Library library in _librariesInCycles) { |
| 1905 for (Source source in library.compilationUnitSources) { |
| 1906 TypeResolverVisitor visitor = new TypeResolverVisitor(library, source, _
typeProvider); |
| 1907 library.getAST(source).accept(visitor); |
| 1908 } |
| 1909 } |
| 1910 } |
| 1911 /** |
| 1912 * Compute a dependency map of libraries reachable from the given library. A d
ependency map is a |
| 1913 * table that maps individual libraries to a list of the libraries that either
import or export |
| 1914 * those libraries. |
| 1915 * <p> |
| 1916 * This map is used to compute all of the libraries involved in a cycle that i
nclude the root |
| 1917 * library. Given that we only add libraries that are reachable from the root
library, when we |
| 1918 * work backward we are guaranteed to only get libraries in the cycle. |
| 1919 * @param library the library currently being added to the dependency map |
| 1920 */ |
| 1921 Map<Library, List<Library>> computeDependencyMap(Library library) { |
| 1922 Map<Library, List<Library>> dependencyMap = new Map<Library, List<Library>>(
); |
| 1923 addToDependencyMap(library, dependencyMap, new Set<Library>()); |
| 1924 return dependencyMap; |
| 1925 } |
| 1926 /** |
| 1927 * Return a collection containing all of the libraries reachable from the give
n library that are |
| 1928 * contained in a cycle that includes the given library. |
| 1929 * @param library the library that must be included in any cycles whose member
s are to be returned |
| 1930 * @return all of the libraries referenced by the given library that have a ci
rcular reference |
| 1931 * back to the given library |
| 1932 */ |
| 1933 Set<Library> computeLibrariesInCycles(Library library) { |
| 1934 Map<Library, List<Library>> dependencyMap = computeDependencyMap(library); |
| 1935 Set<Library> librariesInCycle = new Set<Library>(); |
| 1936 addLibrariesInCycle(library, librariesInCycle, dependencyMap); |
| 1937 return librariesInCycle; |
| 1938 } |
| 1939 /** |
| 1940 * Recursively traverse the libraries reachable from the given library, creati
ng instances of the |
| 1941 * class {@link Library} to represent them, and record the references in the l
ibrary objects. |
| 1942 * @param library the library to be processed to find libaries that have not y
et been traversed |
| 1943 * @throws AnalysisException if some portion of the library graph could not be
traversed |
| 1944 */ |
| 1945 void computeLibraryDependencies(Library library) { |
| 1946 bool explicitlyImportsCore = false; |
| 1947 CompilationUnit unit = library.definingCompilationUnit; |
| 1948 for (Directive directive in unit.directives) { |
| 1949 if (directive is ImportDirective) { |
| 1950 ImportDirective importDirective = (directive as ImportDirective); |
| 1951 Source importedSource = library.getSource(importDirective.uri); |
| 1952 if (importedSource == _coreLibrarySource) { |
| 1953 explicitlyImportsCore = true; |
| 1954 } |
| 1955 Library importedLibrary = _libraryMap[importedSource]; |
| 1956 if (importedLibrary == null) { |
| 1957 importedLibrary = createLibrary(importedSource); |
| 1958 computeLibraryDependencies(importedLibrary); |
| 1959 } |
| 1960 library.addImport(importDirective, importedLibrary); |
| 1961 } else if (directive is ExportDirective) { |
| 1962 ExportDirective exportDirective = (directive as ExportDirective); |
| 1963 Source exportedSource = library.getSource(exportDirective.uri); |
| 1964 Library exportedLibrary = _libraryMap[exportedSource]; |
| 1965 if (exportedLibrary == null) { |
| 1966 exportedLibrary = createLibrary(exportedSource); |
| 1967 computeLibraryDependencies(exportedLibrary); |
| 1968 } |
| 1969 library.addExport(exportDirective, exportedLibrary); |
| 1970 } |
| 1971 } |
| 1972 library.explicitlyImportsCore = explicitlyImportsCore; |
| 1973 if (!explicitlyImportsCore && _coreLibrarySource != library.librarySource) { |
| 1974 Library importedLibrary = _libraryMap[_coreLibrarySource]; |
| 1975 if (importedLibrary == null) { |
| 1976 importedLibrary = createLibrary(_coreLibrarySource); |
| 1977 computeLibraryDependencies(importedLibrary); |
| 1978 } |
| 1979 } |
| 1980 } |
| 1981 /** |
| 1982 * Create an object to represent the information about the library defined by
the compilation unit |
| 1983 * with the given source. |
| 1984 * @param librarySource the source of the library's defining compilation unit |
| 1985 * @return the library object that was created |
| 1986 */ |
| 1987 Library createLibrary(Source librarySource) { |
| 1988 Library library = new Library(_analysisContext, _errorListener, librarySourc
e); |
| 1989 _libraryMap[librarySource] = library; |
| 1990 return library; |
| 1991 } |
| 1992 /** |
| 1993 * Return an array containing the lexical identifiers associated with the node
s in the given list. |
| 1994 * @param names the AST nodes representing the identifiers |
| 1995 * @return the lexical identifiers associated with the nodes in the list |
| 1996 */ |
| 1997 List<String> getIdentifiers(NodeList<SimpleIdentifier> names) { |
| 1998 int count = names.length; |
| 1999 List<String> identifiers = new List<String>.fixedLength(count); |
| 2000 for (int i = 0; i < count; i++) { |
| 2001 identifiers[i] = names[i].name; |
| 2002 } |
| 2003 return identifiers; |
| 2004 } |
| 2005 /** |
| 2006 * As the final step in the process, record the resolved element models with t
he analysis context. |
| 2007 */ |
| 2008 void recordLibraryElements() { |
| 2009 Map<Source, LibraryElement> elementMap = new Map<Source, LibraryElement>(); |
| 2010 for (Library library in _librariesInCycles) { |
| 2011 elementMap[library.librarySource] = library.libraryElement; |
| 2012 } |
| 2013 _analysisContext.recordLibraryElements(elementMap); |
| 2014 } |
| 2015 /** |
| 2016 * Resolve the identifiers and perform type analysis in the libraries in the c
urrent cycle. |
| 2017 * @throws AnalysisException if any of the identifiers could not be resolved o
r if any of the |
| 2018 * libraries could not have their types analyzed |
| 2019 */ |
| 2020 void resolveReferencesAndTypes() { |
| 2021 for (Library library in _librariesInCycles) { |
| 2022 resolveReferencesAndTypes2(library); |
| 2023 } |
| 2024 } |
| 2025 /** |
| 2026 * Resolve the identifiers and perform type analysis in the given library. |
| 2027 * @param library the library to be resolved |
| 2028 * @throws AnalysisException if any of the identifiers could not be resolved o
r if the types in |
| 2029 * the library cannot be analyzed |
| 2030 */ |
| 2031 void resolveReferencesAndTypes2(Library library) { |
| 2032 for (Source source in library.compilationUnitSources) { |
| 2033 ResolverVisitor visitor = new ResolverVisitor(library, source, _typeProvid
er); |
| 2034 library.getAST(source).accept(visitor); |
| 2035 } |
| 2036 } |
| 2037 } |
| 2038 /** |
| 2039 * Instances of the class {@code ResolverVisitor} are used to resolve the nodes
within a single |
| 2040 * compilation unit. |
| 2041 */ |
| 2042 class ResolverVisitor extends ScopedVisitor { |
| 2043 /** |
| 2044 * The object used to resolve the element associated with the current node. |
| 2045 */ |
| 2046 ElementResolver _elementResolver; |
| 2047 /** |
| 2048 * The object used to compute the type associated with the current node. |
| 2049 */ |
| 2050 StaticTypeAnalyzer _typeAnalyzer; |
| 2051 /** |
| 2052 * The class element representing the class containing the current node, or {@
code null} if the |
| 2053 * current node is not contained in a class. |
| 2054 */ |
| 2055 ClassElement _enclosingClass = null; |
| 2056 /** |
| 2057 * The element representing the function containing the current node, or {@cod
e null} if the |
| 2058 * current node is not contained in a function. |
| 2059 */ |
| 2060 ExecutableElement _enclosingFunction = null; |
| 2061 /** |
| 2062 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. |
| 2063 * @param library the library containing the compilation unit being resolved |
| 2064 * @param source the source representing the compilation unit being visited |
| 2065 * @param typeProvider the object used to access the types from the core libra
ry |
| 2066 */ |
| 2067 ResolverVisitor(Library library, Source source, TypeProvider typeProvider) : s
uper(library, source, typeProvider) { |
| 2068 this._elementResolver = new ElementResolver(this); |
| 2069 this._typeAnalyzer = new StaticTypeAnalyzer(this); |
| 2070 } |
| 2071 Object visitClassDeclaration(ClassDeclaration node) { |
| 2072 ClassElement outerType = _enclosingClass; |
| 2073 try { |
| 2074 _enclosingClass = node.element; |
| 2075 _typeAnalyzer.thisType = _enclosingClass == null ? null : _enclosingClass.
type; |
| 2076 super.visitClassDeclaration(node); |
| 2077 } finally { |
| 2078 _typeAnalyzer.thisType = outerType == null ? null : outerType.type; |
| 2079 _enclosingClass = outerType; |
| 2080 } |
| 2081 return null; |
| 2082 } |
| 2083 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 2084 ExecutableElement outerFunction = _enclosingFunction; |
| 2085 try { |
| 2086 SimpleIdentifier functionName = node.name; |
| 2087 _enclosingFunction = (functionName.element as ExecutableElement); |
| 2088 super.visitFunctionDeclaration(node); |
| 2089 } finally { |
| 2090 _enclosingFunction = outerFunction; |
| 2091 } |
| 2092 return null; |
| 2093 } |
| 2094 Object visitFunctionExpression(FunctionExpression node) { |
| 2095 ExecutableElement outerFunction = _enclosingFunction; |
| 2096 try { |
| 2097 _enclosingFunction = node.element; |
| 2098 super.visitFunctionExpression(node); |
| 2099 } finally { |
| 2100 _enclosingFunction = outerFunction; |
| 2101 } |
| 2102 return null; |
| 2103 } |
| 2104 Object visitLibraryIdentifier(LibraryIdentifier node) => null; |
| 2105 Object visitMethodDeclaration(MethodDeclaration node) { |
| 2106 ExecutableElement outerFunction = _enclosingFunction; |
| 2107 try { |
| 2108 _enclosingFunction = node.element; |
| 2109 super.visitMethodDeclaration(node); |
| 2110 } finally { |
| 2111 _enclosingFunction = outerFunction; |
| 2112 } |
| 2113 return null; |
| 2114 } |
| 2115 Object visitNode(ASTNode node) { |
| 2116 node.visitChildren(this); |
| 2117 node.accept(_elementResolver); |
| 2118 node.accept(_typeAnalyzer); |
| 2119 return null; |
| 2120 } |
| 2121 Object visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 2122 SimpleIdentifier prefix6 = node.prefix; |
| 2123 if (prefix6 != null) { |
| 2124 prefix6.accept(this); |
| 2125 } |
| 2126 node.accept(_elementResolver); |
| 2127 node.accept(_typeAnalyzer); |
| 2128 return null; |
| 2129 } |
| 2130 Object visitPropertyAccess(PropertyAccess node) { |
| 2131 Expression target5 = node.target; |
| 2132 if (target5 != null) { |
| 2133 target5.accept(this); |
| 2134 } |
| 2135 node.accept(_elementResolver); |
| 2136 node.accept(_typeAnalyzer); |
| 2137 return null; |
| 2138 } |
| 2139 Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation
node) { |
| 2140 ArgumentList argumentList11 = node.argumentList; |
| 2141 if (argumentList11 != null) { |
| 2142 argumentList11.accept(this); |
| 2143 } |
| 2144 node.accept(_elementResolver); |
| 2145 node.accept(_typeAnalyzer); |
| 2146 return null; |
| 2147 } |
| 2148 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 2149 ArgumentList argumentList12 = node.argumentList; |
| 2150 if (argumentList12 != null) { |
| 2151 argumentList12.accept(this); |
| 2152 } |
| 2153 node.accept(_elementResolver); |
| 2154 node.accept(_typeAnalyzer); |
| 2155 return null; |
| 2156 } |
| 2157 Object visitTypeName(TypeName node) => null; |
| 2158 /** |
| 2159 * Return the class element representing the class containing the current node
, or {@code null} if |
| 2160 * the current node is not contained in a class. |
| 2161 * @return the class element representing the class containing the current nod
e |
| 2162 */ |
| 2163 ClassElement get enclosingClass => _enclosingClass; |
| 2164 /** |
| 2165 * Return the element representing the function containing the current node, o
r {@code null} if |
| 2166 * the current node is not contained in a function. |
| 2167 * @return the element representing the function containing the current node |
| 2168 */ |
| 2169 ExecutableElement get enclosingFunction => _enclosingFunction; |
| 2170 } |
| 2171 /** |
| 2172 * The abstract class {@code ScopedVisitor} maintains name and label scopes as a
n AST structure is |
| 2173 * being visited. |
| 2174 */ |
| 2175 abstract class ScopedVisitor extends GeneralizingASTVisitor<Object> { |
| 2176 /** |
| 2177 * The element for the library containing the compilation unit being visited. |
| 2178 */ |
| 2179 LibraryElement _definingLibrary; |
| 2180 /** |
| 2181 * The source representing the compilation unit being visited. |
| 2182 */ |
| 2183 Source _source; |
| 2184 /** |
| 2185 * The error listener that will be informed of any errors that are found durin
g resolution. |
| 2186 */ |
| 2187 AnalysisErrorListener _errorListener; |
| 2188 /** |
| 2189 * The scope used to resolve identifiers. |
| 2190 */ |
| 2191 Scope _nameScope; |
| 2192 /** |
| 2193 * The object used to access the types from the core library. |
| 2194 */ |
| 2195 TypeProvider _typeProvider; |
| 2196 /** |
| 2197 * The scope used to resolve labels for {@code break} and {@code continue} sta
tements, or{@code null} if no labels have been defined in the current context. |
| 2198 */ |
| 2199 LabelScope _labelScope; |
| 2200 /** |
| 2201 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. |
| 2202 * @param library the library containing the compilation unit being resolved |
| 2203 * @param source the source representing the compilation unit being visited |
| 2204 * @param typeProvider the object used to access the types from the core libra
ry |
| 2205 */ |
| 2206 ScopedVisitor(Library library, Source source, TypeProvider typeProvider) { |
| 2207 this._definingLibrary = library.libraryElement; |
| 2208 this._source = source; |
| 2209 LibraryScope libraryScope2 = library.libraryScope; |
| 2210 this._errorListener = libraryScope2.errorListener; |
| 2211 this._nameScope = libraryScope2; |
| 2212 this._typeProvider = typeProvider; |
| 2213 } |
| 2214 /** |
| 2215 * Return the library element for the library containing the compilation unit
being resolved. |
| 2216 * @return the library element for the library containing the compilation unit
being resolved |
| 2217 */ |
| 2218 LibraryElement get definingLibrary => _definingLibrary; |
| 2219 /** |
| 2220 * Return the object used to access the types from the core library. |
| 2221 * @return the object used to access the types from the core library |
| 2222 */ |
| 2223 TypeProvider get typeProvider => _typeProvider; |
| 2224 Object visitBlock(Block node) { |
| 2225 Scope outerScope = _nameScope; |
| 2226 _nameScope = new EnclosedScope(_nameScope); |
| 2227 try { |
| 2228 super.visitBlock(node); |
| 2229 } finally { |
| 2230 _nameScope = outerScope; |
| 2231 } |
| 2232 return null; |
| 2233 } |
| 2234 Object visitClassDeclaration(ClassDeclaration node) { |
| 2235 Scope outerScope = _nameScope; |
| 2236 try { |
| 2237 _nameScope = new ClassScope(_nameScope, node.element); |
| 2238 super.visitClassDeclaration(node); |
| 2239 } finally { |
| 2240 _nameScope = outerScope; |
| 2241 } |
| 2242 return null; |
| 2243 } |
| 2244 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 2245 Scope outerScope = _nameScope; |
| 2246 try { |
| 2247 _nameScope = new ClassScope(_nameScope, node.element); |
| 2248 super.visitClassTypeAlias(node); |
| 2249 } finally { |
| 2250 _nameScope = outerScope; |
| 2251 } |
| 2252 return null; |
| 2253 } |
| 2254 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 2255 Scope outerScope = _nameScope; |
| 2256 try { |
| 2257 _nameScope = new FunctionScope(_nameScope, node.element); |
| 2258 super.visitConstructorDeclaration(node); |
| 2259 } finally { |
| 2260 _nameScope = outerScope; |
| 2261 } |
| 2262 return null; |
| 2263 } |
| 2264 Object visitDoStatement(DoStatement node) { |
| 2265 LabelScope outerScope = _labelScope; |
| 2266 _labelScope = new LabelScope.con1(outerScope, false, false); |
| 2267 try { |
| 2268 super.visitDoStatement(node); |
| 2269 } finally { |
| 2270 _labelScope = outerScope; |
| 2271 } |
| 2272 return null; |
| 2273 } |
| 2274 Object visitForEachStatement(ForEachStatement node) { |
| 2275 LabelScope outerScope = _labelScope; |
| 2276 _labelScope = new LabelScope.con1(outerScope, false, false); |
| 2277 try { |
| 2278 super.visitForEachStatement(node); |
| 2279 } finally { |
| 2280 _labelScope = outerScope; |
| 2281 } |
| 2282 return null; |
| 2283 } |
| 2284 Object visitForStatement(ForStatement node) { |
| 2285 LabelScope outerScope = _labelScope; |
| 2286 _labelScope = new LabelScope.con1(outerScope, false, false); |
| 2287 try { |
| 2288 super.visitForStatement(node); |
| 2289 } finally { |
| 2290 _labelScope = outerScope; |
| 2291 } |
| 2292 return null; |
| 2293 } |
| 2294 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 2295 FunctionElement function = node.element; |
| 2296 Scope outerScope = _nameScope; |
| 2297 try { |
| 2298 _nameScope = new FunctionScope(_nameScope, function); |
| 2299 super.visitFunctionDeclaration(node); |
| 2300 } finally { |
| 2301 _nameScope = outerScope; |
| 2302 } |
| 2303 _nameScope.define(function); |
| 2304 return null; |
| 2305 } |
| 2306 Object visitFunctionExpression(FunctionExpression node) { |
| 2307 Scope outerScope = _nameScope; |
| 2308 try { |
| 2309 _nameScope = new FunctionScope(_nameScope, node.element); |
| 2310 super.visitFunctionExpression(node); |
| 2311 } finally { |
| 2312 _nameScope = outerScope; |
| 2313 } |
| 2314 return null; |
| 2315 } |
| 2316 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 2317 Scope outerScope = _nameScope; |
| 2318 try { |
| 2319 _nameScope = new FunctionTypeScope(_nameScope, node.element); |
| 2320 super.visitFunctionTypeAlias(node); |
| 2321 } finally { |
| 2322 _nameScope = outerScope; |
| 2323 } |
| 2324 return null; |
| 2325 } |
| 2326 Object visitLabeledStatement(LabeledStatement node) { |
| 2327 LabelScope outerScope = addScopesFor(node.labels); |
| 2328 try { |
| 2329 super.visitLabeledStatement(node); |
| 2330 } finally { |
| 2331 _labelScope = outerScope; |
| 2332 } |
| 2333 return null; |
| 2334 } |
| 2335 Object visitMethodDeclaration(MethodDeclaration node) { |
| 2336 Scope outerScope = _nameScope; |
| 2337 try { |
| 2338 _nameScope = new FunctionScope(_nameScope, node.element); |
| 2339 super.visitMethodDeclaration(node); |
| 2340 } finally { |
| 2341 _nameScope = outerScope; |
| 2342 } |
| 2343 return null; |
| 2344 } |
| 2345 Object visitSwitchCase(SwitchCase node) { |
| 2346 node.expression.accept(this); |
| 2347 LabelScope outerLabelScope = addScopesFor(node.labels); |
| 2348 Scope outerNameScope = _nameScope; |
| 2349 _nameScope = new EnclosedScope(_nameScope); |
| 2350 try { |
| 2351 node.statements.accept(this); |
| 2352 } finally { |
| 2353 _nameScope = outerNameScope; |
| 2354 _labelScope = outerLabelScope; |
| 2355 } |
| 2356 return null; |
| 2357 } |
| 2358 Object visitSwitchDefault(SwitchDefault node) { |
| 2359 LabelScope outerLabelScope = addScopesFor(node.labels); |
| 2360 Scope outerNameScope = _nameScope; |
| 2361 _nameScope = new EnclosedScope(_nameScope); |
| 2362 try { |
| 2363 node.statements.accept(this); |
| 2364 } finally { |
| 2365 _nameScope = outerNameScope; |
| 2366 _labelScope = outerLabelScope; |
| 2367 } |
| 2368 return null; |
| 2369 } |
| 2370 Object visitSwitchStatement(SwitchStatement node) { |
| 2371 LabelScope outerScope = _labelScope; |
| 2372 _labelScope = new LabelScope.con1(outerScope, true, false); |
| 2373 for (SwitchMember member in node.members) { |
| 2374 for (Label label in member.labels) { |
| 2375 SimpleIdentifier labelName = label.label; |
| 2376 LabelElement labelElement = (labelName.element as LabelElement); |
| 2377 _labelScope = new LabelScope.con2(outerScope, labelName.name, labelEleme
nt); |
| 2378 } |
| 2379 } |
| 2380 try { |
| 2381 super.visitSwitchStatement(node); |
| 2382 } finally { |
| 2383 _labelScope = outerScope; |
| 2384 } |
| 2385 return null; |
| 2386 } |
| 2387 Object visitVariableDeclaration(VariableDeclaration node) { |
| 2388 if (node.parent.parent is! TopLevelVariableDeclaration) { |
| 2389 VariableElement element19 = node.element; |
| 2390 if (element19 != null) { |
| 2391 _nameScope.define(element19); |
| 2392 } |
| 2393 } |
| 2394 super.visitVariableDeclaration(node); |
| 2395 return null; |
| 2396 } |
| 2397 Object visitWhileStatement(WhileStatement node) { |
| 2398 LabelScope outerScope = _labelScope; |
| 2399 _labelScope = new LabelScope.con1(outerScope, false, false); |
| 2400 try { |
| 2401 super.visitWhileStatement(node); |
| 2402 } finally { |
| 2403 _labelScope = outerScope; |
| 2404 } |
| 2405 return null; |
| 2406 } |
| 2407 /** |
| 2408 * Return the label scope in which the current node is being resolved. |
| 2409 * @return the label scope in which the current node is being resolved |
| 2410 */ |
| 2411 LabelScope get labelScope => _labelScope; |
| 2412 /** |
| 2413 * Return the name scope in which the current node is being resolved. |
| 2414 * @return the name scope in which the current node is being resolved |
| 2415 */ |
| 2416 Scope get nameScope => _nameScope; |
| 2417 /** |
| 2418 * Report an error with the given error code and arguments. |
| 2419 * @param errorCode the error code of the error to be reported |
| 2420 * @param node the node specifying the location of the error |
| 2421 * @param arguments the arguments to the error, used to compose the error mess
age |
| 2422 */ |
| 2423 void reportError(ResolverErrorCode errorCode, ASTNode node, List<Object> argum
ents) { |
| 2424 _errorListener.onError(new AnalysisError.con2(_source, node.offset, node.len
gth, errorCode, [arguments])); |
| 2425 } |
| 2426 /** |
| 2427 * Report an error with the given error code and arguments. |
| 2428 * @param errorCode the error code of the error to be reported |
| 2429 * @param token the token specifying the location of the error |
| 2430 * @param arguments the arguments to the error, used to compose the error mess
age |
| 2431 */ |
| 2432 void reportError2(ResolverErrorCode errorCode, Token token, List<Object> argum
ents) { |
| 2433 _errorListener.onError(new AnalysisError.con2(_source, token.offset, token.l
ength, errorCode, [arguments])); |
| 2434 } |
| 2435 /** |
| 2436 * Add scopes for each of the given labels. |
| 2437 * @param labels the labels for which new scopes are to be added |
| 2438 * @return the scope that was in effect before the new scopes were added |
| 2439 */ |
| 2440 LabelScope addScopesFor(NodeList<Label> labels) { |
| 2441 LabelScope outerScope = _labelScope; |
| 2442 for (Label label in labels) { |
| 2443 SimpleIdentifier labelNameNode = label.label; |
| 2444 String labelName = labelNameNode.name; |
| 2445 LabelElement labelElement = (labelNameNode.element as LabelElement); |
| 2446 _labelScope = new LabelScope.con2(_labelScope, labelName, labelElement); |
| 2447 } |
| 2448 return outerScope; |
| 2449 } |
| 2450 } |
| 2451 /** |
| 2452 * Instances of the class {@code StaticTypeAnalyzer} perform two type-related ta
sks. First, they |
| 2453 * compute the static type of every expression. Second, they look for any static
type errors or |
| 2454 * warnings that might need to be generated. The requirements for the type analy
zer are: |
| 2455 * <ol> |
| 2456 * <li>Every element that refers to types should be fully populated. |
| 2457 * <li>Every node representing an expression should be resolved to the Type of t
he expression.</li> |
| 2458 * </ol> |
| 2459 */ |
| 2460 class StaticTypeAnalyzer extends SimpleASTVisitor<Object> { |
| 2461 /** |
| 2462 * The resolver driving this participant. |
| 2463 */ |
| 2464 ResolverVisitor _resolver; |
| 2465 /** |
| 2466 * The object providing access to the types defined by the language. |
| 2467 */ |
| 2468 TypeProvider _typeProvider; |
| 2469 /** |
| 2470 * The type representing the class containing the nodes being analyzed, or {@c
ode null} if the |
| 2471 * nodes are not within a class. |
| 2472 */ |
| 2473 InterfaceType _thisType; |
| 2474 /** |
| 2475 * Initialize a newly created type analyzer. |
| 2476 * @param resolver the resolver driving this participant |
| 2477 */ |
| 2478 StaticTypeAnalyzer(ResolverVisitor resolver) { |
| 2479 this._resolver = resolver; |
| 2480 _typeProvider = resolver.typeProvider; |
| 2481 } |
| 2482 /** |
| 2483 * Set the type of the class being analyzed to the given type. |
| 2484 * @param thisType the type representing the class containing the nodes being
analyzed |
| 2485 */ |
| 2486 void set thisType(InterfaceType thisType2) { |
| 2487 this._thisType = thisType2; |
| 2488 } |
| 2489 /** |
| 2490 * The Dart Language Specification, 12.5: <blockquote>The static type of a str
ing literal is{@code String}.</blockquote> |
| 2491 */ |
| 2492 Object visitAdjacentStrings(AdjacentStrings node) => recordType(node, _typePro
vider.stringType); |
| 2493 /** |
| 2494 * The Dart Language Specification, 12.33: <blockquote>The static type of an a
rgument definition |
| 2495 * test is {@code bool}.</blockquote> |
| 2496 */ |
| 2497 Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) => recordType(
node, _typeProvider.boolType); |
| 2498 /** |
| 2499 * The Dart Language Specification, 12.32: <blockquote>... the cast expression
<i>e as T</i> ... |
| 2500 * <p> |
| 2501 * It is a static warning if <i>T</i> does not denote a type available in the
current lexical |
| 2502 * scope. |
| 2503 * <p> |
| 2504 * The static type of a cast expression <i>e as T</i> is <i>T</i>.</blockquote
> |
| 2505 */ |
| 2506 Object visitAsExpression(AsExpression node) => recordType(node, getType2(node.
type)); |
| 2507 /** |
| 2508 * The Dart Language Specification, 12.18: <blockquote> ... an assignment <i>a
</i> of the form |
| 2509 * <i>v = e</i> ... |
| 2510 * <p> |
| 2511 * It is a static type warning if the static type of <i>e</i> may not be assig
ned to the static |
| 2512 * type of <i>v</i>. |
| 2513 * <p> |
| 2514 * The static type of the expression <i>v = e</i> is the static type of <i>e</
i>. |
| 2515 * <p> |
| 2516 * ... an assignment of the form <i>C.v = e</i> ... |
| 2517 * <p> |
| 2518 * It is a static type warning if the static type of <i>e</i> may not be assig
ned to the static |
| 2519 * type of <i>C.v</i>. |
| 2520 * <p> |
| 2521 * The static type of the expression <i>C.v = e</i> is the static type of <i>e
</i>. |
| 2522 * <p> |
| 2523 * ... an assignment of the form <i>e<sub>1</sub>.v = e<sub>2</sub></i> ... |
| 2524 * <p> |
| 2525 * Let <i>T</i> be the static type of <i>e<sub>1</sub></i>. It is a static typ
e warning if |
| 2526 * <i>T</i> does not have an accessible instance setter named <i>v=</i>. It is
a static type |
| 2527 * warning if the static type of <i>e<sub>2</sub></i> may not be assigned to <
i>T</i>. |
| 2528 * <p> |
| 2529 * The static type of the expression <i>e<sub>1</sub>.v = e<sub>2</sub></i> is
the static type of |
| 2530 * <i>e<sub>2</sub></i>. |
| 2531 * <p> |
| 2532 * ... an assignment of the form <i>e<sub>1</sub>[e<sub>2</sub>] = e<sub>3</su
b></i> ... |
| 2533 * <p> |
| 2534 * The static type of the expression <i>e<sub>1</sub>[e<sub>2</sub>] = e<sub>3
</sub></i> is the |
| 2535 * static type of <i>e<sub>3</sub></i>. |
| 2536 * <p> |
| 2537 * A compound assignment of the form <i>v op= e</i> is equivalent to <i>v = v
op e</i>. A compound |
| 2538 * assignment of the form <i>C.v op= e</i> is equivalent to <i>C.v = C.v op e<
/i>. A compound |
| 2539 * assignment of the form <i>e<sub>1</sub>.v op= e<sub>2</sub></i> is equivale
nt to <i>((x) => x.v |
| 2540 * = 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 |
| 2541 * <i>e<sub>2</sub></i>. A compound assignment of the form <i>e<sub>1</sub>[e<
sub>2</sub>] op= |
| 2542 * 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>, |
| 2543 * e<sub>2</sub>)</i> where <i>a</i> and <i>i</i> are a variables that are not
used in |
| 2544 * <i>e<sub>3</sub></i>. </blockquote> |
| 2545 */ |
| 2546 Object visitAssignmentExpression(AssignmentExpression node) { |
| 2547 TokenType operator11 = node.operator.type; |
| 2548 if (operator11 != TokenType.EQ) { |
| 2549 return recordReturnType(node, node.element); |
| 2550 } |
| 2551 Type2 leftType = getType(node.leftHandSide); |
| 2552 Type2 rightType = getType(node.rightHandSide); |
| 2553 if (!rightType.isAssignableTo(leftType)) { |
| 2554 } |
| 2555 return recordType(node, rightType); |
| 2556 } |
| 2557 /** |
| 2558 * The Dart Language Specification, 12.20: <blockquote>The static type of a lo
gical boolean |
| 2559 * expression is {@code bool}.</blockquote> |
| 2560 * <p> |
| 2561 * The Dart Language Specification, 12.21:<blockquote>A bitwise expression of
the form |
| 2562 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n |
| 2563 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A bitwise expression of the form <i
>super op |
| 2564 * e<sub>2</sub></i> is equivalent to the method invocation |
| 2565 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> |
| 2566 * <p> |
| 2567 * The Dart Language Specification, 12.22: <blockquote>The static type of an e
quality expression |
| 2568 * is {@code bool}.</blockquote> |
| 2569 * <p> |
| 2570 * The Dart Language Specification, 12.23: <blockquote>A relational expression
of the form |
| 2571 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n |
| 2572 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A relational expression of the form
<i>super op |
| 2573 * e<sub>2</sub></i> is equivalent to the method invocation |
| 2574 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> |
| 2575 * <p> |
| 2576 * The Dart Language Specification, 12.24: <blockquote>A shift expression of t
he form |
| 2577 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n |
| 2578 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A shift expression of the form <i>s
uper op |
| 2579 * e<sub>2</sub></i> is equivalent to the method invocation |
| 2580 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> |
| 2581 * <p> |
| 2582 * The Dart Language Specification, 12.25: <blockquote>An additive expression
of the form |
| 2583 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n |
| 2584 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. An additive expression of the form
<i>super op |
| 2585 * e<sub>2</sub></i> is equivalent to the method invocation |
| 2586 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> |
| 2587 * <p> |
| 2588 * The Dart Language Specification, 12.26: <blockquote>A multiplicative expres
sion of the form |
| 2589 * <i>e<sub>1</sub> op e<sub>2</sub></i> is equivalent to the method invocatio
n |
| 2590 * <i>e<sub>1</sub>.op(e<sub>2</sub>)</i>. A multiplicative expression of the
form <i>super op |
| 2591 * e<sub>2</sub></i> is equivalent to the method invocation |
| 2592 * <i>super.op(e<sub>2</sub>)</i>.</blockquote> |
| 2593 */ |
| 2594 Object visitBinaryExpression(BinaryExpression node) { |
| 2595 TokenType operator12 = node.operator.type; |
| 2596 if (operator12 == TokenType.AMPERSAND_AMPERSAND || operator12 == TokenType.B
AR_BAR || operator12 == TokenType.EQ_EQ || operator12 == TokenType.BANG_EQ) { |
| 2597 return recordType(node, _typeProvider.boolType); |
| 2598 } |
| 2599 return recordReturnType(node, node.element); |
| 2600 } |
| 2601 /** |
| 2602 * The Dart Language Specification, 12.4: <blockquote>The static type of a boo
lean literal is{@code bool}.</blockquote> |
| 2603 */ |
| 2604 Object visitBooleanLiteral(BooleanLiteral node) => recordType(node, _typeProvi
der.boolType); |
| 2605 /** |
| 2606 * The Dart Language Specification, 12.15.2: <blockquote>A cascaded method inv
ocation expression |
| 2607 * of the form <i>e..suffix</i> is equivalent to the expression <i>(t) {t.suff
ix; return |
| 2608 * t;}(e)</i>.</blockquote> |
| 2609 */ |
| 2610 Object visitCascadeExpression(CascadeExpression node) => recordType(node, getT
ype(node.target)); |
| 2611 /** |
| 2612 * The Dart Language Specification, 12.19: <blockquote> ... a conditional expr
ession <i>c</i> of |
| 2613 * the form <i>e<sub>1</sub> ? e<sub>2</sub> : e<sub>3</sub></i> ... |
| 2614 * <p> |
| 2615 * It is a static type warning if the type of e<sub>1</sub> may not be assigne
d to {@code bool}. |
| 2616 * <p> |
| 2617 * The static type of <i>c</i> is the least upper bound of the static type of
<i>e<sub>2</sub></i> |
| 2618 * and the static type of <i>e<sub>3</sub></i>.</blockquote> |
| 2619 */ |
| 2620 Object visitConditionalExpression(ConditionalExpression node) { |
| 2621 Type2 conditionType = getType(node.condition); |
| 2622 if (conditionType != null && !conditionType.isAssignableTo(_typeProvider.boo
lType)) { |
| 2623 _resolver.reportError(ResolverErrorCode.NON_BOOLEAN_CONDITION, node.condit
ion, []); |
| 2624 } |
| 2625 Type2 thenType = getType(node.thenExpression); |
| 2626 Type2 elseType = getType(node.elseExpression); |
| 2627 if (thenType == null) { |
| 2628 return recordType(node, _typeProvider.dynamicType); |
| 2629 } |
| 2630 Type2 resultType = thenType.getLeastUpperBound(elseType); |
| 2631 return recordType(node, resultType); |
| 2632 } |
| 2633 /** |
| 2634 * The Dart Language Specification, 12.3: <blockquote>The static type of a lit
eral double is{@code double}.</blockquote> |
| 2635 */ |
| 2636 Object visitDoubleLiteral(DoubleLiteral node) => recordType(node, _typeProvide
r.doubleType); |
| 2637 /** |
| 2638 * The Dart Language Specification, 12.9: <blockquote>The static type of a fun
ction literal of the |
| 2639 * form <i>(T<sub>1</sub> a<sub>1</sub>, …, T<sub>n</sub> a<sub>n</sub>
, [T<sub>n+1</sub> |
| 2640 * x<sub>n+1</sub> = d1, …, T<sub>n+k</sub> x<sub>n+k</sub> = dk]) => e
</i> is |
| 2641 * <i>(T<sub>1</sub>, …, Tn, [T<sub>n+1</sub> x<sub>n+1</sub>, …
, T<sub>n+k</sub> |
| 2642 * x<sub>n+k</sub>]) → T<sub>0</sub></i>, where <i>T<sub>0</sub></i> is t
he static type of |
| 2643 * <i>e</i>. In any case where <i>T<sub>i</sub>, 1 <= i <= n</i>, is not
specified, it is |
| 2644 * considered to have been specified as dynamic. |
| 2645 * <p> |
| 2646 * The static type of a function literal of the form <i>(T<sub>1</sub> a<sub>1
</sub>, …, |
| 2647 * 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> |
| 2648 * x<sub>n+k</sub> : dk}) => e</i> is <i>(T<sub>1</sub>, …, T<sub>n</su
b>, {T<sub>n+1</sub> |
| 2649 * x<sub>n+1</sub>, …, T<sub>n+k</sub> x<sub>n+k</sub>}) → T<sub>0
</sub></i>, where |
| 2650 * <i>T<sub>0</sub></i> is the static type of <i>e</i>. In any case where <i>T
<sub>i</sub>, 1 |
| 2651 * <= i <= n</i>, is not specified, it is considered to have been specif
ied as dynamic. |
| 2652 * <p> |
| 2653 * The static type of a function literal of the form <i>(T<sub>1</sub> a<sub>1
</sub>, …, |
| 2654 * 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> |
| 2655 * x<sub>n+k</sub> = dk]) {s}</i> is <i>(T<sub>1</sub>, …, T<sub>n</sub
>, [T<sub>n+1</sub> |
| 2656 * x<sub>n+1</sub>, …, T<sub>n+k</sub> x<sub>n+k</sub>]) → dynamic
</i>. In any case |
| 2657 * where <i>T<sub>i</sub>, 1 <= i <= n</i>, is not specified, it is cons
idered to have been |
| 2658 * specified as dynamic. |
| 2659 * <p> |
| 2660 * The static type of a function literal of the form <i>(T<sub>1</sub> a<sub>1
</sub>, …, |
| 2661 * 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> |
| 2662 * x<sub>n+k</sub> : dk}) {s}</i> is <i>(T<sub>1</sub>, …, T<sub>n</sub
>, {T<sub>n+1</sub> |
| 2663 * x<sub>n+1</sub>, …, T<sub>n+k</sub> x<sub>n+k</sub>}) → dynamic
</i>. In any case |
| 2664 * where <i>T<sub>i</sub>, 1 <= i <= n</i>, is not specified, it is cons
idered to have been |
| 2665 * specified as dynamic.</blockquote> |
| 2666 */ |
| 2667 Object visitFunctionExpression(FunctionExpression node) { |
| 2668 FunctionTypeImpl functionType = (node.element.type as FunctionTypeImpl); |
| 2669 setTypeInformation(functionType, computeReturnType(node), node.parameters); |
| 2670 return recordType(node, functionType); |
| 2671 } |
| 2672 /** |
| 2673 * The Dart Language Specification, 12.14.4: <blockquote>A function expression
invocation <i>i</i> |
| 2674 * has the form <i>e<sub>f</sub>(a<sub>1</sub>, …, a<sub>n</sub>, x<sub
>n+1</sub>: |
| 2675 * a<sub>n+1</sub>, …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>, where <i>
e<sub>f</sub></i> is |
| 2676 * an expression. |
| 2677 * <p> |
| 2678 * It is a static type warning if the static type <i>F</i> of <i>e<sub>f</sub>
</i> may not be |
| 2679 * assigned to a function type. |
| 2680 * <p> |
| 2681 * If <i>F</i> is not a function type, the static type of <i>i</i> is dynamic.
Otherwise the |
| 2682 * static type of <i>i</i> is the declared return type of <i>F</i>.</blockquot
e> |
| 2683 */ |
| 2684 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) =>
recordReturnType(node, node.element); |
| 2685 /** |
| 2686 * The Dart Language Specification, 12.29: <blockquote>An assignable expressio
n of the form |
| 2687 * <i>e<sub>1</sub>[e<sub>2</sub>]</i> is evaluated as a method invocation of
the operator method |
| 2688 * <i>[]</i> on <i>e<sub>1</sub></i> with argument <i>e<sub>2</sub></i>.</bloc
kquote> |
| 2689 */ |
| 2690 Object visitIndexExpression(IndexExpression node) => recordReturnType(node, no
de.element); |
| 2691 /** |
| 2692 * The Dart Language Specification, 12.11.1: <blockquote>The static type of a
new expression of |
| 2693 * either the form <i>new T.id(a<sub>1</sub>, …, a<sub>n</sub>)</i> or
the form <i>new |
| 2694 * T(a<sub>1</sub>, …, a<sub>n</sub>)</i> is <i>T</i>.</blockquote> |
| 2695 * <p> |
| 2696 * The Dart Language Specification, 12.11.2: <blockquote>The static type of a
constant object |
| 2697 * expression of either the form <i>const T.id(a<sub>1</sub>, …, a<sub>
n</sub>)</i> or the |
| 2698 * form <i>const T(a<sub>1</sub>, …, a<sub>n</sub>)</i> is <i>T</i>. </
blockquote> |
| 2699 */ |
| 2700 Object visitInstanceCreationExpression(InstanceCreationExpression node) => rec
ordReturnType(node, node.element); |
| 2701 /** |
| 2702 * The Dart Language Specification, 12.3: <blockquote>The static type of an in
teger literal is{@code int}.</blockquote> |
| 2703 */ |
| 2704 Object visitIntegerLiteral(IntegerLiteral node) => recordType(node, _typeProvi
der.intType); |
| 2705 /** |
| 2706 * The Dart Language Specification, 12.31: <blockquote>It is a static warning
if <i>T</i> does not |
| 2707 * denote a type available in the current lexical scope. |
| 2708 * <p> |
| 2709 * The static type of an is-expression is {@code bool}.</blockquote> |
| 2710 */ |
| 2711 Object visitIsExpression(IsExpression node) => recordType(node, _typeProvider.
boolType); |
| 2712 /** |
| 2713 * The Dart Language Specification, 12.6: <blockquote>The static type of a lis
t literal of the |
| 2714 * form <i><b>const</b> <E>[e<sub>1</sub>, …, e<sub>n</sub>]</i>
or the form |
| 2715 * <i><E>[e<sub>1</sub>, …, e<sub>n</sub>]</i> is {@code List<
E>}. The static |
| 2716 * type a list literal of the form <i><b>const</b> [e<sub>1</sub>, …, e
<sub>n</sub>]</i> or |
| 2717 * the form <i>[e<sub>1</sub>, …, e<sub>n</sub>]</i> is {@code List<
dynamic>}.</blockquote> |
| 2718 */ |
| 2719 Object visitListLiteral(ListLiteral node) { |
| 2720 TypeArgumentList typeArguments8 = node.typeArguments; |
| 2721 if (typeArguments8 != null) { |
| 2722 NodeList<TypeName> arguments3 = typeArguments8.arguments; |
| 2723 if (arguments3 != null && arguments3.length == 1) { |
| 2724 TypeName argumentType = arguments3[0]; |
| 2725 return recordType(node, _typeProvider.listType.substitute5(<Type2> [getT
ype2(argumentType)])); |
| 2726 } |
| 2727 } |
| 2728 return recordType(node, _typeProvider.listType.substitute5(<Type2> [_typePro
vider.dynamicType])); |
| 2729 } |
| 2730 /** |
| 2731 * The Dart Language Specification, 12.7: <blockquote>The static type of a map
literal of the form |
| 2732 * <i><b>const</b> <String, V> {k<sub>1</sub>:e<sub>1</sub>, …, |
| 2733 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i><String, V> {k<sub>1<
/sub>:e<sub>1</sub>, |
| 2734 * …, k<sub>n</sub>:e<sub>n</sub>}</i> is {@code Map<String, V>}.
The static type a |
| 2735 * map literal of the form <i><b>const</b> {k<sub>1</sub>:e<sub>1</sub>, &hell
ip;, |
| 2736 * k<sub>n</sub>:e<sub>n</sub>}</i> or the form <i>{k<sub>1</sub>:e<sub>1</sub
>, …, |
| 2737 * k<sub>n</sub>:e<sub>n</sub>}</i> is {@code Map<String, dynamic>}. |
| 2738 * <p> |
| 2739 * It is a compile-time error if the first type argument to a map literal is n
ot |
| 2740 * <i>String</i>.</blockquote> |
| 2741 */ |
| 2742 Object visitMapLiteral(MapLiteral node) { |
| 2743 TypeArgumentList typeArguments9 = node.typeArguments; |
| 2744 if (typeArguments9 != null) { |
| 2745 NodeList<TypeName> arguments4 = typeArguments9.arguments; |
| 2746 if (arguments4 != null && arguments4.length == 2) { |
| 2747 TypeName keyType = arguments4[0]; |
| 2748 if (keyType != _typeProvider.stringType) { |
| 2749 } |
| 2750 TypeName valueType = arguments4[1]; |
| 2751 return recordType(node, _typeProvider.mapType.substitute5(<Type2> [_type
Provider.stringType, getType2(valueType)])); |
| 2752 } |
| 2753 } |
| 2754 return recordType(node, _typeProvider.mapType.substitute5(<Type2> [_typeProv
ider.stringType, _typeProvider.dynamicType])); |
| 2755 } |
| 2756 /** |
| 2757 * The Dart Language Specification, 12.15.1: <blockquote>An ordinary method in
vocation <i>i</i> |
| 2758 * has the form <i>o.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>
: a<sub>n+1</sub>, |
| 2759 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. |
| 2760 * <p> |
| 2761 * Let <i>T</i> be the static type of <i>o</i>. It is a static type warning if
<i>T</i> does not |
| 2762 * have an accessible instance member named <i>m</i>. If <i>T.m</i> exists, it
is a static warning |
| 2763 * if the type <i>F</i> of <i>T.m</i> may not be assigned to a function type. |
| 2764 * <p> |
| 2765 * If <i>T.m</i> does not exist, or if <i>F</i> is not a function type, the st
atic type of |
| 2766 * <i>i</i> is dynamic. Otherwise the static type of <i>i</i> is the declared
return type of |
| 2767 * <i>F</i>.</blockquote> |
| 2768 * <p> |
| 2769 * The Dart Language Specification, 11.15.3: <blockquote>A static method invoc
ation <i>i</i> has |
| 2770 * the form <i>C.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>: a<
sub>n+1</sub>, |
| 2771 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. |
| 2772 * <p> |
| 2773 * It is a static type warning if the type <i>F</i> of <i>C.m</i> may not be a
ssigned to a |
| 2774 * function type. |
| 2775 * <p> |
| 2776 * 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 |
| 2777 * dynamic. Otherwise the static type of <i>i</i> is the declared return type
of |
| 2778 * <i>F</i>.</blockquote> |
| 2779 * <p> |
| 2780 * The Dart Language Specification, 11.15.4: <blockquote>A super method invoca
tion <i>i</i> has |
| 2781 * the form <i>super.m(a<sub>1</sub>, …, a<sub>n</sub>, x<sub>n+1</sub>
: a<sub>n+1</sub>, |
| 2782 * …, x<sub>n+k</sub>: a<sub>n+k</sub>)</i>. |
| 2783 * <p> |
| 2784 * It is a static type warning if <i>S</i> does not have an accessible instanc
e member named m. If |
| 2785 * <i>S.m</i> exists, it is a static warning if the type <i>F</i> of <i>S.m</i
> may not be |
| 2786 * assigned to a function type. |
| 2787 * <p> |
| 2788 * If <i>S.m</i> does not exist, or if <i>F</i> is not a function type, the st
atic type of |
| 2789 * <i>i</i> is dynamic. Otherwise the static type of <i>i</i> is the declared
return type of |
| 2790 * <i>F</i>.</blockquote> |
| 2791 */ |
| 2792 Object visitMethodInvocation(MethodInvocation node) => recordReturnType(node,
node.methodName.element); |
| 2793 Object visitNamedExpression(NamedExpression node) => recordType(node, getType(
node.expression)); |
| 2794 /** |
| 2795 * The Dart Language Specification, 12.2: <blockquote>The static type of {@cod
e null} is bottom. |
| 2796 * </blockquote> |
| 2797 */ |
| 2798 Object visitNullLiteral(NullLiteral node) => recordType(node, _typeProvider.bo
ttomType); |
| 2799 Object visitParenthesizedExpression(ParenthesizedExpression node) => recordTyp
e(node, getType(node.expression)); |
| 2800 /** |
| 2801 * The Dart Language Specification, 12.28: <blockquote>A postfix expression of
the form |
| 2802 * <i>v++</i>, where <i>v</i> is an identifier, is equivalent to <i>(){var r =
v; v = r + 1; |
| 2803 * return r}()</i>. |
| 2804 * <p> |
| 2805 * A postfix expression of the form <i>C.v++</i> is equivalent to <i>(){var r
= C.v; C.v = r + 1; |
| 2806 * return r}()</i>. |
| 2807 * <p> |
| 2808 * A postfix expression of the form <i>e1.v++</i> is equivalent to <i>(x){var
r = x.v; x.v = r + |
| 2809 * 1; return r}(e1)</i>. |
| 2810 * <p> |
| 2811 * A postfix expression of the form <i>e1[e2]++</i> is equivalent to <i>(a, i)
{var r = a[i]; a[i] |
| 2812 * = r + 1; return r}(e1, e2)</i> |
| 2813 * <p> |
| 2814 * A postfix expression of the form <i>v--</i>, where <i>v</i> is an identifie
r, is equivalent to |
| 2815 * <i>(){var r = v; v = r - 1; return r}()</i>. |
| 2816 * <p> |
| 2817 * A postfix expression of the form <i>C.v--</i> is equivalent to <i>(){var r
= C.v; C.v = r - 1; |
| 2818 * return r}()</i>. |
| 2819 * <p> |
| 2820 * A postfix expression of the form <i>e1.v--</i> is equivalent to <i>(x){var
r = x.v; x.v = r - |
| 2821 * 1; return r}(e1)</i>. |
| 2822 * <p> |
| 2823 * A postfix expression of the form <i>e1[e2]--</i> is equivalent to <i>(a, i)
{var r = a[i]; a[i] |
| 2824 * = r - 1; return r}(e1, e2)</i></blockquote> |
| 2825 */ |
| 2826 Object visitPostfixExpression(PostfixExpression node) => recordType(node, getT
ype(node.operand)); |
| 2827 /** |
| 2828 * See {@link #visitSimpleIdentifier(SimpleIdentifier)}. |
| 2829 */ |
| 2830 Object visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 2831 SimpleIdentifier prefixedIdentifier = node.identifier; |
| 2832 Element element20 = prefixedIdentifier.element; |
| 2833 if (element20 is VariableElement) { |
| 2834 Type2 variableType = ((element20 as VariableElement)).type; |
| 2835 recordType(prefixedIdentifier, variableType); |
| 2836 return recordType(node, variableType); |
| 2837 } else if (element20 is PropertyAccessorElement) { |
| 2838 Type2 propertyType = ((element20 as PropertyAccessorElement)).type.returnT
ype; |
| 2839 recordType(prefixedIdentifier, propertyType); |
| 2840 return recordType(node, propertyType); |
| 2841 } else if (element20 is MethodElement) { |
| 2842 Type2 returnType = ((element20 as MethodElement)).type; |
| 2843 recordType(prefixedIdentifier, returnType); |
| 2844 return recordType(node, returnType); |
| 2845 } else { |
| 2846 } |
| 2847 recordType(prefixedIdentifier, _typeProvider.dynamicType); |
| 2848 return recordType(node, _typeProvider.dynamicType); |
| 2849 } |
| 2850 /** |
| 2851 * The Dart Language Specification, 12.27: <blockquote>A unary expression <i>u
</i> of the form |
| 2852 * <i>op e</i> is equivalent to a method invocation <i>expression e.op()</i>.
An expression of the |
| 2853 * form <i>op super</i> is equivalent to the method invocation <i>super.op()<i
>.</blockquote> |
| 2854 */ |
| 2855 Object visitPrefixExpression(PrefixExpression node) { |
| 2856 TokenType operator13 = node.operator.type; |
| 2857 if (identical(operator13, TokenType.BANG)) { |
| 2858 return recordType(node, _typeProvider.boolType); |
| 2859 } |
| 2860 return recordReturnType(node, node.element); |
| 2861 } |
| 2862 /** |
| 2863 * The Dart Language Specification, 12.13: <blockquote> Property extraction al
lows for a member of |
| 2864 * an object to be concisely extracted from the object. If <i>o</i> is an obje
ct, and if <i>m</i> |
| 2865 * is the name of a method member of <i>o</i>, then |
| 2866 * <ul> |
| 2867 * <li><i>o.m</i> is defined to be equivalent to: <i>(r<sub>1</sub>, …,
r<sub>n</sub>, |
| 2868 * {p<sub>1</sub> : d<sub>1</sub>, …, p<sub>k</sub> : d<sub>k</sub>}){r
eturn |
| 2869 * o.m(r<sub>1</sub>, …, r<sub>n</sub>, p<sub>1</sub>: p<sub>1</sub>, &
hellip;, |
| 2870 * p<sub>k</sub>: p<sub>k</sub>);}</i> if <i>m</i> has required parameters <i>
r<sub>1</sub>, |
| 2871 * …, r<sub>n</sub></i>, and named parameters <i>p<sub>1</sub> …
p<sub>k</sub></i> |
| 2872 * with defaults <i>d<sub>1</sub>, …, d<sub>k</sub></i>.</li> |
| 2873 * <li><i>(r<sub>1</sub>, …, r<sub>n</sub>, [p<sub>1</sub> = d<sub>1</s
ub>, …, |
| 2874 * p<sub>k</sub> = d<sub>k</sub>]){return o.m(r<sub>1</sub>, …, r<sub>n
</sub>, |
| 2875 * p<sub>1</sub>, …, p<sub>k</sub>);}</i> if <i>m</i> has required para
meters |
| 2876 * <i>r<sub>1</sub>, …, r<sub>n</sub></i>, and optional positional para
meters |
| 2877 * <i>p<sub>1</sub> … p<sub>k</sub></i> with defaults <i>d<sub>1</sub>,
…, |
| 2878 * d<sub>k</sub></i>.</li> |
| 2879 * </ul> |
| 2880 * Otherwise, if <i>m</i> is the name of a getter member of <i>o</i> (declared
implicitly or |
| 2881 * explicitly) then <i>o.m</i> evaluates to the result of invoking the getter.
</blockquote> |
| 2882 * <p> |
| 2883 * The Dart Language Specification, 12.17: <blockquote> ... a getter invocatio
n <i>i</i> of the |
| 2884 * form <i>e.m</i> ... |
| 2885 * <p> |
| 2886 * Let <i>T</i> be the static type of <i>e</i>. It is a static type warning if
<i>T</i> does not |
| 2887 * have a getter named <i>m</i>. |
| 2888 * <p> |
| 2889 * The static type of <i>i</i> is the declared return type of <i>T.m</i>, if <
i>T.m</i> exists; |
| 2890 * otherwise the static type of <i>i</i> is dynamic. |
| 2891 * <p> |
| 2892 * ... a getter invocation <i>i</i> of the form <i>C.m</i> ... |
| 2893 * <p> |
| 2894 * It is a static warning if there is no class <i>C</i> in the enclosing lexic
al scope of |
| 2895 * <i>i</i>, or if <i>C</i> does not declare, implicitly or explicitly, a gett
er named <i>m</i>. |
| 2896 * <p> |
| 2897 * The static type of <i>i</i> is the declared return type of <i>C.m</i> if it
exists or dynamic |
| 2898 * otherwise. |
| 2899 * <p> |
| 2900 * ... a top-level getter invocation <i>i</i> of the form <i>m</i>, where <i>m
</i> is an |
| 2901 * identifier ... |
| 2902 * <p> |
| 2903 * The static type of <i>i</i> is the declared return type of <i>m</i>.</block
quote> |
| 2904 */ |
| 2905 Object visitPropertyAccess(PropertyAccess node) { |
| 2906 SimpleIdentifier propertyName2 = node.propertyName; |
| 2907 Element element21 = propertyName2.element; |
| 2908 if (element21 is MethodElement) { |
| 2909 FunctionType type11 = ((element21 as MethodElement)).type; |
| 2910 recordType(propertyName2, type11); |
| 2911 return recordType(node, type11); |
| 2912 } else if (element21 is PropertyAccessorElement) { |
| 2913 PropertyAccessorElement accessor = (element21 as PropertyAccessorElement); |
| 2914 if (accessor.isGetter()) { |
| 2915 if (accessor.type == null) { |
| 2916 recordType(propertyName2, _typeProvider.dynamicType); |
| 2917 return recordType(node, _typeProvider.dynamicType); |
| 2918 } |
| 2919 Type2 returnType4 = accessor.type.returnType; |
| 2920 recordType(propertyName2, returnType4); |
| 2921 return recordType(node, returnType4); |
| 2922 } else { |
| 2923 recordType(propertyName2, VoidTypeImpl.instance); |
| 2924 return recordType(node, VoidTypeImpl.instance); |
| 2925 } |
| 2926 } else { |
| 2927 } |
| 2928 recordType(propertyName2, _typeProvider.dynamicType); |
| 2929 return recordType(node, _typeProvider.dynamicType); |
| 2930 } |
| 2931 /** |
| 2932 * The Dart Language Specification, 12.30: <blockquote>Evaluation of an identi
fier expression |
| 2933 * <i>e</i> of the form <i>id</i> proceeds as follows: |
| 2934 * <p> |
| 2935 * Let <i>d</i> be the innermost declaration in the enclosing lexical scope wh
ose name is |
| 2936 * <i>id</i>. If no such declaration exists in the lexical scope, let <i>d</i>
be the declaration |
| 2937 * of the inherited member named <i>id</i> if it exists. |
| 2938 * <ul> |
| 2939 * <li>If <i>d</i> is a class or type alias <i>T</i>, the value of <i>e</i> is
the unique instance |
| 2940 * of class {@code Type} reifying <i>T</i>. |
| 2941 * <li>If <i>d</i> is a type parameter <i>T</i>, then the value of <i>e</i> is
the value of the |
| 2942 * actual type argument corresponding to <i>T</i> that was passed to the gener
ative constructor |
| 2943 * that created the current binding of this. We are assured that this is well
defined, because if |
| 2944 * we were in a static member the reference to <i>T</i> would be a compile-tim
e error. |
| 2945 * <li>If <i>d</i> is a library variable then: |
| 2946 * <ul> |
| 2947 * <li>If <i>d</i> is of one of the forms <i>var v = e<sub>i</sub>;</i>, <i>T
v = |
| 2948 * e<sub>i</sub>;</i>, <i>final v = e<sub>i</sub>;</i>, <i>final T v = e<sub>i
</sub>;</i>, and no |
| 2949 * value has yet been stored into <i>v</i> then the initializer expression <i>
e<sub>i</sub></i> is |
| 2950 * evaluated. If, during the evaluation of <i>e<sub>i</sub></i>, the getter fo
r <i>v</i> is |
| 2951 * referenced, a CyclicInitializationError is thrown. If the evaluation succee
ded yielding an |
| 2952 * object <i>o</i>, let <i>r = o</i>, otherwise let <i>r = null</i>. In any ca
se, <i>r</i> is |
| 2953 * stored into <i>v</i>. The value of <i>e</i> is <i>r</i>. |
| 2954 * <li>If <i>d</i> is of one of the forms <i>const v = e;</i> or <i>const T v
= e;</i> the result |
| 2955 * of the getter is the value of the compile time constant <i>e</i>. Otherwise |
| 2956 * <li><i>e</i> evaluates to the current binding of <i>id</i>. |
| 2957 * </ul> |
| 2958 * <li>If <i>d</i> is a local variable or formal parameter then <i>e</i> evalu
ates to the current |
| 2959 * binding of <i>id</i>. |
| 2960 * <li>If <i>d</i> is a static method, top level function or local function th
en <i>e</i> |
| 2961 * evaluates to the function defined by <i>d</i>. |
| 2962 * <li>If <i>d</i> is the declaration of a static variable or static getter de
clared in class |
| 2963 * <i>C</i>, then <i>e</i> is equivalent to the getter invocation <i>C.id</i>. |
| 2964 * <li>If <i>d</i> is the declaration of a top level getter, then <i>e</i> is
equivalent to the |
| 2965 * getter invocation <i>id</i>. |
| 2966 * <li>Otherwise, if <i>e</i> occurs inside a top level or static function (be
it function, |
| 2967 * method, getter, or setter) or variable initializer, evaluation of e causes
a NoSuchMethodError |
| 2968 * to be thrown. |
| 2969 * <li>Otherwise <i>e</i> is equivalent to the property extraction <i>this.id<
/i>. |
| 2970 * </ul> |
| 2971 * </blockquote> |
| 2972 */ |
| 2973 Object visitSimpleIdentifier(SimpleIdentifier node) { |
| 2974 Element element22 = node.element; |
| 2975 if (element22 == null) { |
| 2976 return recordType(node, _typeProvider.dynamicType); |
| 2977 } else if (element22 is ClassElement) { |
| 2978 if (isTypeName(node)) { |
| 2979 return recordType(node, ((element22 as ClassElement)).type); |
| 2980 } |
| 2981 return recordType(node, _typeProvider.typeType); |
| 2982 } else if (element22 is TypeVariableElement) { |
| 2983 return recordType(node, ((element22 as TypeVariableElement)).type); |
| 2984 } else if (element22 is TypeAliasElement) { |
| 2985 return recordType(node, ((element22 as TypeAliasElement)).type); |
| 2986 } else if (element22 is VariableElement) { |
| 2987 return recordType(node, ((element22 as VariableElement)).type); |
| 2988 } else if (element22 is MethodElement) { |
| 2989 return recordType(node, ((element22 as MethodElement)).type); |
| 2990 } else if (element22 is PropertyAccessorElement) { |
| 2991 PropertyAccessorElement accessor = (element22 as PropertyAccessorElement); |
| 2992 if (accessor.isGetter()) { |
| 2993 return recordType(node, accessor.type.returnType); |
| 2994 } else { |
| 2995 return recordType(node, accessor.type.normalParameterTypes[0]); |
| 2996 } |
| 2997 } else if (element22 is ExecutableElement) { |
| 2998 return recordType(node, ((element22 as ExecutableElement)).type); |
| 2999 } else if (element22 is PrefixElement) { |
| 3000 return null; |
| 3001 } else { |
| 3002 return recordType(node, _typeProvider.dynamicType); |
| 3003 } |
| 3004 } |
| 3005 /** |
| 3006 * The Dart Language Specification, 12.5: <blockquote>The static type of a str
ing literal is{@code String}.</blockquote> |
| 3007 */ |
| 3008 Object visitSimpleStringLiteral(SimpleStringLiteral node) => recordType(node,
_typeProvider.stringType); |
| 3009 /** |
| 3010 * The Dart Language Specification, 12.5: <blockquote>The static type of a str
ing literal is{@code String}.</blockquote> |
| 3011 */ |
| 3012 Object visitStringInterpolation(StringInterpolation node) => recordType(node,
_typeProvider.stringType); |
| 3013 Object visitSuperExpression(SuperExpression node) => recordType(node, _thisTyp
e == null ? _typeProvider.dynamicType : _thisType.superclass); |
| 3014 /** |
| 3015 * The Dart Language Specification, 12.10: <blockquote>The static type of {@co
de this} is the |
| 3016 * interface of the immediately enclosing class.</blockquote> |
| 3017 */ |
| 3018 Object visitThisExpression(ThisExpression node) => recordType(node, _thisType)
; |
| 3019 /** |
| 3020 * The Dart Language Specification, 12.8: <blockquote>The static type of a thr
ow expression is |
| 3021 * bottom.</blockquote> |
| 3022 */ |
| 3023 Object visitThrowExpression(ThrowExpression node) => recordType(node, _typePro
vider.bottomType); |
| 3024 /** |
| 3025 * Given a function expression, compute the return type of the function. The r
eturn type of |
| 3026 * functions with a block body is {@code dynamicType}, with an expression body
it is the type of |
| 3027 * the expression. |
| 3028 * @param node the function expression whose return type is to be computed |
| 3029 * @return the return type that was computed |
| 3030 */ |
| 3031 Type2 computeReturnType(FunctionExpression node) { |
| 3032 FunctionBody body4 = node.body; |
| 3033 if (body4 is ExpressionFunctionBody) { |
| 3034 return getType(((body4 as ExpressionFunctionBody)).expression); |
| 3035 } |
| 3036 return _typeProvider.dynamicType; |
| 3037 } |
| 3038 /** |
| 3039 * Return the type of the given expression that is to be used for type analysi
s. |
| 3040 * @param expression the expression whose type is to be returned |
| 3041 * @return the type of the given expression |
| 3042 */ |
| 3043 Type2 getType(Expression expression) { |
| 3044 Type2 type = expression.staticType; |
| 3045 if (type == null) { |
| 3046 return _typeProvider.dynamicType; |
| 3047 } |
| 3048 return type; |
| 3049 } |
| 3050 /** |
| 3051 * Return the type represented by the given type name. |
| 3052 * @param typeName the type name representing the type to be returned |
| 3053 * @return the type represented by the type name |
| 3054 */ |
| 3055 Type2 getType2(TypeName typeName) { |
| 3056 Type2 type12 = typeName.type; |
| 3057 if (type12 == null) { |
| 3058 return _typeProvider.dynamicType; |
| 3059 } |
| 3060 return type12; |
| 3061 } |
| 3062 /** |
| 3063 * Return {@code true} if the given node is being used as the name of a type. |
| 3064 * @param node the node being tested |
| 3065 * @return {@code true} if the given node is being used as the name of a type |
| 3066 */ |
| 3067 bool isTypeName(SimpleIdentifier node) { |
| 3068 ASTNode parent8 = node.parent; |
| 3069 return parent8 is TypeName || (parent8 is PrefixedIdentifier && parent8.pare
nt is TypeName) || (parent8 is MethodInvocation && identical(node, ((parent8 as
MethodInvocation)).target)); |
| 3070 } |
| 3071 /** |
| 3072 * Record that the static type of the given node is the return type of the met
hod or function |
| 3073 * represented by the given element. |
| 3074 * @param expression the node whose type is to be recorded |
| 3075 * @param element the element representing the method or function invoked by t
he given node |
| 3076 */ |
| 3077 Object recordReturnType(Expression expression, Element element) { |
| 3078 if (element is ExecutableElement) { |
| 3079 FunctionType type13 = ((element as ExecutableElement)).type; |
| 3080 if (type13 != null) { |
| 3081 return recordType(expression, type13.returnType); |
| 3082 } |
| 3083 } else if (element is VariableElement) { |
| 3084 Type2 variableType = ((element as VariableElement)).type; |
| 3085 if (variableType is FunctionType) { |
| 3086 return recordType(expression, ((variableType as FunctionType)).returnTyp
e); |
| 3087 } |
| 3088 } |
| 3089 return recordType(expression, _typeProvider.dynamicType); |
| 3090 } |
| 3091 /** |
| 3092 * Record that the static type of the given node is the given type. |
| 3093 * @param expression the node whose type is to be recorded |
| 3094 * @param type the static type of the node |
| 3095 */ |
| 3096 Object recordType(Expression expression, Type2 type) { |
| 3097 if (type == null) { |
| 3098 expression.staticType = _typeProvider.dynamicType; |
| 3099 } else { |
| 3100 expression.staticType = type; |
| 3101 } |
| 3102 return null; |
| 3103 } |
| 3104 /** |
| 3105 * Set the return type and parameter type information for the given function t
ype based on the |
| 3106 * given return type and parameter elements. |
| 3107 * @param functionType the function type to be filled in |
| 3108 * @param returnType the return type of the function, or {@code null} if no ty
pe was declared |
| 3109 * @param parameters the elements representing the parameters to the function |
| 3110 */ |
| 3111 void setTypeInformation(FunctionTypeImpl functionType, Type2 returnType7, Form
alParameterList parameterList) { |
| 3112 List<Type2> normalParameterTypes = new List<Type2>(); |
| 3113 List<Type2> optionalParameterTypes = new List<Type2>(); |
| 3114 LinkedHashMap<String, Type2> namedParameterTypes = new LinkedHashMap<String,
Type2>(); |
| 3115 if (parameterList != null) { |
| 3116 for (ParameterElement parameter in parameterList.elements) { |
| 3117 if (parameter.parameterKind == ParameterKind.REQUIRED) { |
| 3118 normalParameterTypes.add(parameter.type); |
| 3119 } else if (parameter.parameterKind == ParameterKind.POSITIONAL) { |
| 3120 optionalParameterTypes.add(parameter.type); |
| 3121 } else if (parameter.parameterKind == ParameterKind.NAMED) { |
| 3122 namedParameterTypes[parameter.name] = parameter.type; |
| 3123 } |
| 3124 } |
| 3125 } |
| 3126 functionType.normalParameterTypes = new List.from(normalParameterTypes); |
| 3127 functionType.optionalParameterTypes = new List.from(optionalParameterTypes); |
| 3128 functionType.namedParameterTypes = namedParameterTypes; |
| 3129 functionType.returnType = returnType7; |
| 3130 } |
| 3131 } |
| 3132 /** |
| 3133 * The interface {@code TypeProvider} defines the behavior of objects that provi
de access to types |
| 3134 * defined by the language. |
| 3135 */ |
| 3136 abstract class TypeProvider { |
| 3137 /** |
| 3138 * Return the type representing the built-in type 'bool'. |
| 3139 * @return the type representing the built-in type 'bool' |
| 3140 */ |
| 3141 InterfaceType get boolType; |
| 3142 /** |
| 3143 * Return the type representing the type 'bottom'. |
| 3144 * @return the type representing the type 'bottom' |
| 3145 */ |
| 3146 Type2 get bottomType; |
| 3147 /** |
| 3148 * Return the type representing the built-in type 'double'. |
| 3149 * @return the type representing the built-in type 'double' |
| 3150 */ |
| 3151 InterfaceType get doubleType; |
| 3152 /** |
| 3153 * Return the type representing the built-in type 'dynamic'. |
| 3154 * @return the type representing the built-in type 'dynamic' |
| 3155 */ |
| 3156 Type2 get dynamicType; |
| 3157 /** |
| 3158 * Return the type representing the built-in type 'Function'. |
| 3159 * @return the type representing the built-in type 'Function' |
| 3160 */ |
| 3161 InterfaceType get functionType; |
| 3162 /** |
| 3163 * Return the type representing the built-in type 'int'. |
| 3164 * @return the type representing the built-in type 'int' |
| 3165 */ |
| 3166 InterfaceType get intType; |
| 3167 /** |
| 3168 * Return the type representing the built-in type 'List'. |
| 3169 * @return the type representing the built-in type 'List' |
| 3170 */ |
| 3171 InterfaceType get listType; |
| 3172 /** |
| 3173 * Return the type representing the built-in type 'Map'. |
| 3174 * @return the type representing the built-in type 'Map' |
| 3175 */ |
| 3176 InterfaceType get mapType; |
| 3177 /** |
| 3178 * Return the type representing the built-in type 'Object'. |
| 3179 * @return the type representing the built-in type 'Object' |
| 3180 */ |
| 3181 InterfaceType get objectType; |
| 3182 /** |
| 3183 * Return the type representing the built-in type 'StackTrace'. |
| 3184 * @return the type representing the built-in type 'StackTrace' |
| 3185 */ |
| 3186 InterfaceType get stackTraceType; |
| 3187 /** |
| 3188 * Return the type representing the built-in type 'String'. |
| 3189 * @return the type representing the built-in type 'String' |
| 3190 */ |
| 3191 InterfaceType get stringType; |
| 3192 /** |
| 3193 * Return the type representing the built-in type 'Type'. |
| 3194 * @return the type representing the built-in type 'Type' |
| 3195 */ |
| 3196 InterfaceType get typeType; |
| 3197 } |
| 3198 /** |
| 3199 * Instances of the class {@code TypeProviderImpl} provide access to types defin
ed by the language |
| 3200 * by looking for those types in the element model for the core library. |
| 3201 */ |
| 3202 class TypeProviderImpl implements TypeProvider { |
| 3203 /** |
| 3204 * The type representing the built-in type 'bool'. |
| 3205 */ |
| 3206 InterfaceType _boolType; |
| 3207 /** |
| 3208 * The type representing the type 'bottom'. |
| 3209 */ |
| 3210 Type2 _bottomType; |
| 3211 /** |
| 3212 * The type representing the built-in type 'double'. |
| 3213 */ |
| 3214 InterfaceType _doubleType; |
| 3215 /** |
| 3216 * The type representing the built-in type 'dynamic'. |
| 3217 */ |
| 3218 Type2 _dynamicType; |
| 3219 /** |
| 3220 * The type representing the built-in type 'Function'. |
| 3221 */ |
| 3222 InterfaceType _functionType; |
| 3223 /** |
| 3224 * The type representing the built-in type 'int'. |
| 3225 */ |
| 3226 InterfaceType _intType; |
| 3227 /** |
| 3228 * The type representing the built-in type 'List'. |
| 3229 */ |
| 3230 InterfaceType _listType; |
| 3231 /** |
| 3232 * The type representing the built-in type 'Map'. |
| 3233 */ |
| 3234 InterfaceType _mapType; |
| 3235 /** |
| 3236 * The type representing the built-in type 'Object'. |
| 3237 */ |
| 3238 InterfaceType _objectType; |
| 3239 /** |
| 3240 * The type representing the built-in type 'StackTrace'. |
| 3241 */ |
| 3242 InterfaceType _stackTraceType; |
| 3243 /** |
| 3244 * The type representing the built-in type 'String'. |
| 3245 */ |
| 3246 InterfaceType _stringType; |
| 3247 /** |
| 3248 * The type representing the built-in type 'Type'. |
| 3249 */ |
| 3250 InterfaceType _typeType; |
| 3251 /** |
| 3252 * Initialize a newly created type provider to provide the types defined in th
e given library. |
| 3253 * @param coreLibrary the element representing the core library (dart:core). |
| 3254 */ |
| 3255 TypeProviderImpl(LibraryElement coreLibrary) { |
| 3256 initializeFrom(coreLibrary); |
| 3257 } |
| 3258 InterfaceType get boolType => _boolType; |
| 3259 Type2 get bottomType => _bottomType; |
| 3260 InterfaceType get doubleType => _doubleType; |
| 3261 Type2 get dynamicType => _dynamicType; |
| 3262 InterfaceType get functionType => _functionType; |
| 3263 InterfaceType get intType => _intType; |
| 3264 InterfaceType get listType => _listType; |
| 3265 InterfaceType get mapType => _mapType; |
| 3266 InterfaceType get objectType => _objectType; |
| 3267 InterfaceType get stackTraceType => _stackTraceType; |
| 3268 InterfaceType get stringType => _stringType; |
| 3269 InterfaceType get typeType => _typeType; |
| 3270 /** |
| 3271 * Return the type with the given name from the given namespace, or {@code nul
l} if there is no |
| 3272 * class with the given name. |
| 3273 * @param namespace the namespace in which to search for the given name |
| 3274 * @param typeName the name of the type being searched for |
| 3275 * @return the type that was found |
| 3276 */ |
| 3277 InterfaceType getType(Namespace namespace, String typeName) { |
| 3278 Element element = namespace.get(typeName); |
| 3279 if (element == null) { |
| 3280 AnalysisEngine.instance.logger.logInformation("No definition of type ${typ
eName}"); |
| 3281 return null; |
| 3282 } |
| 3283 return ((element as ClassElement)).type; |
| 3284 } |
| 3285 /** |
| 3286 * Initialize the types provided by this type provider from the given library. |
| 3287 * @param library the library containing the definitions of the core types |
| 3288 */ |
| 3289 void initializeFrom(LibraryElement library) { |
| 3290 Namespace namespace = new NamespaceBuilder().createPublicNamespace(library); |
| 3291 _boolType = getType(namespace, "bool"); |
| 3292 _bottomType = BottomTypeImpl.instance; |
| 3293 _doubleType = getType(namespace, "double"); |
| 3294 _dynamicType = DynamicTypeImpl.instance; |
| 3295 _functionType = getType(namespace, "Function"); |
| 3296 _intType = getType(namespace, "int"); |
| 3297 _listType = getType(namespace, "List"); |
| 3298 _mapType = getType(namespace, "Map"); |
| 3299 _objectType = getType(namespace, "Object"); |
| 3300 _stackTraceType = getType(namespace, "StackTrace"); |
| 3301 _stringType = getType(namespace, "String"); |
| 3302 _typeType = getType(namespace, "Type"); |
| 3303 } |
| 3304 } |
| 3305 /** |
| 3306 * Instances of the class {@code TypeResolverVisitor} are used to resolve the ty
pes associated with |
| 3307 * the elements in the element model. This includes the types of superclasses, m
ixins, interfaces, |
| 3308 * fields, methods, parameters, and local variables. As a side-effect, this also
finishes building |
| 3309 * the type hierarchy. |
| 3310 */ |
| 3311 class TypeResolverVisitor extends ScopedVisitor { |
| 3312 /** |
| 3313 * Initialize a newly created visitor to resolve the nodes in a compilation un
it. |
| 3314 * @param library the library containing the compilation unit being resolved |
| 3315 * @param source the source representing the compilation unit being visited |
| 3316 * @param typeProvider the object used to access the types from the core libra
ry |
| 3317 */ |
| 3318 TypeResolverVisitor(Library library, Source source, TypeProvider typeProvider)
: super(library, source, typeProvider) { |
| 3319 } |
| 3320 Object visitCatchClause(CatchClause node) { |
| 3321 super.visitCatchClause(node); |
| 3322 SimpleIdentifier exception = node.exceptionParameter; |
| 3323 if (exception != null) { |
| 3324 TypeName exceptionTypeName = node.exceptionType; |
| 3325 Type2 exceptionType; |
| 3326 if (exceptionTypeName == null) { |
| 3327 exceptionType = typeProvider.objectType; |
| 3328 } else { |
| 3329 exceptionType = getType(exceptionTypeName); |
| 3330 } |
| 3331 recordType(exception, exceptionType); |
| 3332 Element element23 = exception.element; |
| 3333 if (element23 is VariableElementImpl) { |
| 3334 ((element23 as VariableElementImpl)).type = exceptionType; |
| 3335 } else { |
| 3336 } |
| 3337 } |
| 3338 SimpleIdentifier stackTrace = node.stackTraceParameter; |
| 3339 if (stackTrace != null) { |
| 3340 recordType(stackTrace, typeProvider.stackTraceType); |
| 3341 } |
| 3342 return null; |
| 3343 } |
| 3344 Object visitClassDeclaration(ClassDeclaration node) { |
| 3345 super.visitClassDeclaration(node); |
| 3346 ClassElementImpl classElement = getClassElement(node.name); |
| 3347 InterfaceType superclassType = null; |
| 3348 ExtendsClause extendsClause4 = node.extendsClause; |
| 3349 if (extendsClause4 != null) { |
| 3350 superclassType = resolveType(extendsClause4.superclass, null, null, null); |
| 3351 } |
| 3352 if (classElement != null) { |
| 3353 if (superclassType == null) { |
| 3354 InterfaceType objectType2 = typeProvider.objectType; |
| 3355 if (classElement.type != objectType2) { |
| 3356 superclassType = objectType2; |
| 3357 } |
| 3358 } |
| 3359 classElement.supertype = superclassType; |
| 3360 } |
| 3361 resolve(classElement, node.withClause, node.implementsClause); |
| 3362 return null; |
| 3363 } |
| 3364 Object visitClassTypeAlias(ClassTypeAlias node) { |
| 3365 super.visitClassTypeAlias(node); |
| 3366 ClassElementImpl classElement = getClassElement(node.name); |
| 3367 InterfaceType superclassType = resolveType(node.superclass, null, null, null
); |
| 3368 if (superclassType == null) { |
| 3369 superclassType = typeProvider.objectType; |
| 3370 } |
| 3371 if (classElement != null && superclassType != null) { |
| 3372 classElement.supertype = superclassType; |
| 3373 } |
| 3374 resolve(classElement, node.withClause, node.implementsClause); |
| 3375 return null; |
| 3376 } |
| 3377 Object visitConstructorDeclaration(ConstructorDeclaration node) { |
| 3378 super.visitConstructorDeclaration(node); |
| 3379 ExecutableElementImpl element24 = (node.element as ExecutableElementImpl); |
| 3380 FunctionTypeImpl type = new FunctionTypeImpl.con1(element24); |
| 3381 setTypeInformation(type, null, element24.parameters); |
| 3382 type.returnType = ((element24.enclosingElement as ClassElement)).type; |
| 3383 element24.type = type; |
| 3384 return null; |
| 3385 } |
| 3386 Object visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 3387 super.visitDefaultFormalParameter(node); |
| 3388 return null; |
| 3389 } |
| 3390 Object visitFieldFormalParameter(FieldFormalParameter node) { |
| 3391 super.visitFieldFormalParameter(node); |
| 3392 Element element25 = node.identifier.element; |
| 3393 if (element25 is ParameterElementImpl) { |
| 3394 ParameterElementImpl parameter = (element25 as ParameterElementImpl); |
| 3395 Type2 type; |
| 3396 TypeName typeName = node.type; |
| 3397 if (typeName == null) { |
| 3398 type = typeProvider.dynamicType; |
| 3399 } else { |
| 3400 type = getType(typeName); |
| 3401 } |
| 3402 parameter.type = type; |
| 3403 } else { |
| 3404 } |
| 3405 return null; |
| 3406 } |
| 3407 Object visitFunctionDeclaration(FunctionDeclaration node) { |
| 3408 super.visitFunctionDeclaration(node); |
| 3409 ExecutableElementImpl element26 = (node.element as ExecutableElementImpl); |
| 3410 FunctionTypeImpl type = new FunctionTypeImpl.con1(element26); |
| 3411 setTypeInformation(type, node.returnType, element26.parameters); |
| 3412 element26.type = type; |
| 3413 return null; |
| 3414 } |
| 3415 Object visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 3416 super.visitFunctionTypeAlias(node); |
| 3417 TypeAliasElementImpl element27 = (node.element as TypeAliasElementImpl); |
| 3418 FunctionTypeImpl type14 = (element27.type as FunctionTypeImpl); |
| 3419 setTypeInformation(type14, node.returnType, element27.parameters); |
| 3420 return null; |
| 3421 } |
| 3422 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 3423 super.visitFunctionTypedFormalParameter(node); |
| 3424 ParameterElementImpl element28 = (node.identifier.element as ParameterElemen
tImpl); |
| 3425 FunctionTypeImpl type = new FunctionTypeImpl.con1((null as ExecutableElement
)); |
| 3426 setTypeInformation(type, node.returnType, getElements(node.parameters)); |
| 3427 element28.type = type; |
| 3428 return null; |
| 3429 } |
| 3430 Object visitMethodDeclaration(MethodDeclaration node) { |
| 3431 super.visitMethodDeclaration(node); |
| 3432 ExecutableElementImpl element29 = (node.element as ExecutableElementImpl); |
| 3433 FunctionTypeImpl type = new FunctionTypeImpl.con1(element29); |
| 3434 setTypeInformation(type, node.returnType, element29.parameters); |
| 3435 element29.type = type; |
| 3436 return null; |
| 3437 } |
| 3438 Object visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 3439 super.visitSimpleFormalParameter(node); |
| 3440 Type2 declaredType; |
| 3441 TypeName typeName = node.type; |
| 3442 if (typeName == null) { |
| 3443 declaredType = typeProvider.dynamicType; |
| 3444 } else { |
| 3445 declaredType = getType(typeName); |
| 3446 } |
| 3447 Element element30 = node.identifier.element; |
| 3448 if (element30 is ParameterElement) { |
| 3449 ((element30 as ParameterElementImpl)).type = declaredType; |
| 3450 } else { |
| 3451 } |
| 3452 return null; |
| 3453 } |
| 3454 Object visitTypeName(TypeName node) { |
| 3455 super.visitTypeName(node); |
| 3456 Identifier typeName = node.name; |
| 3457 Element element = nameScope.lookup(typeName, definingLibrary); |
| 3458 Type2 type = null; |
| 3459 if (element == null) { |
| 3460 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance; |
| 3461 VoidTypeImpl voidType = VoidTypeImpl.instance; |
| 3462 if (typeName.name == dynamicType.name) { |
| 3463 element = dynamicType.element; |
| 3464 type = dynamicType; |
| 3465 setElement(typeName, element); |
| 3466 } else if (typeName.name == voidType.name) { |
| 3467 type = voidType; |
| 3468 } else { |
| 3469 ASTNode parent9 = node.parent; |
| 3470 if (typeName is PrefixedIdentifier && parent9 is ConstructorName) { |
| 3471 ConstructorName name = (parent9 as ConstructorName); |
| 3472 if (name.name == null) { |
| 3473 SimpleIdentifier prefix7 = ((typeName as PrefixedIdentifier)).prefix
; |
| 3474 element = nameScope.lookup(prefix7, definingLibrary); |
| 3475 if (element is PrefixElement) { |
| 3476 return null; |
| 3477 } else if (element != null) { |
| 3478 name.name = ((typeName as PrefixedIdentifier)).identifier; |
| 3479 node.name = prefix7; |
| 3480 typeName = prefix7; |
| 3481 } |
| 3482 } |
| 3483 } |
| 3484 } |
| 3485 } |
| 3486 if (element == null && type == null) { |
| 3487 return null; |
| 3488 } else if (element is ClassElement) { |
| 3489 setElement(typeName, element); |
| 3490 type = ((element as ClassElement)).type; |
| 3491 } else if (element is TypeAliasElement) { |
| 3492 setElement(typeName, element); |
| 3493 type = ((element as TypeAliasElement)).type; |
| 3494 } else if (element is TypeVariableElement) { |
| 3495 setElement(typeName, element); |
| 3496 type = ((element as TypeVariableElement)).type; |
| 3497 } else if (type == null) { |
| 3498 return null; |
| 3499 } |
| 3500 if (type == null) { |
| 3501 return null; |
| 3502 } |
| 3503 TypeArgumentList argumentList = node.typeArguments; |
| 3504 if (argumentList != null) { |
| 3505 NodeList<TypeName> arguments5 = argumentList.arguments; |
| 3506 int argumentCount = arguments5.length; |
| 3507 List<Type2> parameters = getTypeArguments(type); |
| 3508 int parameterCount = parameters.length; |
| 3509 if (argumentCount != parameterCount) { |
| 3510 } |
| 3511 List<Type2> typeArguments = new List<Type2>(argumentCount); |
| 3512 for (int i = 0; i < argumentCount; i++) { |
| 3513 Type2 argumentType = getType(arguments5[i]); |
| 3514 if (argumentType != null) { |
| 3515 typeArguments.add(argumentType); |
| 3516 } |
| 3517 } |
| 3518 if (type is InterfaceTypeImpl) { |
| 3519 InterfaceTypeImpl interfaceType = (type as InterfaceTypeImpl); |
| 3520 argumentCount = typeArguments.length; |
| 3521 if (interfaceType.typeArguments.length == argumentCount) { |
| 3522 type = interfaceType.substitute5(new List.from(typeArguments)); |
| 3523 } else { |
| 3524 } |
| 3525 } else if (type is FunctionTypeImpl) { |
| 3526 FunctionTypeImpl functionType = (type as FunctionTypeImpl); |
| 3527 argumentCount = typeArguments.length; |
| 3528 if (functionType.typeArguments.length == argumentCount) { |
| 3529 type = functionType.substitute4(new List.from(typeArguments)); |
| 3530 } else { |
| 3531 } |
| 3532 } else { |
| 3533 } |
| 3534 } else { |
| 3535 List<Type2> parameters = getTypeArguments(type); |
| 3536 int parameterCount = parameters.length; |
| 3537 if (parameterCount > 0) { |
| 3538 DynamicTypeImpl dynamicType = DynamicTypeImpl.instance; |
| 3539 List<Type2> arguments = new List<Type2>.fixedLength(parameterCount); |
| 3540 for (int i = 0; i < parameterCount; i++) { |
| 3541 arguments[i] = dynamicType; |
| 3542 } |
| 3543 type = type.substitute2(arguments, parameters); |
| 3544 } |
| 3545 } |
| 3546 typeName.staticType = type; |
| 3547 node.type = type; |
| 3548 return null; |
| 3549 } |
| 3550 Object visitVariableDeclaration(VariableDeclaration node) { |
| 3551 super.visitVariableDeclaration(node); |
| 3552 Type2 declaredType; |
| 3553 TypeName typeName = ((node.parent as VariableDeclarationList)).type; |
| 3554 if (typeName == null) { |
| 3555 declaredType = typeProvider.dynamicType; |
| 3556 } else { |
| 3557 declaredType = getType(typeName); |
| 3558 } |
| 3559 Element element31 = node.name.element; |
| 3560 if (element31 is VariableElement) { |
| 3561 ((element31 as VariableElementImpl)).type = declaredType; |
| 3562 if (element31 is FieldElement) { |
| 3563 FieldElement field = (element31 as FieldElement); |
| 3564 PropertyAccessorElementImpl getter3 = (field.getter as PropertyAccessorE
lementImpl); |
| 3565 FunctionTypeImpl getterType = new FunctionTypeImpl.con1(getter3); |
| 3566 getterType.returnType = declaredType; |
| 3567 getter3.type = getterType; |
| 3568 PropertyAccessorElementImpl setter3 = (field.setter as PropertyAccessorE
lementImpl); |
| 3569 if (setter3 != null) { |
| 3570 FunctionTypeImpl setterType = new FunctionTypeImpl.con1(setter3); |
| 3571 setterType.returnType = VoidTypeImpl.instance; |
| 3572 setterType.normalParameterTypes = <Type2> [declaredType]; |
| 3573 setter3.type = setterType; |
| 3574 } |
| 3575 } |
| 3576 } else { |
| 3577 } |
| 3578 return null; |
| 3579 } |
| 3580 /** |
| 3581 * Return the class element that represents the class whose name was provided. |
| 3582 * @param identifier the name from the declaration of a class |
| 3583 * @return the class element that represents the class |
| 3584 */ |
| 3585 ClassElementImpl getClassElement(SimpleIdentifier identifier) { |
| 3586 if (identifier == null) { |
| 3587 return null; |
| 3588 } |
| 3589 Element element32 = identifier.element; |
| 3590 if (element32 is! ClassElementImpl) { |
| 3591 return null; |
| 3592 } |
| 3593 return (element32 as ClassElementImpl); |
| 3594 } |
| 3595 /** |
| 3596 * Return an array containing all of the elements associated with the paramete
rs in the given |
| 3597 * list. |
| 3598 * @param parameterList the list of parameters whose elements are to be return
ed |
| 3599 * @return the elements associated with the parameters |
| 3600 */ |
| 3601 List<ParameterElement> getElements(FormalParameterList parameterList) { |
| 3602 List<ParameterElement> elements = new List<ParameterElement>(); |
| 3603 for (FormalParameter parameter in parameterList.parameters) { |
| 3604 ParameterElement element33 = (parameter.identifier.element as ParameterEle
ment); |
| 3605 if (element33 != null) { |
| 3606 elements.add(element33); |
| 3607 } |
| 3608 } |
| 3609 return new List.from(elements); |
| 3610 } |
| 3611 /** |
| 3612 * Return the type represented by the given type name. |
| 3613 * @param typeName the type name representing the type to be returned |
| 3614 * @return the type represented by the type name |
| 3615 */ |
| 3616 Type2 getType(TypeName typeName) => typeName.type; |
| 3617 /** |
| 3618 * Return the type arguments associated with the given type. |
| 3619 * @param type the type whole type arguments are to be returned |
| 3620 * @return the type arguments associated with the given type |
| 3621 */ |
| 3622 List<Type2> getTypeArguments(Type2 type) { |
| 3623 if (type is InterfaceType) { |
| 3624 return ((type as InterfaceType)).typeArguments; |
| 3625 } else if (type is FunctionType) { |
| 3626 return ((type as FunctionType)).typeArguments; |
| 3627 } |
| 3628 return TypeImpl.EMPTY_ARRAY; |
| 3629 } |
| 3630 /** |
| 3631 * Record that the static type of the given node is the given type. |
| 3632 * @param expression the node whose type is to be recorded |
| 3633 * @param type the static type of the node |
| 3634 */ |
| 3635 Object recordType(Expression expression, Type2 type) { |
| 3636 if (type == null) { |
| 3637 expression.staticType = typeProvider.dynamicType; |
| 3638 } else { |
| 3639 expression.staticType = type; |
| 3640 } |
| 3641 return null; |
| 3642 } |
| 3643 /** |
| 3644 * Resolve the types in the given with and implements clauses and associate th
ose types with the |
| 3645 * given class element. |
| 3646 * @param classElement the class element with which the mixin and interface ty
pes are to be |
| 3647 * associated |
| 3648 * @param withClause the with clause to be resolved |
| 3649 * @param implementsClause the implements clause to be resolved |
| 3650 */ |
| 3651 void resolve(ClassElementImpl classElement, WithClause withClause, ImplementsC
lause implementsClause) { |
| 3652 if (withClause != null) { |
| 3653 List<InterfaceType> mixinTypes2 = resolveTypes(withClause.mixinTypes, null
, null, null); |
| 3654 if (classElement != null) { |
| 3655 classElement.mixins = mixinTypes2; |
| 3656 } |
| 3657 } |
| 3658 if (implementsClause != null) { |
| 3659 List<InterfaceType> interfaceTypes = resolveTypes(implementsClause.interfa
ces, null, null, null); |
| 3660 if (classElement != null) { |
| 3661 classElement.interfaces = interfaceTypes; |
| 3662 } |
| 3663 } |
| 3664 } |
| 3665 /** |
| 3666 * Return the type specified by the given name. |
| 3667 * @param typeName the type name specifying the type to be returned |
| 3668 * @param undefinedError the error to produce if the type name is not defined |
| 3669 * @param nonTypeError the error to produce if the type name is defined to be
something other than |
| 3670 * a type |
| 3671 * @param nonInterfaceType the error to produce if the type is not an interfac
e type |
| 3672 * @return the type specified by the type name |
| 3673 */ |
| 3674 InterfaceType resolveType(TypeName typeName, ResolverErrorCode undefinedError,
ResolverErrorCode nonTypeError, ResolverErrorCode nonInterfaceType) { |
| 3675 Identifier name15 = typeName.name; |
| 3676 Element element = nameScope.lookup(name15, definingLibrary); |
| 3677 if (element == null) { |
| 3678 reportError(undefinedError, name15, []); |
| 3679 } else if (element is ClassElement) { |
| 3680 Type2 classType = ((element as ClassElement)).type; |
| 3681 typeName.type = classType; |
| 3682 if (classType is InterfaceType) { |
| 3683 return (classType as InterfaceType); |
| 3684 } |
| 3685 reportError(nonInterfaceType, name15, []); |
| 3686 } else { |
| 3687 reportError(nonTypeError, name15, []); |
| 3688 } |
| 3689 return null; |
| 3690 } |
| 3691 /** |
| 3692 * Resolve the types in the given list of type names. |
| 3693 * @param typeNames the type names to be resolved |
| 3694 * @param undefinedError the error to produce if the type name is not defined |
| 3695 * @param nonTypeError the error to produce if the type name is defined to be
something other than |
| 3696 * a type |
| 3697 * @param nonInterfaceType the error to produce if the type is not an interfac
e type |
| 3698 * @return an array containing all of the types that were resolved. |
| 3699 */ |
| 3700 List<InterfaceType> resolveTypes(NodeList<TypeName> typeNames, ResolverErrorCo
de undefinedError, ResolverErrorCode nonTypeError, ResolverErrorCode nonInterfac
eType) { |
| 3701 List<InterfaceType> types = new List<InterfaceType>(); |
| 3702 for (TypeName typeName in typeNames) { |
| 3703 InterfaceType type = resolveType(typeName, undefinedError, nonTypeError, n
onInterfaceType); |
| 3704 if (type != null) { |
| 3705 types.add(type); |
| 3706 } |
| 3707 } |
| 3708 return new List.from(types); |
| 3709 } |
| 3710 void setElement(Identifier typeName, Element element41) { |
| 3711 if (element41 != null) { |
| 3712 typeName.element = element41; |
| 3713 if (typeName is PrefixedIdentifier) { |
| 3714 PrefixedIdentifier identifier = (typeName as PrefixedIdentifier); |
| 3715 identifier.identifier.element = element41; |
| 3716 SimpleIdentifier prefix8 = identifier.prefix; |
| 3717 Element prefixElement = nameScope.lookup(prefix8, definingLibrary); |
| 3718 if (prefixElement != null) { |
| 3719 prefix8.element = prefixElement; |
| 3720 } |
| 3721 } |
| 3722 } |
| 3723 } |
| 3724 /** |
| 3725 * Set the return type and parameter type information for the given function t
ype based on the |
| 3726 * given return type and parameter elements. |
| 3727 * @param functionType the function type to be filled in |
| 3728 * @param returnType the return type of the function, or {@code null} if no ty
pe was declared |
| 3729 * @param parameters the elements representing the parameters to the function |
| 3730 */ |
| 3731 void setTypeInformation(FunctionTypeImpl functionType, TypeName returnType8, L
ist<ParameterElement> parameters) { |
| 3732 List<Type2> normalParameterTypes = new List<Type2>(); |
| 3733 List<Type2> optionalParameterTypes = new List<Type2>(); |
| 3734 LinkedHashMap<String, Type2> namedParameterTypes = new LinkedHashMap<String,
Type2>(); |
| 3735 for (ParameterElement parameter in parameters) { |
| 3736 if (parameter.parameterKind == ParameterKind.REQUIRED) { |
| 3737 normalParameterTypes.add(parameter.type); |
| 3738 } else if (parameter.parameterKind == ParameterKind.POSITIONAL) { |
| 3739 optionalParameterTypes.add(parameter.type); |
| 3740 } else if (parameter.parameterKind == ParameterKind.NAMED) { |
| 3741 namedParameterTypes[parameter.name] = parameter.type; |
| 3742 } |
| 3743 } |
| 3744 functionType.normalParameterTypes = new List.from(normalParameterTypes); |
| 3745 functionType.optionalParameterTypes = new List.from(optionalParameterTypes); |
| 3746 functionType.namedParameterTypes = namedParameterTypes; |
| 3747 if (returnType8 == null) { |
| 3748 functionType.returnType = typeProvider.dynamicType; |
| 3749 } else { |
| 3750 functionType.returnType = returnType8.type; |
| 3751 } |
| 3752 } |
| 3753 } |
| 3754 /** |
| 3755 * Instances of the class {@code ClassScope} implement the scope defined by a cl
ass. |
| 3756 */ |
| 3757 class ClassScope extends EnclosedScope { |
| 3758 /** |
| 3759 * Initialize a newly created scope enclosed within another scope. |
| 3760 * @param enclosingScope the scope in which this scope is lexically enclosed |
| 3761 * @param typeElement the element representing the type represented by this sc
ope |
| 3762 */ |
| 3763 ClassScope(Scope enclosingScope, ClassElement typeElement) : super(new Enclose
dScope(enclosingScope)) { |
| 3764 defineTypeParameters(typeElement); |
| 3765 defineMembers(typeElement); |
| 3766 } |
| 3767 /** |
| 3768 * Define the instance members defined by the class. |
| 3769 * @param typeElement the element representing the type represented by this sc
ope |
| 3770 */ |
| 3771 void defineMembers(ClassElement typeElement) { |
| 3772 for (PropertyAccessorElement accessor in typeElement.accessors) { |
| 3773 define(accessor); |
| 3774 } |
| 3775 for (FieldElement field in typeElement.fields) { |
| 3776 define(field); |
| 3777 } |
| 3778 for (MethodElement method in typeElement.methods) { |
| 3779 define(method); |
| 3780 } |
| 3781 } |
| 3782 /** |
| 3783 * Define the type parameters for the class. |
| 3784 * @param typeElement the element representing the type represented by this sc
ope |
| 3785 */ |
| 3786 void defineTypeParameters(ClassElement typeElement) { |
| 3787 Scope parameterScope = enclosingScope; |
| 3788 for (TypeVariableElement parameter in typeElement.typeVariables) { |
| 3789 parameterScope.define(parameter); |
| 3790 } |
| 3791 } |
| 3792 } |
| 3793 /** |
| 3794 * Instances of the class {@code EnclosedScope} implement a scope that is lexica
lly enclosed in |
| 3795 * another scope. |
| 3796 */ |
| 3797 class EnclosedScope extends Scope { |
| 3798 /** |
| 3799 * The scope in which this scope is lexically enclosed. |
| 3800 */ |
| 3801 Scope _enclosingScope; |
| 3802 /** |
| 3803 * Initialize a newly created scope enclosed within another scope. |
| 3804 * @param enclosingScope the scope in which this scope is lexically enclosed |
| 3805 */ |
| 3806 EnclosedScope(Scope enclosingScope) { |
| 3807 this._enclosingScope = enclosingScope; |
| 3808 } |
| 3809 LibraryElement get definingLibrary => _enclosingScope.definingLibrary; |
| 3810 AnalysisErrorListener get errorListener => _enclosingScope.errorListener; |
| 3811 /** |
| 3812 * Return the scope in which this scope is lexically enclosed. |
| 3813 * @return the scope in which this scope is lexically enclosed |
| 3814 */ |
| 3815 Scope get enclosingScope => _enclosingScope; |
| 3816 Element lookup3(String name, LibraryElement referencingLibrary) { |
| 3817 Element element = localLookup(name, referencingLibrary); |
| 3818 if (element != null) { |
| 3819 return element; |
| 3820 } |
| 3821 return _enclosingScope.lookup3(name, referencingLibrary); |
| 3822 } |
| 3823 } |
| 3824 /** |
| 3825 * Instances of the class {@code FunctionScope} implement the scope defined by a
function. |
| 3826 */ |
| 3827 class FunctionScope extends EnclosedScope { |
| 3828 /** |
| 3829 * Initialize a newly created scope enclosed within another scope. |
| 3830 * @param enclosingScope the scope in which this scope is lexically enclosed |
| 3831 * @param functionElement the element representing the type represented by thi
s scope |
| 3832 */ |
| 3833 FunctionScope(Scope enclosingScope, ExecutableElement functionElement) : super
(new EnclosedScope(enclosingScope)) { |
| 3834 defineParameters(functionElement); |
| 3835 } |
| 3836 /** |
| 3837 * Define the parameters for the given function in the scope that encloses thi
s function. |
| 3838 * @param functionElement the element representing the function represented by
this scope |
| 3839 */ |
| 3840 void defineParameters(ExecutableElement functionElement) { |
| 3841 Scope parameterScope = enclosingScope; |
| 3842 if (functionElement.enclosingElement is ExecutableElement) { |
| 3843 String name16 = functionElement.name; |
| 3844 if (name16 != null && !name16.isEmpty) { |
| 3845 parameterScope.define(functionElement); |
| 3846 } |
| 3847 } |
| 3848 for (ParameterElement parameter in functionElement.parameters) { |
| 3849 if (!parameter.isInitializingFormal()) { |
| 3850 parameterScope.define(parameter); |
| 3851 } |
| 3852 } |
| 3853 } |
| 3854 } |
| 3855 /** |
| 3856 * Instances of the class {@code FunctionTypeScope} implement the scope defined
by a function type |
| 3857 * alias. |
| 3858 */ |
| 3859 class FunctionTypeScope extends EnclosedScope { |
| 3860 /** |
| 3861 * Initialize a newly created scope enclosed within another scope. |
| 3862 * @param enclosingScope the scope in which this scope is lexically enclosed |
| 3863 * @param typeElement the element representing the type alias represented by t
his scope |
| 3864 */ |
| 3865 FunctionTypeScope(Scope enclosingScope, TypeAliasElement typeElement) : super(
new EnclosedScope(enclosingScope)) { |
| 3866 defineTypeParameters(typeElement); |
| 3867 } |
| 3868 /** |
| 3869 * Define the type parameters for the function type alias. |
| 3870 * @param typeElement the element representing the type represented by this sc
ope |
| 3871 */ |
| 3872 void defineTypeParameters(TypeAliasElement typeElement) { |
| 3873 Scope parameterScope = enclosingScope; |
| 3874 for (TypeVariableElement parameter in typeElement.typeVariables) { |
| 3875 parameterScope.define(parameter); |
| 3876 } |
| 3877 } |
| 3878 } |
| 3879 /** |
| 3880 * Instances of the class {@code LabelScope} represent a scope in which a single
label is defined. |
| 3881 */ |
| 3882 class LabelScope { |
| 3883 /** |
| 3884 * The label scope enclosing this label scope. |
| 3885 */ |
| 3886 LabelScope _outerScope; |
| 3887 /** |
| 3888 * The label defined in this scope. |
| 3889 */ |
| 3890 String _label; |
| 3891 /** |
| 3892 * The element to which the label resolves. |
| 3893 */ |
| 3894 LabelElement _element; |
| 3895 /** |
| 3896 * The marker used to look up a label element for an unlabeled {@code break} o
r {@code continue}. |
| 3897 */ |
| 3898 static String EMPTY_LABEL = ""; |
| 3899 /** |
| 3900 * The label element returned for scopes that can be the target of an unlabele
d {@code break} or{@code continue}. |
| 3901 */ |
| 3902 static SimpleIdentifier _EMPTY_LABEL_IDENTIFIER = new SimpleIdentifier.full(ne
w StringToken(TokenType.IDENTIFIER, "", 0)); |
| 3903 /** |
| 3904 * Initialize a newly created scope to represent the potential target of an un
labeled{@code break} or {@code continue}. |
| 3905 * @param outerScope the label scope enclosing the new label scope |
| 3906 * @param onSwitchStatement {@code true} if this label is associated with a {@
code switch}statement |
| 3907 * @param onSwitchMember {@code true} if this label is associated with a {@cod
e switch} member |
| 3908 */ |
| 3909 LabelScope.con1(LabelScope outerScope, bool onSwitchStatement, bool onSwitchMe
mber) { |
| 3910 _jtd_constructor_198_impl(outerScope, onSwitchStatement, onSwitchMember); |
| 3911 } |
| 3912 _jtd_constructor_198_impl(LabelScope outerScope, bool onSwitchStatement, bool
onSwitchMember) { |
| 3913 _jtd_constructor_199_impl(outerScope, EMPTY_LABEL, new LabelElementImpl(_EMP
TY_LABEL_IDENTIFIER, onSwitchStatement, onSwitchMember)); |
| 3914 } |
| 3915 /** |
| 3916 * Initialize a newly created scope to represent the given label. |
| 3917 * @param outerScope the label scope enclosing the new label scope |
| 3918 * @param label the label defined in this scope |
| 3919 * @param element the element to which the label resolves |
| 3920 */ |
| 3921 LabelScope.con2(LabelScope outerScope2, String label3, LabelElement element18)
{ |
| 3922 _jtd_constructor_199_impl(outerScope2, label3, element18); |
| 3923 } |
| 3924 _jtd_constructor_199_impl(LabelScope outerScope2, String label3, LabelElement
element18) { |
| 3925 this._outerScope = outerScope2; |
| 3926 this._label = label3; |
| 3927 this._element = element18; |
| 3928 } |
| 3929 /** |
| 3930 * Return the label element corresponding to the given label, or {@code null}
if the given label |
| 3931 * is not defined in this scope. |
| 3932 * @param targetLabel the label being looked up |
| 3933 * @return the label element corresponding to the given label |
| 3934 */ |
| 3935 LabelElement lookup(SimpleIdentifier targetLabel) => lookup2(targetLabel.name)
; |
| 3936 /** |
| 3937 * Return the label element corresponding to the given label, or {@code null}
if the given label |
| 3938 * is not defined in this scope. |
| 3939 * @param targetLabel the label being looked up |
| 3940 * @return the label element corresponding to the given label |
| 3941 */ |
| 3942 LabelElement lookup2(String targetLabel) { |
| 3943 if (_label == targetLabel) { |
| 3944 return _element; |
| 3945 } else if (_outerScope != null) { |
| 3946 return _outerScope.lookup2(targetLabel); |
| 3947 } else { |
| 3948 return null; |
| 3949 } |
| 3950 } |
| 3951 } |
| 3952 /** |
| 3953 * Instances of the class {@code LibraryImportScope} represent the scope contain
ing all of the names |
| 3954 * available from imported libraries. |
| 3955 */ |
| 3956 class LibraryImportScope extends Scope { |
| 3957 /** |
| 3958 * The element representing the library in which this scope is enclosed. |
| 3959 */ |
| 3960 LibraryElement _definingLibrary; |
| 3961 /** |
| 3962 * The listener that is to be informed when an error is encountered. |
| 3963 */ |
| 3964 AnalysisErrorListener _errorListener; |
| 3965 /** |
| 3966 * A list of the namespaces representing the names that are available in this
scope from imported |
| 3967 * libraries. |
| 3968 */ |
| 3969 List<Namespace> _importedNamespaces = new List<Namespace>(); |
| 3970 /** |
| 3971 * Initialize a newly created scope representing the names imported into the g
iven library. |
| 3972 * @param definingLibrary the element representing the library that imports th
e names defined in |
| 3973 * this scope |
| 3974 * @param errorListener the listener that is to be informed when an error is e
ncountered |
| 3975 */ |
| 3976 LibraryImportScope(LibraryElement definingLibrary, AnalysisErrorListener error
Listener) { |
| 3977 this._definingLibrary = definingLibrary; |
| 3978 this._errorListener = errorListener; |
| 3979 createImportedNamespaces(definingLibrary); |
| 3980 } |
| 3981 void define(Element element) { |
| 3982 if (!Scope.isPrivateName(element.name)) { |
| 3983 super.define(element); |
| 3984 } |
| 3985 } |
| 3986 LibraryElement get definingLibrary => _definingLibrary; |
| 3987 AnalysisErrorListener get errorListener => _errorListener; |
| 3988 Element lookup3(String name, LibraryElement referencingLibrary) { |
| 3989 if (Scope.isPrivateName(name)) { |
| 3990 return null; |
| 3991 } |
| 3992 Element foundElement = localLookup(name, referencingLibrary); |
| 3993 if (foundElement != null) { |
| 3994 return foundElement; |
| 3995 } |
| 3996 for (Namespace nameSpace in _importedNamespaces) { |
| 3997 Element element = nameSpace.get(name); |
| 3998 if (element != null) { |
| 3999 if (foundElement == null) { |
| 4000 foundElement = element; |
| 4001 } else { |
| 4002 foundElement = new MultiplyDefinedElementImpl(_definingLibrary.context
, foundElement, element); |
| 4003 } |
| 4004 } |
| 4005 } |
| 4006 if (foundElement != null) { |
| 4007 defineWithoutChecking(foundElement); |
| 4008 } |
| 4009 return foundElement; |
| 4010 } |
| 4011 /** |
| 4012 * Create all of the namespaces associated with the libraries imported into th
is library. The |
| 4013 * names are not added to this scope, but are stored for later reference. |
| 4014 * @param definingLibrary the element representing the library that imports th
e libraries for |
| 4015 * which namespaces will be created |
| 4016 */ |
| 4017 void createImportedNamespaces(LibraryElement definingLibrary) { |
| 4018 NamespaceBuilder builder = new NamespaceBuilder(); |
| 4019 for (ImportElement element in definingLibrary.imports) { |
| 4020 _importedNamespaces.add(builder.createImportNamespace(element)); |
| 4021 } |
| 4022 } |
| 4023 } |
| 4024 /** |
| 4025 * Instances of the class {@code LibraryScope} implement a scope containing all
of the names defined |
| 4026 * in a given library. |
| 4027 */ |
| 4028 class LibraryScope extends EnclosedScope { |
| 4029 /** |
| 4030 * Initialize a newly created scope representing the names defined in the give
n library. |
| 4031 * @param definingLibrary the element representing the library represented by
this scope |
| 4032 * @param errorListener the listener that is to be informed when an error is e
ncountered |
| 4033 */ |
| 4034 LibraryScope(LibraryElement definingLibrary, AnalysisErrorListener errorListen
er) : super(new LibraryImportScope(definingLibrary, errorListener)) { |
| 4035 defineTopLevelNames(definingLibrary); |
| 4036 } |
| 4037 /** |
| 4038 * Add to this scope all of the public top-level names that are defined in the
given compilation |
| 4039 * unit. |
| 4040 * @param compilationUnit the compilation unit defining the top-level names to
be added to this |
| 4041 * scope |
| 4042 */ |
| 4043 void defineLocalNames(CompilationUnitElement compilationUnit) { |
| 4044 for (PropertyAccessorElement element in compilationUnit.accessors) { |
| 4045 define(element); |
| 4046 } |
| 4047 for (FunctionElement element in compilationUnit.functions) { |
| 4048 define(element); |
| 4049 } |
| 4050 for (TypeAliasElement element in compilationUnit.typeAliases) { |
| 4051 define(element); |
| 4052 } |
| 4053 for (ClassElement element in compilationUnit.types) { |
| 4054 define(element); |
| 4055 } |
| 4056 for (VariableElement element in compilationUnit.variables) { |
| 4057 define(element); |
| 4058 } |
| 4059 } |
| 4060 /** |
| 4061 * Add to this scope all of the names that are explicitly defined in the given
library. |
| 4062 * @param definingLibrary the element representing the library that defines th
e names in this |
| 4063 * scope |
| 4064 */ |
| 4065 void defineTopLevelNames(LibraryElement definingLibrary) { |
| 4066 for (PrefixElement prefix in definingLibrary.prefixes) { |
| 4067 define(prefix); |
| 4068 } |
| 4069 defineLocalNames(definingLibrary.definingCompilationUnit); |
| 4070 for (CompilationUnitElement compilationUnit in definingLibrary.parts) { |
| 4071 defineLocalNames(compilationUnit); |
| 4072 } |
| 4073 } |
| 4074 } |
| 4075 /** |
| 4076 * Instances of the class {@code Namespace} implement a mapping of identifiers t
o the elements |
| 4077 * represented by those identifiers. Namespaces are the building blocks for scop
es. |
| 4078 */ |
| 4079 class Namespace { |
| 4080 /** |
| 4081 * A table mapping names that are defined in this namespace to the element rep
resenting the thing |
| 4082 * declared with that name. |
| 4083 */ |
| 4084 Map<String, Element> _definedNames = new Map<String, Element>(); |
| 4085 /** |
| 4086 * Initialize a newly created namespace to have the given defined names. |
| 4087 * @param definedNames the mapping from names that are defined in this namespa
ce to the |
| 4088 * corresponding elements |
| 4089 */ |
| 4090 Namespace(Map<String, Element> definedNames) { |
| 4091 this._definedNames = definedNames; |
| 4092 } |
| 4093 /** |
| 4094 * Return the element in this namespace that is available to the containing sc
ope using the given |
| 4095 * name. |
| 4096 * @param name the name used to reference the |
| 4097 * @return the element represented by the given identifier |
| 4098 */ |
| 4099 Element get(String name) => _definedNames[name]; |
| 4100 /** |
| 4101 * Return a table containing the same mappings as those defined by this namesp
ace. |
| 4102 * @return a table containing the same mappings as those defined by this names
pace |
| 4103 */ |
| 4104 Map<String, Element> get definedNames => new Map<String, Element>(); |
| 4105 } |
| 4106 /** |
| 4107 * Instances of the class {@code NamespaceBuilder} are used to build a {@code Na
mespace}. Namespace |
| 4108 * builders are thread-safe and re-usable. |
| 4109 */ |
| 4110 class NamespaceBuilder { |
| 4111 /** |
| 4112 * Initialize a newly created namespace builder. |
| 4113 */ |
| 4114 NamespaceBuilder() : super() { |
| 4115 } |
| 4116 /** |
| 4117 * Create a namespace representing the export namespace of the given library. |
| 4118 * @param library the library whose export namespace is to be created |
| 4119 * @return the export namespace that was created |
| 4120 */ |
| 4121 Namespace createExportNamespace(LibraryElement library) => new Namespace(creat
eExportMapping(library, new Set<LibraryElement>())); |
| 4122 /** |
| 4123 * Create a namespace representing the import namespace of the given library. |
| 4124 * @param library the library whose import namespace is to be created |
| 4125 * @return the import namespace that was created |
| 4126 */ |
| 4127 Namespace createImportNamespace(ImportElement element) { |
| 4128 Map<String, Element> definedNames = createExportMapping(element.importedLibr
ary, new Set<LibraryElement>()); |
| 4129 definedNames = apply(definedNames, element.combinators); |
| 4130 definedNames = apply2(definedNames, element.prefix); |
| 4131 return new Namespace(definedNames); |
| 4132 } |
| 4133 /** |
| 4134 * Create a namespace representing the public namespace of the given library. |
| 4135 * @param library the library whose public namespace is to be created |
| 4136 * @return the public namespace that was created |
| 4137 */ |
| 4138 Namespace createPublicNamespace(LibraryElement library) { |
| 4139 Map<String, Element> definedNames = new Map<String, Element>(); |
| 4140 addPublicNames(definedNames, library.definingCompilationUnit); |
| 4141 for (CompilationUnitElement compilationUnit in library.parts) { |
| 4142 addPublicNames(definedNames, compilationUnit); |
| 4143 } |
| 4144 return new Namespace(definedNames); |
| 4145 } |
| 4146 /** |
| 4147 * Add all of the names in the given namespace to the given mapping table. |
| 4148 * @param definedNames the mapping table to which the names in the given names
pace are to be added |
| 4149 * @param namespace the namespace containing the names to be added to this nam
espace |
| 4150 */ |
| 4151 void addAll(Map<String, Element> definedNames, Map<String, Element> newNames)
{ |
| 4152 for (MapEntry<String, Element> entry in getMapEntrySet(newNames)) { |
| 4153 definedNames[entry.getKey()] = entry.getValue(); |
| 4154 } |
| 4155 } |
| 4156 /** |
| 4157 * Add all of the names in the given namespace to the given mapping table. |
| 4158 * @param definedNames the mapping table to which the names in the given names
pace are to be added |
| 4159 * @param namespace the namespace containing the names to be added to this nam
espace |
| 4160 */ |
| 4161 void addAll2(Map<String, Element> definedNames2, Namespace namespace) { |
| 4162 addAll(definedNames2, namespace.definedNames); |
| 4163 } |
| 4164 /** |
| 4165 * Add the given element to the given mapping table if it has a publicly visib
le name. |
| 4166 * @param definedNames the mapping table to which the public name is to be add
ed |
| 4167 * @param element the element to be added |
| 4168 */ |
| 4169 void addIfPublic(Map<String, Element> definedNames, Element element) { |
| 4170 String name17 = element.name; |
| 4171 if (name17 != null && !Scope.isPrivateName(name17)) { |
| 4172 definedNames[name17] = element; |
| 4173 } |
| 4174 } |
| 4175 /** |
| 4176 * Add to the given mapping table all of the public top-level names that are d
efined in the given |
| 4177 * compilation unit. |
| 4178 * @param definedNames the mapping table to which the public names are to be a
dded |
| 4179 * @param compilationUnit the compilation unit defining the top-level names to
be added to this |
| 4180 * namespace |
| 4181 */ |
| 4182 void addPublicNames(Map<String, Element> definedNames, CompilationUnitElement
compilationUnit) { |
| 4183 for (PropertyAccessorElement element in compilationUnit.accessors) { |
| 4184 addIfPublic(definedNames, element); |
| 4185 } |
| 4186 for (FunctionElement element in compilationUnit.functions) { |
| 4187 addIfPublic(definedNames, element); |
| 4188 } |
| 4189 for (TypeAliasElement element in compilationUnit.typeAliases) { |
| 4190 addIfPublic(definedNames, element); |
| 4191 } |
| 4192 for (ClassElement element in compilationUnit.types) { |
| 4193 addIfPublic(definedNames, element); |
| 4194 } |
| 4195 for (VariableElement element in compilationUnit.variables) { |
| 4196 addIfPublic(definedNames, element); |
| 4197 } |
| 4198 } |
| 4199 /** |
| 4200 * Apply the given combinators to all of the names in the given mapping table. |
| 4201 * @param definedNames the mapping table to which the namespace operations are
to be applied |
| 4202 * @param combinators the combinators to be applied |
| 4203 */ |
| 4204 Map<String, Element> apply(Map<String, Element> definedNames, List<NamespaceCo
mbinator> combinators) { |
| 4205 for (NamespaceCombinator combinator in combinators) { |
| 4206 if (combinator is __imp_combi.HideCombinator) { |
| 4207 hide(definedNames, ((combinator as __imp_combi.HideCombinator)).hiddenNa
mes); |
| 4208 } else if (combinator is __imp_combi.ShowCombinator) { |
| 4209 definedNames = show(definedNames, ((combinator as __imp_combi.ShowCombin
ator)).shownNames); |
| 4210 } else { |
| 4211 AnalysisEngine.instance.logger.logError("Unknown type of combinator: ${c
ombinator.runtimeType.toString()}"); |
| 4212 } |
| 4213 } |
| 4214 return definedNames; |
| 4215 } |
| 4216 /** |
| 4217 * Apply the given prefix to all of the names in the table of defined names. |
| 4218 * @param definedNames the names that were defined before this operation |
| 4219 * @param prefixElement the element defining the prefix to be added to the nam
es |
| 4220 */ |
| 4221 Map<String, Element> apply2(Map<String, Element> definedNames, PrefixElement p
refixElement) { |
| 4222 if (prefixElement != null) { |
| 4223 String prefix = prefixElement.name; |
| 4224 Map<String, Element> newNames = new Map<String, Element>(); |
| 4225 for (MapEntry<String, Element> entry in getMapEntrySet(definedNames)) { |
| 4226 newNames["${prefix}.${entry.getKey()}"] = entry.getValue(); |
| 4227 } |
| 4228 return newNames; |
| 4229 } else { |
| 4230 return definedNames; |
| 4231 } |
| 4232 } |
| 4233 /** |
| 4234 * Create a mapping table representing the export namespace of the given libra
ry. |
| 4235 * @param library the library whose public namespace is to be created |
| 4236 * @param visitedElements a set of libraries that do not need to be visited wh
en processing the |
| 4237 * export directives of the given library because all of the names defined by
them will |
| 4238 * be added by another library |
| 4239 * @return the mapping table that was created |
| 4240 */ |
| 4241 Map<String, Element> createExportMapping(LibraryElement library, Set<LibraryEl
ement> visitedElements) { |
| 4242 javaSetAdd(visitedElements, library); |
| 4243 try { |
| 4244 Map<String, Element> definedNames = new Map<String, Element>(); |
| 4245 for (ExportElement element in library.exports) { |
| 4246 LibraryElement exportedLibrary3 = element.exportedLibrary; |
| 4247 if (!visitedElements.contains(exportedLibrary3)) { |
| 4248 Map<String, Element> exportedNames = createExportMapping(exportedLibra
ry3, visitedElements); |
| 4249 exportedNames = apply(exportedNames, element.combinators); |
| 4250 addAll(definedNames, exportedNames); |
| 4251 } |
| 4252 } |
| 4253 addAll2(definedNames, ((library.context as AnalysisContextImpl)).getPublic
Namespace(library)); |
| 4254 return definedNames; |
| 4255 } finally { |
| 4256 visitedElements.remove(library); |
| 4257 } |
| 4258 } |
| 4259 /** |
| 4260 * Hide all of the given names by removing them from the given collection of d
efined names. |
| 4261 * @param definedNames the names that were defined before this operation |
| 4262 * @param hiddenNames the names to be hidden |
| 4263 */ |
| 4264 void hide(Map<String, Element> definedNames, List<String> hiddenNames) { |
| 4265 for (String name in hiddenNames) { |
| 4266 definedNames.remove(name); |
| 4267 } |
| 4268 } |
| 4269 /** |
| 4270 * Show only the given names by removing all other names from the given collec
tion of defined |
| 4271 * names. |
| 4272 * @param definedNames the names that were defined before this operation |
| 4273 * @param shownNames the names to be shown |
| 4274 */ |
| 4275 Map<String, Element> show(Map<String, Element> definedNames, List<String> show
nNames) { |
| 4276 Map<String, Element> newNames = new Map<String, Element>(); |
| 4277 for (String name in shownNames) { |
| 4278 Element element = definedNames[name]; |
| 4279 if (element != null) { |
| 4280 newNames[name] = element; |
| 4281 } |
| 4282 } |
| 4283 return newNames; |
| 4284 } |
| 4285 } |
| 4286 /** |
| 4287 * The abstract class {@code Scope} defines the behavior common to name scopes u
sed by the resolver |
| 4288 * to determine which names are visible at any given point in the code. |
| 4289 */ |
| 4290 abstract class Scope { |
| 4291 /** |
| 4292 * The prefix used to mark an identifier as being private to its library. |
| 4293 */ |
| 4294 static String PRIVATE_NAME_PREFIX = "_"; |
| 4295 /** |
| 4296 * The suffix added to the declared name of a setter when looking up the sette
r. Used to |
| 4297 * disambiguate between a getter and a setter that have the same name. |
| 4298 */ |
| 4299 static String SETTER_SUFFIX = "="; |
| 4300 /** |
| 4301 * The name used to look up the method used to implement the unary minus opera
tor. Used to |
| 4302 * disambiguate between the unary and binary operators. |
| 4303 */ |
| 4304 static String UNARY_MINUS = "unary-"; |
| 4305 /** |
| 4306 * Return {@code true} if the given name is a library-private name. |
| 4307 * @param name the name being tested |
| 4308 * @return {@code true} if the given name is a library-private name |
| 4309 */ |
| 4310 static bool isPrivateName(String name) => name != null && name.startsWith(PRIV
ATE_NAME_PREFIX); |
| 4311 /** |
| 4312 * A table mapping names that are defined in this scope to the element represe
nting the thing |
| 4313 * declared with that name. |
| 4314 */ |
| 4315 Map<String, Element> _definedNames = new Map<String, Element>(); |
| 4316 /** |
| 4317 * Initialize a newly created scope to be empty. |
| 4318 */ |
| 4319 Scope() : super() { |
| 4320 } |
| 4321 /** |
| 4322 * Add the given element to this scope. If there is already an element with th
e given name defined |
| 4323 * in this scope, then an error will be generated and the original element wil
l continue to be |
| 4324 * mapped to the name. If there is an element with the given name in an enclos
ing scope, then a |
| 4325 * warning will be generated but the given element will hide the inherited ele
ment. |
| 4326 * @param element the element to be added to this scope |
| 4327 */ |
| 4328 void define(Element element) { |
| 4329 String name = getName(element); |
| 4330 if (_definedNames.containsKey(name)) { |
| 4331 errorListener.onError(getErrorForDuplicate(_definedNames[name], element)); |
| 4332 } else { |
| 4333 Element overriddenElement = lookup3(name, definingLibrary); |
| 4334 if (overriddenElement != null) { |
| 4335 AnalysisError error = getErrorForHiding(overriddenElement, element); |
| 4336 if (error != null) { |
| 4337 errorListener.onError(error); |
| 4338 } |
| 4339 } |
| 4340 _definedNames[name] = element; |
| 4341 } |
| 4342 } |
| 4343 /** |
| 4344 * Return the element with which the given identifier is associated, or {@code
null} if the name |
| 4345 * is not defined within this scope. |
| 4346 * @param identifier the identifier associated with the element to be returned |
| 4347 * @param referencingLibrary the library that contains the reference to the na
me, used to |
| 4348 * implement library-level privacy |
| 4349 * @return the element with which the given identifier is associated |
| 4350 */ |
| 4351 Element lookup(Identifier identifier, LibraryElement referencingLibrary) => lo
okup3(identifier.name, referencingLibrary); |
| 4352 /** |
| 4353 * Add the given element to this scope without checking for duplication or hid
ing. |
| 4354 * @param element the element to be added to this scope |
| 4355 */ |
| 4356 void defineWithoutChecking(Element element) { |
| 4357 _definedNames[getName(element)] = element; |
| 4358 } |
| 4359 /** |
| 4360 * Return the element representing the library in which this scope is enclosed
. |
| 4361 * @return the element representing the library in which this scope is enclose
d |
| 4362 */ |
| 4363 LibraryElement get definingLibrary; |
| 4364 /** |
| 4365 * Return the error code to be used when reporting that a name being defined l
ocally conflicts |
| 4366 * with another element of the same name in the local scope. |
| 4367 * @param existing the first element to be declared with the conflicting name |
| 4368 * @param duplicate another element declared with the conflicting name |
| 4369 * @return the error code used to report duplicate names within a scope |
| 4370 */ |
| 4371 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) => new
AnalysisError.con1(source, ResolverErrorCode.DUPLICATE_MEMBER_ERROR, [existing.
name]); |
| 4372 /** |
| 4373 * Return the error code to be used when reporting that a name being defined l
ocally hides a name |
| 4374 * defined in an outer scope. |
| 4375 * @param hidden the element whose visibility is being hidden |
| 4376 * @param hiding the element that is hiding the visibility of another declarat
ion |
| 4377 * @return the error code used to report name hiding |
| 4378 */ |
| 4379 AnalysisError getErrorForHiding(Element hidden, Element hiding) => new Analysi
sError.con1(source, ResolverErrorCode.DUPLICATE_MEMBER_WARNING, [hidden.name]); |
| 4380 /** |
| 4381 * Return the listener that is to be informed when an error is encountered. |
| 4382 * @return the listener that is to be informed when an error is encountered |
| 4383 */ |
| 4384 AnalysisErrorListener get errorListener; |
| 4385 /** |
| 4386 * Return the source object representing the compilation unit with which error
s related to this |
| 4387 * scope should be associated. |
| 4388 * @return the source object with which errors should be associated |
| 4389 */ |
| 4390 Source get source => definingLibrary.definingCompilationUnit.source; |
| 4391 /** |
| 4392 * Return the element with which the given name is associated, or {@code null}
if the name is not |
| 4393 * defined within this scope. This method only returns elements that are direc
tly defined within |
| 4394 * this scope, not elements that are defined in an enclosing scope. |
| 4395 * @param name the name associated with the element to be returned |
| 4396 * @param referencingLibrary the library that contains the reference to the na
me, used to |
| 4397 * implement library-level privacy |
| 4398 * @return the element with which the given name is associated |
| 4399 */ |
| 4400 Element localLookup(String name, LibraryElement referencingLibrary) => _define
dNames[name]; |
| 4401 /** |
| 4402 * Return the element with which the given name is associated, or {@code null}
if the name is not |
| 4403 * defined within this scope. |
| 4404 * @param name the name associated with the element to be returned |
| 4405 * @param referencingLibrary the library that contains the reference to the na
me, used to |
| 4406 * implement library-level privacy |
| 4407 * @return the element with which the given name is associated |
| 4408 */ |
| 4409 Element lookup3(String name, LibraryElement referencingLibrary); |
| 4410 /** |
| 4411 * Return the name that will be used to look up the given element. |
| 4412 * @param element the element whose look-up name is to be returned |
| 4413 * @return the name that will be used to look up the given element |
| 4414 */ |
| 4415 String getName(Element element) { |
| 4416 if (element is MethodElement) { |
| 4417 MethodElement method = (element as MethodElement); |
| 4418 if (method.name == "-" && method.parameters.length == 0) { |
| 4419 return UNARY_MINUS; |
| 4420 } |
| 4421 } else if (element is PropertyAccessorElement) { |
| 4422 PropertyAccessorElement accessor = (element as PropertyAccessorElement); |
| 4423 if (accessor.isSetter()) { |
| 4424 return "${accessor.name}${SETTER_SUFFIX}"; |
| 4425 } |
| 4426 } |
| 4427 return element.name; |
| 4428 } |
| 4429 } |
| 4430 /** |
| 4431 * The enumeration {@code ResolverErrorCode} defines the error codes used for er
rors detected by the |
| 4432 * resolver. The convention for this class is for the name of the error code to
indicate the problem |
| 4433 * that caused the error to be generated and for the error message to explain wh
at is wrong and, |
| 4434 * when appropriate, how the problem can be corrected. |
| 4435 */ |
| 4436 class ResolverErrorCode implements ErrorCode { |
| 4437 static final ResolverErrorCode BREAK_LABEL_ON_SWITCH_MEMBER = new ResolverErro
rCode('BREAK_LABEL_ON_SWITCH_MEMBER', 0, ErrorType.COMPILE_TIME_ERROR, "Break la
bel resolves to case or default statement"); |
| 4438 static final ResolverErrorCode CANNOT_BE_RESOLVED = new ResolverErrorCode('CAN
NOT_BE_RESOLVED', 1, ErrorType.STATIC_WARNING, "Cannot resolve the name '%s'"); |
| 4439 static final ResolverErrorCode CONTINUE_LABEL_ON_SWITCH = new ResolverErrorCod
e('CONTINUE_LABEL_ON_SWITCH', 2, ErrorType.COMPILE_TIME_ERROR, "A continue label
resolves to switch, must be loop or switch member"); |
| 4440 /** |
| 4441 * It is a compile-time error if [the URI] is not a compile-time constant, or
if [the URI] |
| 4442 * involves string interpolation. |
| 4443 */ |
| 4444 static final ResolverErrorCode INVALID_URI = new ResolverErrorCode('INVALID_UR
I', 3, ErrorType.COMPILE_TIME_ERROR, "URI's used in directives must be compile t
ime constants without interpolation expressions"); |
| 4445 static final ResolverErrorCode LABEL_IN_OUTER_SCOPE = new ResolverErrorCode('L
ABEL_IN_OUTER_SCOPE', 4, ErrorType.COMPILE_TIME_ERROR, "Cannot reference label '
%s' declared in an outer method or function"); |
| 4446 static final ResolverErrorCode MISSING_LIBRARY_DIRECTIVE_IMPORTED = new Resolv
erErrorCode('MISSING_LIBRARY_DIRECTIVE_IMPORTED', 5, ErrorType.COMPILE_TIME_ERRO
R, "Libraries that are imported by other libraries must have a library directive
"); |
| 4447 static final ResolverErrorCode MISSING_LIBRARY_DIRECTIVE_WITH_PART = new Resol
verErrorCode('MISSING_LIBRARY_DIRECTIVE_WITH_PART', 6, ErrorType.COMPILE_TIME_ER
ROR, "Libraries that have parts must have a library directive"); |
| 4448 static final ResolverErrorCode MISSING_PART_OF_DIRECTIVE = new ResolverErrorCo
de('MISSING_PART_OF_DIRECTIVE', 7, ErrorType.COMPILE_TIME_ERROR, "The included p
art must have a part-of directive"); |
| 4449 static final ResolverErrorCode NON_BOOLEAN_CONDITION = new ResolverErrorCode('
NON_BOOLEAN_CONDITION', 8, ErrorType.STATIC_TYPE_WARNING, "Conditions must have
a static type of 'bool'"); |
| 4450 static final ResolverErrorCode PART_WITH_WRONG_LIBRARY_NAME = new ResolverErro
rCode('PART_WITH_WRONG_LIBRARY_NAME', 9, ErrorType.STATIC_WARNING, "The included
part appears to be part of the library '%s'"); |
| 4451 static final ResolverErrorCode UNDEFINED_LABEL = new ResolverErrorCode('UNDEFI
NED_LABEL', 10, ErrorType.COMPILE_TIME_ERROR, "The label '%s' is not defined"); |
| 4452 static final ResolverErrorCode DUPLICATE_MEMBER_ERROR = new ResolverErrorCode(
'DUPLICATE_MEMBER_ERROR', 11, ErrorType.COMPILE_TIME_ERROR, "Duplicate member '%
s'"); |
| 4453 static final ResolverErrorCode DUPLICATE_MEMBER_WARNING = new ResolverErrorCod
e('DUPLICATE_MEMBER_WARNING', 12, ErrorType.STATIC_WARNING, "Duplicate member '%
s'"); |
| 4454 static final List<ResolverErrorCode> values = [BREAK_LABEL_ON_SWITCH_MEMBER, C
ANNOT_BE_RESOLVED, CONTINUE_LABEL_ON_SWITCH, INVALID_URI, LABEL_IN_OUTER_SCOPE,
MISSING_LIBRARY_DIRECTIVE_IMPORTED, MISSING_LIBRARY_DIRECTIVE_WITH_PART, MISSING
_PART_OF_DIRECTIVE, NON_BOOLEAN_CONDITION, PART_WITH_WRONG_LIBRARY_NAME, UNDEFIN
ED_LABEL, DUPLICATE_MEMBER_ERROR, DUPLICATE_MEMBER_WARNING]; |
| 4455 final String __name; |
| 4456 final int __ordinal; |
| 4457 /** |
| 4458 * The type of this error. |
| 4459 */ |
| 4460 ErrorType _type; |
| 4461 /** |
| 4462 * The message template used to create the message to be displayed for this er
ror. |
| 4463 */ |
| 4464 String _message; |
| 4465 /** |
| 4466 * Initialize a newly created error code to have the given type and message. |
| 4467 * @param type the type of this error |
| 4468 * @param message the message template used to create the message to be displa
yed for the error |
| 4469 */ |
| 4470 ResolverErrorCode(this.__name, this.__ordinal, ErrorType type, String message)
{ |
| 4471 this._type = type; |
| 4472 this._message = message; |
| 4473 } |
| 4474 ErrorSeverity get errorSeverity => _type.severity; |
| 4475 String get message => _message; |
| 4476 ErrorType get type => _type; |
| 4477 bool needsRecompilation() => true; |
| 4478 String toString() => __name; |
| 4479 } |
OLD | NEW |