feat(symbol-table): add fuzzy lookup counters (#708)

This commit is contained in:
Kunal Hemnani 2026-04-08 12:23:30 +05:30 • committed by GitHub
parent 9c83060cac
commit 759433722e
4 changed files with 39 additions and 4 deletions

View file

@ -1041,6 +1041,9 @@ async function runChunkedParseAndResolve(
console.log(
`🔍 Resolution cache: ${rcStats.cacheHits} hits, ${rcStats.cacheMisses} misses (${hitRate}% hit rate)`,
);
console.log(
`🔍 Fuzzy Lookups: ${rcStats.fuzzyCallCount} total, ${rcStats.fuzzyCallableCallCount} callable`,
);
}
// ── Worker path quality enrichment: merge TypeEnv file-scope bindings into ExportedTypeMap ──

View file

@ -70,6 +70,8 @@ export interface ResolutionContext {
getStats(): {
fileCount: number;
globalSymbolCount: number;
fuzzyCallCount: number;
fuzzyCallableCallCount: number;
cacheHits: number;
cacheMisses: number;
};

View file

@ -114,7 +114,12 @@ export interface SymbolTable {
/**
* Debugging: See how many symbols are tracked
*/
getStats: () => { fileCount: number; globalSymbolCount: number };
getStats: () => {
fileCount: number;
globalSymbolCount: number;
fuzzyCallCount: number;
fuzzyCallableCallCount: number;
};
/**
* Cleanup memory
@ -150,6 +155,10 @@ export const createSymbolTable = (): SymbolTable => {
const classByName = new Map<string, SymbolDefinition[]>();
const classByQualifiedName = new Map<string, SymbolDefinition[]>();
let fuzzyCallCount = 0;
let fuzzyCallableCallCount = 0;
const CALLABLE_TYPES = new Set(['Function', 'Method', 'Constructor']);
const add = (
@ -267,10 +276,12 @@ export const createSymbolTable = (): SymbolTable => {
};
const lookupFuzzy = (name: string): SymbolDefinition[] => {
fuzzyCallCount++;
return globalIndex.get(name) || [];
};
const lookupFuzzyCallable = (name: string): SymbolDefinition[] => {
fuzzyCallableCallCount++;
if (!callableIndex) {
// Build the callable index lazily on first use
callableIndex = new Map();
@ -317,6 +328,8 @@ export const createSymbolTable = (): SymbolTable => {
const getStats = () => ({
fileCount: fileIndex.size,
globalSymbolCount: globalIndex.size,
fuzzyCallableCallCount: fuzzyCallableCallCount,
fuzzyCallCount: fuzzyCallCount,
});
const clear = () => {
@ -327,6 +340,8 @@ export const createSymbolTable = (): SymbolTable => {
methodByOwner.clear();
classByName.clear();
classByQualifiedName.clear();
fuzzyCallCount = 0;
fuzzyCallableCallCount = 0;
};
return {

View file

@ -88,7 +88,12 @@ describe('SymbolTable', () => {
describe('getStats', () => {
it('returns zero counts for empty table', () => {
expect(table.getStats()).toEqual({ fileCount: 0, globalSymbolCount: 0 });
expect(table.getStats()).toEqual({
fileCount: 0,
globalSymbolCount: 0,
fuzzyCallCount: 0,
fuzzyCallableCallCount: 0,
});
});
it('tracks unique file count correctly', () => {
@ -484,7 +489,12 @@ describe('SymbolTable', () => {
});
table.add('src/models.ts', 'User', 'class:User', 'Class');
table.clear();
expect(table.getStats()).toEqual({ fileCount: 0, globalSymbolCount: 0 });
expect(table.getStats()).toEqual({
fileCount: 0,
globalSymbolCount: 0,
fuzzyCallCount: 0,
fuzzyCallableCallCount: 0,
});
expect(table.lookupExact('src/a.ts', 'foo')).toBeUndefined();
expect(table.lookupFuzzy('foo')).toEqual([]);
expect(table.lookupFieldByOwner('class:User', 'address')).toBeUndefined();
@ -497,7 +507,12 @@ describe('SymbolTable', () => {
table.add('src/a.ts', 'foo', 'func:foo', 'Function');
table.clear();
table.add('src/b.ts', 'bar', 'func:bar', 'Function');
expect(table.getStats()).toEqual({ fileCount: 1, globalSymbolCount: 1 });
expect(table.getStats()).toEqual({
fileCount: 1,
globalSymbolCount: 1,
fuzzyCallCount: 0,
fuzzyCallableCallCount: 0,
});
});
it('resets callableIndex so first lookup after clear rebuilds from scratch', () => {