blob: f8bdc38f2896ee9ac138e319a8bcb420ef07cd5e [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
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';
class LibraryScope implements Scope {
final LibraryElement _libraryElement;
final impl.LibraryScope _implScope;
LibraryScope(LibraryElement libraryElement)
: _libraryElement = libraryElement,
_implScope = impl.LibraryScope(libraryElement);
@override
Element lookup({@required String id, @required bool setter}) {
var name = setter ? '$id=' : id;
var token = SyntheticStringToken(TokenType.IDENTIFIER, name, 0);
var identifier = astFactory.simpleIdentifier(token);
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;
}
}