Merge remote-tracking branch 'origin/main' into fix/kotlin-property-initializer-walk

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
danusha2345
2026-09-08 19:54:11 +03:00
3 changed files with 69 additions and 11 deletions
+2
View File
@@ -222,6 +222,8 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Kotlin `init { }` blocks and destructuring declarations no longer swallow their code: `init { val cfg = load() }` and `val (a, b) = makePair()` contributed no call edge at all, and now attribute to the enclosing class or file.
- A Kotlin property's accessor body now belongs to the property whichever line it is written on, instead of being dropped (same line) or handed to the enclosing class (own line).
- Kotlin properties that hold a lambda, a SAM callback or an anonymous object — `private val frameListener = CameraFrameListener { … }`, the way Android and MSDK callbacks are almost always declared — now contribute call edges. Previously everything inside such an initializer was dropped, so a function reached only through one of these callbacks looked like it had no callers at all and its blast radius came back far too small. Delegated properties (`by lazy { … }`) and plain initializers (`val x = compute()`) were affected the same way and are fixed too. Re-index with `codegraph index -f` after upgrading to pick up the new edges.
- Objective-C headers now index in a project that has no `.m` file. A `.h` file is read as C from its name alone, and only later — once its contents are read — recognized as Objective-C; the grammar for that was never loaded up front, so the file failed with a parser error and nothing in it reached the index. Adding any `.m` file used to make the same header work, which is what made this look arbitrary. Thanks @Juddd. (#1628)
- TypeScript interface methods and properties are now indexed, so `node`, `callers` and impact can find platform `.d.ts` APIs while declaration-only files keep their lower ranking on flow queries; re-index TypeScript projects after upgrading. (#1638)
- Lua and Luau function expressions assigned to locals, table members, or keyed table fields are now indexed as callable nodes. Calls from `local f = function() ... end`, `M.f = function() ... end`, and callback tables such as `M.handlers = { onClick = function() ... end }` are attributed to the named function or method instead of collapsing onto the file node, so callers and impact no longer omit these handlers. Re-index after upgrading. (#1616, #1650)
- **Functions bound with `const` inside another function are symbols now.** `const handleClear = () => {…}` inside a React component — every handler that skips `useCallback` — was invisible to `callers`, `callees` and impact, answering "Symbol not found" exactly the way a function with no callers would. It is indexed like its module-level twin, contained by the enclosing function, with its own calls. Re-index after upgrading. (#1669)
+41
View File
@@ -0,0 +1,41 @@
/**
* Grammar preload set for a file list (#1628).
*
* Path-only detection calls every `.h` file C, but parse-time detection reads
* the source and can reclassify it as C++ or Objective-C. Workers only ever
* receive the grammars named by this set, so a header that turns out to be
* Objective-C in a project with no `.m` file had no parser to go to and the
* file failed outright with `Failed to get parser for language: objc`.
*/
import { describe, it, expect } from 'vitest';
import { preloadLanguagesForFiles } from '../src/extraction';
describe('grammar preload set (#1628)', () => {
it('covers both ambiguous readings of a .h file, C++ and Objective-C', () => {
const langs = preloadLanguagesForFiles(['repro.h']);
// Path-only detection says C…
expect(langs).toContain('c');
// …and parse-time detection may say either of these instead.
expect(langs).toContain('cpp');
expect(langs).toContain('objc');
});
it('adds nothing for a project with no C-family headers', () => {
const langs = preloadLanguagesForFiles(['a.ts', 'b.py']);
expect(langs).not.toContain('c');
expect(langs).not.toContain('cpp');
expect(langs).not.toContain('objc');
});
it('does not duplicate a language the files already need', () => {
const langs = preloadLanguagesForFiles(['repro.h', 'seed.m', 'other.cpp']);
expect(langs.filter((l) => l === 'objc')).toHaveLength(1);
expect(langs.filter((l) => l === 'cpp')).toHaveLength(1);
});
it('honors extension overrides when detecting the base set', () => {
const langs = preloadLanguagesForFiles(['weird.frob'], { '.frob': 'python' });
expect(langs).toContain('python');
});
});
+26 -11
View File
@@ -742,6 +742,30 @@ function findNestedGitRepos(absDir: string, relPrefix: string): string[] {
* scope cannot diverge from each other or from `git ls-files --exclude-standard`
* (#1728).
*/
/**
* The grammars to preload for a file set.
*
* Path-only detection calls every `.h` file C, but parse-time detection reads
* the source and can reclassify it as C++ or Objective-C (`detectLanguage`
* with a `source` argument). Workers only ever get the grammars named here, so
* a header that turns out to be Objective-C in a project with no `.m` file
* found no parser and failed with `Failed to get parser for language: objc`
* (#1628). C++ was already covered; Objective-C was not.
*/
export function preloadLanguagesForFiles(
files: string[],
overrides?: Record<string, Language>
): Language[] {
const languages = [...new Set(files.map((f) => detectLanguage(f, undefined, overrides)))];
if (languages.includes('c')) {
for (const ambiguous of ['cpp', 'objc'] as const) {
if (!languages.includes(ambiguous)) languages.push(ambiguous);
}
}
return languages;
}
export class ScopeIgnore {
private embedded: Array<{ root: string; matcher: Ignore }>;
private defaults: Ignore = defaultsOnlyIgnore();
@@ -1798,11 +1822,7 @@ export class ExtractionOrchestrator {
await new Promise(resolve => setImmediate(resolve));
// Detect needed languages and load grammars in the parse worker
const neededLanguages = [...new Set(files.map((f) => detectLanguage(f, undefined, overrides)))];
// .h files default to 'c' but may be C++ — ensure cpp grammar is loaded when c is needed
if (neededLanguages.includes('c') && !neededLanguages.includes('cpp')) {
neededLanguages.push('cpp');
}
const neededLanguages = preloadLanguagesForFiles(files, overrides);
// Parse files on a pool of worker threads (keeps the main thread free for UI
// and uses every core). Falls back to in-process parsing when the compiled
@@ -3020,12 +3040,7 @@ export class ExtractionOrchestrator {
// Load only grammars needed for changed files
if (filesToIndex.length > 0) {
const overrides = loadExtensionOverrides(this.rootDir);
const neededLanguages = [...new Set(filesToIndex.map((f) => detectLanguage(f, undefined, overrides)))];
// .h files default to 'c' but may be C++ — ensure cpp grammar is loaded
if (neededLanguages.includes('c') && !neededLanguages.includes('cpp')) {
neededLanguages.push('cpp');
}
await loadGrammarsForLanguages(neededLanguages);
await loadGrammarsForLanguages(preloadLanguagesForFiles(filesToIndex, overrides));
}
// Index changed files