getDeclarationRef method

DeclarationRef? getDeclarationRef(
  1. String identifier,
  2. Asset importingSrc, {
  3. String? importPrefix,
})

Looks up a declaration reference for an identifier.

This method resolves an identifier to its declaration, handling imports, exports, and re-exports correctly.

identifier is the name of the identifier to look up. importingSrc is the asset that is importing the identifier. importPrefix is an optional import prefix (e.g., 'prefix' in 'prefix.identifier').

Throws IdentifierNotFoundError if the identifier cannot be resolved.

Implementation

DeclarationRef? getDeclarationRef(
  String identifier,
  Asset importingSrc, {
  String? importPrefix,
}) {
  DeclarationRef buildRef(
    MapEntry<String, int> srcEntry, {
    String? providerId,
  }) {
    return DeclarationRef(
      identifier: identifier,
      srcId: srcEntry.key,
      srcUri: uriForAsset(srcEntry.key),
      providerId: providerId ?? srcEntry.key,
      type: ReferenceType.fromValue(srcEntry.value),
      importingLibrary: importingSrc,
      importPrefix: importPrefix,
    );
  }

  final Map<String, int> possibleSrcs = Map<String, int>.fromEntries(
    identifiers
        .where(
          (List<dynamic> e) => e[GraphIndex.identifierName] == identifier,
        )
        .map(
          (List<dynamic> e) => MapEntry<String, int>(
            e[GraphIndex.identifierSrc],
            e[GraphIndex.identifierType],
          ),
        ),
  );

  final String actualSrc = getParentSrc(importingSrc.id);
  // First check if the identifier is declared directly in this file
  for (final MapEntry<String, int> entry in possibleSrcs.entries) {
    if (entry.key == importingSrc.id || entry.key == actualSrc) {
      return buildRef(entry, providerId: actualSrc);
    }
  }

  // Check all imports of the source file
  final List<List<Object?>> fileImports = <List<Object?>>[
    ...importsOf(importingSrc.id),
    if (assets.containsKey(_coreImportId)) _coreImport,
  ];

  for (final List<Object?> importEntry in fileImports) {
    final String importedFileSrc = importEntry[GraphIndex.directiveSrc] as String;
    final String? prefix = importEntry.elementAtOrNull(GraphIndex.directivePrefix) as String?;
    if (importPrefix != null && importPrefix != prefix) continue;

    // Skip if the identifier is hidden
    final List<dynamic> hides = importEntry[GraphIndex.directiveHide] as List<dynamic>? ?? const <dynamic>[];
    if (hides.contains(identifier)) continue;

    // Skip if the identifier is not shown
    final List<dynamic> shows = importEntry[GraphIndex.directiveShow] as List<dynamic>? ?? const <dynamic>[];
    if (shows.isNotEmpty && !shows.contains(identifier)) continue;

    // Check if the imported file directly declares the identifier
    for (final MapEntry<String, int> entry in possibleSrcs.entries) {
      if (entry.key == importedFileSrc) {
        return buildRef(entry, providerId: importedFileSrc);
      }
    }
  }
  for (final List<Object?> importEntry in fileImports) {
    final String importedFileSrc = importEntry[GraphIndex.directiveSrc] as String;
    final Set<String> visitedSrcs = <String>{};
    final String? src = _traceExportsOf(
      importedFileSrc,
      identifier,
      possibleSrcs.keys,
      visitedSrcs,
    );
    if (src != null) {
      final MapEntry<String, int> srcEntry = possibleSrcs.entries.firstWhere(
        (MapEntry<String, int> k) => k.key == src,
      );
      return buildRef(srcEntry, providerId: importedFileSrc);
    }
  }
  return null;
}