mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
fix(ingestion): two-channel binding lifecycle (closes #1066) + scope-resolution I8 hardening (#1082)
Some checks are pending
CI / quality (push) Waiting to run
CI / tests (push) Waiting to run
CI / e2e (push) Waiting to run
CI / scope-parity (push) Waiting to run
CI / Save PR Metadata (push) Blocked by required conditions
CI / CI Gate (push) Blocked by required conditions
Release Candidate / Check if release candidate should run (push) Waiting to run
Release Candidate / ci (push) Blocked by required conditions
Release Candidate / Publish release candidate to npm (push) Blocked by required conditions
Release Candidate / Build & Push RC Docker images (push) Blocked by required conditions
Some checks are pending
CI / quality (push) Waiting to run
CI / tests (push) Waiting to run
CI / e2e (push) Waiting to run
CI / scope-parity (push) Waiting to run
CI / Save PR Metadata (push) Blocked by required conditions
CI / CI Gate (push) Blocked by required conditions
Release Candidate / Check if release candidate should run (push) Waiting to run
Release Candidate / ci (push) Blocked by required conditions
Release Candidate / Publish release candidate to npm (push) Blocked by required conditions
Release Candidate / Build & Push RC Docker images (push) Blocked by required conditions
* fix(csharp): adaptive tree-sitter buffer + frozen-bucket clone for cross-namespace siblings (#1066) Two coupled regressions surfaced when analyzing real-world C# repos with large source files (issue #1066): 1. Tree-sitter `parser.parse()` is hard-coded to a 32 KB buffer by default. Any file exceeding that threshold throws `Invalid argument` on the worker re-parse path of `populateCsharpNamespaceSiblings` (and the analogous Python / TypeScript captures fallbacks). 2. After the buffer fix unblocks the AST walk, the hook tries to `push()` onto the inner `BindingRef[]` array fetched from `indexes.bindings` — but `materializeBindings` froze that array via `Object.freeze(refs.slice())`. Result: `Cannot add property N, object is not extensible`. Fixes: - `csharp/captures.ts`, `python/captures.ts`, `typescript/captures.ts`: pass `bufferSize: getTreeSitterBufferSize(sourceText.length)` to `parser.parse()` on the cache-miss path so multi-MB files parse. - `csharp/namespace-siblings.ts`: introduce `cloneBindingBucket` to copy the frozen array before mutating, then `set()` the new array back. This is a working but architecturally compromised workaround (#1050 follow-up will replace it with an explicit augmentation channel — see docs/plans/2026-04-26-001 plan). Tests: - New `csharp-large-cache-miss-resolution` fixture (Models/Services/ Other layout, ~77 KB padded UserService.cs) drives the buffer-size failure end-to-end through worker mode. - `csharp.test.ts`: 4 new regression assertions covering both the parse-time buffer-size failure and the freeze workaround. - Per-language captures unit tests gain "large cache-miss file uses adaptive buffer" coverage (TS, Python, C#). - `csharp-hooks.test.ts`: in-memory freeze regression test that reproduces the `Cannot add property` crash without invoking the C# parser at all. Made-with: Cursor * refactor(scope-resolution): add bindingAugmentations channel to indexes Step 1 of the binding-augmentation-channel refactor (issue #1066 follow-up). Pure shape change — no consumers yet. Adds a new `readonly bindingAugmentations` field to `ScopeResolutionIndexes` initialized as an empty `Map` by `finalizeScopeModel`. The new channel is the dedicated post-finalize write target for hooks like `populateCsharpNamespaceSiblings`, so `indexes.bindings` can stay frozen and finalize-owned. Behavior unchanged: nothing reads or writes the new field yet. tsc and the full unit suite remain green. Plan: docs/plans/2026-04-26-001-binding-augmentation-channel.md (local only — `docs/plans/` is gitignored). Made-with: Cursor * feat(scope-resolution): add lookupBindingsAt dual-source helper Step 2 of the binding-augmentation-channel refactor. Introduces a single primitive every walker uses to read both the finalize-owned `indexes.bindings` channel and the post-finalize `indexes.bindingAugmentations` channel. Contract: - Finalized refs come first (preserves existing precedence). - Augmented refs append, deduped by `def.nodeId`. - Empty input on both channels returns a shared frozen empty array. - Single-channel hits return the bucket by reference (no allocation). No consumers are wired yet — Step 3 routes the existing walker primitives through this helper. Augmentations remain empty for every language; behavior of the full suite is unchanged. 8 unit tests pin precedence, dedup, identity for single-channel hits, and the shared-empty-frozen-array sentinel. Made-with: Cursor * refactor(scope-resolution): route binding lookups through lookupBindingsAt Step 3 of the binding-augmentation-channel refactor. Every direct `indexes.bindings.get(...)` consumer in the post-finalize phase is now routed through `lookupBindingsAt` (per-name) or `namesAtScope` + `lookupBindingsAt` (bulk iteration). Routed sites: - `findClassBindingInScope` (walkers.ts) — class-receiver lookups. - `findCallableBindingInScope` (walkers.ts) — free-call lookups. - `findExportedDefByName` (walkers.ts) — module-scope-fallback callable lookups. - `propagateImportedReturnTypes` (passes/imported-return-types.ts) — bulk iteration over an importer's binding entries; switched to `namesAtScope` + per-name `lookupBindingsAt` so post-finalize augmentations are visible to import-derived typeBinding mirrors. Behavior unchanged: augmentations are empty across the suite (Step 4 populates them for C# `populateNamespaceSiblings`). 587 scope-resolution unit tests + 50 integration resolver suites green (4 pre-existing Swift method-implements failures unrelated to this work). Adds `namesAtScope` companion helper for the bulk-iteration callers. Made-with: Cursor * refactor(csharp): write namespace siblings to bindingAugmentations channel Step 4 of the binding-augmentation-channel refactor. The C# `populateNamespaceSiblings` hook is the only consumer that needed to inject cross-file bindings post-finalize, and prior to this change it cloned the (frozen) finalized `BindingRef[]` arrays through a `cloneBindingBucket` helper, then `set()`-back the new array — a workaround for the `Object.freeze` applied by `finalize-algorithm.ts` (issue #1066 root cause). Architecturally that violated `ScopeResolver` Invariant I8 (which permits post-finalize modifications but not in-place mutation of finalized buckets). It also forced read-side consumers to be aware of the workaround. This change: * Switches the three C# write sites to append into `indexes.bindingAugmentations` via `getAugmentationBucket`. The augmentation channel was added in Step 1 and is mutable by contract: inner `BindingRef[]` arrays here are NEVER frozen. * Deletes `cloneBindingBucket` and `getMutableScopeBindings` (workaround helpers no longer needed). * `lookupBindingsAt` (Step 2) merges the two channels transparently for every walker (Step 3), so behavior is unchanged for callers. * Updates the unit test to assert against both channels: finalized bucket stays frozen and untouched, cross-file siblings show up in augmentations only. Renamed the test accordingly. Validation: * `npx tsc --noEmit` clean. * csharp hooks unit + walkers-augmentations unit + csharp integration resolver suite all green (236/236). * Wider `test/unit/scope-resolution test/integration/resolvers` suite: 2507 pass, only 4 pre-existing Swift METHOD_IMPLEMENTS failures remain (unrelated to this work, present on baseline). Refs: issue #1066, ADR-pending binding-augmentation-channel. Made-with: Cursor * feat(scope-resolution): tighten I8 + add validateBindingsImmutability dev guard Step 5 of the binding-augmentation-channel refactor. Captures the new two-channel binding lifecycle in the contract docs and adds a dev-mode runtime validator so a future hook cannot silently drift back into mutating `indexes.bindings`. Contract changes: * `contract/scope-resolver.ts` — rewrote Invariant I8 to describe the two channels (`indexes.bindings` is finalize-output and immutable post-finalize; `indexes.bindingAugmentations` is the append-only post-finalize channel populated by hooks like `populateNamespaceSiblings`). Documented `lookupBindingsAt` as the read-side merger and pointed at the new validator as the enforcement mechanism. * `gitnexus-shared/src/scope-resolution/types.ts` — extended the module-header lifecycle contract to call out `bindingAugmentations` alongside `ReferenceIndex` as the two structures populated after the freeze. Validator: * New `pipeline/validate-bindings-immutability.ts` mirrors the shape of `validateOwnershipParity` (#909): runs only when `NODE_ENV !== 'production' && VALIDATE_SEMANTIC_MODEL !== '0'`, emits via `onWarn`, never throws. Asserts (a) every inner `BindingRef[]` in `indexes.bindings` is `Object.isFrozen`, and (b) every inner array in `indexes.bindingAugmentations` is NOT frozen. * Wired into `pipeline/run.ts` after both `populateNamespaceSiblings` and `propagateImportedReturnTypes`, before `resolveReferenceSites`. One sweep covers the full post-finalize surface. Tests: * `validate-bindings-immutability.test.ts` — 6 cases pinning happy path, both drift directions, multi-violation accumulation, and both production no-op gates. All scope-resolution + csharp resolver tests green (242/242 in the focused run; matches the wider Step 4 baseline). Made-with: Cursor * fix(ingestion): size tree-sitter buffers from UTF-8 bytes Tree-sitter buffer sizing is byte-based, so computing adaptive buffers from JavaScript string length under-sized UTF-8-heavy files. Make getTreeSitterBufferSize accept source text directly and compute Buffer.byteLength internally, then update all parse call sites and max-buffer skip checks to use byte length. Add multibyte cache-miss and cap regressions for C#, Python, TypeScript, and the C# namespace-sibling fallback parse path. Made-with: Cursor * test(scope-resolution): pin augmentation read paths Add focused unit coverage for augmented-only binding reads across the routed walker helpers and imported-return-type propagation path. Clarify I8 wording around lexical Scope.bindings versus post-finalize index channels, and document the intentional local-only behavior of findExportedDef. Also switch the immutability validator tests to Vitest env stubs, document one intentional validator blind spot, and split C# namespace-sibling tests so UTF-8 parsing and augmentation-channel behavior are asserted independently. Made-with: Cursor * test(scope-resolution): avoid slow parser stress fixtures Replace high-cardinality large-file capture fixtures with large padding plus a trailing declaration. This still proves adaptive tree-sitter buffers parse beyond large ASCII and UTF-8-heavy input, without making query matching process thousands of declarations and risking timeouts. Made-with: Cursor * test(scope-resolution): add python and typescript cache-miss resolver regressions Add worker-mode resolver integration coverage mirroring the C# #1066 scenario for Python and TypeScript. Each test builds a temp fixture with large ASCII and UTF-8-heavy source padding, then asserts trailing declarations and call edges still resolve after scope-resolution cache-miss reparsing. Made-with: Cursor * refactor(scope-resolution): gate I8 validator and fast-path namesAtScope Addresses SPARC reviewer feedback on the binding-augmentation channel: - Validator gate is now opt-in outside development. Extract isSemanticModelValidatorEnabled() in utils/env.ts as the single predicate; both validateBindingsImmutability and phase.ts's warn handler share it. Default CLI runs no longer pay the O(binding-buckets) scan, and explicit VALIDATE_SEMANTIC_MODEL=1 now emits warnings even when NODE_ENV is unset. - namesAtScope returns Iterable<string> and zero-allocates when at most one channel is populated (returns Map.keys() directly), only materializing a Set when both channels carry names. The caller-side branching and EMPTY_NAMES escape hatch in propagateImportedReturnTypes are gone -- both helpers handle the empty-augmentation case internally. - C# namespace-siblings header/JSDoc, model JSDoc, I8 contract prose, and the #1066 integration-test header rewritten to say post-finalize fanout appends only to bindingAugmentations; finalized refs come first and win duplicate def.nodeId metadata; local lexical Scope.bindings remains the first-tier shadowing channel. Validator unit-test setup deduplicated via beforeEach and extended with default-CLI no-op + explicit-opt-in cases. Made-with: Cursor
This commit is contained in:
parent
ab077b4c29
commit
98ee665889
35 changed files with 1831 additions and 131 deletions
|
|
@ -10,8 +10,16 @@
|
|||
* Lifecycle contract (RFC §2.8): scopes are **constructed during extraction,
|
||||
* linked during finalize, immutable after finalize**. All fields are
|
||||
* `readonly` at the type level; `Object.freeze` is applied at runtime in dev
|
||||
* builds. `ReferenceIndex` is the sole structure populated after freeze — by
|
||||
* resolution, before emission.
|
||||
* builds.
|
||||
*
|
||||
* Two structures are populated after freeze:
|
||||
* 1. `ReferenceIndex` — by resolution, before emission.
|
||||
* 2. `ScopeResolutionIndexes.bindingAugmentations` — the dedicated
|
||||
* append-only post-finalize binding channel (e.g. C# same-namespace
|
||||
* cross-file fanout). The companion `indexes.bindings` is the
|
||||
* finalize-output channel and is deep-frozen by `materializeBindings`;
|
||||
* walkers consult both via `lookupBindingsAt`. See `ScopeResolver`
|
||||
* Invariant I8 for the full lifecycle contract.
|
||||
*/
|
||||
|
||||
import type { NodeLabel } from '../graph/types.js';
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ export const processCalls = async (
|
|||
if (!tree) {
|
||||
try {
|
||||
tree = parser.parse(file.content, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(file.content.length),
|
||||
bufferSize: getTreeSitterBufferSize(file.content),
|
||||
});
|
||||
} catch (parseError) {
|
||||
continue;
|
||||
|
|
@ -3257,7 +3257,7 @@ export const extractFetchCallsFromFiles = async (
|
|||
if (!tree) {
|
||||
try {
|
||||
tree = parser.parse(file.content, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(file.content.length),
|
||||
bufferSize: getTreeSitterBufferSize(file.content),
|
||||
});
|
||||
} catch {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { Buffer } from 'node:buffer';
|
||||
|
||||
/**
|
||||
* Default minimum buffer size for tree-sitter parsing (512 KB).
|
||||
* tree-sitter requires bufferSize >= file size in bytes.
|
||||
|
|
@ -12,8 +14,13 @@ export const TREE_SITTER_MAX_BUFFER = 32 * 1024 * 1024;
|
|||
|
||||
/**
|
||||
* Compute adaptive buffer size for tree-sitter parsing.
|
||||
* Uses 2× file size, clamped between 512 KB and 32 MB.
|
||||
* Previous 256 KB fixed limit silently skipped files > ~200 KB (e.g., imgui.h at 411 KB).
|
||||
* Uses 2x UTF-8 byte size, clamped between 512 KB and 32 MB.
|
||||
* Keeps tree-sitter's byte-sized buffer above large ASCII and multibyte sources.
|
||||
*/
|
||||
export const getTreeSitterBufferSize = (contentLength: number): number =>
|
||||
Math.min(Math.max(contentLength * 2, TREE_SITTER_BUFFER_SIZE), TREE_SITTER_MAX_BUFFER);
|
||||
export const getTreeSitterContentByteLength = (sourceText: string): number =>
|
||||
Buffer.byteLength(sourceText, 'utf8');
|
||||
|
||||
export const getTreeSitterBufferSize = (sourceText: string): number => {
|
||||
const byteLength = getTreeSitterContentByteLength(sourceText);
|
||||
return Math.min(Math.max(byteLength * 2, TREE_SITTER_BUFFER_SIZE), TREE_SITTER_MAX_BUFFER);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -141,6 +141,11 @@ export function finalizeScopeModel(
|
|||
methodDispatch,
|
||||
imports: finalizeOut.imports,
|
||||
bindings: finalizeOut.bindings,
|
||||
// Empty post-finalize augmentation channel. Populated (if at all)
|
||||
// by language hooks like `populateCsharpNamespaceSiblings` running
|
||||
// AFTER `finalizeScopeModel` returns, before `resolveReferenceSites`
|
||||
// consumes the bundle. Most languages leave it empty.
|
||||
bindingAugmentations: new Map(),
|
||||
referenceSites: Object.freeze([...allReferenceSites]),
|
||||
sccs: finalizeOut.sccs,
|
||||
stats: finalizeOut.stats,
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ export const processHeritage = async (
|
|||
// Use larger bufferSize for files > 32KB
|
||||
try {
|
||||
tree = parser.parse(file.content, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(file.content.length),
|
||||
bufferSize: getTreeSitterBufferSize(file.content),
|
||||
});
|
||||
} catch (parseError) {
|
||||
// Skip files that can't be parsed
|
||||
|
|
@ -414,7 +414,7 @@ export async function extractExtractedHeritageFromFiles(
|
|||
if (!tree) {
|
||||
try {
|
||||
tree = parser.parse(file.content, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(file.content.length),
|
||||
bufferSize: getTreeSitterBufferSize(file.content),
|
||||
});
|
||||
} catch {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ export const processImports = async (
|
|||
if (!tree) {
|
||||
try {
|
||||
tree = parser.parse(file.content, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(file.content.length),
|
||||
bufferSize: getTreeSitterBufferSize(file.content),
|
||||
});
|
||||
} catch (parseError) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { computeCsharpArityMetadata } from './arity-metadata.js';
|
|||
import { synthesizeCsharpReceiverBinding } from './receiver-binding.js';
|
||||
import { getCsharpParser, getCsharpScopeQuery } from './query.js';
|
||||
import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
|
||||
import { getTreeSitterBufferSize } from '../../constants.js';
|
||||
|
||||
/** Declaration anchors that carry function-like arity metadata. */
|
||||
const FUNCTION_DECL_TAGS = [
|
||||
|
|
@ -52,7 +53,9 @@ export function emitCsharpScopeCaptures(
|
|||
// the LanguageProvider contract layer; cast here at the use site.
|
||||
let tree = cachedTree as ReturnType<ReturnType<typeof getCsharpParser>['parse']> | undefined;
|
||||
if (tree === undefined) {
|
||||
tree = getCsharpParser().parse(sourceText);
|
||||
tree = getCsharpParser().parse(sourceText, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(sourceText),
|
||||
});
|
||||
recordCacheMiss();
|
||||
} else {
|
||||
recordCacheHit();
|
||||
|
|
|
|||
|
|
@ -11,17 +11,18 @@
|
|||
* field-chain resolution fails at `findClassBindingInScope('User')`
|
||||
* in the Service.cs scope chain.
|
||||
*
|
||||
* Implementation: after the finalize pass populates `indexes.bindings`
|
||||
* (from explicit `using` directives), walk each file's tree-sitter
|
||||
* AST for `namespace_declaration` / `file_scoped_namespace_declaration`
|
||||
* and `using_directive` nodes. The orchestrator hands us its
|
||||
* `treeCache` so files already parsed by `extractParsedFile` are
|
||||
* re-used instead of re-parsed — `ParsedFile`'s underlying tree is
|
||||
* the single source of truth. Group classes by namespace, and inject
|
||||
* cross-file sibling classes into each Namespace scope's finalized
|
||||
* bindings with `origin: 'namespace'` — a tier below `local` so a
|
||||
* local declaration still shadows a cross-file sibling with the same
|
||||
* name.
|
||||
* Implementation: after the finalize pass populates immutable
|
||||
* `indexes.bindings` (from explicit `using` directives), walk each
|
||||
* file's tree-sitter AST for `namespace_declaration` /
|
||||
* `file_scoped_namespace_declaration` and `using_directive` nodes.
|
||||
* The orchestrator hands us its `treeCache` so files already parsed
|
||||
* by `extractParsedFile` are re-used instead of re-parsed —
|
||||
* `ParsedFile`'s underlying tree is the single source of truth.
|
||||
* Group classes by namespace, and append cross-file sibling classes
|
||||
* into each Namespace scope's `bindingAugmentations` bucket with
|
||||
* `origin: 'namespace'`. Finalized bindings remain first in
|
||||
* `lookupBindingsAt`, and local lexical `Scope.bindings` remains the
|
||||
* first-tier shadowing channel.
|
||||
*
|
||||
* The tree-sitter walk is authoritative: it sees `global using static`,
|
||||
* aliased `using static X = Y.Z;`, attributed namespace declarations,
|
||||
|
|
@ -34,6 +35,7 @@ import type { SyntaxNode } from 'tree-sitter';
|
|||
import type { BindingRef, ParsedFile, Scope, ScopeId, SymbolDefinition } from 'gitnexus-shared';
|
||||
import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
|
||||
import { getCsharpParser } from './query.js';
|
||||
import { getTreeSitterBufferSize } from '../../constants.js';
|
||||
|
||||
interface CsharpFileStructure {
|
||||
/** Declared namespace names in file source order. Empty array means
|
||||
|
|
@ -52,7 +54,11 @@ interface CsharpFileStructure {
|
|||
* shared across calls. */
|
||||
function extractFileStructure(content: string, cachedTree: unknown): CsharpFileStructure {
|
||||
type CsharpTree = ReturnType<ReturnType<typeof getCsharpParser>['parse']>;
|
||||
const tree = (cachedTree as CsharpTree | undefined) ?? getCsharpParser().parse(content);
|
||||
const tree =
|
||||
(cachedTree as CsharpTree | undefined) ??
|
||||
getCsharpParser().parse(content, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(content),
|
||||
});
|
||||
const namespaces: string[] = [];
|
||||
const usingStaticPaths: string[] = [];
|
||||
|
||||
|
|
@ -106,8 +112,8 @@ export interface CsharpSiblingInputs {
|
|||
}
|
||||
|
||||
/**
|
||||
* Mutate `indexes.bindings` in-place, adding cross-file sibling class
|
||||
* defs to each Namespace scope. Class-like defs (Class / Interface /
|
||||
* Append cross-file sibling class defs to each Namespace scope's
|
||||
* `bindingAugmentations` bucket. Class-like defs (Class / Interface /
|
||||
* Struct / Record / Enum) are visible cross-file; method / field
|
||||
* members are not.
|
||||
*/
|
||||
|
|
@ -198,12 +204,15 @@ export function populateCsharpNamespaceSiblings(
|
|||
}
|
||||
}
|
||||
|
||||
// Inject cross-file siblings into each namespace scope's finalized
|
||||
// bindings. `indexes.bindings` is typed `ReadonlyMap<ScopeId, ...>`
|
||||
// but is a plain Map at runtime; mutating here is the established
|
||||
// pattern (see `propagateImportedReturnTypes` which does the same
|
||||
// for module-scope typeBindings).
|
||||
const finalized = indexes.bindings as Map<ScopeId, Map<string, BindingRef[]>>;
|
||||
// Inject cross-file siblings into each namespace scope's
|
||||
// post-finalize augmentation channel (per I8). The
|
||||
// `indexes.bindingAugmentations` map is the dedicated mutable
|
||||
// append-only buffer for post-finalize hooks: inner `BindingRef[]`
|
||||
// arrays here are NEVER frozen (unlike `indexes.bindings`, which
|
||||
// `materializeBindings` freezes). Walkers consult both channels
|
||||
// via `lookupBindingsAt`; we never need to consult or mutate
|
||||
// `indexes.bindings`.
|
||||
const augmentations = indexes.bindingAugmentations as Map<ScopeId, Map<string, BindingRef[]>>;
|
||||
|
||||
// Cross-namespace type-binding propagation: for each file, mirror
|
||||
// method return-type bindings from same-namespace sibling files and
|
||||
|
|
@ -301,17 +310,13 @@ export function populateCsharpNamespaceSiblings(
|
|||
const simpleName = mq.includes('.') ? mq.slice(mq.lastIndexOf('.') + 1) : mq;
|
||||
if (simpleName === '') continue;
|
||||
|
||||
// Add to `indexes.bindings[moduleScope]` so
|
||||
// `findCallableBindingInScope` picks it up.
|
||||
let scopeBindings = finalized.get(moduleScope.id);
|
||||
if (scopeBindings === undefined) {
|
||||
scopeBindings = new Map<string, BindingRef[]>();
|
||||
finalized.set(moduleScope.id, scopeBindings);
|
||||
}
|
||||
const existing = scopeBindings.get(simpleName) ?? [];
|
||||
if (existing.some((b) => b.def.nodeId === memberDef.nodeId)) continue;
|
||||
existing.push({ def: memberDef, origin: 'import' });
|
||||
scopeBindings.set(simpleName, existing);
|
||||
// Append to the augmentation bucket for the importer's module
|
||||
// scope. `findCallableBindingInScope` reads via
|
||||
// `lookupBindingsAt`, which fans out across `bindings` +
|
||||
// `bindingAugmentations`.
|
||||
const bucketArr = getAugmentationBucket(augmentations, moduleScope.id, simpleName);
|
||||
if (bucketArr.some((b) => b.def.nodeId === memberDef.nodeId)) continue;
|
||||
bucketArr.push({ def: memberDef, origin: 'import' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -337,15 +342,9 @@ export function populateCsharpNamespaceSiblings(
|
|||
const q = def.qualifiedName ?? '';
|
||||
const simpleName = q.includes('.') ? q.slice(q.lastIndexOf('.') + 1) : q;
|
||||
if (simpleName === '') continue;
|
||||
let scopeBindings = finalized.get(moduleScope.id);
|
||||
if (scopeBindings === undefined) {
|
||||
scopeBindings = new Map<string, BindingRef[]>();
|
||||
finalized.set(moduleScope.id, scopeBindings);
|
||||
}
|
||||
const existing = scopeBindings.get(simpleName) ?? [];
|
||||
if (existing.some((b) => b.def.nodeId === def.nodeId)) continue;
|
||||
existing.push({ def, origin: 'namespace' });
|
||||
scopeBindings.set(simpleName, existing);
|
||||
const bucketArr = getAugmentationBucket(augmentations, moduleScope.id, simpleName);
|
||||
if (bucketArr.some((b) => b.def.nodeId === def.nodeId)) continue;
|
||||
bucketArr.push({ def, origin: 'namespace' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -366,11 +365,6 @@ export function populateCsharpNamespaceSiblings(
|
|||
}
|
||||
|
||||
for (const { scopeId, filePath } of bucket.scopes) {
|
||||
let scopeBindings = finalized.get(scopeId);
|
||||
if (scopeBindings === undefined) {
|
||||
scopeBindings = new Map<string, BindingRef[]>();
|
||||
finalized.set(scopeId, scopeBindings);
|
||||
}
|
||||
for (const [name, defs] of defsByName) {
|
||||
// Skip names already present locally — `origin: 'local'` in
|
||||
// scope.bindings would naturally shadow the cross-file
|
||||
|
|
@ -378,18 +372,42 @@ export function populateCsharpNamespaceSiblings(
|
|||
const local = bucket.scopes.find((s) => s.filePath === filePath)?.scope.bindings.get(name);
|
||||
if (local !== undefined && local.some((b) => b.origin === 'local')) continue;
|
||||
|
||||
const existing = scopeBindings.get(name) ?? [];
|
||||
let bucketArr: BindingRef[] | null = null;
|
||||
for (const def of defs) {
|
||||
if (def.filePath === filePath) continue; // don't self-reference
|
||||
if (existing.some((b) => b.def.nodeId === def.nodeId)) continue;
|
||||
existing.push({ def, origin: 'namespace' });
|
||||
if (bucketArr === null) bucketArr = getAugmentationBucket(augmentations, scopeId, name);
|
||||
if (bucketArr.some((b) => b.def.nodeId === def.nodeId)) continue;
|
||||
bucketArr.push({ def, origin: 'namespace' });
|
||||
}
|
||||
if (existing.length > 0) scopeBindings.set(name, existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get-or-create a mutable inner bucket inside the `bindingAugmentations`
|
||||
* channel. The inner arrays here are mutable by contract (see
|
||||
* `ScopeResolutionIndexes.bindingAugmentations` doc + scope-resolver I8);
|
||||
* callers may `push` directly. Allocating the outer/inner Maps lazily
|
||||
* keeps the augmentation footprint zero for files with no cross-file
|
||||
* fanout. */
|
||||
function getAugmentationBucket(
|
||||
augmentations: Map<ScopeId, Map<string, BindingRef[]>>,
|
||||
scopeId: ScopeId,
|
||||
name: string,
|
||||
): BindingRef[] {
|
||||
let scopeBindings = augmentations.get(scopeId);
|
||||
if (scopeBindings === undefined) {
|
||||
scopeBindings = new Map<string, BindingRef[]>();
|
||||
augmentations.set(scopeId, scopeBindings);
|
||||
}
|
||||
let bucketArr = scopeBindings.get(name);
|
||||
if (bucketArr === undefined) {
|
||||
bucketArr = [];
|
||||
scopeBindings.set(name, bucketArr);
|
||||
}
|
||||
return bucketArr;
|
||||
}
|
||||
|
||||
function isTypeDef(def: SymbolDefinition): boolean {
|
||||
return (
|
||||
def.type === 'Class' ||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { getPythonParser, getPythonScopeQuery } from './query.js';
|
|||
import { synthesizeReceiverTypeBinding } from './receiver-binding.js';
|
||||
import { computePythonArityMetadata } from './arity-metadata.js';
|
||||
import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
|
||||
import { getTreeSitterBufferSize } from '../../constants.js';
|
||||
|
||||
export function emitPythonScopeCaptures(
|
||||
sourceText: string,
|
||||
|
|
@ -36,7 +37,9 @@ export function emitPythonScopeCaptures(
|
|||
// here at the use site.
|
||||
let tree = cachedTree as ReturnType<ReturnType<typeof getPythonParser>['parse']> | undefined;
|
||||
if (tree === undefined) {
|
||||
tree = getPythonParser().parse(sourceText);
|
||||
tree = getPythonParser().parse(sourceText, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(sourceText),
|
||||
});
|
||||
recordCacheMiss();
|
||||
} else {
|
||||
recordCacheHit();
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import { getTsParser, getTsScopeQuery, tsCachedTreeMatchesGrammar } from './quer
|
|||
import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
|
||||
import { synthesizeTsReceiverBinding } from './receiver-binding.js';
|
||||
import { computeTsArityMetadata } from './arity-metadata.js';
|
||||
import { getTreeSitterBufferSize } from '../../constants.js';
|
||||
|
||||
/** tree-sitter-typescript node types for function-like scopes that may
|
||||
* carry a synthesized `this` binding. Kept in sync with the
|
||||
|
|
@ -125,7 +126,9 @@ export function emitTsScopeCaptures(
|
|||
tree = undefined;
|
||||
}
|
||||
if (tree === undefined) {
|
||||
tree = getTsParser(filePath).parse(sourceText);
|
||||
tree = getTsParser(filePath).parse(sourceText, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(sourceText),
|
||||
});
|
||||
recordCacheMiss();
|
||||
} else {
|
||||
recordCacheHit();
|
||||
|
|
|
|||
|
|
@ -62,8 +62,21 @@ export interface ScopeResolutionIndexes {
|
|||
readonly methodDispatch: MethodDispatchIndex;
|
||||
/** Finalized `ImportEdge[]` per module scope. */
|
||||
readonly imports: ReadonlyMap<ScopeId, readonly ImportEdge[]>;
|
||||
/** Merged bindings (local + imports + wildcards) per module scope. */
|
||||
/** Finalize-output bindings (local + imports + wildcards) per module scope.
|
||||
* Inner `BindingRef[]` arrays are frozen by `materializeBindings`;
|
||||
* this channel is permanently immutable post-finalize. Consumers
|
||||
* MUST read via `lookupBindingsAt` so the augmentation channel is
|
||||
* consulted alongside. See I8 in `contract/scope-resolver.ts`. */
|
||||
readonly bindings: ReadonlyMap<ScopeId, ReadonlyMap<string, readonly BindingRef[]>>;
|
||||
/** Append-only post-finalize augmentation channel. Populated by
|
||||
* language hooks such as `populateNamespaceSiblings` for cross-file
|
||||
* bindings synthesized after finalize (e.g. C# same-namespace
|
||||
* visibility, `using static` member exposure). Inner arrays are
|
||||
* NOT frozen — hooks `push()` directly. Walkers must consult both
|
||||
* this map and `bindings` via `lookupBindingsAt`; finalized refs
|
||||
* are returned first and win duplicate `def.nodeId` metadata, with
|
||||
* unique augmentations appended after. See I8. */
|
||||
readonly bindingAugmentations: ReadonlyMap<ScopeId, ReadonlyMap<string, readonly BindingRef[]>>;
|
||||
/** Pre-resolution usage facts; consumed by the resolution phase. */
|
||||
readonly referenceSites: readonly ReferenceSite[];
|
||||
/** SCC condensation of the file-level import graph — callers that want
|
||||
|
|
|
|||
|
|
@ -48,7 +48,11 @@ import type {
|
|||
FileScopeBindings,
|
||||
ExtractedORMQuery,
|
||||
} from './workers/parse-worker.js';
|
||||
import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from './constants.js';
|
||||
import {
|
||||
getTreeSitterBufferSize,
|
||||
getTreeSitterContentByteLength,
|
||||
TREE_SITTER_MAX_BUFFER,
|
||||
} from './constants.js';
|
||||
|
||||
export type FileProgressCallback = (current: number, total: number, filePath: string) => void;
|
||||
|
||||
|
|
@ -352,7 +356,7 @@ const processParsingSequential = async (
|
|||
}
|
||||
|
||||
// Skip files larger than the max tree-sitter buffer (32 MB)
|
||||
if (file.content.length > TREE_SITTER_MAX_BUFFER) continue;
|
||||
if (getTreeSitterContentByteLength(file.content) > TREE_SITTER_MAX_BUFFER) continue;
|
||||
|
||||
// Vue SFC preprocessing: extract <script> block content
|
||||
let parseContent = file.content;
|
||||
|
|
@ -375,7 +379,7 @@ const processParsingSequential = async (
|
|||
let tree: Parser.Tree;
|
||||
try {
|
||||
tree = parser.parse(parseContent, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(parseContent.length),
|
||||
bufferSize: getTreeSitterBufferSize(parseContent),
|
||||
});
|
||||
} catch (parseError) {
|
||||
console.warn(`Skipping unparseable file: ${file.path}`);
|
||||
|
|
|
|||
|
|
@ -136,14 +136,45 @@
|
|||
* once per workspace at resolve time), and merging would create a
|
||||
* god-interface that complicates future migrations.
|
||||
*
|
||||
* - **I8 — Post-finalize hooks may mutate `Scope.typeBindings` and
|
||||
* `indexes.bindings`.** `propagateImportedReturnTypes` and
|
||||
* `populateNamespaceSiblings` both write to these structures via
|
||||
* `as Map<...>` casts through `ReadonlyMap` facades. Downstream
|
||||
* consumers MUST NOT freeze or snapshot these maps before all
|
||||
* post-finalize hooks have run. The `ReadonlyMap<...>` type on
|
||||
* `ScopeResolutionIndexes` is a read-guidance surface for
|
||||
* consumers, NOT an immutability promise during the resolve phase.
|
||||
* - **I8 — Two-channel binding lifecycle.**
|
||||
* `indexes.bindings` is the **finalize-output channel**. After
|
||||
* `finalizeScopeModel` returns, its inner `BindingRef[]` arrays
|
||||
* are deep-frozen by `materializeBindings` and MUST NOT be
|
||||
* mutated by any post-finalize hook. Treat `indexes.bindings` as
|
||||
* immutable from the moment `finalizeScopeModel` returns.
|
||||
*
|
||||
* `indexes.bindingAugmentations` is the **post-finalize
|
||||
* append-only channel**. Hooks like `populateNamespaceSiblings`
|
||||
* append cross-file bindings synthesized after finalize (C#
|
||||
* same-namespace visibility, `using static` member exposure)
|
||||
* into this channel, NOT into `indexes.bindings`. Inner arrays
|
||||
* here are NEVER frozen — hooks `push()` directly. Any consumer
|
||||
* that reads post-finalize workspace bindings MUST query both
|
||||
* index channels via `lookupBindingsAt`
|
||||
* (`scope-resolution/scope/walkers.ts`); the helper returns
|
||||
* finalized refs first, appends unique augmentation refs after,
|
||||
* and dedupes by `def.nodeId` so finalized metadata wins on
|
||||
* duplicate defs. Per-`Scope.bindings` local declarations are the
|
||||
* lexical extraction channel and remain a separate first-tier
|
||||
* lookup for local shadowing.
|
||||
*
|
||||
* `Scope.typeBindings` remains mutable post-finalize per I6 (it
|
||||
* is intentionally not frozen at any point).
|
||||
*
|
||||
* The `ReadonlyMap<...>` types on `ScopeResolutionIndexes` are
|
||||
* compile-time read-guidance for consumers; structural mutation
|
||||
* of `bindingAugmentations` is performed via a deliberate
|
||||
* `as Map<...>` cast inside the hook implementations and is the
|
||||
* ONLY sanctioned channel for post-finalize binding fanout.
|
||||
*
|
||||
* The dev-mode runtime validator
|
||||
* (`validateBindingsImmutability` in
|
||||
* `scope-resolution/validate-bindings-immutability.ts`) surfaces
|
||||
* any drift — i.e. a hook writing to `indexes.bindings` instead
|
||||
* of `bindingAugmentations`, or producing a non-frozen finalized
|
||||
* bucket — via `onWarn` when explicitly enabled by
|
||||
* `NODE_ENV === 'development' || VALIDATE_SEMANTIC_MODEL === '1'`
|
||||
* (`VALIDATE_SEMANTIC_MODEL=0` is an explicit off switch).
|
||||
*
|
||||
* - **I9 — `SemanticModel` is the single authoritative symbol store.**
|
||||
* Every symbol-indexed lookup (key = `nodeId | simpleName |
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
import type { ParsedFile, ScopeId, TypeRef } from 'gitnexus-shared';
|
||||
import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
|
||||
import type { WorkspaceResolutionIndex } from '../workspace-index.js';
|
||||
import { lookupBindingsAt, namesAtScope } from '../scope/walkers.js';
|
||||
|
||||
/**
|
||||
* Max chain depth for the post-finalize re-follow. Effective end-to-end
|
||||
|
|
@ -136,14 +137,19 @@ export function propagateImportedReturnTypes(
|
|||
for (const filePath of scc.files) {
|
||||
const importerModule = moduleScopeByFile.get(filePath);
|
||||
if (importerModule === undefined) continue;
|
||||
const finalizedBindings = indexes.bindings.get(importerModule.id);
|
||||
if (finalizedBindings === undefined) continue;
|
||||
|
||||
for (const [localName, refs] of finalizedBindings) {
|
||||
// Iterate finalized + augmented binding names at this scope so
|
||||
// post-finalize hooks (e.g. `using static` augmentations from
|
||||
// `populateCsharpNamespaceSiblings`) are visible to the
|
||||
// import-derived typeBinding mirror. Both helpers fast-path when
|
||||
// no augmentations exist for the scope, so the common case is
|
||||
// allocation-free. See I8.
|
||||
for (const localName of namesAtScope(importerModule.id, indexes)) {
|
||||
// Skip if importer already has a typeBinding for this name —
|
||||
// an explicit local annotation must win over import-derived.
|
||||
if (importerModule.typeBindings.has(localName)) continue;
|
||||
|
||||
const refs = lookupBindingsAt(importerModule.id, localName, indexes);
|
||||
for (const ref of refs) {
|
||||
if (ref.origin !== 'import' && ref.origin !== 'reexport') continue;
|
||||
const sourceModule = moduleScopeByFile.get(ref.def.filePath);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import { SupportedLanguages, getLanguageFromFilename } from 'gitnexus-shared';
|
|||
import { readFileContents } from '../../filesystem-walker.js';
|
||||
import { runScopeResolution } from './run.js';
|
||||
import { SCOPE_RESOLVERS } from './registry.js';
|
||||
import { isDev } from '../../utils/env.js';
|
||||
import { isDev, isSemanticModelValidatorEnabled } from '../../utils/env.js';
|
||||
|
||||
export interface ScopeResolutionOutput {
|
||||
/** True when at least one language ran. */
|
||||
|
|
@ -143,7 +143,9 @@ export const scopeResolutionPhase: PipelinePhase<ScopeResolutionOutput> = {
|
|||
treeCache: scopeTreeCache,
|
||||
resolutionConfig,
|
||||
onWarn: (msg) => {
|
||||
if (isDev) console.warn(`[scope-resolution:${lang}] ${msg}`);
|
||||
if (isSemanticModelValidatorEnabled()) {
|
||||
console.warn(`[scope-resolution:${lang}] ${msg}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
provider,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import type { ParsedFile, RegistryProviders } from 'gitnexus-shared';
|
|||
import type { KnowledgeGraph } from '../../../graph/types.js';
|
||||
import type { MutableSemanticModel, SemanticModel } from '../../model/semantic-model.js';
|
||||
import { reconcileOwnership, validateOwnershipParity } from './reconcile-ownership.js';
|
||||
import { validateBindingsImmutability } from './validate-bindings-immutability.js';
|
||||
import { extractParsedFile } from '../../scope-extractor-bridge.js';
|
||||
import { finalizeScopeModel } from '../../finalize-orchestrator.js';
|
||||
import { resolveReferenceSites, type ResolveStats } from '../../resolve-references.js';
|
||||
|
|
@ -174,6 +175,8 @@ export function runScopeResolution(
|
|||
// Cross-file implicit-namespace visibility (C#). Must run before
|
||||
// propagateImportedReturnTypes so the latter pass sees siblings'
|
||||
// class bindings when chasing return-type chains across files.
|
||||
// The hook writes to `bindingAugmentations` only; finalized
|
||||
// `indexes.bindings` remains immutable post-finalize (I8).
|
||||
if (provider.populateNamespaceSiblings !== undefined) {
|
||||
const fileContents = new Map<string, string>();
|
||||
for (const f of files) fileContents.set(f.path, f.content);
|
||||
|
|
@ -195,6 +198,14 @@ export function runScopeResolution(
|
|||
}
|
||||
const tPropagate = PROF ? process.hrtime.bigint() : 0n;
|
||||
|
||||
// Opt-in I8 invariant guard. Runs once after all post-finalize hooks
|
||||
// (`populateNamespaceSiblings`, `propagateImportedReturnTypes`) have
|
||||
// had a chance to drift, so a single sweep covers the full
|
||||
// post-finalize surface visible to `resolveReferenceSites`. No-op in
|
||||
// default CLI runs; enabled by NODE_ENV=development or
|
||||
// VALIDATE_SEMANTIC_MODEL=1.
|
||||
validateBindingsImmutability(indexes, onWarn);
|
||||
|
||||
// ── Phase 3: resolve references via Registry.lookup ────────────────────
|
||||
const registryProviders: RegistryProviders = {
|
||||
arityCompatibility: provider.arityCompatibility,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* Dev-mode runtime validator for the two-channel binding lifecycle
|
||||
* (Contract Invariant I8 in `contract/scope-resolver.ts`).
|
||||
*
|
||||
* The two channels:
|
||||
* - `indexes.bindings` — finalize-output channel. After
|
||||
* `finalizeScopeModel` returns, every inner `BindingRef[]` array
|
||||
* here is deep-frozen by `materializeBindings`. NO post-finalize
|
||||
* hook should ever mutate this map's inner arrays — drift here
|
||||
* manifests at runtime as the `Cannot add property N, object is
|
||||
* not extensible` crash (issue #1066) or, more insidiously, as
|
||||
* a hook silently mutating one of the frozen arrays (a no-op in
|
||||
* production where freezes can be elided, a `TypeError` in dev).
|
||||
*
|
||||
* - `indexes.bindingAugmentations` — post-finalize append-only
|
||||
* channel. Inner arrays here are NEVER frozen; hooks like
|
||||
* `populateNamespaceSiblings` `push()` directly. Walkers consult
|
||||
* both channels via `lookupBindingsAt`.
|
||||
*
|
||||
* This validator runs after every post-finalize hook has executed
|
||||
* (so the dev-mode envelope captures the FULL surface area visible
|
||||
* to `resolveReferenceSites`) and asserts:
|
||||
*
|
||||
* 1. Every inner `BindingRef[]` array in `indexes.bindings` is
|
||||
* `Object.isFrozen` — i.e. finalize produced a frozen bucket
|
||||
* AND no hook accidentally `set()`-back a mutable replacement.
|
||||
*
|
||||
* 2. Every inner `BindingRef[]` array in
|
||||
* `indexes.bindingAugmentations` is NOT frozen — i.e. the
|
||||
* hook used the augmentation channel as designed (mutable
|
||||
* `push()`) and didn't accidentally freeze its own scratch
|
||||
* arrays. Self-documenting; mostly a sanity net.
|
||||
*
|
||||
* Mirrors `validateOwnershipParity` (#909): warns via `onWarn`,
|
||||
* never throws, and is opt-in outside development. Gated by
|
||||
* `isSemanticModelValidatorEnabled()` (`utils/env.ts`).
|
||||
*/
|
||||
|
||||
import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
|
||||
import { isSemanticModelValidatorEnabled } from '../../utils/env.js';
|
||||
|
||||
export function validateBindingsImmutability(
|
||||
indexes: ScopeResolutionIndexes,
|
||||
onWarn: (message: string) => void,
|
||||
): number {
|
||||
if (!isSemanticModelValidatorEnabled()) return 0;
|
||||
|
||||
let violations = 0;
|
||||
|
||||
for (const [scopeId, bucketMap] of indexes.bindings) {
|
||||
for (const [name, bucket] of bucketMap) {
|
||||
if (!Object.isFrozen(bucket)) {
|
||||
onWarn(
|
||||
`binding-immutability: indexes.bindings[${scopeId}][${name}] is NOT frozen — ` +
|
||||
`finalize produced a mutable bucket OR a post-finalize hook replaced a frozen ` +
|
||||
`bucket with a mutable one. Hooks must write to indexes.bindingAugmentations ` +
|
||||
`instead. See ScopeResolver Invariant I8.`,
|
||||
);
|
||||
violations++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [scopeId, bucketMap] of indexes.bindingAugmentations) {
|
||||
for (const [name, bucket] of bucketMap) {
|
||||
if (Object.isFrozen(bucket)) {
|
||||
onWarn(
|
||||
`binding-immutability: indexes.bindingAugmentations[${scopeId}][${name}] is FROZEN — ` +
|
||||
`the augmentation channel is mutable by contract; freezing it defeats the ` +
|
||||
`append-only purpose. See ScopeResolver Invariant I8.`,
|
||||
);
|
||||
violations++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
/**
|
||||
* Scope-chain lookup primitives shared across language providers.
|
||||
*
|
||||
* Four functions:
|
||||
* Five functions:
|
||||
* - `findReceiverTypeBinding` — walk scope.typeBindings up the chain
|
||||
* for a receiver name.
|
||||
* - `findClassBindingInScope` — walk scope.bindings + indexes.bindings
|
||||
* (pre-finalize + post-finalize) for a class-kind binding. Dual-
|
||||
* source is required because the cross-file finalize pass produces
|
||||
* a separate bindings map that is not merged back into scope.bindings.
|
||||
* - `lookupBindingsAt` — read finalized + augmented binding refs at
|
||||
* one scope, deduped by `def.nodeId`. The dual-source-aware
|
||||
* primitive every other binding lookup composes with.
|
||||
* - `findClassBindingInScope` — walk scope.bindings + the indexes via
|
||||
* `lookupBindingsAt` for a class-kind binding.
|
||||
* - `findOwnedMember` — find a method/field owned by a class def
|
||||
* across all parsed files by (ownerId, simpleName).
|
||||
* - `findExportedDef` — find a file-level exported def (top-of-module
|
||||
|
|
@ -19,11 +20,85 @@
|
|||
* as-is for TypeScript, Java, Kotlin, Ruby, etc.
|
||||
*/
|
||||
|
||||
import type { ParsedFile, ScopeId, SymbolDefinition, TypeRef } from 'gitnexus-shared';
|
||||
import type { BindingRef, ParsedFile, ScopeId, SymbolDefinition, TypeRef } from 'gitnexus-shared';
|
||||
import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
|
||||
import type { SemanticModel } from '../../model/semantic-model.js';
|
||||
import type { WorkspaceResolutionIndex } from '../workspace-index.js';
|
||||
|
||||
const EMPTY_BINDINGS: readonly BindingRef[] = Object.freeze([]);
|
||||
|
||||
/**
|
||||
* Look up binding refs at `scopeId` for `name`, consulting both the
|
||||
* finalize-owned `bindings` channel and the post-finalize
|
||||
* `bindingAugmentations` channel (see invariant I8 in
|
||||
* `contract/scope-resolver.ts`). Finalized refs come first; augmented
|
||||
* refs append, deduped by `def.nodeId` so a sibling that's also
|
||||
* explicitly imported doesn't double-emit.
|
||||
*
|
||||
* Returns a shared frozen empty array when neither channel has the
|
||||
* name — callers can compare against `=== EMPTY_BINDINGS` if they
|
||||
* want a fast-path miss check. The bucket arrays are returned by
|
||||
* reference when only one channel populates them; the merged path
|
||||
* allocates a fresh array.
|
||||
*
|
||||
* Walker primitives (`findClassBindingInScope`,
|
||||
* `findCallableBindingInScope`, `findExportedDefByName`) and
|
||||
* post-finalize passes that read finalized bindings (e.g.
|
||||
* `propagateImportedReturnTypes`, `namespace-targets`) MUST go
|
||||
* through this helper instead of `scopes.bindings.get(...)` directly,
|
||||
* so the augmentation channel is always visible.
|
||||
*/
|
||||
export function lookupBindingsAt(
|
||||
scopeId: ScopeId,
|
||||
name: string,
|
||||
scopes: ScopeResolutionIndexes,
|
||||
): readonly BindingRef[] {
|
||||
const finalized = scopes.bindings.get(scopeId)?.get(name);
|
||||
const augmented = scopes.bindingAugmentations.get(scopeId)?.get(name);
|
||||
const fLen = finalized?.length ?? 0;
|
||||
const aLen = augmented?.length ?? 0;
|
||||
if (fLen === 0 && aLen === 0) return EMPTY_BINDINGS;
|
||||
if (aLen === 0) return finalized!;
|
||||
if (fLen === 0) return augmented!;
|
||||
const seen = new Set<string>();
|
||||
const out: BindingRef[] = [];
|
||||
for (const r of finalized!) {
|
||||
seen.add(r.def.nodeId);
|
||||
out.push(r);
|
||||
}
|
||||
for (const r of augmented!) {
|
||||
if (seen.has(r.def.nodeId)) continue;
|
||||
out.push(r);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const EMPTY_NAMES: Iterable<string> = Object.freeze([]) as readonly string[];
|
||||
|
||||
/**
|
||||
* Return the union of bound names at `scopeId` across both the
|
||||
* finalized and augmented channels. Companion to `lookupBindingsAt`
|
||||
* for callers that need to iterate every name at a scope (e.g.
|
||||
* `propagateImportedReturnTypes`). Order is not guaranteed; callers
|
||||
* that need stable iteration should sort externally.
|
||||
*
|
||||
* Fast paths (zero allocation) when at most one channel is populated:
|
||||
* returns the underlying `Map.keys()` iterator directly. Only when both
|
||||
* channels carry names do we materialize a `Set` for deduplication.
|
||||
*/
|
||||
export function namesAtScope(scopeId: ScopeId, scopes: ScopeResolutionIndexes): Iterable<string> {
|
||||
const finalized = scopes.bindings.get(scopeId);
|
||||
const augmented = scopes.bindingAugmentations.get(scopeId);
|
||||
const fSize = finalized?.size ?? 0;
|
||||
const aSize = augmented?.size ?? 0;
|
||||
if (fSize === 0 && aSize === 0) return EMPTY_NAMES;
|
||||
if (aSize === 0) return finalized!.keys();
|
||||
if (fSize === 0) return augmented!.keys();
|
||||
const out = new Set<string>(finalized!.keys());
|
||||
for (const name of augmented!.keys()) out.add(name);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* True when a def's `type` names a class-like declaration — every kind
|
||||
* that collapses to `@scope.class` in the scope-extractor query contract.
|
||||
|
|
@ -78,8 +153,10 @@ export function findReceiverTypeBinding(
|
|||
* Walks the scope chain upward and consults TWO sources at each step:
|
||||
* 1. `scope.bindings` — populated during scope-extraction Pass 2 with
|
||||
* local declarations (`origin: 'local'`).
|
||||
* 2. `indexes.bindings` — populated by the cross-file finalize pass
|
||||
* with import/namespace/wildcard/reexport origins.
|
||||
* 2. The cross-file finalized + augmented bindings, via
|
||||
* `lookupBindingsAt` (per I8: finalized = canonical immutable
|
||||
* output; augmented = post-finalize hooks like
|
||||
* `populateNamespaceSiblings`).
|
||||
*
|
||||
* Without (2) we'd miss every cross-file class-receiver call.
|
||||
*/
|
||||
|
|
@ -103,12 +180,9 @@ export function findClassBindingInScope(
|
|||
}
|
||||
}
|
||||
|
||||
const finalizedScopeBindings = scopes.bindings.get(currentId);
|
||||
const importedBindings = finalizedScopeBindings?.get(receiverName);
|
||||
if (importedBindings !== undefined) {
|
||||
for (const b of importedBindings) {
|
||||
if (isClassLike(b.def.type)) return b.def;
|
||||
}
|
||||
const importedBindings = lookupBindingsAt(currentId, receiverName, scopes);
|
||||
for (const b of importedBindings) {
|
||||
if (isClassLike(b.def.type)) return b.def;
|
||||
}
|
||||
|
||||
currentId = scope.parent;
|
||||
|
|
@ -119,8 +193,9 @@ export function findClassBindingInScope(
|
|||
/**
|
||||
* Look up a callable (Function/Method/Constructor) by name in the
|
||||
* given scope's chain. Uses the dual-source pattern (scope.bindings +
|
||||
* indexes.bindings) so cross-file imports are visible — without it
|
||||
* free calls to imported functions never resolve via the post-pass.
|
||||
* `lookupBindingsAt` for finalized + augmented) so cross-file
|
||||
* imports are visible — without it free calls to imported functions
|
||||
* never resolve via the post-pass.
|
||||
*
|
||||
* Mirrors `findClassBindingInScope` exactly; only the accepted
|
||||
* def-type predicate differs.
|
||||
|
|
@ -147,13 +222,10 @@ export function findCallableBindingInScope(
|
|||
}
|
||||
}
|
||||
|
||||
const finalizedScopeBindings = scopes.bindings.get(currentId);
|
||||
const importedBindings = finalizedScopeBindings?.get(callableName);
|
||||
if (importedBindings !== undefined) {
|
||||
for (const b of importedBindings) {
|
||||
if (b.def.type === 'Function' || b.def.type === 'Method' || b.def.type === 'Constructor') {
|
||||
return b.def;
|
||||
}
|
||||
const importedBindings = lookupBindingsAt(currentId, callableName, scopes);
|
||||
for (const b of importedBindings) {
|
||||
if (b.def.type === 'Function' || b.def.type === 'Method' || b.def.type === 'Constructor') {
|
||||
return b.def;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,11 +366,9 @@ export function findExportedDefByName(
|
|||
if (b.def.type === 'Function' || b.def.type === 'Method') return b.def;
|
||||
}
|
||||
}
|
||||
const finalized = scopes.bindings.get(currentId)?.get(name);
|
||||
if (finalized !== undefined) {
|
||||
for (const b of finalized) {
|
||||
if (b.def.type === 'Function' || b.def.type === 'Method') return b.def;
|
||||
}
|
||||
const finalized = lookupBindingsAt(currentId, name, scopes);
|
||||
for (const b of finalized) {
|
||||
if (b.def.type === 'Function' || b.def.type === 'Method') return b.def;
|
||||
}
|
||||
currentId = scope.parent;
|
||||
}
|
||||
|
|
@ -355,7 +425,12 @@ export function findOwnedMember(
|
|||
* excluded.
|
||||
*
|
||||
* Reads from `WorkspaceResolutionIndex.moduleScopeByFile` (scope-tied
|
||||
* lookup that doesn't live on `SemanticModel`).
|
||||
* lookup that doesn't live on `SemanticModel`). This intentionally
|
||||
* does NOT call `lookupBindingsAt`: `findExportedDef` answers "what
|
||||
* did the target file declare locally at module scope?", while
|
||||
* `bindingAugmentations` models importer-side visibility created by
|
||||
* post-finalize hooks. Callers that need importer-visible exports use
|
||||
* `findExportedDefByName`, which is dual-channel aware.
|
||||
*/
|
||||
export function findExportedDef(
|
||||
targetFile: string,
|
||||
|
|
|
|||
|
|
@ -9,3 +9,17 @@
|
|||
|
||||
/** Whether we're running in development mode (enables verbose console logging). */
|
||||
export const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
/**
|
||||
* Whether scope-resolution dev validators (e.g. `validateBindingsImmutability`)
|
||||
* should run AND emit warnings. Off by default in CLI runs to avoid silent
|
||||
* O(n) scans on large repos; on in `NODE_ENV=development` or when explicitly
|
||||
* opted-in via `VALIDATE_SEMANTIC_MODEL=1`. `VALIDATE_SEMANTIC_MODEL=0` is the
|
||||
* explicit off switch and wins over both.
|
||||
*
|
||||
* Read every call (not memoized) so test setups using `vi.stubEnv` work.
|
||||
*/
|
||||
export const isSemanticModelValidatorEnabled = (): boolean => {
|
||||
if (process.env.VALIDATE_SEMANTIC_MODEL === '0') return false;
|
||||
return process.env.NODE_ENV === 'development' || process.env.VALIDATE_SEMANTIC_MODEL === '1';
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ import Ruby from 'tree-sitter-ruby';
|
|||
import { createRequire } from 'node:module';
|
||||
import { SupportedLanguages } from 'gitnexus-shared';
|
||||
import { getProvider } from '../languages/index.js';
|
||||
import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from '../constants.js';
|
||||
import {
|
||||
getTreeSitterBufferSize,
|
||||
getTreeSitterContentByteLength,
|
||||
TREE_SITTER_MAX_BUFFER,
|
||||
} from '../constants.js';
|
||||
import type { SymbolTableReader } from '../model/symbol-table.js';
|
||||
import type { ExtractedHeritage } from '../model/heritage-map.js';
|
||||
|
||||
|
|
@ -1383,7 +1387,7 @@ const processFileGroup = (
|
|||
|
||||
for (const file of files) {
|
||||
// Skip files larger than the max tree-sitter buffer (32 MB)
|
||||
if (file.content.length > TREE_SITTER_MAX_BUFFER) continue;
|
||||
if (getTreeSitterContentByteLength(file.content) > TREE_SITTER_MAX_BUFFER) continue;
|
||||
|
||||
// Vue SFC preprocessing: extract <script> block content
|
||||
let parseContent = file.content;
|
||||
|
|
@ -1402,7 +1406,7 @@ const processFileGroup = (
|
|||
let tree;
|
||||
try {
|
||||
tree = parser.parse(parseContent, undefined, {
|
||||
bufferSize: getTreeSitterBufferSize(parseContent.length),
|
||||
bufferSize: getTreeSitterBufferSize(parseContent),
|
||||
});
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
6
gitnexus/test/fixtures/lang-resolution/csharp-large-cache-miss-resolution/Models/User.cs
vendored
Normal file
6
gitnexus/test/fixtures/lang-resolution/csharp-large-cache-miss-resolution/Models/User.cs
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace App.Models;
|
||||
|
||||
public class User
|
||||
{
|
||||
public void Save() { }
|
||||
}
|
||||
3
gitnexus/test/fixtures/lang-resolution/csharp-large-cache-miss-resolution/Other/Helper.cs
vendored
Normal file
3
gitnexus/test/fixtures/lang-resolution/csharp-large-cache-miss-resolution/Other/Helper.cs
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
namespace App.Other;
|
||||
|
||||
public class Helper { }
|
||||
548
gitnexus/test/fixtures/lang-resolution/csharp-large-cache-miss-resolution/Services/UserService.cs
vendored
Normal file
548
gitnexus/test/fixtures/lang-resolution/csharp-large-cache-miss-resolution/Services/UserService.cs
vendored
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
using App.Models;
|
||||
using App.Other;
|
||||
|
||||
namespace App.Services;
|
||||
|
||||
// ============================================================================
|
||||
// Regression fixture for GitNexus issue #1066 (PR #1050 follow-up).
|
||||
//
|
||||
// This file is intentionally larger than the 32 KB tree-sitter default buffer.
|
||||
// The scope-resolution phase reparses the file on cache miss (worker mode
|
||||
// can't share `Tree` instances across MessageChannels), so the cache-miss
|
||||
// path must use the adaptive `getTreeSitterBufferSize` rather than the
|
||||
// default. Without that, this file fails with `Invalid argument` and the
|
||||
// `CreateUser -> Save` CALLS edge below would silently disappear.
|
||||
//
|
||||
// In addition, this file declares a local `Helper` while also importing
|
||||
// `App.Other.Helper` via `using App.Other;`. Before the freeze fix in
|
||||
// `populateCsharpNamespaceSiblings`, the cross-namespace inject loop pushed
|
||||
// `App.Other.Helper` onto the frozen `bindings[module]['Helper']` bucket
|
||||
// produced by `finalize-algorithm.ts` (`Object.freeze(refs.slice())`),
|
||||
// throwing `Cannot add property N, object is not extensible` and aborting
|
||||
// the whole `scopeResolution` phase.
|
||||
//
|
||||
// Both regressions are exercised end-to-end through the full pipeline by
|
||||
// the resolver test in `test/integration/resolvers/csharp.test.ts`.
|
||||
// ============================================================================
|
||||
//
|
||||
// Padding section below — each line is a separate `comment` AST node so the
|
||||
// resolver pipeline treats them as a no-op while the source byte count
|
||||
// crosses the 32 KB threshold.
|
||||
// Pad 001 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 002 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 003 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 004 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 005 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 006 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 007 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 008 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 009 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 010 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 011 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 012 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 013 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 014 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 015 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 016 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 017 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 018 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 019 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 020 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 021 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 022 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 023 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 024 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 025 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 026 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 027 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 028 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 029 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 030 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 031 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 032 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 033 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 034 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 035 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 036 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 037 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 038 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 039 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 040 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 041 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 042 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 043 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 044 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 045 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 046 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 047 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 048 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 049 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 050 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 051 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 052 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 053 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 054 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 055 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 056 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 057 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 058 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 059 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 060 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 061 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 062 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 063 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 064 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 065 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 066 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 067 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 068 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 069 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 070 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 071 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 072 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 073 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 074 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 075 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 076 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 077 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 078 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 079 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 080 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 081 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 082 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 083 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 084 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 085 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 086 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 087 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 088 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 089 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 090 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 091 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 092 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 093 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 094 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 095 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 096 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 097 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 098 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 099 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 100 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 101 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 102 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 103 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 104 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 105 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 106 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 107 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 108 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 109 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 110 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 111 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 112 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 113 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 114 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 115 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 116 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 117 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 118 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 119 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 120 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 121 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 122 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 123 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 124 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 125 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 126 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 127 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 128 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 129 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 130 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 131 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 132 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 133 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 134 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 135 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 136 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 137 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 138 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 139 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 140 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 141 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 142 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 143 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 144 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 145 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 146 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 147 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 148 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 149 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 150 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 151 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 152 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 153 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 154 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 155 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 156 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 157 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 158 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 159 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 160 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 161 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 162 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 163 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 164 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 165 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 166 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 167 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 168 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 169 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 170 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 171 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 172 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 173 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 174 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 175 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 176 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 177 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 178 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 179 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 180 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 181 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 182 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 183 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 184 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 185 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 186 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 187 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 188 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 189 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 190 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 191 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 192 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 193 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 194 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 195 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 196 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 197 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 198 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 199 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 200 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 201 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 202 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 203 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 204 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 205 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 206 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 207 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 208 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 209 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 210 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 211 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 212 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 213 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 214 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 215 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 216 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 217 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 218 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 219 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 220 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 221 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 222 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 223 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 224 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 225 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 226 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 227 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 228 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 229 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 230 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 231 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 232 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 233 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 234 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 235 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 236 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 237 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 238 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 239 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 240 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 241 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 242 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 243 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 244 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 245 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 246 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 247 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 248 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 249 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 250 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 251 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 252 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 253 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 254 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 255 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 256 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 257 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 258 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 259 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 260 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 261 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 262 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 263 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 264 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 265 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 266 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 267 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 268 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 269 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 270 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 271 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 272 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 273 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 274 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 275 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 276 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 277 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 278 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 279 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 280 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 281 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 282 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 283 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 284 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 285 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 286 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 287 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 288 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 289 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 290 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 291 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 292 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 293 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 294 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 295 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 296 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 297 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 298 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 299 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 300 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 301 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 302 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 303 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 304 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 305 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 306 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 307 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 308 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 309 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 310 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 311 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 312 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 313 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 314 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 315 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 316 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 317 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 318 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 319 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 320 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 321 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 322 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 323 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 324 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 325 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 326 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 327 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 328 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 329 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 330 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 331 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 332 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 333 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 334 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 335 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 336 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 337 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 338 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 339 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 340 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 341 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 342 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 343 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 344 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 345 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 346 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 347 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 348 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 349 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 350 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 351 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 352 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 353 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 354 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 355 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 356 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 357 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 358 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 359 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 360 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 361 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 362 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 363 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 364 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 365 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 366 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 367 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 368 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 369 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 370 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 371 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 372 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 373 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 374 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 375 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 376 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 377 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 378 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 379 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 380 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 381 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 382 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 383 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 384 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 385 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 386 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 387 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 388 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 389 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 390 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 391 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 392 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 393 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 394 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 395 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 396 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 397 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 398 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 399 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 400 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 401 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 402 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 403 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 404 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 405 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 406 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 407 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 408 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 409 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 410 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 411 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 412 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 413 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 414 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 415 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 416 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 417 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 418 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 419 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 420 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 421 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 422 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 423 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 424 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 425 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 426 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 427 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 428 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 429 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 430 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 431 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 432 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 433 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 434 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 435 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 436 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 437 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 438 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 439 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 440 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 441 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 442 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 443 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 444 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 445 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 446 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 447 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 448 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 449 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 450 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 451 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 452 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 453 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 454 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 455 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 456 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 457 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 458 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 459 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 460 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 461 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 462 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 463 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 464 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 465 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 466 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 467 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 468 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 469 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 470 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 471 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 472 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 473 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 474 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 475 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 476 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 477 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 478 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 479 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 480 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 481 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 482 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 483 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 484 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 485 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 486 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 487 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 488 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 489 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 490 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 491 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 492 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 493 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 494 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 495 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 496 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 497 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 498 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 499 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
// Pad 500 - large-file marker for issue #1066 cache-miss buffer regression. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.
|
||||
|
||||
// ============================================================================
|
||||
// Cross-namespace `using` plus a colliding local `Helper` together exercise
|
||||
// the frozen-bucket fix in populateCsharpNamespaceSiblings. The CreateUser
|
||||
// method below resolves `User` via same-namespace siblings (Models/User.cs)
|
||||
// and `user.Save()` via receiver-typed dispatch.
|
||||
// ============================================================================
|
||||
|
||||
public class Helper { }
|
||||
|
||||
public class UserService
|
||||
{
|
||||
public void CreateUser()
|
||||
{
|
||||
var user = new User();
|
||||
user.Save();
|
||||
}
|
||||
}
|
||||
|
|
@ -2420,3 +2420,68 @@ describe('C# class-name receiver write ACCESSES (merged Case 2 kind-aware branch
|
|||
expect(stray).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Issue #1066 regression: large source files (>32 KB) combined with a
|
||||
// cross-namespace `using` and a colliding local class. Pins both fixes in
|
||||
// the resolver dataset:
|
||||
//
|
||||
// 1. emitCsharpScopeCaptures + extractFileStructure must use the adaptive
|
||||
// `getTreeSitterBufferSize` on cache miss, otherwise UserService.cs
|
||||
// fails to reparse with "Invalid argument" and CreateUser is dropped.
|
||||
// 2. populateCsharpNamespaceSiblings must append to bindingAugmentations
|
||||
// instead of mutating frozen finalize-produced BindingRef[] arrays;
|
||||
// otherwise the cross-namespace inject loop throws "Cannot add property
|
||||
// N, object is not extensible" when the importer also declares the same
|
||||
// simple name locally.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('C# large-file + frozen-bucket regression (issue #1066)', () => {
|
||||
let result: PipelineResult;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Force the worker pool path with low thresholds so the scope-resolution
|
||||
// cache-miss reparse actually fires (workers can't share Tree instances
|
||||
// across MessageChannels). This is what reproduces the >32 KB
|
||||
// "Invalid argument" failure end-to-end through the pipeline.
|
||||
result = await runPipelineFromRepo(
|
||||
path.join(FIXTURES, 'csharp-large-cache-miss-resolution'),
|
||||
() => {},
|
||||
{ workerThresholdsForTest: { minFiles: 1, minBytes: 0 } },
|
||||
);
|
||||
}, 120000);
|
||||
|
||||
it('extracts UserService.CreateUser despite the >32 KB source size', () => {
|
||||
// Without the adaptive-buffer fix, UserService.cs would fail to reparse
|
||||
// on cache miss and CreateUser would not be extracted at all.
|
||||
expect(getNodesByLabel(result, 'Method')).toEqual(
|
||||
expect.arrayContaining(['CreateUser', 'Save']),
|
||||
);
|
||||
});
|
||||
|
||||
it('detects all three classes (User, Helper, UserService)', () => {
|
||||
expect(getNodesByLabel(result, 'Class')).toEqual(
|
||||
expect.arrayContaining(['User', 'Helper', 'UserService']),
|
||||
);
|
||||
});
|
||||
|
||||
it('resolves CreateUser -> User constructor across same namespace', () => {
|
||||
const calls = getRelationships(result, 'CALLS');
|
||||
const ctor = calls.find(
|
||||
(c) => c.source === 'CreateUser' && c.target === 'User' && c.targetLabel === 'Class',
|
||||
);
|
||||
expect(ctor).toBeDefined();
|
||||
expect(ctor!.targetFilePath).toBe('Models/User.cs');
|
||||
});
|
||||
|
||||
it('resolves CreateUser -> Save through namespace siblings', () => {
|
||||
// Without the freeze fix, populateCsharpNamespaceSiblings throws on
|
||||
// the colliding `Helper` bucket, aborting the whole scopeResolution
|
||||
// phase, so no CALLS edges from CreateUser would be emitted at all.
|
||||
const calls = getRelationships(result, 'CALLS');
|
||||
const save = calls.find((c) => c.source === 'CreateUser' && c.target === 'Save');
|
||||
expect(save).toBeDefined();
|
||||
expect(save!.targetFilePath).toBe('Models/User.cs');
|
||||
expect(['import-resolved', 'global']).toContain(save!.rel.reason);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
/**
|
||||
* Python: relative imports + class inheritance + ambiguous module disambiguation
|
||||
*/
|
||||
import { describe, it, expect, beforeAll } from 'vitest';
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||
import path from 'path';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import {
|
||||
FIXTURES,
|
||||
CROSS_FILE_FIXTURES,
|
||||
|
|
@ -14,6 +16,14 @@ import {
|
|||
type PipelineResult,
|
||||
} from './helpers.js';
|
||||
|
||||
function writeFixtureRepo(root: string, files: Record<string, string>): void {
|
||||
for (const [relPath, content] of Object.entries(files)) {
|
||||
const fullPath = path.join(root, relPath);
|
||||
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
||||
fs.writeFileSync(fullPath, content, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Heritage: relative imports + class inheritance
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -2485,3 +2495,61 @@ describe('Python class-body namespace import feeds method receiver-bound call',
|
|||
expect(callEdge!.rel.targetId).toContain('mod.py:helper');
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Issue #1066 sibling regression for Python: force worker-mode extraction so
|
||||
// scope-resolution reparses on cache miss, then assert large ASCII and
|
||||
// UTF-8-heavy source files still produce trailing call edges.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Python large-file cache-miss parser buffer regression', () => {
|
||||
let repoDir: string;
|
||||
let result: PipelineResult;
|
||||
|
||||
beforeAll(async () => {
|
||||
repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gn-python-large-cache-'));
|
||||
writeFixtureRepo(repoDir, {
|
||||
'models.py': `
|
||||
class User:
|
||||
def save(self):
|
||||
return True
|
||||
`,
|
||||
'ascii_app.py': `from models import User
|
||||
|
||||
# ${'x'.repeat(120 * 1024)}
|
||||
def create_ascii_user():
|
||||
user = User()
|
||||
user.save()
|
||||
`,
|
||||
'utf8_app.py': `from models import User
|
||||
|
||||
# ${'漢'.repeat(120_000)}
|
||||
def create_utf8_user():
|
||||
user = User()
|
||||
user.save()
|
||||
`,
|
||||
});
|
||||
result = await runPipelineFromRepo(repoDir, () => {}, {
|
||||
workerThresholdsForTest: { minFiles: 1, minBytes: 0 },
|
||||
});
|
||||
}, 120000);
|
||||
|
||||
afterAll(() => {
|
||||
if (repoDir !== undefined) fs.rmSync(repoDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('extracts trailing functions after large ASCII and UTF-8 padding', () => {
|
||||
expect(getNodesByLabel(result, 'Function')).toEqual(
|
||||
expect.arrayContaining(['create_ascii_user', 'create_utf8_user', 'save']),
|
||||
);
|
||||
});
|
||||
|
||||
it('resolves calls from both padded files to User.save', () => {
|
||||
const calls = getRelationships(result, 'CALLS');
|
||||
for (const source of ['create_ascii_user', 'create_utf8_user']) {
|
||||
const save = calls.find((c) => c.source === source && c.target === 'save');
|
||||
expect(save).toBeDefined();
|
||||
expect(save!.targetFilePath).toBe('models.py');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
/**
|
||||
* TypeScript: heritage resolution + ambiguous symbol disambiguation
|
||||
*/
|
||||
import { describe, it, expect, beforeAll } from 'vitest';
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||
import path from 'path';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import {
|
||||
FIXTURES,
|
||||
getRelationships,
|
||||
|
|
@ -13,6 +15,14 @@ import {
|
|||
type PipelineResult,
|
||||
} from './helpers.js';
|
||||
|
||||
function writeFixtureRepo(root: string, files: Record<string, string>): void {
|
||||
for (const [relPath, content] of Object.entries(files)) {
|
||||
const fullPath = path.join(root, relPath);
|
||||
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
||||
fs.writeFileSync(fullPath, content, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Heritage: class extends + implements interface
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -2815,3 +2825,76 @@ describe('TypeScript namespace re-export barrel (registry-primary)', () => {
|
|||
expect(fromBarrel).toContain('src/base.ts');
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Issue #1066 sibling regression for TypeScript: force worker-mode extraction
|
||||
// so scope-resolution reparses on cache miss, then assert large ASCII and
|
||||
// UTF-8-heavy source files still produce trailing call edges.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('TypeScript large-file cache-miss parser buffer regression', () => {
|
||||
let repoDir: string;
|
||||
let result: PipelineResult;
|
||||
|
||||
beforeAll(async () => {
|
||||
repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gn-ts-large-cache-'));
|
||||
writeFixtureRepo(repoDir, {
|
||||
'src/models.ts': `
|
||||
export class User {
|
||||
save(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
`,
|
||||
'src/ascii-app.ts': `import { User } from './models';
|
||||
|
||||
// ${'x'.repeat(120 * 1024)}
|
||||
export function createAsciiUser(): void {
|
||||
const user = new User();
|
||||
user.save();
|
||||
}
|
||||
`,
|
||||
'src/utf8-app.ts': `import { User } from './models';
|
||||
|
||||
// ${'漢'.repeat(120_000)}
|
||||
export function createUtf8User(): void {
|
||||
const user = new User();
|
||||
user.save();
|
||||
}
|
||||
`,
|
||||
});
|
||||
result = await runPipelineFromRepo(repoDir, () => {}, {
|
||||
workerThresholdsForTest: { minFiles: 1, minBytes: 0 },
|
||||
});
|
||||
}, 120000);
|
||||
|
||||
afterAll(() => {
|
||||
if (repoDir !== undefined) fs.rmSync(repoDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('extracts trailing functions after large ASCII and UTF-8 padding', () => {
|
||||
expect(getNodesByLabel(result, 'Function')).toEqual(
|
||||
expect.arrayContaining(['createAsciiUser', 'createUtf8User']),
|
||||
);
|
||||
});
|
||||
|
||||
it('resolves constructor calls from both padded files to User', () => {
|
||||
const calls = getRelationships(result, 'CALLS');
|
||||
for (const source of ['createAsciiUser', 'createUtf8User']) {
|
||||
const ctor = calls.find(
|
||||
(c) => c.source === source && c.target === 'User' && c.targetLabel === 'Class',
|
||||
);
|
||||
expect(ctor).toBeDefined();
|
||||
expect(ctor!.targetFilePath).toBe('src/models.ts');
|
||||
}
|
||||
});
|
||||
|
||||
it('resolves member calls from both padded files to User.save', () => {
|
||||
const calls = getRelationships(result, 'CALLS');
|
||||
for (const source of ['createAsciiUser', 'createUtf8User']) {
|
||||
const save = calls.find((c) => c.source === source && c.target === 'save');
|
||||
expect(save).toBeDefined();
|
||||
expect(save!.targetFilePath).toBe('src/models.ts');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import type { NodeLabel } from 'gitnexus-shared';
|
|||
import type { LanguageProvider } from '../../src/core/ingestion/language-provider.js';
|
||||
import {
|
||||
getTreeSitterBufferSize,
|
||||
getTreeSitterContentByteLength,
|
||||
TREE_SITTER_BUFFER_SIZE,
|
||||
TREE_SITTER_MAX_BUFFER,
|
||||
} from '../../src/core/ingestion/constants.js';
|
||||
|
|
@ -638,56 +639,69 @@ describe('extractFunctionName (via methodExtractor)', () => {
|
|||
});
|
||||
|
||||
describe('getTreeSitterBufferSize', () => {
|
||||
const expectedBufferSize = (byteLength: number): number =>
|
||||
Math.min(Math.max(byteLength * 2, TREE_SITTER_BUFFER_SIZE), TREE_SITTER_MAX_BUFFER);
|
||||
|
||||
it('returns minimum 512KB for small files', () => {
|
||||
expect(getTreeSitterBufferSize(100)).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
expect(getTreeSitterBufferSize(0)).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
expect(getTreeSitterBufferSize(1000)).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
expect(getTreeSitterBufferSize('x'.repeat(100))).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
expect(getTreeSitterBufferSize('')).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
expect(getTreeSitterBufferSize('x'.repeat(1000))).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
});
|
||||
|
||||
it('returns 2x content length when larger than minimum', () => {
|
||||
const size = 400 * 1024; // 400 KB — 2x = 800 KB > 512 KB min
|
||||
expect(getTreeSitterBufferSize(size)).toBe(size * 2);
|
||||
const size = 400 * 1024; // 400 KB, 2x = 800 KB > 512 KB min
|
||||
expect(getTreeSitterBufferSize('x'.repeat(size))).toBe(size * 2);
|
||||
});
|
||||
|
||||
it('caps at 32MB for very large files', () => {
|
||||
const huge = 20 * 1024 * 1024; // 20 MB — 2x = 40 MB > 32 MB cap
|
||||
const huge = 'x'.repeat(20 * 1024 * 1024); // 20 MB, 2x = 40 MB > 32 MB cap
|
||||
expect(getTreeSitterBufferSize(huge)).toBe(32 * 1024 * 1024);
|
||||
});
|
||||
|
||||
it('returns exactly 512KB at the boundary', () => {
|
||||
// 256KB * 2 = 512KB = minimum, so should return minimum
|
||||
expect(getTreeSitterBufferSize(256 * 1024)).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
expect(getTreeSitterBufferSize('x'.repeat(256 * 1024))).toBe(TREE_SITTER_BUFFER_SIZE);
|
||||
});
|
||||
|
||||
it('scales linearly between min and max', () => {
|
||||
const small = getTreeSitterBufferSize(300 * 1024);
|
||||
const medium = getTreeSitterBufferSize(1 * 1024 * 1024);
|
||||
const large = getTreeSitterBufferSize(5 * 1024 * 1024);
|
||||
const small = getTreeSitterBufferSize('x'.repeat(300 * 1024));
|
||||
const medium = getTreeSitterBufferSize('x'.repeat(1 * 1024 * 1024));
|
||||
const large = getTreeSitterBufferSize('x'.repeat(5 * 1024 * 1024));
|
||||
expect(small).toBeLessThan(medium);
|
||||
expect(medium).toBeLessThan(large);
|
||||
});
|
||||
|
||||
it('sizes from UTF-8 bytes, not UTF-16 code units', () => {
|
||||
const source = '漢'.repeat(190_000);
|
||||
const byteLength = getTreeSitterContentByteLength(source);
|
||||
expect(byteLength).toBe(source.length * 3);
|
||||
expect(getTreeSitterBufferSize(source)).toBe(expectedBufferSize(byteLength));
|
||||
});
|
||||
|
||||
it('caps UTF-8-heavy sources using byte length', () => {
|
||||
const source = '漢'.repeat(6_000_000);
|
||||
expect(getTreeSitterContentByteLength(source)).toBe(source.length * 3);
|
||||
expect(getTreeSitterBufferSize(source)).toBe(TREE_SITTER_MAX_BUFFER);
|
||||
});
|
||||
|
||||
it('TREE_SITTER_MAX_BUFFER is 32MB', () => {
|
||||
expect(TREE_SITTER_MAX_BUFFER).toBe(32 * 1024 * 1024);
|
||||
});
|
||||
|
||||
it('returns max buffer at exact boundary (16MB input)', () => {
|
||||
// 16MB * 2 = 32MB = max
|
||||
expect(getTreeSitterBufferSize(16 * 1024 * 1024)).toBe(TREE_SITTER_MAX_BUFFER);
|
||||
expect(getTreeSitterBufferSize('x'.repeat(16 * 1024 * 1024))).toBe(TREE_SITTER_MAX_BUFFER);
|
||||
});
|
||||
|
||||
it('file just over max returns max buffer', () => {
|
||||
// 17MB * 2 = 34MB > 32MB cap
|
||||
expect(getTreeSitterBufferSize(17 * 1024 * 1024)).toBe(TREE_SITTER_MAX_BUFFER);
|
||||
expect(getTreeSitterBufferSize('x'.repeat(17 * 1024 * 1024))).toBe(TREE_SITTER_MAX_BUFFER);
|
||||
});
|
||||
|
||||
it('handles files between old 512KB limit and new 32MB limit', () => {
|
||||
// This is the range that was previously silently skipped
|
||||
const sizes = [600 * 1024, 1024 * 1024, 5 * 1024 * 1024, 10 * 1024 * 1024];
|
||||
for (const size of sizes) {
|
||||
const bufSize = getTreeSitterBufferSize(size);
|
||||
expect(bufSize).toBeGreaterThanOrEqual(TREE_SITTER_BUFFER_SIZE);
|
||||
expect(bufSize).toBeLessThanOrEqual(TREE_SITTER_MAX_BUFFER);
|
||||
expect(getTreeSitterBufferSize('x'.repeat(size))).toBe(expectedBufferSize(size));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,6 +26,26 @@ describe('emitCsharpScopeCaptures — scopes', () => {
|
|||
expect(all.some((t) => t.includes('@scope.module'))).toBe(true);
|
||||
});
|
||||
|
||||
it('parses large cache-miss files with the adaptive tree-sitter buffer', () => {
|
||||
const padding = 'x'.repeat(600 * 1024);
|
||||
const match = findMatch(
|
||||
`namespace Large;\n// ${padding}\nclass Big { public void AfterPadding() { } }`,
|
||||
(t) => t.includes('@declaration.method'),
|
||||
);
|
||||
expect(match).toBeDefined();
|
||||
expect(match!['@declaration.name'].text).toBe('AfterPadding');
|
||||
});
|
||||
|
||||
it('parses UTF-8-heavy cache-miss files with a byte-sized buffer', () => {
|
||||
const padding = '漢'.repeat(190_000);
|
||||
const match = findMatch(
|
||||
`namespace Large;\n// ${padding}\nclass Big { public void AfterPadding() { } }`,
|
||||
(t) => t.includes('@declaration.method'),
|
||||
);
|
||||
expect(match).toBeDefined();
|
||||
expect(match!['@declaration.name'].text).toBe('AfterPadding');
|
||||
});
|
||||
|
||||
it('captures block-scoped namespaces as @scope.namespace', () => {
|
||||
const all = tagsFor('namespace Foo.Bar { class A { } }');
|
||||
expect(all.some((t) => t.includes('@scope.namespace'))).toBe(true);
|
||||
|
|
|
|||
|
|
@ -18,16 +18,20 @@ import {
|
|||
} from '../../../../src/core/ingestion/languages/csharp/simple-hooks.js';
|
||||
import { csharpMergeBindings } from '../../../../src/core/ingestion/languages/csharp/merge-bindings.js';
|
||||
import { csharpArityCompatibility } from '../../../../src/core/ingestion/languages/csharp/arity.js';
|
||||
import { populateCsharpNamespaceSiblings } from '../../../../src/core/ingestion/languages/csharp/namespace-siblings.js';
|
||||
import type {
|
||||
BindingRef,
|
||||
Callsite,
|
||||
CaptureMatch,
|
||||
ParsedFile,
|
||||
ParsedImport,
|
||||
Scope,
|
||||
ScopeId,
|
||||
ScopeTree,
|
||||
SymbolDefinition,
|
||||
TypeRef,
|
||||
} from 'gitnexus-shared';
|
||||
import type { ScopeResolutionIndexes } from '../../../../src/core/ingestion/model/scope-resolution-indexes.js';
|
||||
|
||||
function fakeScope(
|
||||
kind: Scope['kind'],
|
||||
|
|
@ -189,6 +193,137 @@ describe('csharpArityCompatibility', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('populateCsharpNamespaceSiblings', () => {
|
||||
const classDef = (nodeId: string, filePath: string, qualifiedName: string): SymbolDefinition =>
|
||||
({ nodeId, filePath, qualifiedName, type: 'Class' }) as SymbolDefinition;
|
||||
|
||||
const scope = (
|
||||
id: string,
|
||||
kind: Scope['kind'],
|
||||
filePath: string,
|
||||
parent: ScopeId | null = null,
|
||||
ownedDefs: readonly SymbolDefinition[] = [],
|
||||
): Scope =>
|
||||
({
|
||||
id: id as ScopeId,
|
||||
kind,
|
||||
parent,
|
||||
filePath,
|
||||
range: { startLine: 1, startColumn: 0, endLine: 10, endColumn: 0 },
|
||||
bindings: new Map(),
|
||||
imports: [],
|
||||
ownedDefs,
|
||||
typeBindings: new Map(),
|
||||
}) as unknown as Scope;
|
||||
|
||||
it('writes namespace siblings to the augmentation channel without touching frozen finalized bindings', () => {
|
||||
// Verifies the post-finalize binding-augmentation contract for the
|
||||
// C# namespace-siblings hook (per ScopeResolver I8 + the
|
||||
// `bindingAugmentations` doc on `ScopeResolutionIndexes`):
|
||||
// * `indexes.bindings` (the finalize output) stays frozen and
|
||||
// its inner `BindingRef[]` arrays are NEVER mutated by the
|
||||
// hook — proven here by passing a frozen bucket and asserting
|
||||
// it survives unchanged.
|
||||
// * Cross-file siblings are appended to
|
||||
// `indexes.bindingAugmentations`, the dedicated mutable
|
||||
// append-only buffer.
|
||||
// * Walkers downstream (`lookupBindingsAt`) merge the two layers
|
||||
// transparently — covered by walkers-augmentations.test.ts.
|
||||
// Reproduces the pre-architecture `Cannot add property N, object
|
||||
// is not extensible` crash by carrying a pre-frozen `BindingRef[]`
|
||||
// through `indexes.bindings`. End-to-end coverage is in the
|
||||
// `csharp-large-cache-miss-resolution` fixture.
|
||||
const existing = classDef('def:external.B', 'external.cs', 'Other.B');
|
||||
const sibling = classDef('def:b.B', 'b.cs', 'Demo.B');
|
||||
const moduleA = scope('scope:a:module', 'Module', 'a.cs');
|
||||
const moduleB = scope('scope:b:module', 'Module', 'b.cs');
|
||||
const classB = scope('scope:b:class', 'Class', 'b.cs', moduleB.id, [sibling]);
|
||||
const parsedFiles: ParsedFile[] = [
|
||||
{
|
||||
filePath: 'a.cs',
|
||||
moduleScope: moduleA.id,
|
||||
scopes: Object.freeze([moduleA]),
|
||||
parsedImports: Object.freeze([]),
|
||||
localDefs: Object.freeze([]),
|
||||
referenceSites: Object.freeze([]),
|
||||
} as ParsedFile,
|
||||
{
|
||||
filePath: 'b.cs',
|
||||
moduleScope: moduleB.id,
|
||||
scopes: Object.freeze([moduleB, classB]),
|
||||
parsedImports: Object.freeze([]),
|
||||
localDefs: Object.freeze([sibling]),
|
||||
referenceSites: Object.freeze([]),
|
||||
} as ParsedFile,
|
||||
];
|
||||
const frozenBucket = Object.freeze([{ def: existing, origin: 'import' } as BindingRef]);
|
||||
const bindings = new Map<ScopeId, ReadonlyMap<string, readonly BindingRef[]>>([
|
||||
[moduleA.id, new Map<string, readonly BindingRef[]>([['B', frozenBucket]])],
|
||||
]);
|
||||
const bindingAugmentations = new Map<ScopeId, ReadonlyMap<string, readonly BindingRef[]>>();
|
||||
|
||||
populateCsharpNamespaceSiblings(
|
||||
parsedFiles,
|
||||
{ bindings, bindingAugmentations } as unknown as ScopeResolutionIndexes,
|
||||
{
|
||||
fileContents: new Map([
|
||||
['a.cs', 'namespace Demo;\nclass A { }\n'],
|
||||
['b.cs', 'namespace Demo;\nclass B { }\n'],
|
||||
]),
|
||||
},
|
||||
);
|
||||
|
||||
const finalized = bindings.get(moduleA.id)?.get('B') ?? [];
|
||||
expect(finalized).toBe(frozenBucket);
|
||||
expect(finalized.map((b) => b.def.nodeId)).toEqual(['def:external.B']);
|
||||
expect(Object.isFrozen(finalized)).toBe(true);
|
||||
|
||||
const augmented = bindingAugmentations.get(moduleA.id)?.get('B') ?? [];
|
||||
expect(augmented.map((b) => b.def.nodeId)).toEqual(['def:b.B']);
|
||||
expect(Object.isFrozen(augmented)).toBe(false);
|
||||
});
|
||||
|
||||
it('parses UTF-8-heavy cache-miss files before namespace sibling injection', () => {
|
||||
const sibling = classDef('def:b.B', 'b.cs', 'Demo.B');
|
||||
const moduleA = scope('scope:a:module', 'Module', 'a.cs');
|
||||
const moduleB = scope('scope:b:module', 'Module', 'b.cs');
|
||||
const classB = scope('scope:b:class', 'Class', 'b.cs', moduleB.id, [sibling]);
|
||||
const parsedFiles: ParsedFile[] = [
|
||||
{
|
||||
filePath: 'a.cs',
|
||||
moduleScope: moduleA.id,
|
||||
scopes: Object.freeze([moduleA]),
|
||||
parsedImports: Object.freeze([]),
|
||||
localDefs: Object.freeze([]),
|
||||
referenceSites: Object.freeze([]),
|
||||
} as ParsedFile,
|
||||
{
|
||||
filePath: 'b.cs',
|
||||
moduleScope: moduleB.id,
|
||||
scopes: Object.freeze([moduleB, classB]),
|
||||
parsedImports: Object.freeze([]),
|
||||
localDefs: Object.freeze([sibling]),
|
||||
referenceSites: Object.freeze([]),
|
||||
} as ParsedFile,
|
||||
];
|
||||
const bindingAugmentations = new Map<ScopeId, ReadonlyMap<string, readonly BindingRef[]>>();
|
||||
const padding = '漢'.repeat(190_000);
|
||||
|
||||
populateCsharpNamespaceSiblings(
|
||||
parsedFiles,
|
||||
{ bindings: new Map(), bindingAugmentations } as unknown as ScopeResolutionIndexes,
|
||||
{
|
||||
fileContents: new Map([
|
||||
['a.cs', `namespace Demo;\n// ${padding}\nclass A { }\n`],
|
||||
['b.cs', `namespace Demo;\n// ${padding}\nclass B { }\n`],
|
||||
]),
|
||||
},
|
||||
);
|
||||
|
||||
expect(bindingAugmentations.get(moduleA.id)?.get('B')?.[0]?.def.nodeId).toBe('def:b.B');
|
||||
});
|
||||
});
|
||||
|
||||
describe('csharpReceiverBinding', () => {
|
||||
it('returns the `this` type binding for an instance method scope', () => {
|
||||
const binding: TypeRef = { rawName: 'User', source: 'self' } as unknown as TypeRef;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,16 @@ import { typescriptScopeResolver } from '../../../src/core/ingestion/languages/t
|
|||
import { finalizeScopeModel } from '../../../src/core/ingestion/finalize-orchestrator.js';
|
||||
import { buildWorkspaceResolutionIndex } from '../../../src/core/ingestion/scope-resolution/workspace-index.js';
|
||||
import { propagateImportedReturnTypes } from '../../../src/core/ingestion/scope-resolution/passes/imported-return-types.js';
|
||||
import type { ParsedFile } from 'gitnexus-shared';
|
||||
import type {
|
||||
BindingRef,
|
||||
ParsedFile,
|
||||
Scope,
|
||||
ScopeId,
|
||||
ScopeTree,
|
||||
SymbolDefinition,
|
||||
} from 'gitnexus-shared';
|
||||
import type { ScopeResolutionIndexes } from '../../../src/core/ingestion/model/scope-resolution-indexes.js';
|
||||
import type { WorkspaceResolutionIndex } from '../../../src/core/ingestion/scope-resolution/workspace-index.js';
|
||||
|
||||
interface InMemoryFile {
|
||||
readonly path: string;
|
||||
|
|
@ -197,6 +206,61 @@ import { helper } from './service';
|
|||
}
|
||||
});
|
||||
|
||||
it('mirrors import return types from bindingAugmentations-only refs', () => {
|
||||
const appScopeId = 'scope:app' as ScopeId;
|
||||
const sourceScopeId = 'scope:source' as ScopeId;
|
||||
const appModule = {
|
||||
id: appScopeId,
|
||||
kind: 'Module',
|
||||
parent: null,
|
||||
filePath: 'app.ts',
|
||||
bindings: new Map(),
|
||||
typeBindings: new Map(),
|
||||
} as unknown as Scope;
|
||||
const sourceModule = {
|
||||
id: sourceScopeId,
|
||||
kind: 'Module',
|
||||
parent: null,
|
||||
filePath: 'source.ts',
|
||||
bindings: new Map(),
|
||||
typeBindings: new Map([['getUser', { rawName: 'User', source: 'return-annotation' }]]),
|
||||
} as unknown as Scope;
|
||||
const importedDef = {
|
||||
nodeId: 'def:source.getUser',
|
||||
filePath: 'source.ts',
|
||||
qualifiedName: 'getUser',
|
||||
type: 'Function',
|
||||
} as SymbolDefinition;
|
||||
const scopeTree = {
|
||||
getScope: (id: ScopeId) => {
|
||||
if (id === appScopeId) return appModule;
|
||||
if (id === sourceScopeId) return sourceModule;
|
||||
return undefined;
|
||||
},
|
||||
} as unknown as ScopeTree;
|
||||
const indexes = {
|
||||
scopeTree,
|
||||
bindings: new Map(),
|
||||
bindingAugmentations: new Map([
|
||||
[
|
||||
appScopeId,
|
||||
new Map([['getUser', [{ def: importedDef, origin: 'import' } as BindingRef]]]),
|
||||
],
|
||||
]),
|
||||
sccs: [{ files: ['app.ts'] }],
|
||||
} as unknown as ScopeResolutionIndexes;
|
||||
const workspaceIndex = {
|
||||
moduleScopeByFile: new Map([
|
||||
['app.ts', appModule],
|
||||
['source.ts', sourceModule],
|
||||
]),
|
||||
} as unknown as WorkspaceResolutionIndex;
|
||||
|
||||
propagateImportedReturnTypes([], indexes, workspaceIndex);
|
||||
|
||||
expect(appModule.typeBindings.get('getUser')?.rawName).toBe('User');
|
||||
});
|
||||
|
||||
it('does not throw on a cyclic SCC (partial fixpoint, best-effort)', () => {
|
||||
// a.ts imports from b, b.ts imports from a. The two files form
|
||||
// a single cyclic SCC. Within one pass we mirror what we can;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,20 @@ describe('Python scopes — module / class / function', () => {
|
|||
expect(f.scopes[0]!.kind).toBe('Module');
|
||||
});
|
||||
|
||||
it('case 01b: large cache-miss files use the adaptive tree-sitter buffer', () => {
|
||||
const padding = 'x'.repeat(600 * 1024);
|
||||
const f = parse(`# ${padding}\ndef after_padding():\n return 1\n`);
|
||||
expect(scopesByKind(f, 'Module')).toHaveLength(1);
|
||||
expect(findDef(f, 'after_padding')?.type).toBe('Function');
|
||||
});
|
||||
|
||||
it('case 01c: UTF-8-heavy cache-miss files use byte-sized parser buffers', () => {
|
||||
const padding = '漢'.repeat(190_000);
|
||||
const f = parse(`# ${padding}\ndef after_padding():\n return 1\n`);
|
||||
expect(scopesByKind(f, 'Module')).toHaveLength(1);
|
||||
expect(findDef(f, 'after_padding')?.type).toBe('Function');
|
||||
});
|
||||
|
||||
it('case 02: module-level assignment produces a Variable declaration in Module scope', () => {
|
||||
const f = parse('x = 1\n');
|
||||
expect(scopesByKind(f, 'Module')).toHaveLength(1);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,24 @@ describe('emitTsScopeCaptures — scopes', () => {
|
|||
expect(all.some((t) => t.includes('@scope.module'))).toBe(true);
|
||||
});
|
||||
|
||||
it('parses large cache-miss files with the adaptive tree-sitter buffer', () => {
|
||||
const padding = 'x'.repeat(600 * 1024);
|
||||
const match = findMatch(`// ${padding}\nclass Big { afterPadding(): void {} }`, (t) =>
|
||||
t.includes('@declaration.method'),
|
||||
);
|
||||
expect(match).toBeDefined();
|
||||
expect(match!['@declaration.name'].text).toBe('afterPadding');
|
||||
});
|
||||
|
||||
it('parses UTF-8-heavy cache-miss files with a byte-sized buffer', () => {
|
||||
const padding = '漢'.repeat(190_000);
|
||||
const match = findMatch(`// ${padding}\nclass Big { afterPadding(): void {} }`, (t) =>
|
||||
t.includes('@declaration.method'),
|
||||
);
|
||||
expect(match).toBeDefined();
|
||||
expect(match!['@declaration.name'].text).toBe('afterPadding');
|
||||
});
|
||||
|
||||
it('captures internal_module as @scope.namespace', () => {
|
||||
const all = tagsFor('namespace Foo { class A { } }');
|
||||
expect(all.some((t) => t.includes('@scope.namespace'))).toBe(true);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,177 @@
|
|||
/**
|
||||
* Unit tests for the dev-mode I8 binding-immutability validator.
|
||||
*
|
||||
* Mirrors `validateOwnershipParity` (#909) — happy path + drift
|
||||
* detection + opt-in runtime gating. Pinning these so a
|
||||
* future contributor can't silently re-introduce the issue #1066
|
||||
* shape (a hook mutating `indexes.bindings` instead of
|
||||
* `indexes.bindingAugmentations`) without tripping the validator.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import type { BindingRef, ScopeId } from 'gitnexus-shared';
|
||||
import type { ScopeResolutionIndexes } from '../../../src/core/ingestion/model/scope-resolution-indexes.js';
|
||||
import { validateBindingsImmutability } from '../../../src/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js';
|
||||
|
||||
const mkRef = (nodeId: string): BindingRef =>
|
||||
({
|
||||
def: { nodeId, filePath: 'x.ts', type: 'Class' },
|
||||
origin: 'local',
|
||||
}) as unknown as BindingRef;
|
||||
|
||||
const mkIndexes = (
|
||||
bindings: Map<ScopeId, Map<string, readonly BindingRef[]>>,
|
||||
augmentations: Map<ScopeId, Map<string, BindingRef[]>>,
|
||||
): ScopeResolutionIndexes =>
|
||||
({
|
||||
bindings,
|
||||
bindingAugmentations: augmentations,
|
||||
}) as unknown as ScopeResolutionIndexes;
|
||||
|
||||
describe('validateBindingsImmutability', () => {
|
||||
beforeEach(() => {
|
||||
// Insulate against an ambient VALIDATE_SEMANTIC_MODEL in a developer's
|
||||
// shell. Per-test env tweaks override this baseline as needed.
|
||||
vi.stubEnv('VALIDATE_SEMANTIC_MODEL', undefined);
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it('is silent when finalized buckets are frozen and augmentation buckets are mutable', () => {
|
||||
vi.stubEnv('NODE_ENV', 'development');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', Object.freeze([mkRef('def:Foo')])]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Bar', [mkRef('def:Bar')]]])],
|
||||
]);
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(0);
|
||||
expect(onWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('warns when a bucket in indexes.bindings is NOT frozen', () => {
|
||||
vi.stubEnv('NODE_ENV', 'development');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', [mkRef('def:Foo')] as readonly BindingRef[]]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>();
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(1);
|
||||
expect(onWarn).toHaveBeenCalledTimes(1);
|
||||
expect(onWarn.mock.calls[0][0]).toMatch(/binding-immutability/);
|
||||
expect(onWarn.mock.calls[0][0]).toMatch(/indexes\.bindings/);
|
||||
expect(onWarn.mock.calls[0][0]).toMatch(/I8/);
|
||||
});
|
||||
|
||||
it('warns when a bucket in indexes.bindingAugmentations IS frozen', () => {
|
||||
vi.stubEnv('NODE_ENV', 'development');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>();
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Bar', Object.freeze([mkRef('def:Bar')]) as BindingRef[]]])],
|
||||
]);
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(1);
|
||||
expect(onWarn).toHaveBeenCalledTimes(1);
|
||||
expect(onWarn.mock.calls[0][0]).toMatch(/binding-immutability/);
|
||||
expect(onWarn.mock.calls[0][0]).toMatch(/indexes\.bindingAugmentations/);
|
||||
expect(onWarn.mock.calls[0][0]).toMatch(/I8/);
|
||||
});
|
||||
|
||||
it('does not detect semantically wrong frozen replacements in indexes.bindings', () => {
|
||||
vi.stubEnv('NODE_ENV', 'development');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', Object.freeze([mkRef('def:Wrong')])]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>();
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(0);
|
||||
expect(onWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('counts violations across multiple scopes', () => {
|
||||
vi.stubEnv('NODE_ENV', 'development');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', [mkRef('def:Foo')] as readonly BindingRef[]]])],
|
||||
['scope:b:module', new Map([['Bar', [mkRef('def:Bar')] as readonly BindingRef[]]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>();
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(2);
|
||||
expect(onWarn).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('is a no-op when NODE_ENV=production', () => {
|
||||
vi.stubEnv('NODE_ENV', 'production');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', [mkRef('def:Foo')] as readonly BindingRef[]]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>();
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(0);
|
||||
expect(onWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('is a no-op in default CLI env when NODE_ENV is unset', () => {
|
||||
vi.stubEnv('NODE_ENV', undefined);
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', [mkRef('def:Foo')] as readonly BindingRef[]]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>();
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(0);
|
||||
expect(onWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('runs when VALIDATE_SEMANTIC_MODEL=1 even if NODE_ENV is unset', () => {
|
||||
vi.stubEnv('NODE_ENV', undefined);
|
||||
vi.stubEnv('VALIDATE_SEMANTIC_MODEL', '1');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', [mkRef('def:Foo')] as readonly BindingRef[]]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>();
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(1);
|
||||
expect(onWarn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('is a no-op when VALIDATE_SEMANTIC_MODEL=0', () => {
|
||||
vi.stubEnv('NODE_ENV', 'development');
|
||||
vi.stubEnv('VALIDATE_SEMANTIC_MODEL', '0');
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>([
|
||||
['scope:a:module', new Map([['Foo', [mkRef('def:Foo')] as readonly BindingRef[]]])],
|
||||
]);
|
||||
const augmentations = new Map<ScopeId, Map<string, BindingRef[]>>();
|
||||
const onWarn = vi.fn();
|
||||
|
||||
const violations = validateBindingsImmutability(mkIndexes(bindings, augmentations), onWarn);
|
||||
|
||||
expect(violations).toBe(0);
|
||||
expect(onWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/**
|
||||
* Unit coverage for `lookupBindingsAt` — the dual-source binding
|
||||
* lookup primitive used by every walker that needs cross-file
|
||||
* visibility (Step 2 of the binding-augmentation-channel refactor).
|
||||
*
|
||||
* These tests pin the contract exhaustively: precedence (finalized
|
||||
* first), dedup (by `def.nodeId`), empty-array semantics, and the
|
||||
* shared-empty-frozen-array identity for misses. Every other walker
|
||||
* test in this directory delegates to `lookupBindingsAt` after the
|
||||
* refactor, so a regression here surfaces quickly.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
findCallableBindingInScope,
|
||||
findClassBindingInScope,
|
||||
findExportedDefByName,
|
||||
lookupBindingsAt,
|
||||
} from '../../../src/core/ingestion/scope-resolution/scope/walkers.js';
|
||||
import type { BindingRef, Scope, ScopeId, ScopeTree, SymbolDefinition } from 'gitnexus-shared';
|
||||
import type { ScopeResolutionIndexes } from '../../../src/core/ingestion/model/scope-resolution-indexes.js';
|
||||
import type { WorkspaceResolutionIndex } from '../../../src/core/ingestion/scope-resolution/workspace-index.js';
|
||||
|
||||
const SCOPE = 'scope:m' as ScopeId;
|
||||
|
||||
const def = (nodeId: string): SymbolDefinition =>
|
||||
({ nodeId, filePath: 'm.ts', type: 'Function' }) as SymbolDefinition;
|
||||
|
||||
const ref = (nodeId: string, origin: BindingRef['origin'] = 'local'): BindingRef =>
|
||||
({ def: def(nodeId), origin }) as BindingRef;
|
||||
|
||||
function indexesWith({
|
||||
finalized,
|
||||
augmented,
|
||||
}: {
|
||||
finalized?: readonly BindingRef[];
|
||||
augmented?: readonly BindingRef[];
|
||||
}): ScopeResolutionIndexes {
|
||||
const bindings = new Map<ScopeId, Map<string, readonly BindingRef[]>>();
|
||||
if (finalized !== undefined) {
|
||||
Object.freeze(finalized as BindingRef[]);
|
||||
bindings.set(SCOPE, new Map([['name', finalized]]));
|
||||
}
|
||||
const bindingAugmentations = new Map<ScopeId, Map<string, readonly BindingRef[]>>();
|
||||
if (augmented !== undefined) bindingAugmentations.set(SCOPE, new Map([['name', augmented]]));
|
||||
return { bindings, bindingAugmentations } as unknown as ScopeResolutionIndexes;
|
||||
}
|
||||
|
||||
function scope(id: ScopeId, bindings = new Map<string, readonly BindingRef[]>()): Scope {
|
||||
return {
|
||||
id,
|
||||
kind: 'Module',
|
||||
parent: null,
|
||||
filePath: 'm.ts',
|
||||
range: { startLine: 1, startColumn: 0, endLine: 1, endColumn: 0 },
|
||||
bindings,
|
||||
imports: [],
|
||||
ownedDefs: [],
|
||||
typeBindings: new Map(),
|
||||
} as unknown as Scope;
|
||||
}
|
||||
|
||||
function indexesForScopeLookup(
|
||||
moduleScope: Scope,
|
||||
augmented: Map<string, readonly BindingRef[]>,
|
||||
): ScopeResolutionIndexes {
|
||||
const scopeTree = {
|
||||
getScope: (id: ScopeId) => (id === moduleScope.id ? moduleScope : undefined),
|
||||
} as unknown as ScopeTree;
|
||||
return {
|
||||
scopeTree,
|
||||
bindings: new Map(),
|
||||
bindingAugmentations: new Map([[moduleScope.id, augmented]]),
|
||||
} as unknown as ScopeResolutionIndexes;
|
||||
}
|
||||
|
||||
describe('lookupBindingsAt', () => {
|
||||
it('returns the finalized bucket when augmentations are absent', () => {
|
||||
const finalized = [ref('A'), ref('B')];
|
||||
const out = lookupBindingsAt(SCOPE, 'name', indexesWith({ finalized }));
|
||||
expect(out).toEqual(finalized);
|
||||
// Identity preserved when only one channel populates — no allocation.
|
||||
expect(out).toBe(finalized);
|
||||
});
|
||||
|
||||
it('returns the augmented bucket when finalized is absent', () => {
|
||||
const augmented = [ref('X', 'namespace')];
|
||||
const out = lookupBindingsAt(SCOPE, 'name', indexesWith({ augmented }));
|
||||
expect(out).toEqual(augmented);
|
||||
expect(out).toBe(augmented);
|
||||
});
|
||||
|
||||
it('concatenates with finalized first when both populate disjoint nodeIds', () => {
|
||||
const finalized = [ref('A', 'import'), ref('B', 'import')];
|
||||
const augmented = [ref('C', 'namespace'), ref('D', 'namespace')];
|
||||
const out = lookupBindingsAt(SCOPE, 'name', indexesWith({ finalized, augmented }));
|
||||
expect(out.map((b) => b.def.nodeId)).toEqual(['A', 'B', 'C', 'D']);
|
||||
});
|
||||
|
||||
it('dedupes augmented entries that share a nodeId with finalized (finalized wins)', () => {
|
||||
const finalized = [ref('A', 'import'), ref('B', 'import')];
|
||||
const augmented = [ref('A', 'namespace'), ref('C', 'namespace')];
|
||||
const out = lookupBindingsAt(SCOPE, 'name', indexesWith({ finalized, augmented }));
|
||||
expect(out.map((b) => b.def.nodeId)).toEqual(['A', 'B', 'C']);
|
||||
expect(out.find((b) => b.def.nodeId === 'A')!.origin).toBe('import');
|
||||
});
|
||||
|
||||
it('keeps finalized metadata when the same nodeId appears in both channels', () => {
|
||||
const finalizedDef = {
|
||||
nodeId: 'A',
|
||||
filePath: 'finalized.ts',
|
||||
qualifiedName: 'finalized.A',
|
||||
type: 'Function',
|
||||
} as SymbolDefinition;
|
||||
const augmentedDef = {
|
||||
nodeId: 'A',
|
||||
filePath: 'augmented.ts',
|
||||
qualifiedName: 'augmented.A',
|
||||
type: 'Method',
|
||||
} as SymbolDefinition;
|
||||
const out = lookupBindingsAt(
|
||||
SCOPE,
|
||||
'name',
|
||||
indexesWith({
|
||||
finalized: [{ def: finalizedDef, origin: 'import' } as BindingRef],
|
||||
augmented: [{ def: augmentedDef, origin: 'namespace' } as BindingRef],
|
||||
}),
|
||||
);
|
||||
expect(out).toHaveLength(1);
|
||||
expect(out[0]!.def.filePath).toBe('finalized.ts');
|
||||
expect(out[0]!.def.qualifiedName).toBe('finalized.A');
|
||||
expect(out[0]!.origin).toBe('import');
|
||||
});
|
||||
|
||||
it('returns the shared empty array on a miss in both channels', () => {
|
||||
const a = lookupBindingsAt(SCOPE, 'name', indexesWith({}));
|
||||
const b = lookupBindingsAt(SCOPE, 'other', indexesWith({}));
|
||||
expect(a).toEqual([]);
|
||||
expect(b).toEqual([]);
|
||||
expect(a).toBe(b);
|
||||
expect(Object.isFrozen(a)).toBe(true);
|
||||
});
|
||||
|
||||
it('treats an empty finalized bucket as absent (returns augmented)', () => {
|
||||
const augmented = [ref('Z', 'namespace')];
|
||||
const out = lookupBindingsAt(SCOPE, 'name', indexesWith({ finalized: [], augmented }));
|
||||
expect(out).toBe(augmented);
|
||||
});
|
||||
|
||||
it('treats an empty augmented bucket as absent (returns finalized)', () => {
|
||||
const finalized = [ref('Z', 'import')];
|
||||
const out = lookupBindingsAt(SCOPE, 'name', indexesWith({ finalized, augmented: [] }));
|
||||
expect(out).toBe(finalized);
|
||||
});
|
||||
|
||||
it('returns the shared empty array when both buckets exist but are empty', () => {
|
||||
const out = lookupBindingsAt(SCOPE, 'name', indexesWith({ finalized: [], augmented: [] }));
|
||||
expect(out).toEqual([]);
|
||||
expect(Object.isFrozen(out)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('walker helpers read bindingAugmentations', () => {
|
||||
it('findClassBindingInScope finds class-like refs that exist only in augmentations', () => {
|
||||
const moduleScope = scope(SCOPE);
|
||||
const classRef = {
|
||||
def: { ...def('ClassA'), type: 'Class' },
|
||||
origin: 'namespace',
|
||||
} as BindingRef;
|
||||
const indexes = indexesForScopeLookup(moduleScope, new Map([['ClassA', [classRef]]]));
|
||||
|
||||
expect(findClassBindingInScope(SCOPE, 'ClassA', indexes)?.nodeId).toBe('ClassA');
|
||||
});
|
||||
|
||||
it('findCallableBindingInScope finds callable refs that exist only in augmentations', () => {
|
||||
const moduleScope = scope(SCOPE);
|
||||
const callableRef = { def: def('callMe'), origin: 'import' } as BindingRef;
|
||||
const indexes = indexesForScopeLookup(moduleScope, new Map([['callMe', [callableRef]]]));
|
||||
|
||||
expect(findCallableBindingInScope(SCOPE, 'callMe', indexes)?.nodeId).toBe('callMe');
|
||||
});
|
||||
|
||||
it('findExportedDefByName finds callable refs that exist only in augmentations', () => {
|
||||
const moduleScope = scope(SCOPE);
|
||||
const callableRef = { def: def('fromAugmentation'), origin: 'import' } as BindingRef;
|
||||
const indexes = indexesForScopeLookup(moduleScope, new Map([['run', [callableRef]]]));
|
||||
const workspaceIndex = {
|
||||
moduleScopeByFile: new Map(),
|
||||
} as unknown as WorkspaceResolutionIndex;
|
||||
|
||||
expect(findExportedDefByName('run', SCOPE, indexes, workspaceIndex)?.nodeId).toBe(
|
||||
'fromAugmentation',
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue