| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library analyzer.src.dart.resolver.scope; |
| 6 |
| 7 import 'dart:collection'; |
| 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/element/element.dart'; |
| 11 import 'package:analyzer/src/dart/element/element.dart'; |
| 12 import 'package:analyzer/src/generated/engine.dart'; |
| 13 import 'package:analyzer/src/generated/error.dart'; |
| 14 import 'package:analyzer/src/generated/java_core.dart'; |
| 15 import 'package:analyzer/src/generated/java_engine.dart'; |
| 16 import 'package:analyzer/src/generated/source.dart'; |
| 17 |
| 18 /** |
| 19 * The scope defined by a class. |
| 20 */ |
| 21 class ClassScope extends EnclosedScope { |
| 22 /** |
| 23 * Initialize a newly created scope, enclosed within the [enclosingScope], |
| 24 * based on the given [classElement]. |
| 25 */ |
| 26 ClassScope(Scope enclosingScope, ClassElement classElement) |
| 27 : super(enclosingScope) { |
| 28 if (classElement == null) { |
| 29 throw new IllegalArgumentException("class element cannot be null"); |
| 30 } |
| 31 _defineMembers(classElement); |
| 32 } |
| 33 |
| 34 @override |
| 35 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { |
| 36 if (existing is PropertyAccessorElement && duplicate is MethodElement) { |
| 37 if (existing.nameOffset < duplicate.nameOffset) { |
| 38 return new AnalysisError( |
| 39 duplicate.source, |
| 40 duplicate.nameOffset, |
| 41 duplicate.nameLength, |
| 42 CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME, |
| 43 [existing.displayName]); |
| 44 } else { |
| 45 return new AnalysisError( |
| 46 existing.source, |
| 47 existing.nameOffset, |
| 48 existing.nameLength, |
| 49 CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME, |
| 50 [existing.displayName]); |
| 51 } |
| 52 } |
| 53 return super.getErrorForDuplicate(existing, duplicate); |
| 54 } |
| 55 |
| 56 /** |
| 57 * Define the instance members defined by the given [classElement]. |
| 58 */ |
| 59 void _defineMembers(ClassElement classElement) { |
| 60 for (PropertyAccessorElement accessor in classElement.accessors) { |
| 61 define(accessor); |
| 62 } |
| 63 for (MethodElement method in classElement.methods) { |
| 64 define(method); |
| 65 } |
| 66 } |
| 67 } |
| 68 |
| 69 /** |
| 70 * A scope that is lexically enclosed in another scope. |
| 71 */ |
| 72 class EnclosedScope extends Scope { |
| 73 /** |
| 74 * The scope in which this scope is lexically enclosed. |
| 75 */ |
| 76 @override |
| 77 final Scope enclosingScope; |
| 78 |
| 79 /** |
| 80 * A table mapping names that will be defined in this scope, but right now are |
| 81 * not initialized. According to the scoping rules these names are hidden, |
| 82 * even if they were defined in an outer scope. |
| 83 */ |
| 84 HashMap<String, Element> _hiddenElements = new HashMap<String, Element>(); |
| 85 |
| 86 /** |
| 87 * A flag indicating whether there are any names hidden in this scope. |
| 88 */ |
| 89 bool _hasHiddenName = false; |
| 90 |
| 91 /** |
| 92 * Initialize a newly created scope, enclosed within the [enclosingScope]. |
| 93 */ |
| 94 EnclosedScope(this.enclosingScope); |
| 95 |
| 96 @override |
| 97 AnalysisErrorListener get errorListener => enclosingScope.errorListener; |
| 98 |
| 99 /** |
| 100 * Record that given [element] is declared in this scope, but hasn't been |
| 101 * initialized yet, so it is error to use. If there is already an element with |
| 102 * the given name defined in an outer scope, then it will become unavailable. |
| 103 */ |
| 104 void hide(Element element) { |
| 105 if (element != null) { |
| 106 String name = element.name; |
| 107 if (name != null && !name.isEmpty) { |
| 108 _hiddenElements[name] = element; |
| 109 _hasHiddenName = true; |
| 110 } |
| 111 } |
| 112 } |
| 113 |
| 114 @override |
| 115 Element internalLookup( |
| 116 Identifier identifier, String name, LibraryElement referencingLibrary) { |
| 117 Element element = localLookup(name, referencingLibrary); |
| 118 if (element != null) { |
| 119 return element; |
| 120 } |
| 121 // May be there is a hidden Element. |
| 122 if (_hasHiddenName) { |
| 123 Element hiddenElement = _hiddenElements[name]; |
| 124 if (hiddenElement != null) { |
| 125 errorListener.onError(new AnalysisError( |
| 126 getSource(identifier), |
| 127 identifier.offset, |
| 128 identifier.length, |
| 129 CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, [])); |
| 130 return hiddenElement; |
| 131 } |
| 132 } |
| 133 // Check enclosing scope. |
| 134 return enclosingScope.internalLookup(identifier, name, referencingLibrary); |
| 135 } |
| 136 } |
| 137 |
| 138 /** |
| 139 * The scope defined by a function. |
| 140 */ |
| 141 class FunctionScope extends EnclosedScope { |
| 142 /** |
| 143 * The element representing the function that defines this scope. |
| 144 */ |
| 145 final ExecutableElement _functionElement; |
| 146 |
| 147 /** |
| 148 * A flag indicating whether the parameters have already been defined, used to |
| 149 * prevent the parameters from being defined multiple times. |
| 150 */ |
| 151 bool _parametersDefined = false; |
| 152 |
| 153 /** |
| 154 * Initialize a newly created scope, enclosed within the [enclosingScope], |
| 155 * that represents the given [_functionElement]. |
| 156 */ |
| 157 FunctionScope(Scope enclosingScope, this._functionElement) |
| 158 : super(new EnclosedScope(new EnclosedScope(enclosingScope))) { |
| 159 if (_functionElement == null) { |
| 160 throw new IllegalArgumentException("function element cannot be null"); |
| 161 } |
| 162 _defineTypeParameters(); |
| 163 } |
| 164 |
| 165 /** |
| 166 * Define the parameters for the given function in the scope that encloses |
| 167 * this function. |
| 168 */ |
| 169 void defineParameters() { |
| 170 if (_parametersDefined) { |
| 171 return; |
| 172 } |
| 173 _parametersDefined = true; |
| 174 Scope parameterScope = enclosingScope; |
| 175 for (ParameterElement parameter in _functionElement.parameters) { |
| 176 if (!parameter.isInitializingFormal) { |
| 177 parameterScope.define(parameter); |
| 178 } |
| 179 } |
| 180 } |
| 181 |
| 182 /** |
| 183 * Define the type parameters for the function. |
| 184 */ |
| 185 void _defineTypeParameters() { |
| 186 Scope typeParameterScope = enclosingScope.enclosingScope; |
| 187 for (TypeParameterElement typeParameter |
| 188 in _functionElement.typeParameters) { |
| 189 typeParameterScope.define(typeParameter); |
| 190 } |
| 191 } |
| 192 } |
| 193 |
| 194 /** |
| 195 * The scope defined by a function type alias. |
| 196 */ |
| 197 class FunctionTypeScope extends EnclosedScope { |
| 198 final FunctionTypeAliasElement _typeElement; |
| 199 |
| 200 bool _parametersDefined = false; |
| 201 |
| 202 /** |
| 203 * Initialize a newly created scope, enclosed within the [enclosingScope], |
| 204 * that represents the given [_typeElement]. |
| 205 */ |
| 206 FunctionTypeScope(Scope enclosingScope, this._typeElement) |
| 207 : super(new EnclosedScope(enclosingScope)) { |
| 208 _defineTypeParameters(); |
| 209 } |
| 210 |
| 211 /** |
| 212 * Define the parameters for the function type alias. |
| 213 */ |
| 214 void defineParameters() { |
| 215 if (_parametersDefined) { |
| 216 return; |
| 217 } |
| 218 _parametersDefined = true; |
| 219 for (ParameterElement parameter in _typeElement.parameters) { |
| 220 define(parameter); |
| 221 } |
| 222 } |
| 223 |
| 224 /** |
| 225 * Define the type parameters for the function type alias. |
| 226 */ |
| 227 void _defineTypeParameters() { |
| 228 Scope typeParameterScope = enclosingScope; |
| 229 for (TypeParameterElement typeParameter in _typeElement.typeParameters) { |
| 230 typeParameterScope.define(typeParameter); |
| 231 } |
| 232 } |
| 233 } |
| 234 |
| 235 /** |
| 236 * The scope statements that can be the target of unlabeled `break` and |
| 237 * `continue` statements. |
| 238 */ |
| 239 class ImplicitLabelScope { |
| 240 /** |
| 241 * The implicit label scope associated with the top level of a function. |
| 242 */ |
| 243 static const ImplicitLabelScope ROOT = const ImplicitLabelScope._(null, null); |
| 244 |
| 245 /** |
| 246 * The implicit label scope enclosing this implicit label scope. |
| 247 */ |
| 248 final ImplicitLabelScope outerScope; |
| 249 |
| 250 /** |
| 251 * The statement that acts as a target for break and/or continue statements |
| 252 * at this scoping level. |
| 253 */ |
| 254 final Statement statement; |
| 255 |
| 256 /** |
| 257 * Initialize a newly created scope, enclosed within the [outerScope], |
| 258 * representing the given [statement]. |
| 259 */ |
| 260 const ImplicitLabelScope._(this.outerScope, this.statement); |
| 261 |
| 262 /** |
| 263 * Return the statement which should be the target of an unlabeled `break` or |
| 264 * `continue` statement, or `null` if there is no appropriate target. |
| 265 */ |
| 266 Statement getTarget(bool isContinue) { |
| 267 if (outerScope == null) { |
| 268 // This scope represents the toplevel of a function body, so it doesn't |
| 269 // match either break or continue. |
| 270 return null; |
| 271 } |
| 272 if (isContinue && statement is SwitchStatement) { |
| 273 return outerScope.getTarget(isContinue); |
| 274 } |
| 275 return statement; |
| 276 } |
| 277 |
| 278 /** |
| 279 * Initialize a newly created scope to represent a switch statement or loop |
| 280 * nested within the current scope. [statement] is the statement associated |
| 281 * with the newly created scope. |
| 282 */ |
| 283 ImplicitLabelScope nest(Statement statement) => |
| 284 new ImplicitLabelScope._(this, statement); |
| 285 } |
| 286 |
| 287 /** |
| 288 * A scope in which a single label is defined. |
| 289 */ |
| 290 class LabelScope { |
| 291 /** |
| 292 * The label scope enclosing this label scope. |
| 293 */ |
| 294 final LabelScope _outerScope; |
| 295 |
| 296 /** |
| 297 * The label defined in this scope. |
| 298 */ |
| 299 final String _label; |
| 300 |
| 301 /** |
| 302 * The element to which the label resolves. |
| 303 */ |
| 304 final LabelElement element; |
| 305 |
| 306 /** |
| 307 * The AST node to which the label resolves. |
| 308 */ |
| 309 final AstNode node; |
| 310 |
| 311 /** |
| 312 * Initialize a newly created scope, enclosed within the [_outerScope], |
| 313 * representing the label [_label]. The [node] is the AST node the label |
| 314 * resolves to. The [element] is the element the label resolves to. |
| 315 */ |
| 316 LabelScope(this._outerScope, this._label, this.node, this.element); |
| 317 |
| 318 /** |
| 319 * Return the LabelScope which defines [targetLabel], or `null` if it is not |
| 320 * defined in this scope. |
| 321 */ |
| 322 LabelScope lookup(String targetLabel) { |
| 323 if (_label == targetLabel) { |
| 324 return this; |
| 325 } else if (_outerScope != null) { |
| 326 return _outerScope.lookup(targetLabel); |
| 327 } else { |
| 328 return null; |
| 329 } |
| 330 } |
| 331 } |
| 332 |
| 333 /** |
| 334 * The scope containing all of the names available from imported libraries. |
| 335 */ |
| 336 class LibraryImportScope extends Scope { |
| 337 /** |
| 338 * The element representing the library in which this scope is enclosed. |
| 339 */ |
| 340 final LibraryElement _definingLibrary; |
| 341 |
| 342 /** |
| 343 * The listener that is to be informed when an error is encountered. |
| 344 */ |
| 345 @override |
| 346 final AnalysisErrorListener errorListener; |
| 347 |
| 348 /** |
| 349 * A list of the namespaces representing the names that are available in this
scope from imported |
| 350 * libraries. |
| 351 */ |
| 352 List<Namespace> _importedNamespaces; |
| 353 |
| 354 /** |
| 355 * Initialize a newly created scope representing the names imported into the |
| 356 * [_definingLibrary]. The [errorListener] is the listener that is to be |
| 357 * informed when an error is encountered. |
| 358 */ |
| 359 LibraryImportScope(this._definingLibrary, this.errorListener) { |
| 360 _createImportedNamespaces(); |
| 361 } |
| 362 |
| 363 @override |
| 364 void define(Element element) { |
| 365 if (!Scope.isPrivateName(element.displayName)) { |
| 366 super.define(element); |
| 367 } |
| 368 } |
| 369 |
| 370 @override |
| 371 Source getSource(AstNode node) { |
| 372 Source source = super.getSource(node); |
| 373 if (source == null) { |
| 374 source = _definingLibrary.definingCompilationUnit.source; |
| 375 } |
| 376 return source; |
| 377 } |
| 378 |
| 379 @override |
| 380 Element internalLookup( |
| 381 Identifier identifier, String name, LibraryElement referencingLibrary) { |
| 382 Element foundElement = localLookup(name, referencingLibrary); |
| 383 if (foundElement != null) { |
| 384 return foundElement; |
| 385 } |
| 386 for (int i = 0; i < _importedNamespaces.length; i++) { |
| 387 Namespace nameSpace = _importedNamespaces[i]; |
| 388 Element element = nameSpace.get(name); |
| 389 if (element != null) { |
| 390 if (foundElement == null) { |
| 391 foundElement = element; |
| 392 } else if (!identical(foundElement, element)) { |
| 393 foundElement = MultiplyDefinedElementImpl.fromElements( |
| 394 _definingLibrary.context, foundElement, element); |
| 395 } |
| 396 } |
| 397 } |
| 398 if (foundElement is MultiplyDefinedElementImpl) { |
| 399 foundElement = _removeSdkElements( |
| 400 identifier, name, foundElement as MultiplyDefinedElementImpl); |
| 401 } |
| 402 if (foundElement is MultiplyDefinedElementImpl) { |
| 403 String foundEltName = foundElement.displayName; |
| 404 List<Element> conflictingMembers = foundElement.conflictingElements; |
| 405 int count = conflictingMembers.length; |
| 406 List<String> libraryNames = new List<String>(count); |
| 407 for (int i = 0; i < count; i++) { |
| 408 libraryNames[i] = _getLibraryName(conflictingMembers[i]); |
| 409 } |
| 410 libraryNames.sort(); |
| 411 errorListener.onError(new AnalysisError( |
| 412 getSource(identifier), |
| 413 identifier.offset, |
| 414 identifier.length, |
| 415 StaticWarningCode.AMBIGUOUS_IMPORT, [ |
| 416 foundEltName, |
| 417 StringUtilities.printListOfQuotedNames(libraryNames) |
| 418 ])); |
| 419 return foundElement; |
| 420 } |
| 421 if (foundElement != null) { |
| 422 defineNameWithoutChecking(name, foundElement); |
| 423 } |
| 424 return foundElement; |
| 425 } |
| 426 |
| 427 /** |
| 428 * Create all of the namespaces associated with the libraries imported into |
| 429 * this library. The names are not added to this scope, but are stored for |
| 430 * later reference. |
| 431 */ |
| 432 void _createImportedNamespaces() { |
| 433 NamespaceBuilder builder = new NamespaceBuilder(); |
| 434 List<ImportElement> imports = _definingLibrary.imports; |
| 435 int count = imports.length; |
| 436 _importedNamespaces = new List<Namespace>(count); |
| 437 for (int i = 0; i < count; i++) { |
| 438 _importedNamespaces[i] = |
| 439 builder.createImportNamespaceForDirective(imports[i]); |
| 440 } |
| 441 } |
| 442 |
| 443 /** |
| 444 * Return the name of the library that defines given [element]. |
| 445 */ |
| 446 String _getLibraryName(Element element) { |
| 447 if (element == null) { |
| 448 return StringUtilities.EMPTY; |
| 449 } |
| 450 LibraryElement library = element.library; |
| 451 if (library == null) { |
| 452 return StringUtilities.EMPTY; |
| 453 } |
| 454 List<ImportElement> imports = _definingLibrary.imports; |
| 455 int count = imports.length; |
| 456 for (int i = 0; i < count; i++) { |
| 457 if (identical(imports[i].importedLibrary, library)) { |
| 458 return library.definingCompilationUnit.displayName; |
| 459 } |
| 460 } |
| 461 List<String> indirectSources = new List<String>(); |
| 462 for (int i = 0; i < count; i++) { |
| 463 LibraryElement importedLibrary = imports[i].importedLibrary; |
| 464 if (importedLibrary != null) { |
| 465 for (LibraryElement exportedLibrary |
| 466 in importedLibrary.exportedLibraries) { |
| 467 if (identical(exportedLibrary, library)) { |
| 468 indirectSources |
| 469 .add(importedLibrary.definingCompilationUnit.displayName); |
| 470 } |
| 471 } |
| 472 } |
| 473 } |
| 474 int indirectCount = indirectSources.length; |
| 475 StringBuffer buffer = new StringBuffer(); |
| 476 buffer.write(library.definingCompilationUnit.displayName); |
| 477 if (indirectCount > 0) { |
| 478 buffer.write(" (via "); |
| 479 if (indirectCount > 1) { |
| 480 indirectSources.sort(); |
| 481 buffer.write(StringUtilities.printListOfQuotedNames(indirectSources)); |
| 482 } else { |
| 483 buffer.write(indirectSources[0]); |
| 484 } |
| 485 buffer.write(")"); |
| 486 } |
| 487 return buffer.toString(); |
| 488 } |
| 489 |
| 490 /** |
| 491 * Given a collection of elements (captured by the [foundElement]) that the |
| 492 * [identifier] (with the given [name]) resolved to, remove from the list all |
| 493 * of the names defined in the SDK and return the element(s) that remain. |
| 494 */ |
| 495 Element _removeSdkElements(Identifier identifier, String name, |
| 496 MultiplyDefinedElementImpl foundElement) { |
| 497 List<Element> conflictingElements = foundElement.conflictingElements; |
| 498 List<Element> nonSdkElements = new List<Element>(); |
| 499 Element sdkElement = null; |
| 500 for (Element member in conflictingElements) { |
| 501 if (member.library.isInSdk) { |
| 502 sdkElement = member; |
| 503 } else { |
| 504 nonSdkElements.add(member); |
| 505 } |
| 506 } |
| 507 if (sdkElement != null && nonSdkElements.length > 0) { |
| 508 String sdkLibName = _getLibraryName(sdkElement); |
| 509 String otherLibName = _getLibraryName(nonSdkElements[0]); |
| 510 errorListener.onError(new AnalysisError( |
| 511 getSource(identifier), |
| 512 identifier.offset, |
| 513 identifier.length, |
| 514 StaticWarningCode.CONFLICTING_DART_IMPORT, |
| 515 [name, sdkLibName, otherLibName])); |
| 516 } |
| 517 if (nonSdkElements.length == conflictingElements.length) { |
| 518 // None of the members were removed |
| 519 return foundElement; |
| 520 } else if (nonSdkElements.length == 1) { |
| 521 // All but one member was removed |
| 522 return nonSdkElements[0]; |
| 523 } else if (nonSdkElements.length == 0) { |
| 524 // All members were removed |
| 525 AnalysisEngine.instance.logger |
| 526 .logInformation("Multiply defined SDK element: $foundElement"); |
| 527 return foundElement; |
| 528 } |
| 529 return new MultiplyDefinedElementImpl( |
| 530 _definingLibrary.context, nonSdkElements); |
| 531 } |
| 532 } |
| 533 |
| 534 /** |
| 535 * A scope containing all of the names defined in a given library. |
| 536 */ |
| 537 class LibraryScope extends EnclosedScope { |
| 538 /** |
| 539 * Initialize a newly created scope representing the names defined in the |
| 540 * [definingLibrary]. The [errorListener] is the listener that is to be |
| 541 * informed when an error is encountered |
| 542 */ |
| 543 LibraryScope( |
| 544 LibraryElement definingLibrary, AnalysisErrorListener errorListener) |
| 545 : super(new LibraryImportScope(definingLibrary, errorListener)) { |
| 546 _defineTopLevelNames(definingLibrary); |
| 547 } |
| 548 |
| 549 @override |
| 550 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { |
| 551 if (existing is PrefixElement) { |
| 552 // TODO(scheglov) consider providing actual 'nameOffset' from the |
| 553 // synthetic accessor |
| 554 int offset = duplicate.nameOffset; |
| 555 if (duplicate is PropertyAccessorElement) { |
| 556 PropertyAccessorElement accessor = duplicate; |
| 557 if (accessor.isSynthetic) { |
| 558 offset = accessor.variable.nameOffset; |
| 559 } |
| 560 } |
| 561 return new AnalysisError( |
| 562 duplicate.source, |
| 563 offset, |
| 564 duplicate.nameLength, |
| 565 CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER, |
| 566 [existing.displayName]); |
| 567 } |
| 568 return super.getErrorForDuplicate(existing, duplicate); |
| 569 } |
| 570 |
| 571 /** |
| 572 * Add to this scope all of the public top-level names that are defined in the |
| 573 * given [compilationUnit]. |
| 574 */ |
| 575 void _defineLocalNames(CompilationUnitElement compilationUnit) { |
| 576 for (PropertyAccessorElement element in compilationUnit.accessors) { |
| 577 define(element); |
| 578 } |
| 579 for (ClassElement element in compilationUnit.enums) { |
| 580 define(element); |
| 581 } |
| 582 for (FunctionElement element in compilationUnit.functions) { |
| 583 define(element); |
| 584 } |
| 585 for (FunctionTypeAliasElement element |
| 586 in compilationUnit.functionTypeAliases) { |
| 587 define(element); |
| 588 } |
| 589 for (ClassElement element in compilationUnit.types) { |
| 590 define(element); |
| 591 } |
| 592 } |
| 593 |
| 594 /** |
| 595 * Add to this scope all of the names that are explicitly defined in the |
| 596 * [definingLibrary]. |
| 597 */ |
| 598 void _defineTopLevelNames(LibraryElement definingLibrary) { |
| 599 for (PrefixElement prefix in definingLibrary.prefixes) { |
| 600 define(prefix); |
| 601 } |
| 602 _defineLocalNames(definingLibrary.definingCompilationUnit); |
| 603 for (CompilationUnitElement compilationUnit in definingLibrary.parts) { |
| 604 _defineLocalNames(compilationUnit); |
| 605 } |
| 606 } |
| 607 } |
| 608 |
| 609 /** |
| 610 * A mapping of identifiers to the elements represented by those identifiers. |
| 611 * Namespaces are the building blocks for scopes. |
| 612 */ |
| 613 class Namespace { |
| 614 /** |
| 615 * An empty namespace. |
| 616 */ |
| 617 static Namespace EMPTY = new Namespace(new HashMap<String, Element>()); |
| 618 |
| 619 /** |
| 620 * A table mapping names that are defined in this namespace to the element |
| 621 * representing the thing declared with that name. |
| 622 */ |
| 623 final HashMap<String, Element> _definedNames; |
| 624 |
| 625 /** |
| 626 * Initialize a newly created namespace to have the [_definedNames]. |
| 627 */ |
| 628 Namespace(this._definedNames); |
| 629 |
| 630 /** |
| 631 * Return a table containing the same mappings as those defined by this |
| 632 * namespace. |
| 633 */ |
| 634 Map<String, Element> get definedNames => _definedNames; |
| 635 |
| 636 /** |
| 637 * Return the element in this namespace that is available to the containing |
| 638 * scope using the given name. |
| 639 */ |
| 640 Element get(String name) => _definedNames[name]; |
| 641 } |
| 642 |
| 643 /** |
| 644 * The builder used to build a namespace. Namespace builders are thread-safe and |
| 645 * re-usable. |
| 646 */ |
| 647 class NamespaceBuilder { |
| 648 /** |
| 649 * Create a namespace representing the export namespace of the given [element]
. |
| 650 */ |
| 651 Namespace createExportNamespaceForDirective(ExportElement element) { |
| 652 LibraryElement exportedLibrary = element.exportedLibrary; |
| 653 if (exportedLibrary == null) { |
| 654 // |
| 655 // The exported library will be null if the URI does not reference a valid |
| 656 // library. |
| 657 // |
| 658 return Namespace.EMPTY; |
| 659 } |
| 660 HashMap<String, Element> exportedNames = _getExportMapping(exportedLibrary); |
| 661 exportedNames = _applyCombinators(exportedNames, element.combinators); |
| 662 return new Namespace(exportedNames); |
| 663 } |
| 664 |
| 665 /** |
| 666 * Create a namespace representing the export namespace of the given [library]
. |
| 667 */ |
| 668 Namespace createExportNamespaceForLibrary(LibraryElement library) { |
| 669 HashMap<String, Element> exportedNames = _getExportMapping(library); |
| 670 return new Namespace(exportedNames); |
| 671 } |
| 672 |
| 673 /** |
| 674 * Create a namespace representing the import namespace of the given [element]
. |
| 675 */ |
| 676 Namespace createImportNamespaceForDirective(ImportElement element) { |
| 677 LibraryElement importedLibrary = element.importedLibrary; |
| 678 if (importedLibrary == null) { |
| 679 // |
| 680 // The imported library will be null if the URI does not reference a valid |
| 681 // library. |
| 682 // |
| 683 return Namespace.EMPTY; |
| 684 } |
| 685 HashMap<String, Element> exportedNames = _getExportMapping(importedLibrary); |
| 686 exportedNames = _applyCombinators(exportedNames, element.combinators); |
| 687 exportedNames = _applyPrefix(exportedNames, element.prefix); |
| 688 return new Namespace(exportedNames); |
| 689 } |
| 690 |
| 691 /** |
| 692 * Create a namespace representing the public namespace of the given |
| 693 * [library]. |
| 694 */ |
| 695 Namespace createPublicNamespaceForLibrary(LibraryElement library) { |
| 696 HashMap<String, Element> definedNames = new HashMap<String, Element>(); |
| 697 _addPublicNames(definedNames, library.definingCompilationUnit); |
| 698 for (CompilationUnitElement compilationUnit in library.parts) { |
| 699 _addPublicNames(definedNames, compilationUnit); |
| 700 } |
| 701 return new Namespace(definedNames); |
| 702 } |
| 703 |
| 704 /** |
| 705 * Add all of the names in the given [namespace] to the table of |
| 706 * [definedNames]. |
| 707 */ |
| 708 void _addAllFromNamespace( |
| 709 Map<String, Element> definedNames, Namespace namespace) { |
| 710 if (namespace != null) { |
| 711 definedNames.addAll(namespace.definedNames); |
| 712 } |
| 713 } |
| 714 |
| 715 /** |
| 716 * Add the given [element] to the table of [definedNames] if it has a |
| 717 * publicly visible name. |
| 718 */ |
| 719 void _addIfPublic(Map<String, Element> definedNames, Element element) { |
| 720 String name = element.name; |
| 721 if (name != null && !Scope.isPrivateName(name)) { |
| 722 definedNames[name] = element; |
| 723 } |
| 724 } |
| 725 |
| 726 /** |
| 727 * Add to the table of [definedNames] all of the public top-level names that |
| 728 * are defined in the given [compilationUnit]. |
| 729 * namespace |
| 730 */ |
| 731 void _addPublicNames(Map<String, Element> definedNames, |
| 732 CompilationUnitElement compilationUnit) { |
| 733 for (PropertyAccessorElement element in compilationUnit.accessors) { |
| 734 _addIfPublic(definedNames, element); |
| 735 } |
| 736 for (ClassElement element in compilationUnit.enums) { |
| 737 _addIfPublic(definedNames, element); |
| 738 } |
| 739 for (FunctionElement element in compilationUnit.functions) { |
| 740 _addIfPublic(definedNames, element); |
| 741 } |
| 742 for (FunctionTypeAliasElement element |
| 743 in compilationUnit.functionTypeAliases) { |
| 744 _addIfPublic(definedNames, element); |
| 745 } |
| 746 for (ClassElement element in compilationUnit.types) { |
| 747 _addIfPublic(definedNames, element); |
| 748 } |
| 749 } |
| 750 |
| 751 /** |
| 752 * Apply the given [combinators] to all of the names in the given table of |
| 753 * [definedNames]. |
| 754 */ |
| 755 HashMap<String, Element> _applyCombinators( |
| 756 HashMap<String, Element> definedNames, |
| 757 List<NamespaceCombinator> combinators) { |
| 758 for (NamespaceCombinator combinator in combinators) { |
| 759 if (combinator is HideElementCombinator) { |
| 760 definedNames = _hide(definedNames, combinator.hiddenNames); |
| 761 } else if (combinator is ShowElementCombinator) { |
| 762 definedNames = _show(definedNames, combinator.shownNames); |
| 763 } else { |
| 764 // Internal error. |
| 765 AnalysisEngine.instance.logger |
| 766 .logError("Unknown type of combinator: ${combinator.runtimeType}"); |
| 767 } |
| 768 } |
| 769 return definedNames; |
| 770 } |
| 771 |
| 772 /** |
| 773 * Apply the prefix defined by the [prefixElement] to all of the names in the |
| 774 * table of [definedNames]. |
| 775 */ |
| 776 HashMap<String, Element> _applyPrefix( |
| 777 HashMap<String, Element> definedNames, PrefixElement prefixElement) { |
| 778 if (prefixElement != null) { |
| 779 String prefix = prefixElement.name; |
| 780 HashMap<String, Element> newNames = new HashMap<String, Element>(); |
| 781 definedNames.forEach((String name, Element element) { |
| 782 newNames["$prefix.$name"] = element; |
| 783 }); |
| 784 return newNames; |
| 785 } else { |
| 786 return definedNames; |
| 787 } |
| 788 } |
| 789 |
| 790 /** |
| 791 * Create a mapping table representing the export namespace of the given |
| 792 * [library]. The set of [visitedElements] contains the libraries that do not |
| 793 * need to be visited when processing the export directives of the given |
| 794 * library because all of the names defined by them will be added by another |
| 795 * library. |
| 796 */ |
| 797 HashMap<String, Element> _computeExportMapping( |
| 798 LibraryElement library, HashSet<LibraryElement> visitedElements) { |
| 799 visitedElements.add(library); |
| 800 try { |
| 801 HashMap<String, Element> definedNames = new HashMap<String, Element>(); |
| 802 for (ExportElement element in library.exports) { |
| 803 LibraryElement exportedLibrary = element.exportedLibrary; |
| 804 if (exportedLibrary != null && |
| 805 !visitedElements.contains(exportedLibrary)) { |
| 806 // |
| 807 // The exported library will be null if the URI does not reference a |
| 808 // valid library. |
| 809 // |
| 810 HashMap<String, Element> exportedNames = |
| 811 _computeExportMapping(exportedLibrary, visitedElements); |
| 812 exportedNames = _applyCombinators(exportedNames, element.combinators); |
| 813 definedNames.addAll(exportedNames); |
| 814 } |
| 815 } |
| 816 _addAllFromNamespace( |
| 817 definedNames, |
| 818 (library.context as InternalAnalysisContext) |
| 819 .getPublicNamespace(library)); |
| 820 return definedNames; |
| 821 } finally { |
| 822 visitedElements.remove(library); |
| 823 } |
| 824 } |
| 825 |
| 826 HashMap<String, Element> _getExportMapping(LibraryElement library) { |
| 827 if (library is LibraryElementImpl) { |
| 828 if (library.exportNamespace != null) { |
| 829 return library.exportNamespace.definedNames; |
| 830 } else { |
| 831 HashMap<String, Element> exportMapping = |
| 832 _computeExportMapping(library, new HashSet<LibraryElement>()); |
| 833 library.exportNamespace = new Namespace(exportMapping); |
| 834 return exportMapping; |
| 835 } |
| 836 } |
| 837 return _computeExportMapping(library, new HashSet<LibraryElement>()); |
| 838 } |
| 839 |
| 840 /** |
| 841 * Return a new map of names which has all the names from [definedNames] |
| 842 * with exception of [hiddenNames]. |
| 843 */ |
| 844 Map<String, Element> _hide( |
| 845 HashMap<String, Element> definedNames, List<String> hiddenNames) { |
| 846 HashMap<String, Element> newNames = |
| 847 new HashMap<String, Element>.from(definedNames); |
| 848 for (String name in hiddenNames) { |
| 849 newNames.remove(name); |
| 850 newNames.remove("$name="); |
| 851 } |
| 852 return newNames; |
| 853 } |
| 854 |
| 855 /** |
| 856 * Return a new map of names which has only [shownNames] from [definedNames]. |
| 857 */ |
| 858 HashMap<String, Element> _show( |
| 859 HashMap<String, Element> definedNames, List<String> shownNames) { |
| 860 HashMap<String, Element> newNames = new HashMap<String, Element>(); |
| 861 for (String name in shownNames) { |
| 862 Element element = definedNames[name]; |
| 863 if (element != null) { |
| 864 newNames[name] = element; |
| 865 } |
| 866 String setterName = "$name="; |
| 867 element = definedNames[setterName]; |
| 868 if (element != null) { |
| 869 newNames[setterName] = element; |
| 870 } |
| 871 } |
| 872 return newNames; |
| 873 } |
| 874 } |
| 875 |
| 876 /** |
| 877 * A name scope used by the resolver to determine which names are visible at any |
| 878 * given point in the code. |
| 879 */ |
| 880 abstract class Scope { |
| 881 /** |
| 882 * The prefix used to mark an identifier as being private to its library. |
| 883 */ |
| 884 static int PRIVATE_NAME_PREFIX = 0x5F; |
| 885 |
| 886 /** |
| 887 * The suffix added to the declared name of a setter when looking up the |
| 888 * setter. Used to disambiguate between a getter and a setter that have the |
| 889 * same name. |
| 890 */ |
| 891 static String SETTER_SUFFIX = "="; |
| 892 |
| 893 /** |
| 894 * The name used to look up the method used to implement the unary minus |
| 895 * operator. Used to disambiguate between the unary and binary operators. |
| 896 */ |
| 897 static String UNARY_MINUS = "unary-"; |
| 898 |
| 899 /** |
| 900 * A table mapping names that are defined in this scope to the element |
| 901 * representing the thing declared with that name. |
| 902 */ |
| 903 HashMap<String, Element> _definedNames = new HashMap<String, Element>(); |
| 904 |
| 905 /** |
| 906 * A flag indicating whether there are any names defined in this scope. |
| 907 */ |
| 908 bool _hasName = false; |
| 909 |
| 910 /** |
| 911 * Return the scope in which this scope is lexically enclosed. |
| 912 */ |
| 913 Scope get enclosingScope => null; |
| 914 |
| 915 /** |
| 916 * Return the listener that is to be informed when an error is encountered. |
| 917 */ |
| 918 AnalysisErrorListener get errorListener; |
| 919 |
| 920 /** |
| 921 * Add the given [element] to this scope. If there is already an element with |
| 922 * the given name defined in this scope, then an error will be generated and |
| 923 * the original element will continue to be mapped to the name. If there is an |
| 924 * element with the given name in an enclosing scope, then a warning will be |
| 925 * generated but the given element will hide the inherited element. |
| 926 */ |
| 927 void define(Element element) { |
| 928 String name = _getName(element); |
| 929 if (name != null && !name.isEmpty) { |
| 930 if (_definedNames.containsKey(name)) { |
| 931 errorListener |
| 932 .onError(getErrorForDuplicate(_definedNames[name], element)); |
| 933 } else { |
| 934 _definedNames[name] = element; |
| 935 _hasName = true; |
| 936 } |
| 937 } |
| 938 } |
| 939 |
| 940 /** |
| 941 * Add the given [element] to this scope without checking for duplication or |
| 942 * hiding. |
| 943 */ |
| 944 void defineNameWithoutChecking(String name, Element element) { |
| 945 _definedNames[name] = element; |
| 946 _hasName = true; |
| 947 } |
| 948 |
| 949 /** |
| 950 * Add the given [element] to this scope without checking for duplication or |
| 951 * hiding. |
| 952 */ |
| 953 void defineWithoutChecking(Element element) { |
| 954 _definedNames[_getName(element)] = element; |
| 955 _hasName = true; |
| 956 } |
| 957 |
| 958 /** |
| 959 * Return the error code to be used when reporting that a name being defined |
| 960 * locally conflicts with another element of the same name in the local scope. |
| 961 * [existing] is the first element to be declared with the conflicting name, |
| 962 * while [duplicate] another element declared with the conflicting name. |
| 963 */ |
| 964 AnalysisError getErrorForDuplicate(Element existing, Element duplicate) { |
| 965 // TODO(brianwilkerson) Customize the error message based on the types of |
| 966 // elements that share the same name. |
| 967 // TODO(jwren) There are 4 error codes for duplicate, but only 1 is being |
| 968 // generated. |
| 969 Source source = duplicate.source; |
| 970 return new AnalysisError(source, duplicate.nameOffset, duplicate.nameLength, |
| 971 CompileTimeErrorCode.DUPLICATE_DEFINITION, [existing.displayName]); |
| 972 } |
| 973 |
| 974 /** |
| 975 * Return the source that contains the given [identifier], or the source |
| 976 * associated with this scope if the source containing the identifier could |
| 977 * not be determined. |
| 978 */ |
| 979 Source getSource(AstNode identifier) { |
| 980 CompilationUnit unit = |
| 981 identifier.getAncestor((node) => node is CompilationUnit); |
| 982 if (unit != null) { |
| 983 CompilationUnitElement unitElement = unit.element; |
| 984 if (unitElement != null) { |
| 985 return unitElement.source; |
| 986 } |
| 987 } |
| 988 return null; |
| 989 } |
| 990 |
| 991 /** |
| 992 * Return the element with which the given [name] is associated, or `null` if |
| 993 * the name is not defined within this scope. The [identifier] is the |
| 994 * identifier node to lookup element for, used to report correct kind of a |
| 995 * problem and associate problem with. The [referencingLibrary] is the library |
| 996 * that contains the reference to the name, used to implement library-level |
| 997 * privacy. |
| 998 */ |
| 999 Element internalLookup( |
| 1000 Identifier identifier, String name, LibraryElement referencingLibrary); |
| 1001 |
| 1002 /** |
| 1003 * Return the element with which the given [name] is associated, or `null` if |
| 1004 * the name is not defined within this scope. This method only returns |
| 1005 * elements that are directly defined within this scope, not elements that are |
| 1006 * defined in an enclosing scope. The [referencingLibrary] is the library that |
| 1007 * contains the reference to the name, used to implement library-level privacy
. |
| 1008 */ |
| 1009 Element localLookup(String name, LibraryElement referencingLibrary) { |
| 1010 if (_hasName) { |
| 1011 return _definedNames[name]; |
| 1012 } |
| 1013 return null; |
| 1014 } |
| 1015 |
| 1016 /** |
| 1017 * Return the element with which the given [identifier] is associated, or |
| 1018 * `null` if the name is not defined within this scope. The |
| 1019 * [referencingLibrary] is the library that contains the reference to the |
| 1020 * name, used to implement library-level privacy. |
| 1021 */ |
| 1022 Element lookup(Identifier identifier, LibraryElement referencingLibrary) => |
| 1023 internalLookup(identifier, identifier.name, referencingLibrary); |
| 1024 |
| 1025 /** |
| 1026 * Return the name that will be used to look up the given [element]. |
| 1027 */ |
| 1028 String _getName(Element element) { |
| 1029 if (element is MethodElement) { |
| 1030 MethodElement method = element; |
| 1031 if (method.name == "-" && method.parameters.length == 0) { |
| 1032 return UNARY_MINUS; |
| 1033 } |
| 1034 } |
| 1035 return element.name; |
| 1036 } |
| 1037 |
| 1038 /** |
| 1039 * Return `true` if the given [name] is a library-private name. |
| 1040 */ |
| 1041 static bool isPrivateName(String name) => |
| 1042 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX); |
| 1043 } |
| 1044 |
| 1045 /** |
| 1046 * The scope defined by the type parameters in a class. |
| 1047 */ |
| 1048 class TypeParameterScope extends EnclosedScope { |
| 1049 /** |
| 1050 * Initialize a newly created scope, enclosed within the [enclosingScope], |
| 1051 * that defined the type parameters from the given [classElement]. |
| 1052 */ |
| 1053 TypeParameterScope(Scope enclosingScope, ClassElement classElement) |
| 1054 : super(enclosingScope) { |
| 1055 if (classElement == null) { |
| 1056 throw new IllegalArgumentException("class element cannot be null"); |
| 1057 } |
| 1058 _defineTypeParameters(classElement); |
| 1059 } |
| 1060 |
| 1061 /** |
| 1062 * Define the type parameters declared by the [classElement]. |
| 1063 */ |
| 1064 void _defineTypeParameters(ClassElement classElement) { |
| 1065 for (TypeParameterElement typeParameter in classElement.typeParameters) { |
| 1066 define(typeParameter); |
| 1067 } |
| 1068 } |
| 1069 } |
| OLD | NEW |