Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

Commit

Permalink
Add PrefixElement.scope to API.
Browse files Browse the repository at this point in the history
Change-Id: Ie673f521301d6ddc1b40d86ef7c02544f07e53fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154160
Commit-Queue: Konstantin Shcheglov <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
  • Loading branch information
scheglov authored and [email protected] committed Jul 12, 2020
1 parent 8e69e0d commit eb38d2a
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pkg/analyzer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Added `InterfaceType.allSupertypes`.
* Added `InterfaceType.asInstanceOf(ClassElement)`.
* Removed deprecated internal `bogus-disabled` and `bogus-enabled`.
* Added `Scope` and `LibraryElement.scope`.
* Added `Scope`, `LibraryElement.scope`, and `PrefixElement.scope`.

## 0.39.12
* Deprecated `canUseSummaries` in `DartSdkManager` constructor.
Expand Down
5 changes: 5 additions & 0 deletions pkg/analyzer/lib/dart/element/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,11 @@ abstract class ParameterElement
abstract class PrefixElement implements Element {
@override
LibraryElement get enclosingElement;

/// Return the name lookup scope for this import prefix. It consists of
/// elements imported into the enclosing library with this prefix. The
/// namespace combinators of the import directives are taken into account.
Scope get scope;
}

/// A variable that might be subject to type promotion. This might be a local
Expand Down
6 changes: 6 additions & 0 deletions pkg/analyzer/lib/src/dart/element/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6958,6 +6958,9 @@ mixin ParameterElementMixin implements ParameterElement {

/// A concrete implementation of a [PrefixElement].
class PrefixElementImpl extends ElementImpl implements PrefixElement {
/// The scope of this prefix, `null` if it has not been created yet.
PrefixScope _scope;

/// Initialize a newly created method element to have the given [name] and
/// [nameOffset].
PrefixElementImpl(String name, int nameOffset) : super(name, nameOffset);
Expand Down Expand Up @@ -6992,6 +6995,9 @@ class PrefixElementImpl extends ElementImpl implements PrefixElement {
return super.nameOffset;
}

@override
Scope get scope => _scope ??= PrefixScope(this);

@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitPrefixElement(this);

Expand Down
87 changes: 87 additions & 0 deletions pkg/analyzer/lib/src/dart/element/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/resolver/scope.dart' as impl;
import 'package:meta/meta.dart';

Expand All @@ -26,3 +27,89 @@ class LibraryScope implements Scope {
return _implScope.lookup(identifier, _libraryElement);
}
}

class PrefixScope implements Scope {
final PrefixElement _element;
final Map<String, Element> _getters = {};
final Map<String, Element> _setters = {};

PrefixScope(this._element) {
for (var import in _element.enclosingElement.imports) {
if (import.prefix == _element) {
var elements = impl.NamespaceBuilder().getImportedElements(import);
elements.forEach(_add);
}
}
}

@override
Element lookup({@required String id, @required bool setter}) {
var map = setter ? _setters : _getters;
return map[id];
}

void _add(Element element) {
var setter = element is PropertyAccessorElement && element.isSetter;
_addTo(
map: setter ? _setters : _getters,
element: element,
);
}

void _addTo({
@required Map<String, Element> map,
@required Element element,
}) {
var id = element.displayName;

var existing = map[id];
if (existing != null && existing != element) {
map[id] = _merge(existing, element);
return;
}

map[id] = element;
}

Element _merge(Element existing, Element other) {
if (_isSdkElement(existing)) {
if (!_isSdkElement(other)) {
return other;
}
} else {
if (_isSdkElement(other)) {
return existing;
}
}

var conflictingElements = <Element>{};
_addElement(conflictingElements, existing);
_addElement(conflictingElements, other);

var definingLibrary = _element.enclosingElement;
return MultiplyDefinedElementImpl(
definingLibrary.context,
definingLibrary.session,
conflictingElements.first.name,
conflictingElements.toList(),
);
}

static void _addElement(
Set<Element> conflictingElements,
Element element,
) {
if (element is MultiplyDefinedElementImpl) {
conflictingElements.addAll(element.conflictingElements);
} else {
conflictingElements.add(element);
}
}

static bool _isSdkElement(Element element) {
if (element is NeverElementImpl) {
return true;
}
return element.library.isInSdk;
}
}
13 changes: 13 additions & 0 deletions pkg/analyzer/lib/src/dart/resolver/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,19 @@ class NamespaceBuilder {
return Namespace(definedNames);
}

/// Return elements imported with the given [element].
Iterable<Element> getImportedElements(ImportElement element) {
var importedLibrary = element.importedLibrary;

// If the URI is invalid.
if (importedLibrary == null) {
return [];
}

var map = _getExportMapping(importedLibrary);
return _applyCombinators(map, element.combinators).values;
}

/// Add all of the names in the given [namespace] to the table of
/// [definedNames].
void _addAllFromNamespace(
Expand Down
Loading

0 comments on commit eb38d2a

Please sign in to comment.