gitnexus 1.6.12-rc.4 → 1.6.12-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +5 -8
- package/dist/core/ingestion/languages/zig/scope-resolver.js +2 -0
- package/dist/core/ingestion/languages/zig/workspace-static-gating.d.ts +8 -0
- package/dist/core/ingestion/languages/zig/workspace-static-gating.js +76 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +13 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +1 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +5 -0
- package/package.json +1 -1
|
@@ -11,17 +11,14 @@
|
|
|
11
11
|
* Conservative by design: we only tag an edge when we can prove the
|
|
12
12
|
* gating expression evaluates to `false`. Anything ambiguous → live.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
14
|
+
* Supported scope:
|
|
15
15
|
*
|
|
16
16
|
* (a) **File-local** consts (`pub const FOO = false;`, plus const-to-const
|
|
17
17
|
* aliases up to 5 hops), built once per file by `buildZigBoolConstMap`.
|
|
18
|
-
* (b) **Cross-file** (`const cfg = @import("./cfg.zig");
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* returns `undefined`, because the capture emitter runs in the parse
|
|
23
|
-
* worker and sees only the current file. Tracked in #3162. Until then
|
|
24
|
-
* every `cfg.FOO` condition folds to unknown, i.e. live.
|
|
18
|
+
* (b) **Cross-file** direct imports (`const cfg = @import("./cfg.zig");
|
|
19
|
+
* if (cfg.FOO)`) are enriched after per-file extraction. The workspace
|
|
20
|
+
* caller supplies `importAliases` and `lookupBoolsForPath`; the parse
|
|
21
|
+
* worker still uses empty/undefined inputs and remains file-local.
|
|
25
22
|
*
|
|
26
23
|
* Also out of scope: multi-hop member access (`cfg.sub.FOO`), re-exported
|
|
27
24
|
* consts, runtime-evaluated bools (`const FOO = computeIt();`), and
|
|
@@ -16,6 +16,7 @@ import { resolveZigImportInternal } from '../../import-resolvers/zig.js';
|
|
|
16
16
|
import { zigProvider } from '../zig.js';
|
|
17
17
|
import { expandZigWildcardNames, zigArityCompatibility, zigMergeBindings } from './index.js';
|
|
18
18
|
import { populateZigRangeBindings } from './range-binding.js';
|
|
19
|
+
import { populateZigWorkspaceStaticGating } from './workspace-static-gating.js';
|
|
19
20
|
export const zigScopeResolver = {
|
|
20
21
|
language: SupportedLanguages.Zig,
|
|
21
22
|
languageProvider: zigProvider,
|
|
@@ -48,6 +49,7 @@ export const zigScopeResolver = {
|
|
|
48
49
|
arityCompatibility: zigArityCompatibility,
|
|
49
50
|
buildMro: (graph, parsedFiles, nodeLookup) => buildMro(graph, parsedFiles, nodeLookup, defaultLinearize),
|
|
50
51
|
populateOwners: (parsed) => populateClassOwnedMembers(parsed),
|
|
52
|
+
populateWorkspaceReferences: populateZigWorkspaceStaticGating,
|
|
51
53
|
// Payload captures — `for (items) |it|`, `if (opt) |v|`, `while (it.next())
|
|
52
54
|
// |x|` — typed from the subject's binding after finalize (F6).
|
|
53
55
|
populateRangeBindings: populateZigRangeBindings,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ParsedFile } from '../../../../_shared/index.js';
|
|
2
|
+
export declare function populateZigWorkspaceStaticGating(parsedFiles: ParsedFile[], ctx: {
|
|
3
|
+
readonly fileContents: ReadonlyMap<string, string>;
|
|
4
|
+
readonly treeCache?: {
|
|
5
|
+
get(filePath: string): unknown;
|
|
6
|
+
};
|
|
7
|
+
readonly resolutionConfig?: unknown;
|
|
8
|
+
}): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getTreeSitterBufferSize } from '../../constants.js';
|
|
2
|
+
import { resolveZigImportInternal } from '../../import-resolvers/zig.js';
|
|
3
|
+
import { buildZigBoolConstMap, collectZigStaticGatedRanges, isPositionStaticGated, } from '../../call-extractors/zig-static-gating.js';
|
|
4
|
+
import { parseSourceSafe, ParseTimeoutError } from '../../../tree-sitter/safe-parse.js';
|
|
5
|
+
import { getZigParser } from './query.js';
|
|
6
|
+
export function populateZigWorkspaceStaticGating(parsedFiles, ctx) {
|
|
7
|
+
const parser = getZigParser();
|
|
8
|
+
const trees = new Map();
|
|
9
|
+
const bools = new Map();
|
|
10
|
+
for (const parsed of parsedFiles) {
|
|
11
|
+
const source = ctx.fileContents.get(parsed.filePath);
|
|
12
|
+
if (source === undefined)
|
|
13
|
+
continue;
|
|
14
|
+
let tree = ctx.treeCache?.get(parsed.filePath);
|
|
15
|
+
if (tree === undefined) {
|
|
16
|
+
try {
|
|
17
|
+
tree = parseSourceSafe(parser, source, undefined, {
|
|
18
|
+
bufferSize: getTreeSitterBufferSize(source),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
if (err instanceof ParseTimeoutError)
|
|
23
|
+
continue;
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
trees.set(parsed.filePath, tree);
|
|
28
|
+
bools.set(parsed.filePath, buildZigBoolConstMap(tree.rootNode));
|
|
29
|
+
}
|
|
30
|
+
const knownPaths = new Set(trees.keys());
|
|
31
|
+
for (const [index, parsed] of parsedFiles.entries()) {
|
|
32
|
+
const tree = trees.get(parsed.filePath);
|
|
33
|
+
if (tree === undefined)
|
|
34
|
+
continue;
|
|
35
|
+
const aliases = collectImportAliases(tree, parsed.filePath, knownPaths, ctx.resolutionConfig);
|
|
36
|
+
if (aliases.size === 0)
|
|
37
|
+
continue;
|
|
38
|
+
const ranges = collectZigStaticGatedRanges(tree.rootNode, bools.get(parsed.filePath) ?? new Map(), aliases, (filePath) => bools.get(filePath));
|
|
39
|
+
if (ranges.length === 0)
|
|
40
|
+
continue;
|
|
41
|
+
const next = parsed.referenceSites.map((site) => site.kind === 'call' &&
|
|
42
|
+
site.staticGated !== true &&
|
|
43
|
+
isPositionStaticGated(site.atRange.startLine, site.atRange.startCol, ranges)
|
|
44
|
+
? { ...site, staticGated: true }
|
|
45
|
+
: site);
|
|
46
|
+
parsedFiles[index] = Object.freeze({ ...parsed, referenceSites: Object.freeze(next) });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function collectImportAliases(tree, fromFile, knownPaths, resolutionConfig) {
|
|
50
|
+
const candidates = new Map();
|
|
51
|
+
const declarationCounts = new Map();
|
|
52
|
+
for (const decl of tree.rootNode.descendantsOfType('variable_declaration')) {
|
|
53
|
+
const names = decl.namedChildren.filter((node) => node.type === 'identifier');
|
|
54
|
+
const binding = names[0]?.text;
|
|
55
|
+
if (binding === undefined)
|
|
56
|
+
continue;
|
|
57
|
+
declarationCounts.set(binding, (declarationCounts.get(binding) ?? 0) + 1);
|
|
58
|
+
const builtin = decl.namedChildren.find((node) => node.type === 'builtin_function' && node.text.startsWith('@import('));
|
|
59
|
+
const raw = builtin?.descendantsOfType('string').at(0)?.text;
|
|
60
|
+
if (raw === undefined)
|
|
61
|
+
continue;
|
|
62
|
+
const specifier = raw.replace(/^['"]|['"]$/g, '');
|
|
63
|
+
const target = resolveZigImportInternal(fromFile, specifier, knownPaths, resolutionConfig);
|
|
64
|
+
if (target !== null)
|
|
65
|
+
candidates.set(binding, target);
|
|
66
|
+
}
|
|
67
|
+
const aliases = new Map();
|
|
68
|
+
for (const [binding, target] of candidates) {
|
|
69
|
+
// Alias lookup below is name-based rather than position-aware. If a name
|
|
70
|
+
// is redeclared in another lexical scope, fail open instead of applying
|
|
71
|
+
// either module's constants to every use of that spelling.
|
|
72
|
+
if (declarationCounts.get(binding) === 1)
|
|
73
|
+
aliases.set(binding, target);
|
|
74
|
+
}
|
|
75
|
+
return aliases;
|
|
76
|
+
}
|
|
@@ -615,6 +615,19 @@ export interface ScopeResolver {
|
|
|
615
615
|
readonly populateWorkspaceOwners?: (parsedFiles: readonly ParsedFile[], ctx: {
|
|
616
616
|
readonly fileContents: ReadonlyMap<string, string>;
|
|
617
617
|
}) => void;
|
|
618
|
+
/**
|
|
619
|
+
* Optional workspace-wide enrichment of extracted reference sites. Runs
|
|
620
|
+
* after all files have been extracted and before reference finalization.
|
|
621
|
+
* Use this when a per-file capture needs conservative facts from an
|
|
622
|
+
* imported sibling (for example a compile-time branch constant).
|
|
623
|
+
*/
|
|
624
|
+
readonly populateWorkspaceReferences?: (parsedFiles: ParsedFile[], ctx: {
|
|
625
|
+
readonly fileContents: ReadonlyMap<string, string>;
|
|
626
|
+
readonly treeCache?: {
|
|
627
|
+
get(filePath: string): unknown;
|
|
628
|
+
};
|
|
629
|
+
readonly resolutionConfig?: unknown;
|
|
630
|
+
}) => void;
|
|
618
631
|
/**
|
|
619
632
|
* Recognize a `super(...)`-style receiver text. Python returns
|
|
620
633
|
* `/^super\s*\(/.test(t)`. Java returns `t === 'super'`. C++ may
|
|
@@ -55,6 +55,7 @@ const NOOP_OUTPUT = Object.freeze({
|
|
|
55
55
|
/** Select source files that must be materialized for one resolver pass. */
|
|
56
56
|
export function selectScopeSourcePathsToRead(provider, primaryFilePaths, preExtractedByPath) {
|
|
57
57
|
const hasPostExtractHooks = provider.populateWorkspaceOwners !== undefined ||
|
|
58
|
+
provider.populateWorkspaceReferences !== undefined ||
|
|
58
59
|
provider.populateNamespaceSiblings !== undefined ||
|
|
59
60
|
provider.populateRangeBindings !== undefined ||
|
|
60
61
|
provider.emitPostResolutionEdges !== undefined;
|
|
@@ -312,6 +312,11 @@ export function runScopeResolution(input, provider) {
|
|
|
312
312
|
}
|
|
313
313
|
logHeapProbe('sr-extract-end', `lang=${provider.language} parsedFiles=${parsedFiles.length} preExtractedHits=${preExtractedHits} skipped=${filesSkipped}`);
|
|
314
314
|
provider.populateWorkspaceOwners?.(parsedFiles, { fileContents: getFileContents() });
|
|
315
|
+
provider.populateWorkspaceReferences?.(parsedFiles, {
|
|
316
|
+
fileContents: getFileContents(),
|
|
317
|
+
treeCache,
|
|
318
|
+
resolutionConfig: input.resolutionConfig,
|
|
319
|
+
});
|
|
315
320
|
// A callable-flow-only provider has no reason to build the whole-graph
|
|
316
321
|
// lookup or finalize ordinary references when none of its files emitted a
|
|
317
322
|
// callable fact. This keeps the opt-in path proportional to source scanning
|
package/package.json
CHANGED