Skip to content

ADFA-4867: Point Kotlin code actions at their own tooltip tags - #1582

Open
itsaky-adfa wants to merge 6 commits into
stagefrom
fix/ADFA-4867
Open

ADFA-4867: Point Kotlin code actions at their own tooltip tags#1582
itsaky-adfa wants to merge 6 commits into
stagefrom
fix/ADFA-4867

Conversation

@itsaky-adfa

@itsaky-adfa itsaky-adfa commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Jira: ADFA-4867

Tooltip content is authored per tag (ADFA-4730) and looked up by the literal tag string, so a wrong tag fails silently at runtime: the action shows another action's tooltip, or none at all. Three of the five Kotlin code actions on stage were wrong.

Tag wiring

Kotlin action (UI label) Before After
Comment line editor.codeactions.comment (shared with Java) editor.codeactions.kotlin.comment
Uncomment line editor.codeactions.uncomment (shared with Java) editor.codeactions.kotlin.uncomment
Import class(es) editor.codeactions.kotlin.fiximports editor.codeactions.kotlin.addimport
Organize imports none editor.codeactions.kotlin.organizeimports
Null-safety fixes none editor.codeactions.kotlin.nullsafetyfix
Implement members editor.codeactions.overridesuper (Java's) editor.codeactions.kotlin.overridesuper

Organize imports and Null-safety fixes shipped with no tag at all, orphaning content authored for them. Implement members was showing Java's "Override superclass methods" tooltip. Import class(es) pointed at a tag naming a different action, one ADFA-4821 records as not implemented for Kotlin.

CommentLineAction and UncommentLineAction live in lsp/api and serve both languages, so the tag is now a required constructor argument and each menu passes its own. Deliberately not defaulted, so a new language cannot silently inherit another language's tooltip.

Review by commit

  1. f79a1cec3 - extracts computeImportCandidates as an internal seam, mirroring OrganizeImportsAction.computeOrganizeEdit. AddImportActionTest (added in ADFA-4747) calls this method, which the same commit removed, so :lsp:kotlin test sources have not compiled since 24 Jul and no unit test in the module could run. Candidates are now keyed by fully-qualified name instead of JvmSymbol; postExec only ever used symbol.fqName, and keying by it collapses two index entries for the same class into a single chooser entry.
  2. 8436ce8dc - the tag wiring above, plus KotlinCodeActionTooltipTagTest.

Each commit compiles on its own.

Notes for review

  • The large diffs on CommentLineAction.kt, UncommentLineAction.kt and JavaCodeActionsMenu.kt are the Spotless file-level ratchet reindenting each touched file in full. The behavioural change in each is a few lines.
  • editor.codeactions.kotlin.addimport is new and has no content authored yet.
  • Nothing here is visible in the app until ADFA-4868: the code-actions submenu resolves actions under EDITOR_TEXT_ACTIONS instead of EDITOR_CODE_ACTIONS, so no tooltip tag is read today. This PR makes the data correct; ADFA-4868 makes it reachable.
  • The overlapping tag changes previously carried by ADFA-4613: Surround with try/catch code action #1524 have been removed from that branch, which is now try/catch only.

Testing

  • KotlinCodeActionTooltipTagTest 2/2 and AddImportActionTest 5/5, confirmed from the JUnit XML.
  • :lsp:kotlin, :lsp:java, :lsp:api and :idetooltips compile; spotlessCheck clean.
  • Not verified on device, since ADFA-4868 makes code-action tooltips unreachable.

AddImportActionTest, added in ADFA-4747, calls computeImportCandidates,
which the same commit removed. :lsp:kotlin test sources have not compiled
since, so no unit test in the module could run.

Extract the candidate resolution back out of execAction as an internal
seam, mirroring OrganizeImportsAction.computeOrganizeEdit.

Candidates are now keyed by fully-qualified name rather than JvmSymbol.
postExec only ever used symbol.fqName, and keying by it collapses two
index entries for the same class into a single chooser entry.
Tooltip content is authored per tag (ADFA-4730) and looked up by the
literal string, so a wrong tag fails silently at runtime: the action
shows another action's tooltip, or none at all.

- Organize imports and Null-safety fixes carried no tag, orphaning the
  content authored for them.
- Implement members used Java's editor.codeactions.overridesuper.
- Import class(es) used editor.codeactions.kotlin.fiximports, which
  describes a different action, and one ADFA-4821 records as not
  implemented for Kotlin. It now uses .kotlin.addimport.
- Comment and Uncomment are shared with Java, so the tag becomes a
  required constructor argument and each language passes its own. Not
  defaulted, so a new language cannot silently inherit another's tooltip.

KotlinCodeActionTooltipTagTest pins all six id-to-tag pairs and asserts
no Kotlin action borrows a Java tag.

editor.codeactions.kotlin.addimport is new and has no content authored
yet. Nothing here is visible in the app until ADFA-4868 is fixed: the
code-actions submenu resolves actions under the wrong location, so no
tooltip tag is read today.
@itsaky-adfa itsaky-adfa self-assigned this Jul 27, 2026
@itsaky-adfa
itsaky-adfa requested a review from a team July 27, 2026 13:46

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Jul 27, 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 Plus

Run ID: d37f6274-6eb6-4e70-9f6d-534d70a7063e

📥 Commits

Reviewing files that changed from the base of the PR and between c7c209b and ca0e0db.

📒 Files selected for processing (3)
  • idetooltips/src/main/java/com/itsaky/androidide/idetooltips/TooltipTag.kt
  • lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/actions/AddImportAction.kt
  • lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • idetooltips/src/main/java/com/itsaky/androidide/idetooltips/TooltipTag.kt
  • lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt
  • lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/actions/AddImportAction.kt

📝 Walkthrough
  • Added Kotlin-specific tooltip tags for comment, uncomment, import-class, organize imports, implement-members, and null-safety code actions.
  • Updated line comment actions (CommentLineAction, UncommentLineAction) to require explicit language-specific tooltip tags, and wired Kotlin actions to use Kotlin tooltip tag constants.
  • Updated Kotlin import-class action to use the correct tooltip tag and prevented duplicate chooser entries by keying import candidates by fully qualified class name.
  • Restored computeImportCandidates as an internal test seam.
  • Set/standardized tooltip tags for Kotlin quick-fix actions (e.g., implement-members, null-safety, organize imports) and refactored several action IDs into companion object constants.
  • Added regression coverage (KotlinCodeActionTooltipTagTest) validating Kotlin tooltip tag mappings and ensuring Kotlin actions don’t use Java tooltip tags.
  • Risk: tooltip behavior remains unreachable until ADFA-4868 is addressed.

Walkthrough

Kotlin code actions now use dedicated tooltip tags for commenting, imports, overrides, null-safety fixes, and organizing imports. Comment actions accept injected tags, menus wire language-specific values, AddImportAction returns fully-qualified-name keyed candidates, and tests verify the Kotlin tag mapping.

Changes

Kotlin code-action tagging

Layer / File(s) Summary
Action tag contracts and menu wiring
idetooltips/.../TooltipTag.kt, lsp/api/.../actions/*LineAction.kt, lsp/java/.../JavaCodeActionsMenu.kt, lsp/kotlin/.../KotlinCodeActionsMenu.kt
Adds Kotlin-specific tooltip constants, injects tags into comment actions, and wires Java/Kotlin menu values.
Kotlin action tags and import candidates
lsp/kotlin/.../actions/{AddImportAction,ImplementMembersAction,NullSafetyAction,OrganizeImportsAction,SurroundWithTryCatchAction}.kt
Assigns dedicated Kotlin tags, centralizes action IDs, and changes import candidates and chooser titles to use fully-qualified names.
Kotlin tooltip mapping validation
lsp/kotlin/src/test/.../KotlinCodeActionTooltipTagTest.kt
Verifies every Kotlin action has its expected, non-empty Kotlin-namespaced tooltip tag.

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

Sequence Diagram(s)

sequenceDiagram
  participant ResolveReference
  participant AddImportAction
  participant ktSymbolIndex
  participant CodeActionChooser
  ResolveReference->>AddImportAction: provide diagnostic extras
  AddImportAction->>ktSymbolIndex: query classifier candidates
  ktSymbolIndex-->>AddImportAction: return candidates keyed by fqName
  AddImportAction->>CodeActionChooser: display fqName edit choices
Loading

Possibly related PRs

Suggested reviewers: jatezzz, dara-abijo-adfa

Poem

A rabbit hops through Kotlin code,
Tags bloom along the action road.
Imports find their names so clear,
Comments whisper, “click me, please!”
Null fixes twitch a helpful ear.
🌿 Bugs nap beneath the trees.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: Kotlin code actions are routed to their own tooltip tags.
Description check ✅ Passed The description is directly related to the PR and accurately explains the tooltip-tag and action-seam changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ADFA-4867

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/CommentLineAction.kt`:
- Around line 34-41: Document both public constructors of CommentLineAction in
lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/CommentLineAction.kt:34-41
and UncommentLineAction in
lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/UncommentLineAction.kt:34-41
with KDoc describing the comment/uncomment contract, the required per-language
tag parameter, and how that tag is used for tooltips.

In
`@lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt`:
- Around line 19-28: Update the expected map in KotlinCodeActionTooltipTagTest
to match KotlinCodeActionsMenu by adding the missing SurroundWithTryCatchAction
mapping, or restrict actualTags to the six regression-targeted actions. Ensure
the assertion compares equivalent action sets.
- Around line 3-5: Update KotlinCodeActionTooltipTagTest to replace JUnit 4
`@Test` and org.junit.Assert assertions with org.junit.jupiter.api test APIs and
com.google.truth.Truth.assertThat(). Add the required Jupiter and Truth test
dependencies to the lsp/kotlin module, preserving the existing test behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c6a38b0f-f38a-4b90-ab58-bf1e72ac509b

📥 Commits

Reviewing files that changed from the base of the PR and between cd39538 and 22de019.

📒 Files selected for processing (10)
  • idetooltips/src/main/java/com/itsaky/androidide/idetooltips/TooltipTag.kt
  • lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/CommentLineAction.kt
  • lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/UncommentLineAction.kt
  • lsp/java/src/main/java/com/itsaky/androidide/lsp/java/actions/JavaCodeActionsMenu.kt
  • lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionsMenu.kt
  • lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/actions/AddImportAction.kt
  • lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/actions/ImplementMembersAction.kt
  • lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/actions/NullSafetyAction.kt
  • lsp/kotlin/src/main/java/com/itsaky/androidide/lsp/kotlin/actions/OrganizeImportsAction.kt
  • lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt

Comment on lines +34 to +41
class CommentLineAction(
lang: String,
private val targetFileExtensions: List<String>,
private val lineCommentToken: String,
tag: String,
) : EditorActionItem {
constructor(lang: String, extension: String, lineCommentToken: String, tag: String) :
this(lang, listOf(extension), lineCommentToken, tag)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Document the new required per-language tooltip-tag API.

Both public action constructors gained a mandatory tag parameter, so their KDoc should define its per-language requirement and tooltip behavior.

  • lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/CommentLineAction.kt#L34-L41: document the comment action contract and required tag.
  • lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/UncommentLineAction.kt#L34-L41: document the uncomment action contract and required tag.
📍 Affects 2 files
  • lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/CommentLineAction.kt#L34-L41 (this comment)
  • lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/UncommentLineAction.kt#L34-L41
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/CommentLineAction.kt`
around lines 34 - 41, Document both public constructors of CommentLineAction in
lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/CommentLineAction.kt:34-41
and UncommentLineAction in
lsp/api/src/main/java/com/itsaky/androidide/lsp/actions/UncommentLineAction.kt:34-41
with KDoc describing the comment/uncomment contract, the required per-language
tag parameter, and how that tag is used for tooltips.

Source: Coding guidelines

Comment on lines +3 to +5
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'junit|truth' lsp/kotlin/build.gradle.kts gradle/libs.versions.toml

Repository: appdevforall/CodeOnTheGo

Length of output: 885


🏁 Script executed:

#!/bin/bash
set -e

echo "== candidate files =="
fd -a 'KotlinCodeActionTooltipTagTest.kt|lsp/kotlin/build.gradle.kts|gradle/libs.versions.toml' . | sed 's#^\./##'

echo "== target test file outline/size/content =="
wc -l lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt
sed -n '1,90p' lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt

echo "== lsp/kotlin build relevant deps/tests =="
sed -n '1,220p' lsp/kotlin/build.gradle.kts | nl -ba

echo "== repository junit/truth usage summary =="
python3 - <<'PY'
from pathlib import Path
import re
repo = next(p for p in [Path('.'), Path('/tmp/repo')] if p.exists())
files=[]
for p in Path('.').rglob('*'):
    if p.is_file():
        try:
            text=p.read_text(errors='ignore')
        except Exception:
            continue
        if re.search(r'import\s+(org\.junit\.jupiter|org\.junit\.Assert|org\.junit\.Test|org\.junit\.Assertions|org\.junit\.Assertions\.|com\.google\.truth|android\.test\.ext\.junit)', text):
            files.append((str(p), text.count('import '), text.count('assertThat'), text.count('assertEquals'), '`@Test`'))
for fn,count_imp,count_t,eq,test in sorted(files):
    if count_imp:
        print(f"{fn}: imports={count_imp} truth_assert={count_t} junit_eq={eq} junit_test={test}")
PY

echo "== exact imports/usages in target file =="
rg -n 'import\s+(org\.junit|com\.google\.truth|androidx\.test\.ext\.junit)|`@Test`|assertEquals|assertTrue|assertThat' lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt

Repository: appdevforall/CodeOnTheGo

Length of output: 2247


🏁 Script executed:

#!/bin/bash
set -e

echo "== lsp/kotlin/build.gradle.kts =="
sed -n '1,220p' lsp/kotlin/build.gradle.kts

echo "== gradle libs versions relevant entries =="
sed -n '1,45p' gradle/libs.versions.toml
sed -n '268,278p' gradle/libs.versions.toml

echo "== all junit 4 vs Jupiter usage in lsp/kotlin src/test =="
python3 - <<'PY'
from pathlib import Path
for p in Path('lsp/kotlin/src/test/java').rglob('*'):
    if p.suffix not in {'.kt','.java'}:
        continue
    txt = p.read_text(errors='ignore')
    legacy = '`@Test`' in txt and 'junit.jupiter' not in txt and 'import org.junit.Assert' in txt
    jupiter = 'org.junit.jupiter' in txt
    truth = 'com.google.truth' in txt or 'Truth.assertThat' in txt
    if legacy or jupiter or truth:
        print(f"{p}: legacy_junit4_asserts={legacy} jupiter_import={jupiter} truth_import={truth}")
PY

Repository: appdevforall/CodeOnTheGo

Length of output: 8046


Use the mandated Jupiter and Truth test APIs.

lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTagTest.kt still uses JUnit 4 @Test and org.junit.Assert assertions. Add Jupiter/Truth test dependencies for this module and rewrite the tests to use org.junit.jupiter.api plus com.google.truth.Truth.assertThat().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@lsp/kotlin/src/test/java/com/itsaky/androidide/lsp/kotlin/KotlinCodeActionTooltipTagTest.kt`
around lines 3 - 5, Update KotlinCodeActionTooltipTagTest to replace JUnit 4
`@Test` and org.junit.Assert assertions with org.junit.jupiter.api test APIs and
com.google.truth.Truth.assertThat(). Add the required Jupiter and Truth test
dependencies to the lsp/kotlin module, preserving the existing test behavior.

Source: Coding guidelines

Two changes.

The Import class(es) tag becomes editor.codeactions.kotlin.importclasses,
matching the label users actually see. addimport described the class name in
our code rather than the user-facing concept, and Elissa names tags by the
latter.

Action ids move into each action's companion object as a single definition and
are reused from there, following the pattern already in FieldBasedAction. The
tooltip-tag test was the second place these ids were spelled out; it now reads
the companion ids and the TooltipTag constants instead of literals.

CommentLineAction and UncommentLineAction take a companion idFor(lang) rather
than a const, since one instance is registered per language. KT_LANG in
KotlinCodeActionsMenu becomes internal so the test uses the same value the
menu does.

Also adds the Surround with try/catch entry to the test, which ADFA-4613
registered after this branch was cut.
…uper

Implement members only inserts stubs for inherited members whose effective
modality is ABSTRACT (AbstractMemberStubs.kt, membersToImplement). It cannot
override a concrete open member, so it is the equivalent of Java's "Implement
abstract method(s)" widened to properties -- not of Java's "Override superclass
methods", which offers any non-final inherited method
(OverrideSuperclassMethodsAction.kt:141).

The tag now says what the action does. editor.codeactions.kotlin.overridesuper
is retired; editor.codeactions.kotlin.implementmembers is new and needs content
authored.

The label stays "Implement members" -- that is what IntelliJ and Android Studio
call it, so it is what Kotlin developers expect.

Java's ImplementAbstractMethodsAction borrows editor.codeactions.overridesuper
for the same reason, so neither language had a correct tag for this. That half
is tracked in ADFA-4869.
Her updated table on ADFA-4821 spells it editor.codeactions.kotlin.importclass,
singular. We had importclasses. She owns the tag namespace, so match it.

Every other Kotlin tag in that table already matches what this branch wires.
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.

2 participants