Skip to content

Surface Kotlin object companions on Compose class bindings via CompanionStatic rename#1468

Draft
Copilot wants to merge 4 commits into
mainfrom
copilot/fix-kotlin-object-companion-surfacing
Draft

Surface Kotlin object companions on Compose class bindings via CompanionStatic rename#1468
Copilot wants to merge 4 commits into
mainfrom
copilot/fix-kotlin-object-companion-surfacing

Conversation

Copilot AI commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #1467.

Problem

When a Kotlin class has an object Companion, the JVM emits two things on the outer class:

  1. A nested type <Outer>.Companion
  2. A public static final Companion Companion; field that holds the singleton

C# does not allow a nested type and a static member to share a name on the same class, so the binding generator silently drops the static field. Net effect: consumers can see the nested Companion type but cannot get an instance of it, leaving members like Color.Companion.Red, BlendMode.Companion.Clear, KeyboardOptions.Companion.Default, TextStyle.Companion.Default, FontWeight.Companion.Bold, Brush.Companion.HorizontalGradient(...), etc. unreachable from C# (they're only available via raw JNI).

Fix

Rename every *.Companion nested peer to CompanionStatic via a one-line wildcard XPath in the affected packages' Transforms/Metadata.xml:

<attr path="/api/package/class[substring(@name,string-length(@name)-9)='.Companion']" name="managedName">CompanionStatic</attr>

The collision is resolved at the type level so the consumer-facing property keeps its natural Kotlin/Java name. The generator now emits public static <Outer>.CompanionStatic Companion { get; } on every outer class whose Kotlin object Companion peer was previously colliding:

// before: not reachable from C# at all (field dropped due to name collision)
// after:
var red = Color.Companion.Red;
var clear = BlendMode.Companion.Clear;
var defaultKb = KeyboardOptions.Companion.Default;

CompanionStatic only appears as a return type in IntelliSense / decompiled signatures — it doesn't appear in normal call-site code.

This is the same wildcard pattern (and the same CompanionStatic rename) that this repo already uses in kotlin-stdlib, okio-jvm, aicore, and genai-prompt.

Interface companions are unaffected — the generator hoists those to top-level <Outer>Companion before this rename matches.

Packages updated

Package New static Companion accessors
androidx.compose.foundation/foundation-android 24
androidx.compose.ui/ui-graphics-android 35
androidx.compose.ui/ui-text-android 38
Total 97

Each accessor returns the renamed <Outer>.CompanionStatic peer, so all of its members (constants, factory methods, savers, defaults) are reachable directly from C# via the natural <Outer>.Companion.Foo syntax.

ui-graphics-android bumps the NuGet revision to 1.11.2.3 (stacking on top of #1471's 1.11.2.2); ui-graphics-android/Transforms/Metadata.xml carries both #1471's SolidColor(long) constructor re-introduction and the new companion rename.

Verification

  • ✅ All three packages build cleanly for both net9.0-android35.0 and net10.0-android36.0.
  • dotnet cake --target=metadata-verify passes.
  • PublicAPI.Unshipped.txt updated for the three packages with the new static Companion.get accessors plus the renamed nested CompanionStatic types and their members.
  • ✅ Merged with main (picks up Bind stripped SolidColor(long) constructor in Compose UI.Graphics #1471) — both fixes coexist on ui-graphics-android.

…ionStatic rename

Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Kotlin object companion field visibility on outer class binding Surface Kotlin object companions on Compose class bindings Jun 10, 2026
Copilot AI requested a review from jonathanpeppers June 10, 2026 18:09
The previous commit enumerated 7 specific Kotlin companion classes by name
across foundation-android (1), ui-graphics-android (1), and ui-text-android
(5). That fixed those 7 but left 62 more classes with the same problem in
just these three packages: ScrollState.Companion, LazyListState.Companion,
BlendMode.Companion, Brush.Companion, Path.Companion, ImeAction.Companion,
TextRange.Companion, AnnotatedString.Companion, and many others were still
unreachable without raw JNI.

Replace the per-class entries with the same wildcard XPath that
kotlin-stdlib, okio-jvm, com.google.ai.edge.aicore, and com.google.mlkit
genai-prompt already use:

    <attr path="/api/package/class[substring(@name,string-length(@name)-9)
          ='.Companion']"
          name="managedName">CompanionStatic</attr>

This renames every nested *.Companion peer in the package to CompanionStatic,
letting the binding generator emit `public static <Outer>.CompanionStatic
Companion { get; }` on every outer class.

After this change:

    foundation-android : 24 new static Companion accessors
    ui-graphics-android: 35 new static Companion accessors
    ui-text-android    : 45 new static Companion accessors
                        ---
                         104 total (vs. 7 in the previous revision)

Interface companions are unaffected — the binding generator hoists them to
top-level <Outer>Companion before this rename matches, so `Path.Companion`,
`ImageBitmap.Companion`, `DrawScope.Companion`, etc. surface correctly via
their hoisted peer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers changed the title Surface Kotlin object companions on Compose class bindings Surface all Kotlin object companions on Compose class bindings via wildcard CompanionStatic rename Jun 11, 2026
@jonathanpeppers jonathanpeppers changed the title Surface all Kotlin object companions on Compose class bindings via wildcard CompanionStatic rename Surface Kotlin object companions on Compose class bindings via CompanionInstance field Jun 11, 2026
@jonathanpeppers jonathanpeppers force-pushed the copilot/fix-kotlin-object-companion-surfacing branch from e4c6515 to 90d2610 Compare June 11, 2026 22:09
@jonathanpeppers jonathanpeppers changed the title Surface Kotlin object companions on Compose class bindings via CompanionInstance field Surface Kotlin object companions on Compose class bindings via CompanionStatic rename Jun 11, 2026
# Conflicts:
#	source/androidx.compose.ui/ui-graphics-android/Transforms/Metadata.xml
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.

Kotlin object companion field not surfaced on outer class binding (KeyboardOptions.Companion, TextStyle.Companion, ...)

2 participants