Issue 23067. Report HintCode.DEPRECATED_EXPORT_USE

It found a few cases for `BytesBuilder` exported from `dart:io`.
I fixed most of them in a separate CL.

But package:flutter (itself only) is clean.

There are a few violations in google3.
I will ignore most of them, and fix a few.

Bug: https://github.com/dart-lang/sdk/issues/23067
Change-Id: Ic89370ad84caa60fd49326c2bc60ad5d927e2264
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/248343
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index 3f8f4d7..5adb652 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -1223,6 +1223,8 @@
   status: hasFix
 HintCode.DEAD_CODE_ON_CATCH_SUBTYPE:
   status: hasFix
+HintCode.DEPRECATED_EXPORT_USE:
+  status: needsEvaluation
 HintCode.DEPRECATED_EXTENDS_FUNCTION:
   status: needsFix
   notes: |-
diff --git a/pkg/analyzer/lib/dart/element/scope.dart b/pkg/analyzer/lib/dart/element/scope.dart
index 0fdfa0c..1b2a745 100644
--- a/pkg/analyzer/lib/dart/element/scope.dart
+++ b/pkg/analyzer/lib/dart/element/scope.dart
@@ -5,6 +5,8 @@
 import 'package:analyzer/dart/element/element.dart';
 
 /// Scopes are used to resolve names to elements.
+///
+/// Clients may not extend, implement or mix-in this class.
 abstract class Scope {
   /// Return the result of lexical lookup for the given [id], not `null`.
   ///
@@ -14,9 +16,10 @@
   ScopeLookupResult lookup(String id);
 }
 
-class ScopeLookupResult {
-  final Element? getter;
-  final Element? setter;
-
-  ScopeLookupResult(this.getter, this.setter);
+/// The result of a single name lookup.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class ScopeLookupResult {
+  Element? get getter;
+  Element? get setter;
 }
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 6d41685..df3709c 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -553,6 +553,7 @@
   HintCode.DEAD_CODE,
   HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
   HintCode.DEAD_CODE_ON_CATCH_SUBTYPE,
+  HintCode.DEPRECATED_EXPORT_USE,
   HintCode.DEPRECATED_EXTENDS_FUNCTION,
   HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION,
   HintCode.DEPRECATED_IMPLEMENTS_FUNCTION,
diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart
index 7eb9526..259ad2c 100644
--- a/pkg/analyzer/lib/src/dart/element/scope.dart
+++ b/pkg/analyzer/lib/src/dart/element/scope.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/dart/element/scope.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/summary2/combinator.dart';
+import 'package:analyzer/src/summary2/export.dart';
 
 /// The scope defined by a class.
 class ClassScope extends EnclosedScope {
@@ -37,7 +38,7 @@
     var getter = _getters[id];
     var setter = _setters[id];
     if (getter != null || setter != null) {
-      return ScopeLookupResult(getter, setter);
+      return ScopeLookupResultImpl(getter, setter);
     }
 
     return _parent.lookup(id);
@@ -92,6 +93,20 @@
   }
 }
 
+class ImportedElement {
+  final Element element;
+
+  /// This flag is set to `true` if [element] is available using import
+  /// directives where every imported library re-exports the element, and
+  /// every such `export` directive is marked as deprecated.
+  final bool isFromDeprecatedExport;
+
+  ImportedElement({
+    required this.element,
+    required this.isFromDeprecatedExport,
+  });
+}
+
 class LibraryScope extends EnclosedScope {
   final LibraryElement _element;
   final List<ExtensionElement> extensions = [];
@@ -133,8 +148,8 @@
 
 class PrefixScope implements Scope {
   final LibraryOrAugmentationElement _library;
-  final Map<String, Element> _getters = {};
-  final Map<String, Element> _setters = {};
+  final Map<String, ImportedElement> _getters = {};
+  final Map<String, ImportedElement> _setters = {};
   final Set<ExtensionElement> _extensions = {};
   LibraryElement? _deferredLibrary;
 
@@ -150,7 +165,12 @@
             final reference = exportedReference.reference;
             if (combinators.allows(reference.name)) {
               final element = elementFactory.elementOfReference(reference)!;
-              _add(element);
+              final importedElement = ImportedElement(
+                element: element,
+                isFromDeprecatedExport:
+                    _isFromDeprecatedExport(importedLibrary, exportedReference),
+              );
+              _add(importedElement);
             }
           }
           if (import.isDeferred) {
@@ -165,19 +185,20 @@
   ScopeLookupResult lookup(String id) {
     var deferredLibrary = _deferredLibrary;
     if (deferredLibrary != null && id == FunctionElement.LOAD_LIBRARY_NAME) {
-      return ScopeLookupResult(deferredLibrary.loadLibraryFunction, null);
+      return ScopeLookupResultImpl(deferredLibrary.loadLibraryFunction, null);
     }
 
     var getter = _getters[id];
     var setter = _setters[id];
-    return ScopeLookupResult(getter, setter);
+    return PrefixScopeLookupResult(getter, setter);
   }
 
-  void _add(Element element) {
+  void _add(ImportedElement imported) {
+    final element = imported.element;
     if (element is PropertyAccessorElement && element.isSetter) {
-      _addTo(map: _setters, element: element);
+      _addTo(map: _setters, incoming: imported);
     } else {
-      _addTo(map: _getters, element: element);
+      _addTo(map: _getters, incoming: imported);
       if (element is ExtensionElement) {
         _extensions.add(element);
       }
@@ -185,18 +206,30 @@
   }
 
   void _addTo({
-    required Map<String, Element> map,
-    required Element element,
+    required Map<String, ImportedElement> map,
+    required ImportedElement incoming,
   }) {
-    var id = element.displayName;
+    final id = incoming.element.displayName;
+    final existing = map[id];
 
-    var existing = map[id];
-    if (existing != null && existing != element) {
-      map[id] = _merge(existing, element);
+    if (existing == null) {
+      map[id] = incoming;
       return;
     }
 
-    map[id] = element;
+    if (existing.element == incoming.element) {
+      map[id] = ImportedElement(
+        element: incoming.element,
+        isFromDeprecatedExport:
+            existing.isFromDeprecatedExport && incoming.isFromDeprecatedExport,
+      );
+      return;
+    }
+
+    map[id] = ImportedElement(
+      element: _merge(existing.element, incoming.element),
+      isFromDeprecatedExport: false,
+    );
   }
 
   Element _merge(Element existing, Element other) {
@@ -233,6 +266,23 @@
     }
   }
 
+  /// Return `true` if [exportedReference] comes only from deprecated exports.
+  static bool _isFromDeprecatedExport(
+    LibraryElementImpl importedLibrary,
+    ExportedReference exportedReference,
+  ) {
+    if (exportedReference is ExportedReferenceExported) {
+      for (final exportIndex in exportedReference.indexes) {
+        final export = importedLibrary.exports[exportIndex];
+        if (!export.hasDeprecated) {
+          return false;
+        }
+      }
+      return true;
+    }
+    return false;
+  }
+
   static bool _isSdkElement(Element element) {
     if (element is DynamicElementImpl || element is NeverElementImpl) {
       return true;
@@ -244,6 +294,32 @@
   }
 }
 
+class PrefixScopeLookupResult implements ScopeLookupResult {
+  final ImportedElement? importedGetter;
+  final ImportedElement? importedSetter;
+
+  PrefixScopeLookupResult(
+    this.importedGetter,
+    this.importedSetter,
+  );
+
+  @override
+  Element? get getter => importedGetter?.element;
+
+  @override
+  Element? get setter => importedSetter?.element;
+}
+
+class ScopeLookupResultImpl implements ScopeLookupResult {
+  @override
+  final Element? getter;
+
+  @override
+  final Element? setter;
+
+  ScopeLookupResultImpl(this.getter, this.setter);
+}
+
 class TypeParameterScope extends EnclosedScope {
   TypeParameterScope(
     super.parent,
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
index 4d4efcf..5536f34 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.g.dart
@@ -94,6 +94,14 @@
     hasPublishedDocs: true,
   );
 
+  ///  Parameters:
+  ///  0: the name of the element
+  static const HintCode DEPRECATED_EXPORT_USE = HintCode(
+    'DEPRECATED_EXPORT_USE',
+    "The ability to import '{0}' indirectly has been deprecated.",
+    correctionMessage: "Try importing '{0}' directly.",
+  );
+
   ///  No parameters.
   static const HintCode DEPRECATED_EXTENDS_FUNCTION = HintCode(
     'DEPRECATED_SUBTYPE_OF_FUNCTION',
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index c7169aa..6d951b3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -5,6 +5,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
@@ -19,10 +20,11 @@
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/migratable_ast_info_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/scope_helpers.dart';
 import 'package:analyzer/src/generated/super_context.dart';
 import 'package:analyzer/src/generated/variable_type_provider.dart';
 
-class MethodInvocationResolver {
+class MethodInvocationResolver with ScopeHelpers {
   /// Resolver visitor is separated from the elements resolver, which calls
   /// this method resolver. If we rewrite a [MethodInvocation] node, we put
   /// the resulting [FunctionExpressionInvocation] into the original node
@@ -75,6 +77,9 @@
         _extensionResolver = _resolver.extensionResolver,
         _inferenceHelper = inferenceHelper;
 
+  @override
+  ErrorReporter get errorReporter => _resolver.errorReporter;
+
   TypeSystemImpl get _typeSystem => _resolver.typeSystem;
 
   void resolve(
@@ -584,7 +589,13 @@
       String name,
       List<WhyNotPromotedGetter> whyNotPromotedList,
       {required DartType? contextType}) {
-    var element = nameNode.scopeLookupResult!.getter;
+    final scopeLookupResult = nameNode.scopeLookupResult!;
+    reportDeprecatedExportUseGetter(
+      scopeLookupResult: scopeLookupResult,
+      node: nameNode,
+    );
+
+    var element = scopeLookupResult.getter;
     if (element != null) {
       element = _resolver.toLegacyElement(element);
       nameNode.staticElement = element;
@@ -668,7 +679,13 @@
       }
     }
 
-    var element = prefix.scope.lookup(name).getter;
+    final scopeLookupResult = prefix.scope.lookup(name);
+    reportDeprecatedExportUseGetter(
+      scopeLookupResult: scopeLookupResult,
+      node: nameNode,
+    );
+
+    var element = scopeLookupResult.getter;
     element = _resolver.toLegacyElement(element);
     nameNode.staticElement = element;
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
index 1d564ff..63e41ad 100644
--- a/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/named_type_resolver.dart
@@ -18,15 +18,18 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/scope_helpers.dart';
 
 /// Helper for resolving types.
 ///
 /// The client must set [nameScope] before calling [resolve].
-class NamedTypeResolver {
+class NamedTypeResolver with ScopeHelpers {
   final LibraryElementImpl _libraryElement;
   final TypeSystemImpl typeSystem;
   final DartType dynamicType;
   final bool isNonNullableByDefault;
+
+  @override
   final ErrorReporter errorReporter;
 
   late Scope nameScope;
@@ -96,10 +99,8 @@
       }
 
       if (prefixElement is PrefixElement) {
-        var nameNode = typeIdentifier.identifier;
-        var name = nameNode.name;
-
-        var element = prefixElement.scope.lookup(name).getter;
+        final nameNode = typeIdentifier.identifier;
+        final element = _lookupGetter(prefixElement.scope, nameNode);
         nameNode.staticElement = element;
         _resolveToElement(node, element);
         return;
@@ -113,14 +114,13 @@
       node.type = dynamicType;
     } else {
       var nameNode = typeIdentifier as SimpleIdentifierImpl;
-      var name = nameNode.name;
 
-      if (name == 'void') {
+      if (nameNode.name == 'void') {
         node.type = VoidTypeImpl.instance;
         return;
       }
 
-      var element = nameScope.lookup(name).getter;
+      final element = _lookupGetter(nameScope, nameNode);
       nameNode.staticElement = element;
       _resolveToElement(node, element);
     }
@@ -282,6 +282,15 @@
     }
   }
 
+  Element? _lookupGetter(Scope scope, SimpleIdentifier node) {
+    final scopeLookupResult = scope.lookup(node.name);
+    reportDeprecatedExportUseGetter(
+      scopeLookupResult: scopeLookupResult,
+      node: node,
+    );
+    return scopeLookupResult.getter;
+  }
+
   void _resolveToElement(NamedTypeImpl node, Element? element) {
     if (element == null) {
       node.type = dynamicType;
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index 28f5ec9..6ddcf05 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -18,16 +18,18 @@
 import 'package:analyzer/src/error/assignment_verifier.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/scope_helpers.dart';
 import 'package:analyzer/src/generated/super_context.dart';
 
-class PropertyElementResolver {
+class PropertyElementResolver with ScopeHelpers {
   final ResolverVisitor _resolver;
 
   PropertyElementResolver(this._resolver);
 
-  LibraryElement get _definingLibrary => _resolver.definingLibrary;
+  @override
+  ErrorReporter get errorReporter => _resolver.errorReporter;
 
-  ErrorReporter get _errorReporter => _resolver.errorReporter;
+  LibraryElement get _definingLibrary => _resolver.definingLibrary;
 
   ExtensionMemberResolver get _extensionResolver => _resolver.extensionResolver;
 
@@ -81,7 +83,7 @@
 
     if (identical(targetType, NeverTypeImpl.instance)) {
       // TODO(scheglov) Report directly in TypePropertyResolver?
-      _errorReporter.reportErrorForNode(
+      errorReporter.reportErrorForNode(
         HintCode.RECEIVER_OF_TYPE_NEVER,
         target,
       );
@@ -214,10 +216,18 @@
       );
     }
 
+    final scopeLookupResult = node.scopeLookupResult!;
+    reportDeprecatedExportUse(
+      scopeLookupResult: scopeLookupResult,
+      node: node,
+      hasRead: hasRead,
+      hasWrite: hasWrite,
+    );
+
     Element? readElementRequested;
     Element? readElementRecovery;
     if (hasRead) {
-      var readLookup = LexicalLookup.resolveGetter(node.scopeLookupResult!) ??
+      var readLookup = LexicalLookup.resolveGetter(scopeLookupResult) ??
           _resolver.thisLookupGetter(node);
       readElementRequested = _resolver.toLegacyElement(readLookup?.requested);
       if (readElementRequested is PropertyAccessorElement &&
@@ -231,12 +241,12 @@
     Element? writeElementRequested;
     Element? writeElementRecovery;
     if (hasWrite) {
-      var writeLookup = LexicalLookup.resolveSetter(node.scopeLookupResult!) ??
+      var writeLookup = LexicalLookup.resolveSetter(scopeLookupResult) ??
           _resolver.thisLookupSetter(node);
       writeElementRequested = _resolver.toLegacyElement(writeLookup?.requested);
       writeElementRecovery = _resolver.toLegacyElement(writeLookup?.recovery);
 
-      AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
+      AssignmentVerifier(_resolver.definingLibrary, errorReporter).verify(
         node: node,
         requested: writeElementRequested,
         recovery: writeElementRecovery,
@@ -261,7 +271,7 @@
   ) {
     if (element.isStatic) return false;
 
-    _errorReporter.reportErrorForNode(
+    errorReporter.reportErrorForNode(
       CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
       identifier,
       [identifier.name],
@@ -276,7 +286,7 @@
   ) {
     if (element != null && element.isStatic) {
       if (target is ExtensionOverride) {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
           propertyName,
         );
@@ -296,7 +306,7 @@
           // It is safe to assume that `enclosingElement.name` is non-`null`
           // because it can only be `null` for extensions, and we handle that
           // case above.
-          _errorReporter.reportErrorForNode(
+          errorReporter.reportErrorForNode(
               CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
               propertyName, [
             propertyName.name,
@@ -339,7 +349,7 @@
     var offset = leftBracket.offset;
     var length = rightBracket.end - offset;
 
-    _errorReporter.reportErrorForOffset(errorCode, offset, length, arguments);
+    errorReporter.reportErrorForOffset(errorCode, offset, length, arguments);
   }
 
   PropertyElementResolverResult _resolve({
@@ -408,7 +418,7 @@
     }
 
     if (targetType.isVoid) {
-      _errorReporter.reportErrorForNode(
+      errorReporter.reportErrorForNode(
         CompileTimeErrorCode.USE_OF_VOID_RESULT,
         propertyName,
       );
@@ -424,13 +434,13 @@
       // type literal (which can only be a type instantiation of a type alias
       // of a function type).
       if (hasRead) {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_GETTER_ON_FUNCTION_TYPE,
           propertyName,
           [propertyName.name, target.type.name.name],
         );
       } else {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_SETTER_ON_FUNCTION_TYPE,
           propertyName,
           [propertyName.name, target.type.name.name],
@@ -457,7 +467,7 @@
     if (hasRead) {
       _checkForStaticMember(target, propertyName, result.getter);
       if (result.needsGetterError) {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_GETTER,
           propertyName,
           [propertyName.name, targetType],
@@ -468,7 +478,7 @@
     if (hasWrite) {
       _checkForStaticMember(target, propertyName, result.setter);
       if (result.needsSetterError) {
-        AssignmentVerifier(_definingLibrary, _errorReporter).verify(
+        AssignmentVerifier(_definingLibrary, errorReporter).verify(
           node: propertyName,
           requested: null,
           recovery: result.getter,
@@ -521,7 +531,7 @@
         var code = typeReference.isEnum
             ? CompileTimeErrorCode.UNDEFINED_ENUM_CONSTANT
             : CompileTimeErrorCode.UNDEFINED_GETTER;
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           code,
           propertyName,
           [propertyName.name, typeReference.name],
@@ -536,7 +546,7 @@
       if (writeElement != null) {
         writeElement = _resolver.toLegacyElement(writeElement);
         if (!_isAccessible(writeElement)) {
-          _errorReporter.reportErrorForNode(
+          errorReporter.reportErrorForNode(
             CompileTimeErrorCode.PRIVATE_SETTER,
             propertyName,
             [propertyName.name],
@@ -549,7 +559,7 @@
       } else {
         // Recovery, try to use getter.
         writeElementRecovery = typeReference.getGetter(propertyName.name);
-        AssignmentVerifier(_definingLibrary, _errorReporter).verify(
+        AssignmentVerifier(_definingLibrary, errorReporter).verify(
           node: propertyName,
           requested: null,
           recovery: writeElementRecovery,
@@ -584,7 +594,7 @@
         // This method is only called for extension overrides, and extension
         // overrides can only refer to named extensions.  So it is safe to
         // assume that `extension.name` is non-`null`.
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
           propertyName,
           [memberName, extension.name!],
@@ -604,7 +614,7 @@
       writeElement = extension.getSetter(memberName);
 
       if (writeElement == null) {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           // This method is only called for extension overrides, and extension
           // overrides can only refer to named extensions.  So it is safe to
           // assume that `extension.name` is non-`null`.
@@ -637,7 +647,7 @@
   }) {
     if (target.parent is CascadeExpression) {
       // Report this error and recover by treating it like a non-cascade.
-      _errorReporter.reportErrorForNode(
+      errorReporter.reportErrorForNode(
         CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE,
         target.extensionName,
       );
@@ -655,7 +665,7 @@
         // This method is only called for extension overrides, and extension
         // overrides can only refer to named extensions.  So it is safe to
         // assume that `element.name` is non-`null`.
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
           propertyName,
           [memberName, element.name!],
@@ -671,7 +681,7 @@
         // This method is only called for extension overrides, and extension
         // overrides can only refer to named extensions.  So it is safe to
         // assume that `element.name` is non-`null`.
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
           propertyName,
           [memberName, element.name!],
@@ -694,6 +704,12 @@
     required bool forAnnotation,
   }) {
     var lookupResult = target.scope.lookup(identifier.name);
+    reportDeprecatedExportUse(
+      scopeLookupResult: lookupResult,
+      node: identifier,
+      hasRead: hasRead,
+      hasWrite: hasWrite,
+    );
 
     var readElement = _resolver.toLegacyElement(lookupResult.getter);
     var writeElement = _resolver.toLegacyElement(lookupResult.setter);
@@ -704,7 +720,7 @@
             prefix: target.name,
             name: identifier.name,
           )) {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
           identifier,
           [identifier.name, target.name],
@@ -751,13 +767,13 @@
           readElement =
               _resolver.inheritance.getInherited2(targetType.element, name);
           if (readElement != null) {
-            _errorReporter.reportErrorForNode(
+            errorReporter.reportErrorForNode(
               CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
               propertyName,
               [readElement.kind.displayName, propertyName.name],
             );
           } else {
-            _errorReporter.reportErrorForNode(
+            errorReporter.reportErrorForNode(
               CompileTimeErrorCode.UNDEFINED_SUPER_GETTER,
               propertyName,
               [propertyName.name, targetType],
@@ -793,13 +809,13 @@
             inherited: true,
           );
           if (writeElement != null) {
-            _errorReporter.reportErrorForNode(
+            errorReporter.reportErrorForNode(
               CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
               propertyName,
               [writeElement.kind.displayName, propertyName.name],
             );
           } else {
-            _errorReporter.reportErrorForNode(
+            errorReporter.reportErrorForNode(
               CompileTimeErrorCode.UNDEFINED_SUPER_SETTER,
               propertyName,
               [propertyName.name, targetType],
diff --git a/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
index 35266a2..9846ada 100644
--- a/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/simple_identifier_resolver.dart
@@ -15,8 +15,9 @@
 import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/scope_helpers.dart';
 
-class SimpleIdentifierResolver {
+class SimpleIdentifierResolver with ScopeHelpers {
   final ResolverVisitor _resolver;
 
   final InvocationInferenceHelper _inferenceHelper;
@@ -24,7 +25,8 @@
   SimpleIdentifierResolver(this._resolver)
       : _inferenceHelper = _resolver.inferenceHelper;
 
-  ErrorReporter get _errorReporter => _resolver.errorReporter;
+  @override
+  ErrorReporter get errorReporter => _resolver.errorReporter;
 
   TypeProviderImpl get _typeProvider => _resolver.typeProvider;
 
@@ -37,6 +39,8 @@
 
     _resolver.checkReadOfNotAssignedLocalVariable(node, node.staticElement);
 
+    _reportDeprecatedExportUse(node);
+
     _resolve1(node);
     _resolve2(node, contextType: contextType);
   }
@@ -103,6 +107,16 @@
     return false;
   }
 
+  void _reportDeprecatedExportUse(SimpleIdentifierImpl node) {
+    final scopeLookupResult = node.scopeLookupResult;
+    if (scopeLookupResult != null) {
+      reportDeprecatedExportUseGetter(
+        scopeLookupResult: scopeLookupResult,
+        node: node,
+      );
+    }
+  }
+
   void _resolve1(SimpleIdentifierImpl node) {
     //
     // Synthetic identifiers have been already reported during parsing.
@@ -158,14 +172,14 @@
     var enclosingClass = _resolver.enclosingClass;
     if (_isFactoryConstructorReturnType(node) &&
         !identical(element, enclosingClass)) {
-      _errorReporter.reportErrorForNode(
+      errorReporter.reportErrorForNode(
           CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node);
     } else if (_isConstructorReturnType(node) &&
         !identical(element, enclosingClass)) {
       // This error is now reported by the parser.
       element = null;
     } else if (element is PrefixElement && !_isValidAsPrefix(node)) {
-      _errorReporter.reportErrorForNode(
+      errorReporter.reportErrorForNode(
         CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
         node,
         [element.name],
@@ -173,13 +187,13 @@
     } else if (element == null) {
       // TODO(brianwilkerson) Recover from this error.
       if (node.name == "await" && _resolver.enclosingFunction != null) {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_IDENTIFIER_AWAIT,
           node,
         );
       } else if (!_resolver.definingLibrary
           .shouldIgnoreUndefinedIdentifier(node)) {
-        _errorReporter.reportErrorForNode(
+        errorReporter.reportErrorForNode(
           CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
           node,
           [node.name],
diff --git a/pkg/analyzer/lib/src/generated/scope_helpers.dart b/pkg/analyzer/lib/src/generated/scope_helpers.dart
new file mode 100644
index 0000000..a49da26
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/scope_helpers.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2022, 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/element/scope.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/element/scope.dart';
+import 'package:analyzer/src/error/codes.dart';
+
+/// Methods useful for [Scope] for resolution, but not belonging to it. This
+/// mixin exists to allow code to be more easily shared between separate
+/// resolvers.
+mixin ScopeHelpers {
+  ErrorReporter get errorReporter;
+
+  void reportDeprecatedExportUse({
+    required ScopeLookupResult scopeLookupResult,
+    required SimpleIdentifier node,
+    required bool hasRead,
+    required bool hasWrite,
+  }) {
+    if (hasRead) {
+      reportDeprecatedExportUseGetter(
+        scopeLookupResult: scopeLookupResult,
+        node: node,
+      );
+    }
+
+    if (hasWrite) {
+      reportDeprecatedExportUseSetter(
+        scopeLookupResult: scopeLookupResult,
+        node: node,
+      );
+    }
+  }
+
+  void reportDeprecatedExportUseGetter({
+    required ScopeLookupResult scopeLookupResult,
+    required SimpleIdentifier node,
+  }) {
+    if (scopeLookupResult is PrefixScopeLookupResult) {
+      _reportDeprecatedExportUse(
+        node: node,
+        imported: scopeLookupResult.importedGetter,
+      );
+    }
+  }
+
+  void reportDeprecatedExportUseSetter({
+    required ScopeLookupResult scopeLookupResult,
+    required SimpleIdentifier node,
+  }) {
+    if (scopeLookupResult is PrefixScopeLookupResult) {
+      _reportDeprecatedExportUse(
+        node: node,
+        imported: scopeLookupResult.importedSetter,
+      );
+    }
+  }
+
+  void _reportDeprecatedExportUse({
+    required SimpleIdentifier node,
+    required final ImportedElement? imported,
+  }) {
+    if (imported != null && imported.isFromDeprecatedExport) {
+      errorReporter.reportErrorForNode(
+        HintCode.DEPRECATED_EXPORT_USE,
+        node,
+        [node.name],
+      );
+    }
+  }
+}
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index f0e456a..de28c26 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -17677,6 +17677,12 @@
     problemMessage: "Declaring a class named 'Function' is deprecated."
     correctionMessage: Try renaming the class.
     comment: Users should not create a class named `Function` anymore.
+  DEPRECATED_EXPORT_USE:
+    problemMessage: "The ability to import '{0}' indirectly has been deprecated."
+    correctionMessage: "Try importing '{0}' directly."
+    comment: |-
+      Parameters:
+      0: the name of the element
   DEPRECATED_MEMBER_USE:
     problemMessage: "'{0}' is deprecated and shouldn't be used."
     correctionMessage: Try replacing the use of the deprecated member with the replacement.
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 91d48d2a9..be50344 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -1886,6 +1886,7 @@
     put: [k07]
 elementFactory
   hasElement
+    dart:_internal
     dart:async
     dart:core
     package:dart.test/test.dart
diff --git a/pkg/analyzer/test/src/diagnostics/deprecated_export_use_test.dart b/pkg/analyzer/test/src/diagnostics/deprecated_export_use_test.dart
new file mode 100644
index 0000000..9209fb5
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/deprecated_export_use_test.dart
@@ -0,0 +1,471 @@
+// Copyright (c) 2022, 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/src/dart/error/hint_codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(DeprecatedExportUseTest);
+  });
+}
+
+@reflectiveTest
+class DeprecatedExportUseTest extends PubPackageResolutionTest {
+  test_deprecated_class_asExpression() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart';
+
+void f() {
+  A;
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 31, 1),
+    ]);
+  }
+
+  test_deprecated_class_asExpression_prefixed() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart' as prefix;
+
+void f() {
+  prefix.A;
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 48, 1),
+    ]);
+  }
+
+  test_deprecated_class_asType() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart';
+
+void f(A a) {}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 25, 1),
+    ]);
+  }
+
+  test_deprecated_class_asType_prefixed() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart' as prefix;
+
+void f(prefix.A a) {}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 42, 1),
+    ]);
+  }
+
+  test_deprecated_class_import_show() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart' show A;
+
+void f(A a) {}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 32, 1),
+    ]);
+  }
+
+  test_deprecated_function() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+void foo() {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart';
+
+void f() {
+  foo();
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 31, 3),
+    ]);
+  }
+
+  test_deprecated_function_prefixed() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+void foo() {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart' as prefix;
+
+void f() {
+  prefix.foo();
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 48, 3),
+    ]);
+  }
+
+  test_deprecated_getter() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+int get foo => 0;
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+/// Does not prevent the hint.
+set foo(int _) {}
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart';
+
+void f() {
+  foo;
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 31, 3),
+    ]);
+  }
+
+  test_deprecated_getter_prefixed() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+int get foo => 0;
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+/// Does not prevent the hint.
+set foo(int _) {}
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart' as prefix;
+
+void f() {
+  prefix.foo;
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 48, 3),
+    ]);
+  }
+
+  test_deprecated_setter() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+void set foo(int _) {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+/// Does not prevent the hint.
+int get foo => 0;
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart';
+
+void f() {
+  foo = 0;
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 31, 3),
+    ]);
+  }
+
+  test_deprecated_setter_prefixed() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+void set foo(int _) {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+/// Does not prevent the hint.
+int get foo => 0;
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart' as prefix;
+
+void f() {
+  prefix.foo = 0;
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 48, 3),
+    ]);
+  }
+
+  test_deprecated_variable() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+var foo = 0;
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'b.dart';
+
+void f() {
+  foo;
+}
+''', [
+      error(HintCode.DEPRECATED_EXPORT_USE, 31, 3),
+    ]);
+  }
+
+  test_notDeprecated_class_hasDirectImport() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+''');
+
+    await assertNoErrorsInCode('''
+import 'a.dart';
+import 'b.dart';
+
+void f(A a) {}
+''');
+  }
+
+  test_notDeprecated_class_hasNotDeprecatedExport() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+// Not deprecated.
+export 'a.dart';
+''');
+
+    await assertNoErrorsInCode('''
+import 'b.dart';
+
+void f(A a) {}
+''');
+  }
+
+  test_notDeprecated_class_import_hide() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+class B {}
+''');
+
+    await assertNoErrorsInCode('''
+import 'a.dart';
+import 'b.dart' hide A;
+
+void f(A a, B b) {}
+''');
+  }
+
+  test_notDeprecated_class_onlyNotDeprecatedExport() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+class A {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+export 'a.dart';
+''');
+
+    await assertNoErrorsInCode('''
+import 'b.dart';
+
+void f(A a) {}
+''');
+  }
+
+  test_notDeprecated_getter_useSetter() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+int get foo => 0;
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+set foo(int _) {}
+''');
+
+    await assertNoErrorsInCode('''
+import 'b.dart';
+
+void f() {
+  foo = 0;
+}
+''');
+  }
+
+  test_notDeprecated_getter_useSetter_prefixed() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+int get foo => 0;
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+set foo(int _) {}
+''');
+
+    await assertNoErrorsInCode('''
+import 'b.dart' as prefix;
+
+void f() {
+  prefix.foo = 0;
+}
+''');
+  }
+
+  test_notDeprecated_setter_useGetter() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+set foo(int _) {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+int get foo => 0;
+''');
+
+    await assertNoErrorsInCode('''
+import 'b.dart';
+
+void f() {
+  foo;
+}
+''');
+  }
+
+  test_notDeprecated_setter_useGetter_prefixed() async {
+    newFile('$testPackageLibPath/a.dart', r'''
+set foo(int _) {}
+''');
+
+    newFile('$testPackageLibPath/b.dart', r'''
+library b;
+
+@deprecated
+export 'a.dart';
+
+int get foo => 0;
+''');
+
+    await assertNoErrorsInCode('''
+import 'b.dart' as prefix;
+
+void f() {
+  prefix.foo;
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 2e99aee..3f25d0f 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -137,6 +137,7 @@
 import 'deferred_import_of_extension_test.dart' as deferred_import_of_extension;
 import 'definitely_unassigned_late_local_variable_test.dart'
     as definitely_unassigned_late_local_variable;
+import 'deprecated_export_use_test.dart' as deprecated_export_use;
 import 'deprecated_extends_function_test.dart' as deprecated_extends_function;
 import 'deprecated_function_class_declaration_test.dart'
     as deprecated_function_class_declaration;
@@ -888,6 +889,7 @@
     default_value_on_required_parameter.main();
     deferred_import_of_extension.main();
     definitely_unassigned_late_local_variable.main();
+    deprecated_export_use.main();
     deprecated_extends_function.main();
     deprecated_function_class_declaration.main();
     deprecated_implements_function.main();