mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-29 06:46:49 +08:00
Land upstream #1686 (maxmilian + bompus kernel/CG-28 follow-ups) onto current main. tree-sitter-typescript interface members (method_signature / property_signature) were never listed in the TS extractor, so platform .d.ts APIs had no declaration nodes for call edges. Mirrors on the Rust kernel path; keeps CG-28 damping for pure-interface declaration files; filters damped files from the explore RWR seed set. Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
This commit is contained in:
co-authored by
Colby McHenry
parent
8c047342cd
commit
ee83636acb
+55
-8
@@ -55,6 +55,24 @@ function isLowValueFile(filePath: string, generated?: ReadonlySet<string>): bool
|
||||
|
||||
const SQLITE_PARAM_CHUNK_SIZE = 500;
|
||||
|
||||
/**
|
||||
* A SQL predicate: is the node aliased `alias` a member an INTERFACE declares?
|
||||
*
|
||||
* `method_signature` / `property_signature` enter the graph as `method` /
|
||||
* `property` nodes hung off their interface by a `contains` edge (#1638). They
|
||||
* have no body and originate no behaviour, so for a structural judgement about
|
||||
* a FILE they are the interface restated, not an extra thing the file declares.
|
||||
* See {@link QueryBuilder.getAmbientDeclarationPathsAmong}, the one caller, for
|
||||
* why treating them as opaque would break that rule in three places at once.
|
||||
*
|
||||
* Seeks `idx_edges_target_kind`, so it costs a key lookup per row rather than a
|
||||
* join over the whole edge table.
|
||||
*/
|
||||
const IS_INTERFACE_MEMBER = (alias: string): string => `EXISTS (
|
||||
SELECT 1 FROM edges ce JOIN nodes owner ON owner.id = ce.source
|
||||
WHERE ce.target = ${alias}.id AND ce.kind = 'contains' AND owner.kind = 'interface'
|
||||
)`;
|
||||
|
||||
/**
|
||||
* How much of the exact-name bonus a `deprioritize`d path keeps (#982). Damped
|
||||
* rather than zeroed: a query that genuinely targets that tree must still rank
|
||||
@@ -2736,6 +2754,29 @@ export class QueryBuilder {
|
||||
* restricted to the candidate list: the file that imports it is usually
|
||||
* not itself a candidate.
|
||||
*
|
||||
* ### Interface MEMBERS are transparent to all four conditions
|
||||
*
|
||||
* A `method_signature` / `property_signature` inside an interface enters the
|
||||
* graph as a `method` / `property` node (#1638). Read literally that would
|
||||
* break every condition here at once: condition 2 sees non-type kinds and
|
||||
* stops flagging, and — worse, because it is silent — condition 4 starts
|
||||
* seeing inbound `calls` edges the moment a call site through the shim's API
|
||||
* finally has a signature to land on. An ambient `.d.ts` would quietly lose
|
||||
* its damping precisely BECAUSE the platform API it declares is widely used.
|
||||
*
|
||||
* So an interface-owned member is treated the way `parameter` already is: it
|
||||
* neither qualifies, disqualifies, nor counts as inbound dependency. That is
|
||||
* not a new judgement call, it is what keeps the rule measuring what it was
|
||||
* measured on — before #1638 these nodes did not exist, so excluding them
|
||||
* reproduces the 0–4% flag rate the thresholds above were tuned against. It
|
||||
* is also the semantically right answer: a signature with no body is on the
|
||||
* same side of the line as the interface that owns it, and a call edge
|
||||
* landing on one is still not a file that can answer a flow question.
|
||||
*
|
||||
* The interface ITSELF is untouched: the `references` edges an importing
|
||||
* module aims at `UploadStorage` still disqualify the file under (4), which
|
||||
* is what keeps a depended-on `types.ts` out of the flag.
|
||||
*
|
||||
* Bounded-lookup like {@link getGeneratedPathsAmong}: callers hold a ranked
|
||||
* candidate list, so this is a partial-index probe over a handful of paths.
|
||||
*/
|
||||
@@ -2751,14 +2792,15 @@ export class QueryBuilder {
|
||||
// things the file declares, so they neither qualify nor disqualify.
|
||||
const rows = this.db
|
||||
.prepare(`
|
||||
SELECT file_path,
|
||||
SUM(CASE WHEN kind NOT IN ('file','import','export','parameter')
|
||||
SELECT n.file_path AS file_path,
|
||||
SUM(CASE WHEN n.kind NOT IN ('file','import','export','parameter')
|
||||
AND NOT ${IS_INTERFACE_MEMBER('n')}
|
||||
THEN 1 ELSE 0 END) AS declared,
|
||||
SUM(CASE WHEN kind IN ('interface','type_alias','enum','enum_member','namespace')
|
||||
SUM(CASE WHEN n.kind IN ('interface','type_alias','enum','enum_member','namespace')
|
||||
THEN 1 ELSE 0 END) AS typeDeclared
|
||||
FROM nodes
|
||||
WHERE file_path IN (${placeholders})
|
||||
GROUP BY file_path
|
||||
FROM nodes n
|
||||
WHERE n.file_path IN (${placeholders})
|
||||
GROUP BY n.file_path
|
||||
`)
|
||||
.all(...chunk) as Array<{ file_path: string; declared: number; typeDeclared: number }>;
|
||||
let candidates = rows
|
||||
@@ -2775,17 +2817,22 @@ export class QueryBuilder {
|
||||
);
|
||||
candidates = candidates.filter((p) => !hit.has(p));
|
||||
};
|
||||
// (3) originates behaviour
|
||||
// (3) originates behaviour — a signature has no body to originate from,
|
||||
// so an edge attributed to one is not evidence about this file.
|
||||
disqualify(`
|
||||
SELECT DISTINCT n.file_path AS file_path
|
||||
FROM edges e JOIN nodes n ON n.id = e.source
|
||||
WHERE e.kind IN ('calls','instantiates') AND n.file_path IN ($IN$)
|
||||
AND NOT ${IS_INTERFACE_MEMBER('n')}
|
||||
`);
|
||||
// (4) something outside the file depends on it
|
||||
// (4) something outside the file depends on it — but a call that lands on
|
||||
// an interface's own signature is a use of the API, not a dependency on
|
||||
// this file's structure. The edges aimed at the interface still count.
|
||||
disqualify(`
|
||||
SELECT DISTINCT t.file_path AS file_path
|
||||
FROM edges e JOIN nodes t ON t.id = e.target JOIN nodes s ON s.id = e.source
|
||||
WHERE t.file_path IN ($IN$) AND s.file_path <> t.file_path
|
||||
AND NOT ${IS_INTERFACE_MEMBER('t')}
|
||||
`);
|
||||
for (const path of candidates) found.add(path);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user