Skip to content

Index opted-in Android vendor source and cover Java/AIDL language cases - #15

Open
mixxer wants to merge 58 commits into
mainfrom
fix/android-platform-language-coverage
Open

mixxer wants to merge 58 commits into
mainfrom
fix/android-platform-language-coverage

Conversation

@mixxer

@mixxer mixxer commented Sep 28, 2026

Copy link
Copy Markdown
Owner

Changes

  • Let codegraph.json include: ["vendor/"] index Android vendor Java/Kotlin/C++ implementation source, even when Git ignores it. Other built-in dependency/build skips and explicit excludes still apply. Git fast-path change detection now sees included files and their deletion.
  • Resolve Java generic extends/implements against the declared type while preserving qualified nested names, in both wasm and native extraction.
  • Index methods inside Java enum constant class bodies in both extraction paths.
  • Reject cross-package calls to Java package-private members while preserving same-package access and the implicit public access of members in public interfaces.
  • Read annotated AIDL return methods such as @nullable IBluetoothLe getBluetoothLe() in both AIDL and HAL declaration scans. This syntax occurs in public AOSP hardware/interfaces revision 863f96ecdd628638da61a302f13615e61eec6d60.

Validation

  • Node 24: 331 focused tests passed, including 5 new Android/Java regressions.
  • New regressions passed with CODEGRAPH_KERNEL=0 and with the rebuilt native Java kernel (getKernel() loaded and kernelSupports('java') true).
  • npm run build passed; cargo check and npm run build:kernel passed.
  • The public AOSP AIDL example is source evidence for syntax; this PR does not claim any match to the unrelated 37-row decompiled corpus discussed in upstream fix(java): resolve calls through static fields colbymchenry/codegraph#1949.

mixxer and others added 30 commits September 23, 2026 10:40
Add AIDL, JNI, HAL, service, and IPC evidence tools with Java/Kotlin
extraction and resolution fixes and regression coverage.

Document supported analysis, evidence limits, and public reference inputs.
Add contributor guidance and GitHub PR and merge-queue checks for
Node 22/24 and native kernel parity.
…ct_literal

Native kernel parity gaps found in Codex cross-review of the AOSP/AAOS
extension rebase (upstream ba3c21e):

- java.rs extract_anonymous_class pushed the truncated (bare-segment)
  type name as the `extends` reference instead of the full dotted
  name, unlike wasm's tree-sitter.ts (2026-09-11 fix). This silently
  broke AOSP's qualified-name AIDL Stub lookups (`IFoo.Stub`) on any
  file routed to the native kernel.
- kotlin.rs had no `object_literal` handling at all (`object :
  IFoo.Stub() { ... }`), the dominant AIDL Stub idiom in Kotlin AOSP
  sources — wasm's extractKotlinObjectLiteral existed precisely
  because this idiom had 0% recall before it was added. Ported the
  extraction (delegation_specifier walk, extends/instantiates refs,
  kotlinObjectScopeDepth identity binding) verbatim from tree-sitter.ts.

Verified: full suite (284 files / 4877 tests) passes, including
kernel-kotlin-parity, kotlin-object-literal, and all aosp-*.test.ts.
inferJavaFieldReceiverType reads a field's type from its signature, in the
Java shape `Type name`. Kotlin properties are indexed without a signature, and
primary-constructor properties (`class A(private val repo: Repo)`) are not
indexed at all, so every Kotlin `prop.method()` got no type and fell through to
name-only guessing: the interface method, or any same-named method elsewhere
(`probe.close()` on a `lateinit var probe: HttpProbe` resolved to an unrelated
class's `close`).

For Kotlin the type is now read from the declaration: the property's own lines
(`name: Type`, or `name = Type(…)`), or the class header before its first
member for a constructor property. A nested type keeps its outer type
(`HardwareLock.Lease` → `HardwareLock::Lease`), so it matches that `Lease` and
not another class's. resolveMethodOnType still validates the method.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion

tree-sitter-kotlin has no `fun interface` (Kotlin 1.4 functional
interfaces). The declaration parsed as a broken function, and when a doc
comment followed it, error recovery swallowed the NEXT declaration too: an
interface and its methods went missing, surfacing as top-level functions,
or a class vanished with its members. The Kotlin extractor's preParse now
blanks the `fun` of a `fun interface` declaration (three spaces for three
letters, so offsets hold); the kernel receives the same bytes through the
preParse hoist and no longer defers these files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nguessed

Two more receivers the Kotlin resolver could not type:
- A local or property bound to a call (`val lease = HardwareLock.tryBegin()`,
  `private val schema = Checker.load()`) is typed by the callee's declared
  return type, from its signature. A return type nested in the callee's
  owner keeps it (`Lease` in `HardwareLock` → `HardwareLock::Lease`).
- A receiver whose type the project does not declare (`Regex`,
  `Properties`, a call on `Executors`) now gets no edge. The name-only
  fallback used to bind it to any project method of the same name: a
  `regex.find()` to an unrelated `find`, `socket.connect()` to a
  `connect` elsewhere, a `close()` to itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…railing-lambda constructors

More Kotlin receivers the resolver could not type, found on real apps:
- A `val` property is indexed as a `constant` and a companion-object
  property as a `variable`; the property lookup only took `field`.
- `var mode = Mode.ON` is typed by its enum (project enums only; `Limits.MAX`
  is an Int).
- `val t = Thread { … }` is a constructor too (trailing lambda, no parens).
- `val old = current ?: return` / `current!!` / `val x = current` take the
  aliased value's type; `requireNotNull(x)` / `checkNotNull(x)` take x's.
- A typed parameter of the enclosing function or overridden callback
  (`onOpen(webSocket: WebSocket, …)`) is used when nothing else names one.
- Known stdlib factories (`listOf`, `mutableMapOf`, `lazy`, `thread`, …)
  return a library type; any other library function leaves the type unknown.
A library type still gets no edge: `thread.join()`, `process.destroy()`,
`webSocket.send()` no longer bind to project methods (or a test fake) of the
same name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Kotlin call through a receiver chain (`engine.pump.drain()`,
`this.engine.drain()`, `a?.b?.c()`) was extracted as the bare method
name, so it could only be name-guessed: a same-named method in the
caller's file, or any project method when the chain ended in a library
type (`runtime.reconnectTask?.cancel()` on a `ScheduledFuture`).

The extractor (wasm path and kernel, in parity) now keeps a chain of up
to four identifier segments. The resolver types the first segment as a
single receiver (`this` is the enclosing class, a type name its object
or companion), then each next segment as a property or enum entry
declared in the class of the type before it, read from that class's own
file. A typed chain resolves on its type; a chain through a library
type gets no edge unless the project declares an extension of that name
on a library type; an untyped chain resolves as the bare method name,
exactly as before. A constructor call with type arguments
(`Crate<Int>()`, `mutableListOf<T>()`) now types its value too.

The alias test now picks the anonymous object's `onOpen` and ignores
synthesized override edges, so it holds once object-literal members are
extracted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nonymous objects

A receiver (or chain segment) that the enclosing class does not declare is
looked up in its project supertypes, read from each class header (breadth-
first, at most four levels); a library or ambiguous supertype is not walked,
so the receiver stays unknown and keeps the name-only resolution.

The local declaration scan continues from a function nested in another (an
anonymous object's member, a local function) into the outer function above
it, skipping sibling functions whose locals are not visible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(kotlin): resolve imported type calls by qualified name
…-calls

# Conflicts:
#	src/resolution/name-matcher.ts
…fork

fix(java): integrate static-field calls into fork main
mixxer and others added 27 commits September 26, 2026 00:33
fix: trim idle project connections during active calls
fix(kotlin): preserve visible imported receiver extensions
…-calls-fork-followup

# Conflicts:
#	CHANGELOG.md
…llowup

Follow up on Java static field call resolution
fix(security): block symlinked sensitive home directories
…egrate-1931

# Conflicts:
#	CONTRIBUTING.md
#	docs/README.md
…egrate-1928

# Conflicts:
#	CHANGELOG.md
#	__tests__/aosp-aidl.test.ts
#	__tests__/aosp-common.test.ts
#	__tests__/aosp-content-provider.test.ts
#	__tests__/aosp-hal.test.ts
#	__tests__/aosp-jni.test.ts
#	__tests__/aosp-local-socket.test.ts
#	__tests__/aosp-messenger.test.ts
#	__tests__/aosp-permission-broadcast.test.ts
#	__tests__/aosp-system-service.test.ts
#	docs/design/android-platform-analysis.md
#	src/aosp/aidl.ts
#	src/aosp/common.ts
#	src/aosp/content_provider.ts
#	src/aosp/hal.ts
#	src/aosp/jni.ts
#	src/aosp/local_socket.ts
#	src/aosp/messenger.ts
#	src/aosp/permission_broadcast.ts
#	src/aosp/system_service.ts
#	src/bin/codegraph.ts
#	src/db/queries.ts
#	src/mcp/tools.ts
Integrate contributor guides from upstream colbymchenry#1931
…k/integrate-1927

# Conflicts:
#	__tests__/extraction.test.ts
#	__tests__/kotlin-object-literal.test.ts
#	__tests__/resolution.test.ts
#	codegraph-kernel/src/java.rs
#	codegraph-kernel/src/kotlin.rs
#	src/extraction/tree-sitter.ts
#	src/resolution/name-matcher.ts
Integrate Kotlin property receiver resolution from upstream colbymchenry#1933
Integrate Java/Kotlin anonymous inheritance follow-up from upstream colbymchenry#1927
Integrate reviewed Android platform analysis from upstream colbymchenry#1928
Sync fork with upstream main and preserve Android resolver fixes
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T07:30:37.945564Z 77c6515 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 77c6515d09

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/extraction/index.ts
function defaultsOnlyIgnore(): Ignore {
return ignore().add(DEFAULT_IGNORE_PATTERNS);
function defaultsOnlyIgnore(allowVendor = false): Ignore {
return ignore().add(allowVendor ? DEFAULT_IGNORE_PATTERNS.filter((p) => p !== 'vendor/') : DEFAULT_IGNORE_PATTERNS);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep nested vendor dependency directories excluded

When codegraph.json includes vendor/, removing the vendor/ pattern from this matcher disables that default at every depth, so paths such as vendor/oem/tool/vendor/dependency/*.go are traversed and indexed as well. Those nested vendor directories are third-party dependency trees rather than the opted-in Android vendor implementation tree, potentially inflating and polluting the graph; exempt only the selected top-level vendor subtree while retaining the nested-directory exclusion.

AGENTS.md reference: AGENTS.md:L120-L124

Useful? React with 👍 / 👎.

Comment on lines +868 to +869
if (owner?.visibility === 'public' &&
(owner.kind === 'interface' || (owner.kind === 'enum' && candidate.kind === 'enum_member'))) return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor implicit visibility through nested Java interfaces

For a legal declaration such as public interface Outer { interface Inner { static void api() {} } }, both Inner and api are implicitly public, but the extracted Inner node has no explicit visibility. When resolving Outer.Inner.api() from another package, this check sees the method's immediate owner as non-public and falls through to the same-package test, dropping the valid call edge. Effective interface visibility needs to account recursively for implicit-public nested interfaces rather than requiring the immediate owner to carry an explicit public modifier.

Useful? React with 👍 / 👎.

Comment thread src/extraction/index.ts
const candidates = new Set([...gitChanges.deleted, ...gitChanges.modified, ...gitChanges.added, ...dirtyPaths!]);
const include = loadIncludeMatcher(this.rootDir);
if (include) {
for (const file of collectIncludedFilesForRoot(this.rootDir)) candidates.add(file);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid hashing every included file on clean status checks

Whenever an include matcher exists, this adds every included file to the Git fast-path candidate set, after which the loop reads and hashes every candidate even when its recorded size and mtime are unchanged. With the intended include: ["vendor/"] on a large Android tree, a clean codegraph status becomes proportional to all vendor source bytes, while MCP status commonly reaches its 8-second measurement timeout and reports freshness as unknown; apply the same size/mtime prefilter used by sync() before reading these files.

AGENTS.md reference: AGENTS.md:L120-L124

Useful? React with 👍 / 👎.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant