// Copyright (c) 2019, 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/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/error/codes.dart';

/// A visitor that visits ASTs and fills [UsedImportedElements].
class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor<void> {
  final LibraryElement library;
  final UsedImportedElements usedElements = UsedImportedElements();

  GatherUsedImportedElementsVisitor(this.library);

  @override
  void visitAssignmentExpression(AssignmentExpression node) {
    _recordAssignmentTarget(node, node.leftHandSide);
    return super.visitAssignmentExpression(node);
  }

  @override
  void visitBinaryExpression(BinaryExpression node) {
    _recordIfExtensionMember(node.staticElement);
    return super.visitBinaryExpression(node);
  }

  @override
  void visitExportDirective(ExportDirective node) {
    _visitDirective(node);
  }

  @override
  void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
    _recordIfExtensionMember(node.staticElement);
    return super.visitFunctionExpressionInvocation(node);
  }

  @override
  void visitImportDirective(ImportDirective node) {
    _visitDirective(node);
  }

  @override
  void visitIndexExpression(IndexExpression node) {
    _recordIfExtensionMember(node.staticElement);
    return super.visitIndexExpression(node);
  }

  @override
  void visitLibraryDirective(LibraryDirective node) {
    _visitDirective(node);
  }

  @override
  void visitPostfixExpression(PostfixExpression node) {
    _recordAssignmentTarget(node, node.operand);
    return super.visitPostfixExpression(node);
  }

  @override
  void visitPrefixExpression(PrefixExpression node) {
    _recordAssignmentTarget(node, node.operand);
    _recordIfExtensionMember(node.staticElement);
    return super.visitPrefixExpression(node);
  }

  @override
  void visitSimpleIdentifier(SimpleIdentifier node) {
    _visitIdentifier(node, node.staticElement);
  }

  void _recordAssignmentTarget(
    CompoundAssignmentExpression node,
    Expression target,
  ) {
    if (target is PrefixedIdentifier) {
      _visitIdentifier(target.identifier, node.readElement);
      _visitIdentifier(target.identifier, node.writeElement);
    } else if (target is PropertyAccess) {
      _visitIdentifier(target.propertyName, node.readElement);
      _visitIdentifier(target.propertyName, node.writeElement);
    } else if (target is SimpleIdentifier) {
      _visitIdentifier(target, node.readElement);
      _visitIdentifier(target, node.writeElement);
    }
  }

  void _recordIfExtensionMember(Element? element) {
    if (element != null) {
      var enclosingElement = element.enclosingElement;
      if (enclosingElement is ExtensionElement) {
        _recordUsedExtension(enclosingElement);
      }
    }
  }

  /// If the given [identifier] is prefixed with a [PrefixElement], fill the
  /// corresponding `UsedImportedElements.prefixMap` entry and return `true`.
  bool _recordPrefixMap(SimpleIdentifier identifier, Element element) {
    bool recordIfTargetIsPrefixElement(Expression? target) {
      if (target is SimpleIdentifier) {
        var targetElement = target.staticElement;
        if (targetElement is PrefixElement) {
          List<Element> prefixedElements = usedElements.prefixMap
              .putIfAbsent(targetElement, () => <Element>[]);
          prefixedElements.add(element);
          return true;
        }
      }
      return false;
    }

    var parent = identifier.parent;
    if (parent is MethodInvocation && parent.methodName == identifier) {
      return recordIfTargetIsPrefixElement(parent.target);
    }
    if (parent is PrefixedIdentifier && parent.identifier == identifier) {
      return recordIfTargetIsPrefixElement(parent.prefix);
    }
    return false;
  }

  /// Records use of an unprefixed [element].
  void _recordUsedElement(Element element) {
    // Ignore if an unknown library.
    var containingLibrary = element.library;
    if (containingLibrary == null) {
      return;
    }
    // Ignore if a local element.
    if (library == containingLibrary) {
      return;
    }
    // Remember the element.
    usedElements.elements.add(element);
  }

  void _recordUsedExtension(ExtensionElement extension) {
    // Ignore if a local element.
    if (library == extension.library) {
      return;
    }
    // Remember the element.
    usedElements.usedExtensions.add(extension);
  }

  /// Visit identifiers used by the given [directive].
  void _visitDirective(Directive directive) {
    directive.documentationComment?.accept(this);
    directive.metadata.accept(this);
  }

  void _visitIdentifier(SimpleIdentifier identifier, Element? element) {
    if (element == null) {
      return;
    }
    // Record `importPrefix.identifier` into 'prefixMap'.
    if (_recordPrefixMap(identifier, element)) {
      return;
    }
    var enclosingElement = element.enclosingElement;
    if (enclosingElement is CompilationUnitElement) {
      _recordUsedElement(element);
    } else if (enclosingElement is ExtensionElement) {
      _recordUsedExtension(enclosingElement);
      return;
    } else if (element is PrefixElement) {
      usedElements.prefixMap.putIfAbsent(element, () => <Element>[]);
    } else if (element is MultiplyDefinedElement) {
      // If the element is multiply defined then call this method recursively
      // for each of the conflicting elements.
      List<Element> conflictingElements = element.conflictingElements;
      int length = conflictingElements.length;
      for (int i = 0; i < length; i++) {
        Element elt = conflictingElements[i];
        _visitIdentifier(identifier, elt);
      }
    }
  }
}

/// Instances of the class `ImportsVerifier` visit all of the referenced
/// libraries in the source code verifying that all of the imports are used,
/// otherwise a [HintCode.UNUSED_IMPORT] hint is generated with
/// [generateUnusedImportHints].
///
/// Additionally, [generateDuplicateImportHints] generates
/// [HintCode.DUPLICATE_IMPORT] hints and [HintCode.UNUSED_SHOWN_NAME] hints.
///
/// While this class does not yet have support for an "Organize Imports" action,
/// this logic built up in this class could be used for such an action in the
/// future.
class ImportsVerifier {
  /// All [ImportDirective]s of the current library.
  final List<ImportDirective> _allImports = [];

  /// A list of [ImportDirective]s that the current library imports, but does
  /// not use.
  ///
  /// As identifiers are visited by this visitor and an import has been
  /// identified as being used by the library, the [ImportDirective] is removed
  /// from this list. After all the sources in the library have been evaluated,
  /// this list represents the set of unused imports.
  ///
  /// See [ImportsVerifier.generateUnusedImportErrors].
  final List<ImportDirective> _unusedImports = [];

  /// After the list of [unusedImports] has been computed, this list is a proper
  /// subset of the unused imports that are listed more than once.
  final List<ImportDirective> _duplicateImports = [];

  /// This list is a proper subset of the unused exports that are listed more
  /// than once.
  final List<ExportDirective> _duplicateExports = [];

  /// The cache of [Namespace]s for [ImportDirective]s.
  final Map<ImportDirective, Namespace> _namespaceMap = {};

  /// This is a map between prefix elements and the import directives from which
  /// they are derived. In cases where a type is referenced via a prefix
  /// element, the import directive can be marked as used (removed from the
  /// unusedImports) by looking at the resolved `lib` in `lib.X`, instead of
  /// looking at which library the `lib.X` resolves.
  final Map<PrefixElement, List<ImportDirective>> _prefixElementMap = {};

  /// A map of identifiers that the current library's imports show, but that the
  /// library does not use.
  ///
  /// Each import directive maps to a list of the identifiers that are imported
  /// via the "show" keyword.
  ///
  /// As each identifier is visited by this visitor, it is identified as being
  /// used by the library, and the identifier is removed from this map (under
  /// the import that imported it). After all the sources in the library have
  /// been evaluated, each list in this map's values present the set of unused
  /// shown elements.
  ///
  /// See [ImportsVerifier.generateUnusedShownNameHints].
  final Map<ImportDirective, List<SimpleIdentifier>> _unusedShownNamesMap = {};

  /// A map of names that are hidden more than once.
  final Map<NamespaceDirective, List<SimpleIdentifier>>
      _duplicateHiddenNamesMap = {};

  /// A map of names that are shown more than once.
  final Map<NamespaceDirective, List<SimpleIdentifier>>
      _duplicateShownNamesMap = {};

  void addImports(CompilationUnit node) {
    final importsWithLibraries = <_NamespaceDirective>[];
    final exportsWithLibraries = <_NamespaceDirective>[];
    for (var directive in node.directives) {
      if (directive is ImportDirective) {
        var libraryElement = directive.element?.importedLibrary;
        if (libraryElement == null) {
          continue;
        }
        _allImports.add(directive);
        _unusedImports.add(directive);
        importsWithLibraries.add(
          _NamespaceDirective(
            node: directive,
            library: libraryElement,
          ),
        );
        //
        // Initialize prefixElementMap
        //
        if (directive.asKeyword != null) {
          var prefixIdentifier = directive.prefix;
          if (prefixIdentifier != null) {
            var element = prefixIdentifier.staticElement;
            if (element is PrefixElement) {
              var list = _prefixElementMap[element];
              if (list == null) {
                list = <ImportDirective>[];
                _prefixElementMap[element] = list;
              }
              list.add(directive);
            }
            // TODO (jwren) Can the element ever not be a PrefixElement?
          }
        }
        _addShownNames(directive);
      } else if (directive is ExportDirective) {
        var libraryElement = directive.element?.exportedLibrary;
        if (libraryElement == null) {
          continue;
        }
        exportsWithLibraries.add(
          _NamespaceDirective(
            node: directive,
            library: libraryElement,
          ),
        );
      }

      if (directive is NamespaceDirective) {
        _addDuplicateShownHiddenNames(directive);
      }
    }
    var importDuplicates = _duplicates(importsWithLibraries);
    for (var duplicate in importDuplicates) {
      _duplicateImports.add(duplicate as ImportDirective);
    }
    var exportDuplicates = _duplicates(exportsWithLibraries);
    for (var duplicate in exportDuplicates) {
      _duplicateExports.add(duplicate as ExportDirective);
    }
  }

  /// Any time after the defining compilation unit has been visited by this
  /// visitor, this method can be called to report an
  /// [StaticWarningCode.DUPLICATE_EXPORT] hint for each of the export
  /// directives in the [_duplicateExports] list.
  void generateDuplicateExportHints(ErrorReporter errorReporter) {
    var length = _duplicateExports.length;
    for (var i = 0; i < length; i++) {
      errorReporter.reportErrorForNode(
          WarningCode.DUPLICATE_EXPORT, _duplicateExports[i].uri);
    }
  }

  /// Any time after the defining compilation unit has been visited by this
  /// visitor, this method can be called to report an
  /// [StaticWarningCode.DUPLICATE_IMPORT] hint for each of the import
  /// directives in the [_duplicateImports] list.
  void generateDuplicateImportHints(ErrorReporter errorReporter) {
    var length = _duplicateImports.length;
    for (var i = 0; i < length; i++) {
      errorReporter.reportErrorForNode(
          WarningCode.DUPLICATE_IMPORT, _duplicateImports[i].uri);
    }
  }

  /// Report a [StaticWarningCode.DUPLICATE_SHOWN_NAME] and
  /// [StaticWarningCode.DUPLICATE_HIDDEN_NAME] hints for each duplicate shown
  /// or hidden name.
  ///
  /// Only call this method after all of the compilation units have been visited
  /// by this visitor.
  void generateDuplicateShownHiddenNameHints(ErrorReporter reporter) {
    _duplicateHiddenNamesMap.forEach(
        (NamespaceDirective directive, List<SimpleIdentifier> identifiers) {
      int length = identifiers.length;
      for (int i = 0; i < length; i++) {
        Identifier identifier = identifiers[i];
        reporter.reportErrorForNode(
            WarningCode.DUPLICATE_HIDDEN_NAME, identifier);
      }
    });
    _duplicateShownNamesMap.forEach(
        (NamespaceDirective directive, List<SimpleIdentifier> identifiers) {
      int length = identifiers.length;
      for (int i = 0; i < length; i++) {
        Identifier identifier = identifiers[i];
        reporter.reportErrorForNode(
            WarningCode.DUPLICATE_SHOWN_NAME, identifier);
      }
    });
  }

  /// Report an [HintCode.UNNECESSARY_IMPORT] hint for each unnecessary import.
  ///
  /// Only call this method after unused imports have been determined by
  /// [removeUsedElements].
  void generateUnnecessaryImportHints(ErrorReporter errorReporter,
      List<UsedImportedElements> usedImportedElementsList) {
    var usedImports = {..._allImports}..removeAll(_unusedImports);

    var verifier = _UnnecessaryImportsVerifier(_namespaceMap, usedImports);
    verifier.processUsedElements(
        usedImportedElementsList, _prefixElementMap, _allImports);
    verifier.reportImports(errorReporter);
  }

  /// Report an [HintCode.UNUSED_IMPORT] hint for each unused import.
  ///
  /// Only call this method after all of the compilation units have been visited
  /// by this visitor.
  ///
  /// @param errorReporter the error reporter used to report the set of
  ///        [HintCode.UNUSED_IMPORT] hints
  void generateUnusedImportHints(ErrorReporter errorReporter) {
    int length = _unusedImports.length;
    for (int i = 0; i < length; i++) {
      ImportDirective unusedImport = _unusedImports[i];
      // Check that the imported URI exists and isn't dart:core
      var importElement = unusedImport.element;
      if (importElement != null) {
        var libraryElement = importElement.importedLibrary;
        if (libraryElement == null ||
            libraryElement.isDartCore ||
            libraryElement.isSynthetic) {
          continue;
        }
      }
      StringLiteral uri = unusedImport.uri;
      // We can safely assume that `uri.stringValue` is non-`null`, because the
      // only way for it to be `null` is if the import contains a string
      // interpolation, in which case the import wouldn't have resolved and
      // would not have been included in [_unusedImports].
      errorReporter
          .reportErrorForNode(HintCode.UNUSED_IMPORT, uri, [uri.stringValue!]);
    }
  }

  /// Use the error [reporter] to report an [HintCode.UNUSED_SHOWN_NAME] hint
  /// for each unused shown name.
  ///
  /// This method should only be invoked after all of the compilation units have
  /// been visited by this visitor.
  void generateUnusedShownNameHints(ErrorReporter reporter) {
    _unusedShownNamesMap.forEach(
        (ImportDirective importDirective, List<SimpleIdentifier> identifiers) {
      if (_unusedImports.contains(importDirective)) {
        // The whole import is unused, not just one or more shown names from it,
        // so an "unused_import" hint will be generated, making it unnecessary
        // to generate hints for the individual names.
        return;
      }
      int length = identifiers.length;
      for (int i = 0; i < length; i++) {
        Identifier identifier = identifiers[i];
        var duplicateNames = _duplicateShownNamesMap[importDirective];
        if (duplicateNames == null || !duplicateNames.contains(identifier)) {
          // Only generate a hint if we won't also generate a
          // "duplicate_shown_name" hint for the same identifier.
          reporter.reportErrorForNode(
              HintCode.UNUSED_SHOWN_NAME, identifier, [identifier.name]);
        }
      }
    });
  }

  /// Remove elements from [_unusedImports] using the given [usedElements].
  void removeUsedElements(UsedImportedElements usedElements) {
    bool everythingIsKnownToBeUsed() =>
        _unusedImports.isEmpty && _unusedShownNamesMap.isEmpty;

    // Process import prefixes.
    for (var entry in usedElements.prefixMap.entries) {
      if (everythingIsKnownToBeUsed()) {
        return;
      }
      var prefix = entry.key;
      var importDirectives = _prefixElementMap[prefix];
      if (importDirectives == null) {
        continue;
      }
      var elements = entry.value;
      // Find import directives using namespaces.
      for (var importDirective in importDirectives) {
        if (elements.isEmpty) {
          // [prefix] and [elements] were added to [usedElements.prefixMap] but
          // [elements] is empty, so the prefix was referenced incorrectly.
          // Another diagnostic about the prefix reference is reported, and we
          // shouldn't confuse by also reporting an unused prefix.
          _unusedImports.remove(importDirective);
        }
        var namespace = _namespaceMap.computeNamespace(importDirective);
        if (namespace == null) {
          continue;
        }
        for (var element in elements) {
          if (namespace.providesPrefixed(prefix.name, element)) {
            _unusedImports.remove(importDirective);
            _removeFromUnusedShownNamesMap(element, importDirective);
          }
        }
      }
    }

    // Process top-level elements.
    for (Element element in usedElements.elements) {
      if (everythingIsKnownToBeUsed()) {
        return;
      }
      // Find import directives using namespaces.
      for (ImportDirective importDirective in _allImports) {
        var namespace = _namespaceMap.computeNamespace(importDirective);
        if (namespace == null) {
          continue;
        }
        if (namespace.provides(element)) {
          _unusedImports.remove(importDirective);
          _removeFromUnusedShownNamesMap(element, importDirective);
        }
      }
    }
    // Process extension elements.
    for (ExtensionElement extensionElement in usedElements.usedExtensions) {
      if (everythingIsKnownToBeUsed()) {
        return;
      }
      var elementName = extensionElement.name!;
      // Find import directives using namespaces.
      for (ImportDirective importDirective in _allImports) {
        var namespace = _namespaceMap.computeNamespace(importDirective);
        if (namespace == null) {
          continue;
        }
        var prefix = importDirective.prefix?.name;
        if (prefix == null) {
          if (namespace.get(elementName) == extensionElement) {
            _unusedImports.remove(importDirective);
            _removeFromUnusedShownNamesMap(extensionElement, importDirective);
          }
        } else {
          // An extension might be used solely because one or more instance
          // members are referenced, which does not require explicit use of the
          // prefix. We still indicate that the import directive is used.
          if (namespace.getPrefixed(prefix, elementName) == extensionElement) {
            _unusedImports.remove(importDirective);
            _removeFromUnusedShownNamesMap(extensionElement, importDirective);
          }
        }
      }
    }
  }

  /// Add duplicate shown and hidden names from [directive] into
  /// [_duplicateHiddenNamesMap] and [_duplicateShownNamesMap].
  void _addDuplicateShownHiddenNames(NamespaceDirective directive) {
    for (var combinator in directive.combinators) {
      // Use a Set to find duplicates in faster than O(n^2) time.
      var identifiers = <Element>{};
      if (combinator is HideCombinator) {
        for (var name in combinator.hiddenNames) {
          var element = name.staticElement;
          if (element != null) {
            if (!identifiers.add(element)) {
              // [name] is a duplicate.
              List<SimpleIdentifier> duplicateNames =
                  _duplicateHiddenNamesMap.putIfAbsent(directive, () => []);
              duplicateNames.add(name);
            }
          }
        }
      } else if (combinator is ShowCombinator) {
        for (var name in combinator.shownNames) {
          var element = name.staticElement;
          if (element != null) {
            if (!identifiers.add(element)) {
              // [name] is a duplicate.
              List<SimpleIdentifier> duplicateNames =
                  _duplicateShownNamesMap.putIfAbsent(directive, () => []);
              duplicateNames.add(name);
            }
          }
        }
      }
    }
  }

  /// Add every shown name from [importDirective] into [_unusedShownNamesMap].
  void _addShownNames(ImportDirective importDirective) {
    List<SimpleIdentifier> identifiers = <SimpleIdentifier>[];
    _unusedShownNamesMap[importDirective] = identifiers;
    for (Combinator combinator in importDirective.combinators) {
      if (combinator is ShowCombinator) {
        for (SimpleIdentifier name in combinator.shownNames) {
          if (name.staticElement != null) {
            identifiers.add(name);
          }
        }
      }
    }
  }

  /// Return the duplicates in [directives].
  List<NamespaceDirective> _duplicates(List<_NamespaceDirective> directives) {
    var duplicates = <NamespaceDirective>[];
    if (directives.length > 1) {
      // order the list of directives to find duplicates in faster than
      // O(n^2) time
      directives.sort((import1, import2) {
        return import1.libraryUriStr.compareTo(import2.libraryUriStr);
      });
      var currentDirective = directives[0];
      for (var i = 1; i < directives.length; i++) {
        final nextDirective = directives[i];
        if (currentDirective.libraryUriStr == nextDirective.libraryUriStr &&
            ImportDirectiveImpl.areSyntacticallyIdenticalExceptUri(
              currentDirective.node,
              nextDirective.node,
            )) {
          // Add either the currentDirective or nextDirective depending on which
          // comes second, this guarantees that the first of the duplicates
          // won't be highlighted.
          if (currentDirective.node.offset < nextDirective.node.offset) {
            duplicates.add(nextDirective.node);
          } else {
            duplicates.add(currentDirective.node);
          }
        }
        currentDirective = nextDirective;
      }
    }
    return duplicates;
  }

  /// Remove [element] from the list of names shown by [importDirective].
  void _removeFromUnusedShownNamesMap(
      Element element, ImportDirective importDirective) {
    var identifiers = _unusedShownNamesMap[importDirective];
    if (identifiers == null) {
      return;
    }

    /// When an element is used, it might be converted into a `Member`,
    /// to apply substitution, or turn it into legacy. But using something
    /// is purely declaration based.
    bool hasElement(SimpleIdentifier identifier, Element element) {
      return identifier.staticElement?.declaration == element.declaration;
    }

    int length = identifiers.length;
    for (int i = 0; i < length; i++) {
      var identifier = identifiers[i];
      if (element is PropertyAccessorElement) {
        // If the getter or setter of a variable is used, then the variable (the
        // shown name) is used.
        if (hasElement(identifier, element.variable)) {
          identifiers.remove(identifier);
          break;
        }
      } else {
        if (hasElement(identifier, element)) {
          identifiers.remove(identifier);
          break;
        }
      }
    }
    if (identifiers.isEmpty) {
      _unusedShownNamesMap.remove(importDirective);
    }
  }
}

/// A container with information about used imports prefixes and used imported
/// elements.
class UsedImportedElements {
  /// The map of referenced prefix elements and the elements that they prefix.
  final Map<PrefixElement, List<Element>> prefixMap = {};

  /// The set of referenced top-level elements.
  final Set<Element> elements = {};

  /// The set of extensions defining members that are referenced.
  final Set<ExtensionElement> usedExtensions = {};
}

/// [NamespaceDirective] with non-null imported or exported [LibraryElement].
class _NamespaceDirective {
  final NamespaceDirective node;
  final LibraryElement library;

  _NamespaceDirective({
    required this.node,
    required this.library,
  });

  /// Returns the absolute URI of the library.
  String get libraryUriStr => '${library.source.uri}';
}

/// A class which verifies (and reports) whether any import directives are
/// unnecessary.
///
/// In a given library, every import directive has a set of "used elements," the
/// subset of elements provided by the import which are used in the library. In
/// a given library, an import directive is "unnecessary" if there exists at
/// least one other import directive with the same prefix as the aforementioned
/// import directive, and a "used elements" set which is a proper superset of
/// the aforementioned import directive's "used elements" set.
class _UnnecessaryImportsVerifier {
  /// The cache of [Namespace]s for [ImportDirective]s.
  final Map<ImportDirective, Namespace> _namespaceMap;

  /// The set of imports which provide at least one element used in the library.
  final Set<ImportDirective> _usedImports;

  /// The mapping of each import to its "used elements" set.
  ///
  /// This is computed in [processUsedElements].
  final Map<ImportDirective, Set<Element>> _usedElementSets = {};

  _UnnecessaryImportsVerifier(this._namespaceMap, this._usedImports);

  /// Determines the "used elements" set for each import directive in
  /// [allImports].
  void processUsedElements(
    List<UsedImportedElements> usedImportedElementsList,
    Map<PrefixElement, List<ImportDirective>> prefixElementMap,
    List<ImportDirective> allImports,
  ) {
    assert(_usedElementSets.isEmpty);
    for (var usedElements in usedImportedElementsList) {
      _processPrefixedElements(usedElements, prefixElementMap);
      _processUnprefixedElements(usedElements);
      _processExtensionElements(usedElements, allImports);
    }
  }

  /// Reports the import directives which are unnecessary.
  void reportImports(ErrorReporter errorReporter) {
    for (var importDirective in _usedImports) {
      if (!_usedElementSets.containsKey(importDirective)) continue;
      for (var otherImport in _usedImports) {
        if (otherImport == importDirective) continue;
        if (importDirective.prefix?.name != otherImport.prefix?.name) continue;
        if (!_usedElementSets.containsKey(otherImport)) continue;
        var importElementSet = _usedElementSets[importDirective]!;
        var otherElementSet = _usedElementSets[otherImport]!;
        if (otherElementSet.containsAll(importElementSet)) {
          if (otherElementSet.length > importElementSet.length) {
            StringLiteral uri = importDirective.uri;
            // The only way an import URI's `stringValue` can be `null` is if
            // the string contained interpolations, in which case the import
            // would have failed to resolve, and we would never reach here.  So
            // it is safe to assume that `uri.stringValue` and
            // `otherImport.uri.stringValue` are both non-`null`.
            errorReporter.reportErrorForNode(HintCode.UNNECESSARY_IMPORT, uri,
                [uri.stringValue!, otherImport.uri.stringValue!]);
            // Break out of the loop of "other imports" to prevent reporting
            // UNNECESSARY_IMPORT on [importDirective] multiple times.
            break;
          }
        }
      }
    }
  }

  void _processExtensionElements(
      UsedImportedElements usedElements, List<ImportDirective> allImports) {
    for (ExtensionElement extensionElement in usedElements.usedExtensions) {
      var elementName = extensionElement.name;
      if (elementName == null) break;
      // Find import directives using namespaces.
      for (ImportDirective importDirective in allImports) {
        var namespace = _namespaceMap.computeNamespace(importDirective);
        if (namespace == null) {
          continue;
        }
        var prefix = importDirective.prefix?.name;
        if (prefix == null) {
          if (namespace.get(elementName) == extensionElement) {
            _usedElementSets
                .putIfAbsent(importDirective, () => {})
                .add(extensionElement);
          }
        } else {
          // An extension might be used solely because one or more instance
          // members are referenced, which does not require explicit use of
          // the prefix. We still indicate that the import directive is used.
          if (namespace.getPrefixed(prefix, elementName) == extensionElement) {
            _usedElementSets
                .putIfAbsent(importDirective, () => {})
                .add(extensionElement);
          }
        }
      }
    }
  }

  void _processPrefixedElements(UsedImportedElements usedElements,
      Map<PrefixElement, List<ImportDirective>> prefixElementMap) {
    usedElements.prefixMap
        .forEach((PrefixElement prefix, List<Element> elements) {
      var importsForPrefix = prefixElementMap[prefix];
      if (importsForPrefix == null) {
        return;
      }
      for (var importDirective in importsForPrefix) {
        var namespace = _namespaceMap.computeNamespace(importDirective);
        if (namespace == null) {
          continue;
        }
        for (var element in elements) {
          if (namespace.providesPrefixed(prefix.name, element)) {
            _usedElementSets
                .putIfAbsent(importDirective, () => {})
                .add(element);
          }
        }
      }
    });
  }

  void _processUnprefixedElements(UsedImportedElements usedElements) {
    for (var element in usedElements.elements) {
      for (var importDirective in _usedImports) {
        var namespace = _namespaceMap.computeNamespace(importDirective);
        if (namespace == null) {
          continue;
        }
        if (namespace.provides(element)) {
          _usedElementSets.putIfAbsent(importDirective, () => {}).add(element);
        }
      }
    }
  }
}

extension on Map<ImportDirective, Namespace> {
  /// Lookup and return the [Namespace] in this Map.
  ///
  /// If this map does not have the computed namespace, compute it and cache it
  /// in this map. If [importDirective] is not resolved or is not resolvable,
  /// `null` is returned.
  Namespace? computeNamespace(ImportDirective importDirective) {
    var namespace = this[importDirective];
    if (namespace == null) {
      var importElement = importDirective.element;
      if (importElement != null) {
        namespace = importElement.namespace;
        this[importDirective] = namespace;
      }
    }
    return namespace;
  }
}

extension on Namespace {
  /// Returns whether this provides [element], taking into account system
  /// library shadowing.
  bool provides(Element element) {
    var elementFromNamespace = get(element.name!);
    return elementFromNamespace != null &&
        !_isShadowing(element, elementFromNamespace);
  }

  /// Returns whether this provides [element] with [prefix], taking into account
  /// system library shadowing.
  bool providesPrefixed(String prefix, Element element) {
    var elementFromNamespace = getPrefixed(prefix, element.name!);
    return elementFromNamespace != null &&
        !_isShadowing(element, elementFromNamespace);
  }

  /// Returns whether [e1] shadows [e2], assuming each is an imported element,
  /// and that each is imported with the same prefix.
  ///
  /// Returns false if the source of either element is `null`.
  bool _isShadowing(Element e1, Element e2) {
    var source1 = e1.source;
    if (source1 == null) {
      return false;
    }
    var source2 = e2.source;
    if (source2 == null) {
      return false;
    }
    return !source1.uri.isScheme('dart') && source2.uri.isScheme('dart');
  }
}
