| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.src.dart.resolver.scope; | 5 library analyzer.src.dart.resolver.scope; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 getSource(identifier), | 121 getSource(identifier), |
| 122 identifier.offset, | 122 identifier.offset, |
| 123 identifier.length, | 123 identifier.length, |
| 124 CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, [])); | 124 CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, [])); |
| 125 return hiddenElement; | 125 return hiddenElement; |
| 126 } | 126 } |
| 127 } | 127 } |
| 128 // Check enclosing scope. | 128 // Check enclosing scope. |
| 129 return enclosingScope.internalLookup(identifier, name, referencingLibrary); | 129 return enclosingScope.internalLookup(identifier, name, referencingLibrary); |
| 130 } | 130 } |
| 131 |
| 132 @override |
| 133 Element _internalLookupPrefixed(Identifier identifier, String prefix, |
| 134 String name, LibraryElement referencingLibrary) { |
| 135 return enclosingScope._internalLookupPrefixed( |
| 136 identifier, prefix, name, referencingLibrary); |
| 137 } |
| 131 } | 138 } |
| 132 | 139 |
| 133 /** | 140 /** |
| 134 * The scope defined by a function. | 141 * The scope defined by a function. |
| 135 */ | 142 */ |
| 136 class FunctionScope extends EnclosedScope { | 143 class FunctionScope extends EnclosedScope { |
| 137 /** | 144 /** |
| 138 * The element representing the function that defines this scope. | 145 * The element representing the function that defines this scope. |
| 139 */ | 146 */ |
| 140 final ExecutableElement _functionElement; | 147 final ExecutableElement _functionElement; |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 @override | 347 @override |
| 341 final AnalysisErrorListener errorListener; | 348 final AnalysisErrorListener errorListener; |
| 342 | 349 |
| 343 /** | 350 /** |
| 344 * A list of the namespaces representing the names that are available in this
scope from imported | 351 * A list of the namespaces representing the names that are available in this
scope from imported |
| 345 * libraries. | 352 * libraries. |
| 346 */ | 353 */ |
| 347 List<Namespace> _importedNamespaces; | 354 List<Namespace> _importedNamespaces; |
| 348 | 355 |
| 349 /** | 356 /** |
| 357 * A table mapping prefixes that have been referenced to a map from the names |
| 358 * that have been referenced to the element associated with the prefixed name. |
| 359 */ |
| 360 Map<String, Map<String, Element>> _definedPrefixedNames; |
| 361 |
| 362 /** |
| 350 * Initialize a newly created scope representing the names imported into the | 363 * Initialize a newly created scope representing the names imported into the |
| 351 * [_definingLibrary]. The [errorListener] is the listener that is to be | 364 * [_definingLibrary]. The [errorListener] is the listener that is to be |
| 352 * informed when an error is encountered. | 365 * informed when an error is encountered. |
| 353 */ | 366 */ |
| 354 LibraryImportScope(this._definingLibrary, this.errorListener) { | 367 LibraryImportScope(this._definingLibrary, this.errorListener) { |
| 355 _createImportedNamespaces(); | 368 _createImportedNamespaces(); |
| 356 } | 369 } |
| 357 | 370 |
| 358 @override | 371 @override |
| 359 void define(Element element) { | 372 void define(Element element) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 List<ImportElement> imports = _definingLibrary.imports; | 442 List<ImportElement> imports = _definingLibrary.imports; |
| 430 int count = imports.length; | 443 int count = imports.length; |
| 431 _importedNamespaces = new List<Namespace>(count); | 444 _importedNamespaces = new List<Namespace>(count); |
| 432 for (int i = 0; i < count; i++) { | 445 for (int i = 0; i < count; i++) { |
| 433 _importedNamespaces[i] = | 446 _importedNamespaces[i] = |
| 434 builder.createImportNamespaceForDirective(imports[i]); | 447 builder.createImportNamespaceForDirective(imports[i]); |
| 435 } | 448 } |
| 436 } | 449 } |
| 437 | 450 |
| 438 /** | 451 /** |
| 452 * Add the given [element] to this scope without checking for duplication or |
| 453 * hiding. |
| 454 */ |
| 455 void _definePrefixedNameWithoutChecking( |
| 456 String prefix, String name, Element element) { |
| 457 _definedPrefixedNames ??= new HashMap<String, Map<String, Element>>(); |
| 458 Map<String, Element> unprefixedNames = _definedPrefixedNames.putIfAbsent( |
| 459 prefix, () => new HashMap<String, Element>()); |
| 460 unprefixedNames[name] = element; |
| 461 } |
| 462 |
| 463 /** |
| 439 * Return the name of the library that defines given [element]. | 464 * Return the name of the library that defines given [element]. |
| 440 */ | 465 */ |
| 441 String _getLibraryName(Element element) { | 466 String _getLibraryName(Element element) { |
| 442 if (element == null) { | 467 if (element == null) { |
| 443 return StringUtilities.EMPTY; | 468 return StringUtilities.EMPTY; |
| 444 } | 469 } |
| 445 LibraryElement library = element.library; | 470 LibraryElement library = element.library; |
| 446 if (library == null) { | 471 if (library == null) { |
| 447 return StringUtilities.EMPTY; | 472 return StringUtilities.EMPTY; |
| 448 } | 473 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 475 indirectSources.sort(); | 500 indirectSources.sort(); |
| 476 buffer.write(StringUtilities.printListOfQuotedNames(indirectSources)); | 501 buffer.write(StringUtilities.printListOfQuotedNames(indirectSources)); |
| 477 } else { | 502 } else { |
| 478 buffer.write(indirectSources[0]); | 503 buffer.write(indirectSources[0]); |
| 479 } | 504 } |
| 480 buffer.write(")"); | 505 buffer.write(")"); |
| 481 } | 506 } |
| 482 return buffer.toString(); | 507 return buffer.toString(); |
| 483 } | 508 } |
| 484 | 509 |
| 510 @override |
| 511 Element _internalLookupPrefixed(Identifier identifier, String prefix, |
| 512 String name, LibraryElement referencingLibrary) { |
| 513 Element foundElement = _localPrefixedLookup(prefix, name); |
| 514 if (foundElement != null) { |
| 515 return foundElement; |
| 516 } |
| 517 for (int i = 0; i < _importedNamespaces.length; i++) { |
| 518 Namespace nameSpace = _importedNamespaces[i]; |
| 519 Element element = nameSpace.getPrefixed(prefix, name); |
| 520 if (element != null) { |
| 521 if (foundElement == null) { |
| 522 foundElement = element; |
| 523 } else if (!identical(foundElement, element)) { |
| 524 foundElement = MultiplyDefinedElementImpl.fromElements( |
| 525 _definingLibrary.context, foundElement, element); |
| 526 } |
| 527 } |
| 528 } |
| 529 Element element = foundElement; |
| 530 if (element is MultiplyDefinedElementImpl) { |
| 531 foundElement = _removeSdkElements(identifier, name, element); |
| 532 } |
| 533 if (foundElement is MultiplyDefinedElementImpl) { |
| 534 String foundEltName = foundElement.displayName; |
| 535 List<Element> conflictingMembers = foundElement.conflictingElements; |
| 536 int count = conflictingMembers.length; |
| 537 List<String> libraryNames = new List<String>(count); |
| 538 for (int i = 0; i < count; i++) { |
| 539 libraryNames[i] = _getLibraryName(conflictingMembers[i]); |
| 540 } |
| 541 libraryNames.sort(); |
| 542 errorListener.onError(new AnalysisError( |
| 543 getSource(identifier), |
| 544 identifier.offset, |
| 545 identifier.length, |
| 546 StaticWarningCode.AMBIGUOUS_IMPORT, [ |
| 547 foundEltName, |
| 548 StringUtilities.printListOfQuotedNames(libraryNames) |
| 549 ])); |
| 550 return foundElement; |
| 551 } |
| 552 if (foundElement != null) { |
| 553 _definePrefixedNameWithoutChecking(prefix, name, foundElement); |
| 554 } |
| 555 return foundElement; |
| 556 } |
| 557 |
| 558 /** |
| 559 * Return the element with which the given [prefix] and [name] are associated, |
| 560 * or `null` if the name is not defined within this scope. |
| 561 */ |
| 562 Element _localPrefixedLookup(String prefix, String name) { |
| 563 if (_definedPrefixedNames != null) { |
| 564 Map<String, Element> unprefixedNames = _definedPrefixedNames[prefix]; |
| 565 if (unprefixedNames != null) { |
| 566 return unprefixedNames[name]; |
| 567 } |
| 568 } |
| 569 return null; |
| 570 } |
| 571 |
| 485 /** | 572 /** |
| 486 * Given a collection of elements (captured by the [foundElement]) that the | 573 * Given a collection of elements (captured by the [foundElement]) that the |
| 487 * [identifier] (with the given [name]) resolved to, remove from the list all | 574 * [identifier] (with the given [name]) resolved to, remove from the list all |
| 488 * of the names defined in the SDK and return the element(s) that remain. | 575 * of the names defined in the SDK and return the element(s) that remain. |
| 489 */ | 576 */ |
| 490 Element _removeSdkElements(Identifier identifier, String name, | 577 Element _removeSdkElements(Identifier identifier, String name, |
| 491 MultiplyDefinedElementImpl foundElement) { | 578 MultiplyDefinedElementImpl foundElement) { |
| 492 List<Element> conflictingElements = foundElement.conflictingElements; | 579 List<Element> conflictingElements = foundElement.conflictingElements; |
| 493 List<Element> nonSdkElements = new List<Element>(); | 580 List<Element> nonSdkElements = new List<Element>(); |
| 494 Element sdkElement = null; | 581 Element sdkElement = null; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 Namespace(this._definedNames); | 710 Namespace(this._definedNames); |
| 624 | 711 |
| 625 /** | 712 /** |
| 626 * Return a table containing the same mappings as those defined by this | 713 * Return a table containing the same mappings as those defined by this |
| 627 * namespace. | 714 * namespace. |
| 628 */ | 715 */ |
| 629 Map<String, Element> get definedNames => _definedNames; | 716 Map<String, Element> get definedNames => _definedNames; |
| 630 | 717 |
| 631 /** | 718 /** |
| 632 * Return the element in this namespace that is available to the containing | 719 * Return the element in this namespace that is available to the containing |
| 633 * scope using the given name. | 720 * scope using the given name, or `null` if there is no such element. |
| 634 */ | 721 */ |
| 635 Element get(String name) => _definedNames[name]; | 722 Element get(String name) => _definedNames[name]; |
| 723 |
| 724 /** |
| 725 * Return the element in this namespace whose name is the result of combining |
| 726 * the [prefix] and the [name], separated by a period, or `null` if there is |
| 727 * no such element. |
| 728 */ |
| 729 Element getPrefixed(String prefix, String name) => null; |
| 636 } | 730 } |
| 637 | 731 |
| 638 /** | 732 /** |
| 639 * The builder used to build a namespace. Namespace builders are thread-safe and | 733 * The builder used to build a namespace. Namespace builders are thread-safe and |
| 640 * re-usable. | 734 * re-usable. |
| 641 */ | 735 */ |
| 642 class NamespaceBuilder { | 736 class NamespaceBuilder { |
| 643 /** | 737 /** |
| 644 * Create a namespace representing the export namespace of the given [element]
. | 738 * Create a namespace representing the export namespace of the given [element]
. |
| 645 */ | 739 */ |
| (...skipping 26 matching lines...) Expand all Loading... |
| 672 LibraryElement importedLibrary = element.importedLibrary; | 766 LibraryElement importedLibrary = element.importedLibrary; |
| 673 if (importedLibrary == null) { | 767 if (importedLibrary == null) { |
| 674 // | 768 // |
| 675 // The imported library will be null if the URI does not reference a valid | 769 // The imported library will be null if the URI does not reference a valid |
| 676 // library. | 770 // library. |
| 677 // | 771 // |
| 678 return Namespace.EMPTY; | 772 return Namespace.EMPTY; |
| 679 } | 773 } |
| 680 HashMap<String, Element> exportedNames = _getExportMapping(importedLibrary); | 774 HashMap<String, Element> exportedNames = _getExportMapping(importedLibrary); |
| 681 exportedNames = _applyCombinators(exportedNames, element.combinators); | 775 exportedNames = _applyCombinators(exportedNames, element.combinators); |
| 682 exportedNames = _applyPrefix(exportedNames, element.prefix); | 776 PrefixElement prefix = element.prefix; |
| 777 if (prefix != null) { |
| 778 return new PrefixedNamespace(prefix.name, exportedNames); |
| 779 } |
| 683 return new Namespace(exportedNames); | 780 return new Namespace(exportedNames); |
| 684 } | 781 } |
| 685 | 782 |
| 686 /** | 783 /** |
| 687 * Create a namespace representing the public namespace of the given | 784 * Create a namespace representing the public namespace of the given |
| 688 * [library]. | 785 * [library]. |
| 689 */ | 786 */ |
| 690 Namespace createPublicNamespaceForLibrary(LibraryElement library) { | 787 Namespace createPublicNamespaceForLibrary(LibraryElement library) { |
| 691 HashMap<String, Element> definedNames = new HashMap<String, Element>(); | 788 HashMap<String, Element> definedNames = new HashMap<String, Element>(); |
| 692 _addPublicNames(definedNames, library.definingCompilationUnit); | 789 _addPublicNames(definedNames, library.definingCompilationUnit); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 758 } else { | 855 } else { |
| 759 // Internal error. | 856 // Internal error. |
| 760 AnalysisEngine.instance.logger | 857 AnalysisEngine.instance.logger |
| 761 .logError("Unknown type of combinator: ${combinator.runtimeType}"); | 858 .logError("Unknown type of combinator: ${combinator.runtimeType}"); |
| 762 } | 859 } |
| 763 } | 860 } |
| 764 return definedNames; | 861 return definedNames; |
| 765 } | 862 } |
| 766 | 863 |
| 767 /** | 864 /** |
| 768 * Apply the prefix defined by the [prefixElement] to all of the names in the | |
| 769 * table of [definedNames]. | |
| 770 */ | |
| 771 HashMap<String, Element> _applyPrefix( | |
| 772 HashMap<String, Element> definedNames, PrefixElement prefixElement) { | |
| 773 if (prefixElement != null) { | |
| 774 String prefix = prefixElement.name; | |
| 775 HashMap<String, Element> newNames = new HashMap<String, Element>(); | |
| 776 definedNames.forEach((String name, Element element) { | |
| 777 newNames["$prefix.$name"] = element; | |
| 778 }); | |
| 779 return newNames; | |
| 780 } else { | |
| 781 return definedNames; | |
| 782 } | |
| 783 } | |
| 784 | |
| 785 /** | |
| 786 * Create a mapping table representing the export namespace of the given | 865 * Create a mapping table representing the export namespace of the given |
| 787 * [library]. The set of [visitedElements] contains the libraries that do not | 866 * [library]. The set of [visitedElements] contains the libraries that do not |
| 788 * need to be visited when processing the export directives of the given | 867 * need to be visited when processing the export directives of the given |
| 789 * library because all of the names defined by them will be added by another | 868 * library because all of the names defined by them will be added by another |
| 790 * library. | 869 * library. |
| 791 */ | 870 */ |
| 792 HashMap<String, Element> _computeExportMapping( | 871 HashMap<String, Element> _computeExportMapping( |
| 793 LibraryElement library, HashSet<LibraryElement> visitedElements) { | 872 LibraryElement library, HashSet<LibraryElement> visitedElements) { |
| 794 visitedElements.add(library); | 873 visitedElements.add(library); |
| 795 try { | 874 try { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 element = definedNames[setterName]; | 941 element = definedNames[setterName]; |
| 863 if (element != null) { | 942 if (element != null) { |
| 864 newNames[setterName] = element; | 943 newNames[setterName] = element; |
| 865 } | 944 } |
| 866 } | 945 } |
| 867 return newNames; | 946 return newNames; |
| 868 } | 947 } |
| 869 } | 948 } |
| 870 | 949 |
| 871 /** | 950 /** |
| 951 * A mapping of identifiers to the elements represented by those identifiers. |
| 952 * Namespaces are the building blocks for scopes. |
| 953 */ |
| 954 class PrefixedNamespace implements Namespace { |
| 955 /** |
| 956 * The prefix that is prepended to each of the defined names. |
| 957 */ |
| 958 final String _prefix; |
| 959 |
| 960 /** |
| 961 * The length of the prefix. |
| 962 */ |
| 963 final int _length; |
| 964 |
| 965 /** |
| 966 * A table mapping names that are defined in this namespace to the element |
| 967 * representing the thing declared with that name. |
| 968 */ |
| 969 final HashMap<String, Element> _definedNames; |
| 970 |
| 971 /** |
| 972 * Initialize a newly created namespace to have the names resulting from |
| 973 * prefixing each of the [_definedNames] with the given [_prefix] (and a |
| 974 * period). |
| 975 */ |
| 976 PrefixedNamespace(String prefix, this._definedNames) |
| 977 : _prefix = prefix, |
| 978 _length = prefix.length; |
| 979 |
| 980 @override |
| 981 Map<String, Element> get definedNames { |
| 982 Map<String, Element> definedNames = <String, Element>{}; |
| 983 _definedNames.forEach((String name, Element element) { |
| 984 definedNames["$_prefix.$name"] = element; |
| 985 }); |
| 986 return definedNames; |
| 987 } |
| 988 |
| 989 @override |
| 990 Element get(String name) { |
| 991 if (name.startsWith(_prefix)) { |
| 992 if (name.codeUnitAt(_length) == '.'.codeUnitAt(0)) { |
| 993 return _definedNames[name.substring(_length + 1)]; |
| 994 } |
| 995 } |
| 996 return null; |
| 997 } |
| 998 |
| 999 @override |
| 1000 Element getPrefixed(String prefix, String name) { |
| 1001 if (prefix == _prefix) { |
| 1002 return _definedNames[name]; |
| 1003 } |
| 1004 return null; |
| 1005 } |
| 1006 } |
| 1007 |
| 1008 /** |
| 872 * A name scope used by the resolver to determine which names are visible at any | 1009 * A name scope used by the resolver to determine which names are visible at any |
| 873 * given point in the code. | 1010 * given point in the code. |
| 874 */ | 1011 */ |
| 875 abstract class Scope { | 1012 abstract class Scope { |
| 876 /** | 1013 /** |
| 877 * The prefix used to mark an identifier as being private to its library. | 1014 * The prefix used to mark an identifier as being private to its library. |
| 878 */ | 1015 */ |
| 879 static int PRIVATE_NAME_PREFIX = 0x5F; | 1016 static int PRIVATE_NAME_PREFIX = 0x5F; |
| 880 | 1017 |
| 881 /** | 1018 /** |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 } | 1139 } |
| 1003 return null; | 1140 return null; |
| 1004 } | 1141 } |
| 1005 | 1142 |
| 1006 /** | 1143 /** |
| 1007 * Return the element with which the given [identifier] is associated, or | 1144 * Return the element with which the given [identifier] is associated, or |
| 1008 * `null` if the name is not defined within this scope. The | 1145 * `null` if the name is not defined within this scope. The |
| 1009 * [referencingLibrary] is the library that contains the reference to the | 1146 * [referencingLibrary] is the library that contains the reference to the |
| 1010 * name, used to implement library-level privacy. | 1147 * name, used to implement library-level privacy. |
| 1011 */ | 1148 */ |
| 1012 Element lookup(Identifier identifier, LibraryElement referencingLibrary) => | 1149 Element lookup(Identifier identifier, LibraryElement referencingLibrary) { |
| 1013 internalLookup(identifier, identifier.name, referencingLibrary); | 1150 if (identifier is PrefixedIdentifier) { |
| 1151 return _internalLookupPrefixed(identifier, identifier.prefix.name, |
| 1152 identifier.identifier.name, referencingLibrary); |
| 1153 } |
| 1154 return internalLookup(identifier, identifier.name, referencingLibrary); |
| 1155 } |
| 1014 | 1156 |
| 1015 /** | 1157 /** |
| 1016 * Return the name that will be used to look up the given [element]. | 1158 * Return the name that will be used to look up the given [element]. |
| 1017 */ | 1159 */ |
| 1018 String _getName(Element element) { | 1160 String _getName(Element element) { |
| 1019 if (element is MethodElement) { | 1161 if (element is MethodElement) { |
| 1020 MethodElement method = element; | 1162 MethodElement method = element; |
| 1021 if (method.name == "-" && method.parameters.length == 0) { | 1163 if (method.name == "-" && method.parameters.length == 0) { |
| 1022 return UNARY_MINUS; | 1164 return UNARY_MINUS; |
| 1023 } | 1165 } |
| 1024 } | 1166 } |
| 1025 return element.name; | 1167 return element.name; |
| 1026 } | 1168 } |
| 1027 | 1169 |
| 1028 /** | 1170 /** |
| 1171 * Return the element with which the given [prefix] and [name] are associated, |
| 1172 * or `null` if the name is not defined within this scope. The [identifier] is |
| 1173 * the identifier node to lookup element for, used to report correct kind of a |
| 1174 * problem and associate problem with. The [referencingLibrary] is the library |
| 1175 * that contains the reference to the name, used to implement library-level |
| 1176 * privacy. |
| 1177 */ |
| 1178 Element _internalLookupPrefixed(Identifier identifier, String prefix, |
| 1179 String name, LibraryElement referencingLibrary); |
| 1180 |
| 1181 /** |
| 1029 * Return `true` if the given [name] is a library-private name. | 1182 * Return `true` if the given [name] is a library-private name. |
| 1030 */ | 1183 */ |
| 1031 static bool isPrivateName(String name) => | 1184 static bool isPrivateName(String name) => |
| 1032 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX); | 1185 name != null && StringUtilities.startsWithChar(name, PRIVATE_NAME_PREFIX); |
| 1033 } | 1186 } |
| 1034 | 1187 |
| 1035 /** | 1188 /** |
| 1036 * The scope defined by the type parameters in a class. | 1189 * The scope defined by the type parameters in a class. |
| 1037 */ | 1190 */ |
| 1038 class TypeParameterScope extends EnclosedScope { | 1191 class TypeParameterScope extends EnclosedScope { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1050 | 1203 |
| 1051 /** | 1204 /** |
| 1052 * Define the type parameters declared by the [classElement]. | 1205 * Define the type parameters declared by the [classElement]. |
| 1053 */ | 1206 */ |
| 1054 void _defineTypeParameters(ClassElement classElement) { | 1207 void _defineTypeParameters(ClassElement classElement) { |
| 1055 for (TypeParameterElement typeParameter in classElement.typeParameters) { | 1208 for (TypeParameterElement typeParameter in classElement.typeParameters) { |
| 1056 define(typeParameter); | 1209 define(typeParameter); |
| 1057 } | 1210 } |
| 1058 } | 1211 } |
| 1059 } | 1212 } |
| OLD | NEW |