Fix device labels missing from run tabs on IntelliJ 2025.3+#8796
Fix device labels missing from run tabs on IntelliJ 2025.3+#8796pq merged 1 commit intoflutter:mainfrom
Conversation
IntelliJ commit aaa88849ba4c (Jul 2025) changed the myDisplayNameView field type from MutableReactiveProperty (a public class) to MutableStateFlow (whose runtime class StateFlowImpl is package-private). The existing reflection called Method.invoke() on a public setValue method, which throws IllegalAccessException when the declaring class is not accessible. The exception was caught silently, so device names never appeared in run tabs. Replace the field-level reflection with a call to RunContentDescriptor.setDisplayName(), a protected method added in IntelliJ commit b923077ed65d (Sep 2025). This calls a stable API method on a public class rather than depending on the internal type of a private field. Fixes flutter#8795
|
Hey wow. This is really fantastic. Thanks especially for the thoughtful write-up. I do so wish there was a way around this that didn't lean on reflection but this is a lot safer than what was there so it feels like a win. I wonder if this could be the root of #8794 too? |
|
Glad to help! This feature is pretty helpful and important for my workflow, so when I found those labels to be removed, my first thought was "why on earth did they remove the labels!"; I was dying to know who was behind the decision and how / why that choice was made, which started me on this wild goose chase, scouring the IntelliJ codebase before finally realizing (1) it's not an Android studio feature, and (2) it wasn't an intentional removal, but rather just a regression 😂 As for the reflection approach, yeah not my favorite pattern, & I'm open to others, seems robust enough for me though, now that I understand it. |
|
Awesome. This LGTM, so let's land it. We may have missed today's dev-channel build, but it should be in tomorrow's and you can grab it and enjoy the fruits of your labor! Instructions here if you're game to try that: https://github.com/flutter/flutter-intellij/blob/main/docs/Dev-Channel.md |
|
One thing that occurs to me... We should confirm (if you haven't already) that For extra credit, we might consider adding a test that asserts that we can access something that can set a display name. Maybe introducing a function like: @visibleForTesting
static @Nullable BiConsumer<RunContentDescriptor, String> getDisplaySetter() { ... }where the test could be something like assertNotNull(LaunchState.getDisplaySetter());@lukemmtt: WDYT? |
|
Good thinking; I checked the 251 branch source and can confirm As for the test, good idea, sorry that slipped my mind! I went ahead and implemented your suggestion with Thank you @pq! |
…liJ build Extracts the reflection lookup into a @VisibleForTesting getDisplaySetter() method and adds a test asserting it returns non-null. Serves as a regression guard: if JetBrains removes or renames setDisplayName in a future build, the test will fail loudly rather than the feature silently breaking for users. Follow-up to flutter#8796.
|
That's awesome. Thanks so much! Looking at your PR now... |
…liJ build (#8809) Follow-up to #8796. Extracts the reflection lookup into a `@VisibleForTesting getDisplaySetter()` method and adds a test asserting it returns non-null. This serves as a regression guard: if JetBrains removes or renames `setDisplayName` in a future build, the test will fail loudly rather than the feature silently breaking for users (which was the original failure mode in #8795). Verified locally by running the test against the real SDK (passes), then temporarily corrupting the method name to `setDisplayName_doesNotExist` (fails with the expected assertion message). I've reviewed the contributor guide and applied the relevant portions to this PR.
Summary
IllegalAccessExceptionthat silently prevents device names from appearing in Run/Debug tab titles on IntelliJ 2025.3 (Android Studio Panda)RunContentDescriptor.setDisplayName()API instead of reaching into a private field's internal typeFixes #8795
Problem
In IntelliJ 2025.3, the
myDisplayNameViewfield onRunContentDescriptorchanged fromMutableReactiveProperty(a public class) toMutableStateFlow(whose runtime classStateFlowImplis package-private). The existing reflection code callsMethod.invoke()on thesetValuemethod found viagetMethod(), which throwsIllegalAccessExceptionwhen the declaring class is not accessible — even though the method itself is public. The exception is caught silently, so run tabs show "main.dart" instead of "main.dart (macOS)".Regression introduced by JetBrains/intellij-community@
aaa88849ba4c(Jul 14, 2025).Fix
Replace the field-level reflection (
getDeclaredField("myDisplayNameView")→getMethod("setValue")→invoke()) with a call toRunContentDescriptor.setDisplayName(), an existing protected method onRunContentDescriptor. This calls a stable API method on a public class rather than depending on the internal type of a private field.An alternative minimal fix would be to add
setValueMethod.setAccessible(true)before the existinginvoke()call, but calling a stable API method on a public class is more resilient than depending on the internal type of a private field.Before & After
Before fix
After fix:
Contribution guidelines:
dart format.