( ref: UnresolvedRef, context: ResolutionContext )
| 9579 | } |
| 9580 | |
| 9581 | function matchReferenceInner( |
| 9582 | ref: UnresolvedRef, |
| 9583 | context: ResolutionContext |
| 9584 | ): ResolvedRef | null { |
| 9585 | // Function-as-value refs (#756) resolve ONLY through the dedicated matcher — |
| 9586 | // never the fuzzy/qualified fallthrough below (a wrong callback edge is |
| 9587 | // worse than none). |
| 9588 | if (ref.referenceKind === 'function_ref') { |
| 9589 | return matchFunctionRef(ref, context); |
| 9590 | } |
| 9591 | |
| 9592 | // ArkTS chained UI attributes — emitted with a leading dot (`.titleStyle`, |
| 9593 | // `.width`) by the extractor — resolve ONLY to decorator-marked attribute |
| 9594 | // helpers: `@Extend`/`@Styles`/`@AnimatableExtend` functions (and global |
| 9595 | // `@Builder`s used attribute-position). Framework attributes (`.width`, |
| 9596 | // `.fontSize` — on nearly every UI line) match no such helper and stay |
| 9597 | // unresolved, NEVER falling through to bare-name matching: on a samples |
| 9598 | // monorepo that fallthrough manufactured 36k wrong edges, giving single |
| 9599 | // same-named properties thousands of false callers. Ambiguity rule matches |
| 9600 | // the rest of the file: several same-named helpers → prefer the call-site |
| 9601 | // file, still ambiguous → drop the ref rather than guess. |
| 9602 | if (ref.language === 'arkts' && ref.referenceName.startsWith('.')) { |
| 9603 | const base = ref.referenceName.slice(1); |
| 9604 | const candidates = context |
| 9605 | .getNodesByName(base) |
| 9606 | .filter( |
| 9607 | (n) => |
| 9608 | n.language === 'arkts' && |
| 9609 | n.kind === 'function' && |
| 9610 | (n.decorators ?? []).some((d) => ARKUI_ATTRIBUTE_DECORATORS.has(d)) |
| 9611 | ); |
| 9612 | const chosen = |
| 9613 | candidates.length > 1 ? preferCallSiteFile(candidates, ref.filePath) : candidates; |
| 9614 | if (chosen.length !== 1) return null; |
| 9615 | return { |
| 9616 | original: ref, |
| 9617 | targetNodeId: chosen[0]!.id, |
| 9618 | confidence: 0.85, |
| 9619 | resolvedBy: 'exact-match', |
| 9620 | }; |
| 9621 | } |
| 9622 | |
| 9623 | // `import java.lang.reflect.Field;` — the file's `Field` is the JDK's, never |
| 9624 | // a project class of that name (gson's production code bound it to a test's |
| 9625 | // nested `ParameterizedTypesTest.Field`). |
| 9626 | if ((ref.language === 'java' || ref.language === 'kotlin') && ref.referenceKind !== 'imports' && |
| 9627 | isJavaOutsideImport(ref.referenceName.split('.')[0]!, ref, context)) { |
| 9628 | return null; |
| 9629 | } |
| 9630 | |
| 9631 | // A symbolic name in a Scala type is a type (`F ~> G`) or a kind-projector |
| 9632 | // placeholder (`Either[A, *]`) — never an operator method, by any strategy. |
| 9633 | if (ref.language === 'scala' && ref.referenceKind === 'references' && /^[^\w\s]+$/.test(ref.referenceName)) { |
| 9634 | const types = context.getNodesByName(ref.referenceName).filter((n) => n.language === 'scala' && (SCALA_TYPE_KINDS.has(n.kind) || n.kind === 'type_alias')); |
| 9635 | const chosen = types.length > 1 ? preferCallSiteFile(types, ref.filePath) : types; |
| 9636 | return chosen.length === 1 ? { original: ref, targetNodeId: chosen[0]!.id, confidence: 0.8, resolvedBy: 'exact-match' } : null; |
| 9637 | } |
| 9638 |
no test coverage detected