Skip to content

Resolve getDisplayName also when inherited or returning non-null String - #136

Merged
sergio-sastre merged 2 commits into
sergio-sastre:masterfrom
zaburen:bugfix/issue#135_inherited_getdisplayname
Jul 6, 2026
Merged

Resolve getDisplayName also when inherited or returning non-null String#136
sergio-sastre merged 2 commits into
sergio-sastre:masterfrom
zaburen:bugfix/issue#135_inherited_getdisplayname

Conversation

@zaburen

@zaburen zaburen commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #135

What

  • getDisplayNameFunction(): look the function up via memberFunctions instead of declaredMemberFunctions, so implementations inherited from an interface default or an abstract superclass are found. kotlin-reflect returns the most-derived override and the function is called on the provider instance, so dispatch stays correct.
  • Accept a non-null String return type as well as String? (legal covariant overrides of AndroidX's getDisplayName(index: Int): String?).

Tests

  • 3 new fixture providers beside the existing AndroidStringProviderWithDisplayName: declared non-null return, interface-default inherited, abstract-superclass inherited — each with its own preview group.
  • New AndroidComposablePreviewParameterDisplayNameTest: scans the fixture package and asserts previewIndexDisplayName for all four shapes. Written before the fix: the three new cases failed with expected:<[Jim, Jens]> but was:<[null, null]>; the control (declared nullable) passed — and it keeps guarding the same-name decoy overload (getDisplayName(index: Int?) returning "WRONG").
  • New goldens for the 3 new fixture previews (roborazzi runtime + sourceset, paparazzi) — the filenames now carry the Jim/Jens display names.
  • All checks green locally on JDK 17: :tests:testApi (468 tests), :tests:testSourceSets, paparazziPreviewsRuntime/SourceSet -Pverify=true, roborazziPreviewsRuntime/SourceSet -Pverify=true, metalavaCheckCompatibility for all 5 modules (no public API change). No existing golden changes.

Behavior note

  • Providers that inherit or covariantly narrow getDisplayName start resolving names — consumers who relied on the index fallback for such providers will see index → name screenshot-ID changes when they upgrade.
  • AndroidX's base PreviewParameterProvider.getDisplayName (default null) now matches for every provider; it returns null, so previews without a real implementation keep today's index fallback unchanged.

Repro

https://github.com/zaburen/composable-preview-scanner-displayname-repro — fails 3/4 against 0.9.0; its -Pfixed mode swaps in the patched scanner from this branch and passes 4/4.

Summary by CodeRabbit

  • Bug Fixes

    • Improved how preview parameter display names are detected, so the app now uses the correct non-null display-name method in more cases.
    • Better handling for display names inherited from interfaces and abstract superclasses, reducing incorrect preview name resolution.
  • Tests

    • Added coverage for display-name edge cases to verify preview names are generated consistently across multiple provider setups.

previewIndexDisplayName was always null unless the provider declared
getDisplayName(index: Int): String? directly on the concrete class:

- declaredMemberFunctions excludes inherited members, so an interface
  default or superclass implementation was never found
- the matcher only accepted a nullable String? return, so a provider
  narrowing the return type to String never matched

Look the function up via memberFunctions (kotlin-reflect returns the
most-derived override) and accept a non-null String return as well.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 40734d59-62ad-4942-9aba-824fac385b6f

📥 Commits

Reviewing files that changed from the base of the PR and between 10b2f90 and ad930e3.

📒 Files selected for processing (2)
  • tests/src/main/java/sergio/sastre/composable/preview/scanner/android/previewparametersdisplayname/Composables.kt
  • tests/src/test/java/sergio/sastre/composable/preview/scanner/tests/api/main/screenshotid/AndroidComposablePreviewParameterDisplayNameEdgeCasesTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/src/main/java/sergio/sastre/composable/preview/scanner/android/previewparametersdisplayname/Composables.kt

Walkthrough

The getDisplayName resolution in ComposablePreviewWithPreviewParameterMapper now uses memberFunctions instead of declaredMemberFunctions and accepts non-nullable String return types, fixing cases where inherited or non-nullable getDisplayName implementations previously resolved to null display names. New test fixtures and a parameterized JUnit test validate these scenarios.

Changes

getDisplayName resolution fix

Layer / File(s) Summary
Mapper reflection lookup changes
core/.../ComposablePreviewWithPreviewParameterMapper.kt
Switches from declaredMemberFunctions to memberFunctions for discovering getDisplayName, and widens the return-type match to accept non-nullable String in addition to String?.
New provider fixtures and previews
tests/.../previewparametersdisplayname/Composables.kt
Updates the decoy getDisplayName(Int?) to throw instead of returning a wrong value; adds providers with non-nullable, interface-inherited, and superclass-inherited getDisplayName implementations, each wired to a new @Preview composable.
Display-name resolution tests
tests/.../AndroidComposablePreviewParameterDisplayNameEdgeCasesTest.kt
Adds a parameterized test class with an enum of edge-case scenarios, scanning previews by group and asserting resolved display names match expectations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Mapper as ComposablePreviewWithPreviewParameterMapper
  participant Reflection as KotlinReflect
  participant Provider as ProviderInstance
  Mapper->>Reflection: providerInstance::class.memberFunctions
  Reflection-->>Mapper: getDisplayName(Int) candidates (String or String?)
  Mapper->>Provider: call getDisplayName(index)
  Provider-->>Mapper: display name value (inherited or non-nullable)
Loading

Poem

A rabbit dug through reflection's burrow deep,
Found names that inherited providers keep.
No longer null, no longer lost,
Non-nullable strings cross the frost.
Hop, hop, hooray — the display names leap! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the key fix: resolving getDisplayName for inherited implementations and non-null String returns.
Linked Issues check ✅ Passed The code and tests address the issue’s required fixes: inherited lookup, non-null String support, and rejecting the Int? decoy overload.
Out of Scope Changes check ✅ Passed The changes are focused on the reported display-name resolution bug and the accompanying validation tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zaburen
zaburen marked this pull request as ready for review July 6, 2026 08:15
@sergio-sastre

Copy link
Copy Markdown
Owner

@zaburen Looks very good!
I've just converted the tests into Parameterized, but everything remains.
Thank you very much for your contribution, I'll merge it and release a new version with the bug fix today

@sergio-sastre
sergio-sastre self-requested a review July 6, 2026 15:34
@sergio-sastre
sergio-sastre merged commit 43781c1 into sergio-sastre:master Jul 6, 2026
8 checks passed
@zaburen

zaburen commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

@sergio-sastre
Thank you very much for your attention and time on this issue.

My team and I greatly appreciate you and your amazing tool!

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.

previewIndexDisplayName is null when getDisplayName is inherited or returns non-null String

2 participants