( ref: UnresolvedRef, context: ResolutionContext )
| 392 | * Try to resolve a reference by exact name match |
| 393 | */ |
| 394 | export function matchByExactName( |
| 395 | ref: UnresolvedRef, |
| 396 | context: ResolutionContext |
| 397 | ): ResolvedRef | null { |
| 398 | // `import`-kind nodes are import STATEMENTS, not definitions, so a reference |
| 399 | // resolving to a sibling file's `import` is a meaningless edge — the real |
| 400 | // import→definition resolution is the import resolver's job (resolveViaImport), |
| 401 | // never name-matching here. Excluding them also removes a quadratic blow-up: |
| 402 | // a ubiquitous package (`react`, `@superset-ui/core`, Python `logging`/`typing`) |
| 403 | // is re-declared as an `import` node in every file that imports it, so K |
| 404 | // unresolved import refs each scored K same-named import candidates through |
| 405 | // findBestMatch — O(K²) per package, the dominant cost of "Resolving refs" on |
| 406 | // large import-heavy (front-end + back-end) repos (#915). |
| 407 | const candidates = applyLanguageGate(context.getNodesByName(ref.referenceName), ref) |
| 408 | .filter((n) => n.kind !== 'import') |
| 409 | // Nested locals are only reachable from inside their container (#1230). |
| 410 | .filter((n) => isLexicallyReachable(n, ref, context)); |
| 411 | |
| 412 | if (candidates.length === 0) { |
| 413 | return null; |
| 414 | } |
| 415 | |
| 416 | // If only one match, use it — but penalize cross-language matches |
| 417 | if (candidates.length === 1) { |
| 418 | const isCrossLanguage = candidates[0]!.language !== ref.language; |
| 419 | return { |
| 420 | original: ref, |
| 421 | targetNodeId: candidates[0]!.id, |
| 422 | confidence: isCrossLanguage ? 0.5 : 0.9, |
| 423 | resolvedBy: 'exact-match', |
| 424 | }; |
| 425 | } |
| 426 | |
| 427 | // Ubiquitous-name ceiling (#999): above it, picking one target among K |
| 428 | // same-named defs by directory proximity is unreliable AND O(K) per ref — the |
| 429 | // quadratic behind the "Resolving refs" wedge on theme/SDK-vendoring repos. |
| 430 | // Decline; the precise strategies (qualified-name, import, class-name) already |
| 431 | // ran. Falls through to fuzzy, which itself only resolves a UNIQUE candidate. |
| 432 | if (candidates.length > AMBIGUOUS_NAME_CEILING) { |
| 433 | return null; |
| 434 | } |
| 435 | |
| 436 | // Multiple matches - try to narrow down |
| 437 | const bestMatch = findBestMatch(ref, candidates, context); |
| 438 | if (bestMatch) { |
| 439 | // Lower confidence when the match is from a distant/unrelated module |
| 440 | const proximity = computePathProximity(ref.filePath, bestMatch.filePath); |
| 441 | const confidence = proximity >= 30 ? 0.7 : 0.4; |
| 442 | return { |
| 443 | original: ref, |
| 444 | targetNodeId: bestMatch.id, |
| 445 | confidence, |
| 446 | resolvedBy: 'exact-match', |
| 447 | }; |
| 448 | } |
| 449 | |
| 450 | return null; |
| 451 | } |
no test coverage detected