Skip to content

Fix IntelliJ split-debug tab labels regression#8908

Merged
auto-submit[bot] merged 10 commits into
flutter:mainfrom
lukemmtt:codex/fix-intellij-run-tab-labels
May 4, 2026
Merged

Fix IntelliJ split-debug tab labels regression#8908
auto-submit[bot] merged 10 commits into
flutter:mainfrom
lukemmtt:codex/fix-intellij-run-tab-labels

Conversation

@lukemmtt
Copy link
Copy Markdown
Contributor

@lukemmtt lukemmtt commented Apr 15, 2026

Summary

  • restore device-qualified Run/Debug tab titles on the newer IntelliJ split-debugger path
  • keep the existing descriptor mutation as a fallback for the older path
  • add a regression test that fails loudly if the reflective builder hooks disappear again

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 LaunchState and AttachState into FlutterDebugSessionUtils, 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=plain

Manually tested and did indeed verify, the labels are back once again with this fix.

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.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/io/flutter/run/FlutterDebugSessionUtils.java
Comment thread src/io/flutter/run/FlutterDebugSessionUtils.java
Comment thread src/io/flutter/run/LaunchState.java Outdated
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.
@lukemmtt
Copy link
Copy Markdown
Contributor Author

lukemmtt commented Apr 16, 2026

@blasko If you'd like to use the fix immediately, you can use this plugin compiled from this branch:
flutter-intellij.zip

Or clone and compile it yourself:
tmpdir="$(mktemp -d)" && git clone --depth 1 --single-branch --branch codex/fix-intellij-run-tab-labels https://github.com/lukemmtt/flutter-intellij.git "$tmpdir" && (cd "$tmpdir" && ./gradlew buildPlugin) && cp "$tmpdir/build/distributions/flutter-intellij.zip" ./flutter-intellij.zip

Then you can just add the plugin manually under "Settings > Plugins > Gear icon on that page > Install plugin from Disk":
Screenshot 2026-04-15 at 8 16 51 PM

@blasko
Copy link
Copy Markdown

blasko commented Apr 16, 2026

@blasko If you'd like to use the fix immediately, you can use this plugin compiled from this branch: flutter-intellij.zip

Or clone and compile it yourself: tmpdir="$(mktemp -d)" && git clone --depth 1 --single-branch --branch codex/fix-intellij-run-tab-labels https://github.com/lukemmtt/flutter-intellij.git "$tmpdir" && (cd "$tmpdir" && ./gradlew buildPlugin) && cp "$tmpdir/build/distributions/flutter-intellij.zip" ./flutter-intellij.zip

Then you can just add the plugin manually under "Settings > Plugins > Gear icon on that page > Install plugin from Disk": Screenshot 2026-04-15 at 8 16 51 PM

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.
@lukemmtt
Copy link
Copy Markdown
Contributor Author

happy to help! Thanks for the clear report

lukemmtt and others added 3 commits April 18, 2026 11:20
…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.
@helin24
Copy link
Copy Markdown
Member

helin24 commented Apr 30, 2026

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.

@lukemmtt
Copy link
Copy Markdown
Contributor Author

lukemmtt commented May 3, 2026

@helin24 All settled, thanks!

@helin24
Copy link
Copy Markdown
Member

helin24 commented May 4, 2026

@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)?

@lukemmtt
Copy link
Copy Markdown
Contributor Author

lukemmtt commented May 4, 2026

@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!

Copy link
Copy Markdown
Member

@helin24 helin24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @lukemmtt ! I looked over the code more and this LGTM. I will let @pq review as well.

@helin24 helin24 requested a review from pq May 4, 2026 17:29
@pq pq added the kokoro:run Triggers a Kokoro build (required for PRs submitted by members outside flutter). label May 4, 2026
@kokoro-team kokoro-team removed the kokoro:run Triggers a Kokoro build (required for PRs submitted by members outside flutter). label May 4, 2026
Copy link
Copy Markdown
Collaborator

@pq pq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. Thanks!

@pq pq added the autosubmit When this label is applied to a PR, the PR will be submitted as soon as all checks are green. label May 4, 2026
@auto-submit auto-submit Bot merged commit 178e42b into flutter:main May 4, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit When this label is applied to a PR, the PR will be submitted as soon as all checks are green.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IntelliJ split-debug tabs not showing device labels

5 participants