Skip to content

Add manual JNI surface report - #210

Merged
jonathanpeppers merged 3 commits into
mainfrom
jonathanpeppers/manual-jni-report
Jun 9, 2026
Merged

Add manual JNI surface report#210
jonathanpeppers merged 3 commits into
mainfrom
jonathanpeppers/manual-jni-report

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Owner

Mirrors the api-coverage skill/report pair. Adds:

  • scripts/manual-jni-report.cs — single-file dotnet run program (regex/text scan, no Roslyn). Walks src/ComposeNet.Compose/, anchors each JNIEnv.* 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 the api-coverage skill style.

Totals

  • 255 C# files scanned
  • 47 files contain manual JNI or a JCW
  • 196 raw JNIEnv.* call sites
  • 1485 lines inside flagged members
  • 25 Java Callable Wrappers (4 with raw JNI inside, 21 pure-managed delegate adapters)
  • 202 [ComposeBridge] partials and 95 [ComposeFacade] partials (excluded)
  • 0.66 raw-JNI : generator-emitted ratio

Top 3 candidates for future generator migration

  1. Suspend functionsSuspendBridges.cs (1 file, 4 entry points) and SuspendBridge.cs itself. Currently 100 % hand-written awaiting a [ComposeBridge(Suspend = true)] shape. AGENTS.md already sketches the formalisation: "Do not add a [ComposeBridge] generator path yet; once a third suspend API is needed, formalise as ComposeBridgeAttribute(Suspend = true)." We're past the threshold (4 instance bridges + 2 static-with-$default shapes), so this is the highest-leverage win.
  2. Value-class scope methods in ComposeBridges.cs (BoxScopeAlign, BoxScopeMatchParentSize, RowScopeAlignVertical, ColumnScopeAlignHorizontal, plus FocusRequesterRequestFocus) — the binder strips the Alignment/Alignment.Horizontal/Alignment.Vertical @JvmInline value class overloads. Blocked on dotnet/java-interop#1440; once that lands, the existing ComposeValueTypes.cs registry handles them automatically.
  3. ExposedDropdownMenu (multi-line $default + synthetic marker) and ModifierPointerInput (Java-side helper allocation via <AndroidJavaSource>) — both currently sit alongside their [ComposeFacade] partials in ComposeBridges.cs because the generator has no shape for "trailing Object marker = null slot" 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

dotnet run scripts/manual-jni-report.cs
git diff --stat docs/manual-jni.md  # 0 (idempotent modulo timestamp)

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

jonathanpeppers and others added 2 commits June 9, 2026 12:40
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
jonathanpeppers marked this pull request as ready for review June 9, 2026 17:56
Copilot AI review requested due to automatic review settings June 9, 2026 17:56

Copilot AI 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.

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 run script to scan src/ComposeNet.Compose/ and generate a markdown report.
  • Checks in the generated docs/manual-jni.md artifact 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.

Comment thread scripts/manual-jni-report.cs Outdated
Comment thread scripts/manual-jni-report.cs
Comment thread scripts/manual-jni-report.cs
Comment thread scripts/manual-jni-report.cs Outdated
Comment thread scripts/manual-jni-report.cs Outdated
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>
@jonathanpeppers
jonathanpeppers enabled auto-merge (squash) June 9, 2026 18:13
@jonathanpeppers
jonathanpeppers merged commit b47df97 into main Jun 9, 2026
1 check passed
@jonathanpeppers
jonathanpeppers deleted the jonathanpeppers/manual-jni-report branch June 9, 2026 18:14
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.

2 participants