Fix IntelliJ split-debug tab labels regression#8908
Conversation
The March 31 debug-session helper switched newer IntelliJ builds onto XDebuggerManager.newSessionBuilder(), but that path never seeded the builder with the device-qualified session title. On split-debugger builds the visible run tab title is derived from the builder configuration instead of later RunContentDescriptor mutation, so plain IntelliJ could lose device labels even while Android Studio still showed them. Pass the device-qualified name through LaunchState and AttachState into FlutterDebugSessionUtils, then configure sessionName, showTab(true), and contentToReuse before startSession(). Keep the existing RunContentDescriptor.setDisplayName() reflection as a fallback for the older path, and add a regression test that fails loudly if JetBrains removes the reflective builder hooks this fix now depends on. Verified with ./gradlew compileJava --console=plain and ./gradlew test --tests io.flutter.run.LaunchStateTest --tests io.flutter.run.FlutterDebugSessionUtilsTest --console=plain.
There was a problem hiding this comment.
Code Review
This pull request introduces support for labeled debug tabs by utilizing reflection to access newer IntelliJ SDK APIs, such as sessionName and contentToReuse, within the debug session builder. It updates AttachState and LaunchState to incorporate device names into session titles and adds a unit test to verify reflection hook availability. Review feedback highlights a critical need to harden the reflection initialization logic to prevent null pointer exceptions, a request to refactor a method that exceeds the style guide's 30-line limit, and a recommendation to deduplicate the device name formatting logic shared across multiple classes.
Only cache the new session-builder reflection hooks after the mandatory builder methods are all present, which keeps newer IntelliJ builds from tripping a null-path before the legacy fallback can run. Extracts the builder, fallback, and descriptor helpers out of startSessionAndGetDescriptor() and reuses one device-qualified tab-title helper for both launch and attach flows. Verified with ./gradlew compileJava --console=plain and ./gradlew test --tests io.flutter.run.LaunchStateTest --tests io.flutter.run.FlutterDebugSessionUtilsTest --console=plain.
|
@blasko If you'd like to use the fix immediately, you can use this plugin compiled from this branch: Or clone and compile it yourself: Then you can just add the plugin manually under "Settings > Plugins > Gear icon on that page > Install plugin from Disk": |
I Installed the zip, and the functionality is back. That was quick, thanks! It's not fun having 8+ physical devices to target and no visuals on what tab is "what", lol. |
Moves the device-qualified run-tab naming helper onto FlutterDevice so both launch and attach flows build the same title from one shared implementation instead of relying on LaunchState inheritance. This keeps the earlier session-builder hardening and reflection refactor intact while finishing the remaining Gemini cleanup around duplicated naming logic. Adds a focused unit test for the shared helper, including device-name normalization, and verifies the existing split-debug reflection and display-setter checks still pass. Verified with ./gradlew compileJava --console=plain and ./gradlew test --tests io.flutter.run.LaunchStateTest --tests io.flutter.run.FlutterDebugSessionUtilsTest --tests io.flutter.run.FlutterDeviceTest --console=plain.
|
happy to help! Thanks for the clear report |
…ooks The tab-naming fix relies on calling contentToReuse, sessionName, and showTab before startSession(), but the test SDK lacks newSessionBuilder() so this path ran untested. Extract Method handles into a BuilderHooks record that tests can inject, then add a test asserting the exact call sequence. Catches ordering regressions without requiring a newer SDK or IDE UI harness.
|
Apologies for the delay reviewing this and thanks for the contribution! Can you reply to the gemini comments (and potentially make changes) before I do a more thorough review? Also add your information to the AUTHORS page and add a changelog entry. |
|
@helin24 All settled, thanks! |
|
@lukemmtt Sorry to be unclear! Can you address the comments that gemini code assist left above; i.e. reply whether they are relevant or not, resolve when fixed (or explained as not relevant)? |
|
@helin24 I'm so sorry, I had drafted replies and thought I had submitted via the cli but they didn't go through 😭 doing that now! |


Summary
Fixes #8907.
Problem
#8796 fixed the original
RunContentDescriptor.setDisplayName()regression, but Blasko reported that plain IntelliJ still lost device labels while Android Studio worked:The later split-debugger helper from #8878 moved newer IntelliJ builds onto
XDebuggerManager.newSessionBuilder(), but that path never seeded the builder with the device-qualified session title. On split-debugger builds the visible tab title is derived from the builder configuration rather than the later descriptor mutation alone, so IntelliJ could regress while Android Studio stayed fine.Fix
Pass the device-qualified title through
LaunchStateandAttachStateintoFlutterDebugSessionUtils, then configure the builder with:sessionName(...)showTab(true)contentToReuse(...)before
startSession()runs.The existing
RunContentDescriptor.setDisplayName()reflection stays in place as a fallback for the older path.Tests
./gradlew compileJava --console=plain./gradlew test --tests io.flutter.run.LaunchStateTest --tests io.flutter.run.FlutterDebugSessionUtilsTest --console=plainManually tested and did indeed verify, the labels are back once again with this fix.