| // 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/element/element.dart'; | 
 | import 'package:analyzer/dart/element/scope.dart'; | 
 | import 'package:analyzer/src/dart/element/element.dart'; | 
 | import 'package:analyzer/src/dart/resolver/scope.dart' as impl; | 
 | import 'package:meta/meta.dart'; | 
 |  | 
 | /// The scope defined by a class. | 
 | class ClassScope extends EnclosedScope { | 
 |   ClassScope(Scope parent, ClassElement element) : super(parent) { | 
 |     element.accessors.forEach(_addPropertyAccessor); | 
 |     element.methods.forEach(_addGetter); | 
 |   } | 
 | } | 
 |  | 
 | /// The scope for the initializers in a constructor. | 
 | class ConstructorInitializerScope extends EnclosedScope { | 
 |   ConstructorInitializerScope(Scope parent, ConstructorElement element) | 
 |       : super(parent) { | 
 |     element.parameters.forEach(_addGetter); | 
 |   } | 
 | } | 
 |  | 
 | /// A scope that is lexically enclosed in another scope. | 
 | class EnclosedScope implements Scope { | 
 |   final Scope _parent; | 
 |   final Map<String, Element> _getters = {}; | 
 |   final Map<String, Element> _setters = {}; | 
 |  | 
 |   EnclosedScope(Scope parent) : _parent = parent; | 
 |  | 
 |   Scope get parent => _parent; | 
 |  | 
 |   @Deprecated('Use lookup2() that is closer to the language specification') | 
 |   @override | 
 |   Element lookup({@required String id, @required bool setter}) { | 
 |     var result = lookup2(id); | 
 |     return setter ? result.setter : result.getter; | 
 |   } | 
 |  | 
 |   @override | 
 |   ScopeLookupResult lookup2(String id) { | 
 |     var getter = _getters[id]; | 
 |     var setter = _setters[id]; | 
 |     if (getter != null || setter != null) { | 
 |       return ScopeLookupResult(getter, setter); | 
 |     } | 
 |  | 
 |     return _parent.lookup2(id); | 
 |   } | 
 |  | 
 |   void _addGetter(Element element) { | 
 |     _addTo(_getters, element); | 
 |   } | 
 |  | 
 |   void _addPropertyAccessor(PropertyAccessorElement element) { | 
 |     if (element.isGetter) { | 
 |       _addGetter(element); | 
 |     } else { | 
 |       _addSetter(element); | 
 |     } | 
 |   } | 
 |  | 
 |   void _addSetter(Element element) { | 
 |     _addTo(_setters, element); | 
 |   } | 
 |  | 
 |   void _addTo(Map<String, Element> map, Element element) { | 
 |     var id = element.displayName; | 
 |     map[id] ??= element; | 
 |   } | 
 | } | 
 |  | 
 | /// The scope defined by an extension. | 
 | class ExtensionScope extends EnclosedScope { | 
 |   ExtensionScope( | 
 |     Scope parent, | 
 |     ExtensionElement element, | 
 |   ) : super(parent) { | 
 |     element.accessors.forEach(_addPropertyAccessor); | 
 |     element.methods.forEach(_addGetter); | 
 |   } | 
 | } | 
 |  | 
 | class FormalParameterScope extends EnclosedScope { | 
 |   FormalParameterScope( | 
 |     Scope parent, | 
 |     List<ParameterElement> elements, | 
 |   ) : super(parent) { | 
 |     for (var parameter in elements) { | 
 |       if (parameter is! FieldFormalParameterElement) { | 
 |         _addGetter(parameter); | 
 |       } | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | class LibraryScope extends EnclosedScope { | 
 |   final LibraryElement _element; | 
 |   final List<ExtensionElement> extensions = []; | 
 |  | 
 |   LibraryScope(LibraryElement element) | 
 |       : _element = element, | 
 |         super(_LibraryImportScope(element)) { | 
 |     extensions.addAll((_parent as _LibraryImportScope).extensions); | 
 |  | 
 |     _element.prefixes.forEach(_addGetter); | 
 |     _element.units.forEach(_addUnitElements); | 
 |   } | 
 |  | 
 |   bool shouldIgnoreUndefined({ | 
 |     @required String prefix, | 
 |     @required String name, | 
 |   }) { | 
 |     Iterable<NamespaceCombinator> getShowCombinators( | 
 |         ImportElement importElement) { | 
 |       return importElement.combinators.whereType<ShowElementCombinator>(); | 
 |     } | 
 |  | 
 |     if (prefix != null) { | 
 |       for (var importElement in _element.imports) { | 
 |         if (importElement.prefix?.name == prefix && | 
 |             importElement.importedLibrary?.isSynthetic != false) { | 
 |           var showCombinators = getShowCombinators(importElement); | 
 |           if (showCombinators.isEmpty) { | 
 |             return true; | 
 |           } | 
 |           for (ShowElementCombinator combinator in showCombinators) { | 
 |             if (combinator.shownNames.contains(name)) { | 
 |               return true; | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |     } else { | 
 |       // TODO(scheglov) merge for(s). | 
 |       for (var importElement in _element.imports) { | 
 |         if (importElement.prefix == null && | 
 |             importElement.importedLibrary?.isSynthetic != false) { | 
 |           for (ShowElementCombinator combinator | 
 |               in getShowCombinators(importElement)) { | 
 |             if (combinator.shownNames.contains(name)) { | 
 |               return true; | 
 |             } | 
 |           } | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     return false; | 
 |   } | 
 |  | 
 |   void _addExtension(ExtensionElement element) { | 
 |     _addGetter(element); | 
 |     if (!extensions.contains(element)) { | 
 |       extensions.add(element); | 
 |     } | 
 |   } | 
 |  | 
 |   void _addUnitElements(CompilationUnitElement compilationUnit) { | 
 |     compilationUnit.accessors.forEach(_addPropertyAccessor); | 
 |     compilationUnit.enums.forEach(_addGetter); | 
 |     compilationUnit.extensions.forEach(_addExtension); | 
 |     compilationUnit.functions.forEach(_addGetter); | 
 |     compilationUnit.functionTypeAliases.forEach(_addGetter); | 
 |     compilationUnit.mixins.forEach(_addGetter); | 
 |     compilationUnit.types.forEach(_addGetter); | 
 |   } | 
 | } | 
 |  | 
 | class LocalScope extends EnclosedScope { | 
 |   LocalScope(Scope parent) : super(parent); | 
 |  | 
 |   void add(Element element) { | 
 |     _addGetter(element); | 
 |   } | 
 | } | 
 |  | 
 | class PrefixScope implements Scope { | 
 |   final LibraryElement _library; | 
 |   final Map<String, Element> _getters = {}; | 
 |   final Map<String, Element> _setters = {}; | 
 |   final Set<ExtensionElement> _extensions = {}; | 
 |  | 
 |   PrefixScope(this._library, PrefixElement prefix) { | 
 |     for (var import in _library.imports) { | 
 |       if (import.prefix == prefix) { | 
 |         var elements = impl.NamespaceBuilder().getImportedElements(import); | 
 |         elements.forEach(_add); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   @Deprecated('Use lookup2() that is closer to the language specification') | 
 |   @override | 
 |   Element lookup({@required String id, @required bool setter}) { | 
 |     var result = lookup2(id); | 
 |     return setter ? result.setter : result.getter; | 
 |   } | 
 |  | 
 |   @override | 
 |   ScopeLookupResult lookup2(String id) { | 
 |     var getter = _getters[id]; | 
 |     var setter = _setters[id]; | 
 |     return ScopeLookupResult(getter, setter); | 
 |   } | 
 |  | 
 |   void _add(Element element) { | 
 |     if (element is PropertyAccessorElement && element.isSetter) { | 
 |       _addTo(map: _setters, element: element); | 
 |     } else { | 
 |       _addTo(map: _getters, element: element); | 
 |       if (element is ExtensionElement) { | 
 |         _extensions.add(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); | 
 |  | 
 |     return MultiplyDefinedElementImpl( | 
 |       _library.context, | 
 |       _library.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 DynamicElementImpl || element is NeverElementImpl) { | 
 |       return true; | 
 |     } | 
 |     if (element is MultiplyDefinedElement) { | 
 |       return false; | 
 |     } | 
 |     return element.library.isInSdk; | 
 |   } | 
 | } | 
 |  | 
 | class TypeParameterScope extends EnclosedScope { | 
 |   TypeParameterScope( | 
 |     Scope parent, | 
 |     List<TypeParameterElement> elements, | 
 |   ) : super(parent) { | 
 |     elements.forEach(_addGetter); | 
 |   } | 
 | } | 
 |  | 
 | class _LibraryImportScope implements Scope { | 
 |   final LibraryElement _library; | 
 |   final PrefixScope _nullPrefixScope; | 
 |   List<ExtensionElement> _extensions; | 
 |  | 
 |   _LibraryImportScope(LibraryElement library) | 
 |       : _library = library, | 
 |         _nullPrefixScope = PrefixScope(library, null); | 
 |  | 
 |   List<ExtensionElement> get extensions { | 
 |     return _extensions ??= { | 
 |       ..._nullPrefixScope._extensions, | 
 |       for (var prefix in _library.prefixes) | 
 |         ...(prefix.scope as PrefixScope)._extensions, | 
 |     }.toList(); | 
 |   } | 
 |  | 
 |   @Deprecated('Use lookup2() that is closer to the language specification') | 
 |   @override | 
 |   Element lookup({@required String id, @required bool setter}) { | 
 |     throw UnimplementedError(); | 
 |   } | 
 |  | 
 |   @override | 
 |   ScopeLookupResult lookup2(String id) { | 
 |     return _nullPrefixScope.lookup2(id); | 
 |   } | 
 | } |