import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:code_builder/code_builder.dart';

ReferenceBuilder toBuilder(DartType type, List<ImportElement> imports) =>
    reference(type.name, _importFrom(type, imports))
        .toTyped(_coerceTypeArgs(type, imports));

String _importFrom(DartType dartType, List<ImportElement> imports) {
  var definingLibrary = dartType.element.library;
  for (final import in imports) {
    if (_definesLibrary(import.importedLibrary, definingLibrary) &&
        // We might have some collection of show/hide that hides this symbol.
        // Easier to avoid then do this wrong, for now (b/35879283).
        import.combinators.isEmpty) {
      return import.uri;
    }
  }
  return null;
}

bool _definesLibrary(LibraryElement importedLibrary, LibraryElement library) =>
    importedLibrary == library ||
    importedLibrary.exportedLibraries
        .any((exportedLibrary) => _definesLibrary(exportedLibrary, library));

Iterable<TypeBuilder> _coerceTypeArgs(
    DartType type, List<ImportElement> imports) {
  if (type is! ParameterizedType) return const [];
  var typeArgs = (type as ParameterizedType).typeArguments;
  if (typeArgs.every((t) => t.isDynamic)) return const [];
  return typeArgs.map((type) => toBuilder(type, imports));
}

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:code_builder/code_builder.dart';

ReferenceBuilder toBuilder(DartType type, List<ImportElement> imports) =>
    reference(type.name, _importFrom(type, imports))
        .toTyped(_coerceTypeArgs(type, imports));

String _importFrom(DartType dartType, List<ImportElement> imports) {
  for (final import in imports) {
    final exportedElement =
        import.importedLibrary.exportNamespace?.get(dartType.element.name);
    if (exportedElement == dartType.element) {
      return import.uri;
    }
  }
  return null;
}

Iterable<TypeBuilder> _coerceTypeArgs(
    DartType type, List<ImportElement> imports) {
  if (type is! ParameterizedType) return const [];
  var typeArgs = (type as ParameterizedType).typeArguments;
  if (typeArgs.every((t) => t.isDynamic)) return const [];
  return typeArgs.map((type) => toBuilder(type, imports));
}

Replace manual searching through imports/exports with LibraryElement.exportNamespace.
SourceGen: Replace manual searching through imports/exports with LibraryElement.exportNamespace.

The analyzer already determines which elements are visible from a library, and exposes that information via the namespace, so we don't need to do a recursive search ourselves.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=152160527
