Skip to content

ADFA-5048 (5/5): Add the Java extract-method action, edit builder and tests - #1821

Open
Daniel-ADFA wants to merge 4 commits into
feat/ADFA-5048-signature-analysisfrom
feat/ADFA-5048-action-and-tests
Open

ADFA-5048 (5/5): Add the Java extract-method action, edit builder and tests#1821
Daniel-ADFA wants to merge 4 commits into
feat/ADFA-5048-signature-analysisfrom
feat/ADFA-5048-action-and-tests

Conversation

@Daniel-ADFA

@Daniel-ADFA Daniel-ADFA commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Stack 5 of 5 for ADFA-5048, the tip. Base: #1820. This is the PR that makes the feature reachable, and it carries the tests for the whole stack.

  • ExtractMethodAction (ide.editor.lsp.java.extractMethod), registered in JavaCodeActionsMenu, with a tooltip tag (editor.codeactions.extractmethod).
  • ExtractMethodEdit.kt - builds the rewrite: the new declaration after the enclosing member, the call site in place, indentation matched to the anchor, text-block interiors untouched.
  • JavaExtractMethodUi.kt - adapts the plan to the :lsp:ui contract from PR 1.
  • Spec: docs/features/java-extract-method.md (R1-R16), status Implemented.

Tests, 41 in this PR: ExtractMethodRegionTest (8), ExtractMethodPlanTest (25), ExtractMethodEditTest (8), plus JavacFixture helpers (methodPlanAfter, methodPlanOver, applyMethod).

Verification

  • :lsp:java:testV7DebugUnitTest --tests "com.itsaky.androidide.lsp.java.refactor.*" plus the :lsp:ui, :lsp:refactor-core and :lsp:kotlin refactor suites: 419 tests, 0 failures, unchanged from before the split. The --tests filter is required; the unfiltered :lsp:java suite exceeds its 10-minute task timeout.
  • Every intermediate branch in the stack compiles alone.
  • On device (arm64 emulator), against the acceptance criteria: menu entry, sheet, taken-name validation, extraction applied, undo in two steps, Kotlin sheet unaffected, statement-range selection. Screenshots and a step-by-step log are attached to the ticket.
  • Font scale 1.0 and 2.0 on the sheet.

Steps to QA are on the ticket.

Emits the two replacements: the region becomes a call, the new method appears
after the anchor member. Descending document order is mandatory, not
stylistic -- applyActionEdits applies each edit with line/column ranges
against whatever the text is at that moment, so an earlier edit must never
shift a later one. In Java the insertion always leads, since the anchor
contains the region.

The method is emitted fully indented at the anchor's own indentation, because
code-action edits bypass the editor's auto-indent. Lines inside a text block
are emitted byte-for-byte: their whitespace is part of the literal's value.

Known consequence, tracked by ADFA-5081: nothing on that path calls
beginBatchEdit, so this costs two undo steps and the intermediate state does
not compile.
Registers "Extract method" in the Java code-actions menu with one new tooltip
tag, editor.codeactions.extractmethod, fixed by ADFA-4821.

One attributed compile produces the plan on a background thread; the sheet
does pure string and offset arithmetic and never re-enters javac on confirm.
No prepare() visibility gate: deciding extractability needs that compile,
far too costly for the UI thread, so the action stays visible on any Java
file and reports a specific refusal instead.

The document version is re-read on confirm rather than trusted from the plan,
and a plan built while the document was closed carries no version to compare,
so it refuses rather than applying spans on trust.

No new strings: every message this needs already exists from ADFA-5080.
41 cases across three layers, mirroring the extract-variable split so a
failure localises: region resolution (parse only), the analysis rules and
every refusal reason, and the emitted text.

Every plan case feeds the rewritten file back through javac via compiles().
That is the assertion that matters for throws, static and captured types,
where a signature that merely looks plausible is exactly the failure mode
those rules exist to prevent.

JavacFixture gains methodPlanAfter/methodPlanOver/applyMethod. Selecting by
text rather than offsets keeps a snap-outward case readable: the selection is
written exactly as a finger would have dragged it.
The feature doc states the Java deltas from the Kotlin spec against the same
R1-R16 numbering, so the two read side by side, and records what is
deliberately not supported.

ADR 0013 anticipated its own revisit -- "reconsider once extract-method and
inline-variable have landed and the UI surface is known". Both have now
landed in both languages, and the trigger turned out to be duplication
between two modules rather than a third appearing. The rule is now: a
refactoring sheet used by more than one language server lives in :lsp:ui
behind a plain-data contract; one used by exactly one stays in its own
module, as Kotlin's inline-variable sheet does.

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

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