Add manual JNI surface report - #210
Merged
Merged
Conversation
Mirrors the api-coverage skill/report pair. The generator program walks src/ComposeNet.Compose/, anchors each JNIEnv.* call to its enclosing member, excludes [ComposeBridge] / [ComposeFacade] generator-emitted partials, and writes a markdown inventory to docs/manual-jni.md. The report measures what's left for the bridge generator to absorb: 196 raw-JNI sites across 47 files, 25 JCWs (4 with raw JNI, 21 pure-managed delegate adapters), and 297 generator-emitted partials. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three targeted tweaks surfaced by parallel sub-agent evaluations of the manual-jni skill: - Frontmatter description: make JCW + suspend-bridge scope explicit so trigger precision improves on JCW-only inventory questions (was "medium confidence" in edge-case trigger eval). - "Improving Why not generated?" section: rewrote the priority list to describe the script's actual behaviour. ExtractWhy walks upward from the member and the explicit `Why raw JNI` / `Why manual` marker wins regardless of which comment style (`///` XML doc remarks or plain `//`) hosts it. Previous wording implied a strict global priority that the code doesn't actually apply. - Troubleshooting > spurious diffs: replaced the vague "verify with git diff" advice with the concrete `git diff -U0 ... | rg @@` diagnostic for locating the source-line drift that shifted a reported member range. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
marked this pull request as ready for review
June 9, 2026 17:56
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a new “manual JNI surface” reporting workflow to inventory remaining hand-written JNI usage in ComposeNet.Compose (raw JNIEnv.* call sites + composenet/... Java Callable Wrappers), mirroring the existing api-coverage skill/report pair.
Changes:
- Adds a single-file
dotnet runscript to scansrc/ComposeNet.Compose/and generate a markdown report. - Checks in the generated
docs/manual-jni.mdartifact for reviewable diffs over time. - Adds a GitHub Skills guide documenting how to regenerate/interpret the report.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| scripts/manual-jni-report.cs | Implements regex-based scanning, member anchoring, rationale extraction, and report generation. |
| docs/manual-jni.md | Generated report output checked into the repo. |
| .github/skills/manual-jni/SKILL.md | Workflow documentation for regenerating and validating the report. |
Five defense-in-depth fixes to scripts/manual-jni-report.cs surfaced by
the automated reviewer. All are robustness improvements — the current
docs/manual-jni.md is byte-identical (modulo timestamp) so no entries
shift, but the script no longer relies on the absence of certain
patterns in the source.
1. ScanMembers gates member detection on brace depth. Captures
depthAtLineStart before counting current-line braces and only
matches when depthAtLineStart == classStack.Peek().Depth + 1, so
method-shaped statements inside method bodies (local functions,
single-line lambdas) cant be mistaken for member declarations.
2. MaskBlockComments pre-pass masks /* ... */ contents (preserving
line count and newlines) before any code-shape analysis sees the
file. Block-commented JNIEnv.* references no longer count as call
sites and block-commented braces no longer skew FindMemberEnd /
FindClassEnd tracking.
3. FindJcwClasses replaces the hard j < i + 10 scan limit with
scan-until-non-skippable: blank, //, ///, /*, *, and other [
attribute lines are skipped; anything else bails. Larger doc/
attribute prologues between [Register] and the class body work,
and an unexpected non-class line bails rather than guesses.
4. StripLineComment now masks string/char literals via MaskStringsAndChars
before scanning for //. Handles verbatim (@"..."), char-escape
('\"'), and (by virtue of MaskStringsAndChars) any other supported
literal form. Eliminates the entire class of "URL inside @-string
truncates the line" failures the old hand-rolled tokenizer missed.
5. Header comment no longer claims member detection covers property
accessors or class init; only methods and constructors are actually
matched. Avoids future contributor confusion when the report
doesnt classify a JNI call inside a get/set accessor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mirrors the
api-coverageskill/report pair. Adds:scripts/manual-jni-report.cs— single-filedotnet runprogram (regex/text scan, no Roslyn). Walkssrc/ComposeNet.Compose/, anchors eachJNIEnv.*call to its enclosing member, excludes[ComposeBridge]/[ComposeFacade]/[ComposeDefaults]generator-decorated partials, and pulls a "Why not generated?" rationale from existing XML<remarks>and adjacent// ...comments.docs/manual-jni.md— generated artifact, checked in deliberately so PR diffs surface migrations to the bridge generator..github/skills/manual-jni/SKILL.md— workflow guide matching theapi-coverageskill style.Totals
JNIEnv.*call sites[ComposeBridge]partials and 95[ComposeFacade]partials (excluded)Top 3 candidates for future generator migration
SuspendBridges.cs(1 file, 4 entry points) andSuspendBridge.csitself. Currently 100 % hand-written awaiting a[ComposeBridge(Suspend = true)]shape.AGENTS.mdalready sketches the formalisation: "Do not add a[ComposeBridge]generator path yet; once a third suspend API is needed, formalise asComposeBridgeAttribute(Suspend = true)." We're past the threshold (4 instance bridges + 2 static-with-$defaultshapes), so this is the highest-leverage win.ComposeBridges.cs(BoxScopeAlign,BoxScopeMatchParentSize,RowScopeAlignVertical,ColumnScopeAlignHorizontal, plusFocusRequesterRequestFocus) — the binder strips theAlignment/Alignment.Horizontal/Alignment.Vertical@JvmInline value classoverloads. Blocked ondotnet/java-interop#1440; once that lands, the existingComposeValueTypes.csregistry handles them automatically.ExposedDropdownMenu(multi-line$default+ synthetic marker) andModifierPointerInput(Java-side helper allocation via<AndroidJavaSource>) — both currently sit alongside their[ComposeFacade]partials inComposeBridges.csbecause the generator has no shape for "trailingObject marker = nullslot" or "constructed Java-side adapter forwarded to a non-bound interface". A new bridge attribute property —[ComposeBridge(SyntheticMarker = true)]and a parallel constructed-adapter shape — would absorb both.The report's per-file detail surfaces the remaining 6 raw-JNI files (
KotlinResult,SaveableBridges,TextFieldValueBridges,ShapesBridges,ThemeBridges,TextStyleCompanion) and 21 pure-managed JCWs as a longer tail; each entry has a "Why not generated?" column extracted from existing source comments where present, TODO otherwise.Verification
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com