Skip to content

Keep MockUtil declarations used across files and switch labels - #1086

Draft
martinfrancois wants to merge 1 commit into
openrewrite:mainfrom
martinfrancois:repro/mock-utils-cross-file-case-label
Draft

Keep MockUtil declarations used across files and switch labels#1086
martinfrancois wants to merge 1 commit into
openrewrite:mainfrom
martinfrancois:repro/mock-utils-cross-file-case-label

Conversation

@martinfrancois

@martinfrancois martinfrancois commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Suggested review order: 50 of 52 (Score: 1)
Review first: openrewrite/rewrite-migrate-java#1197

What's changed?

Adds 2 known-failing tests to MockUtilsToStaticTest that reproduce two defects in MockUtilsToStatic: the recipe removes a MockUtil field that another source file still uses, and it never removes a fully migrated MockUtil declaration that sits directly under a case label. No recipe code changes. The tests are marked @Disabled so the suite stays green; removing the annotation shows the failures. The class had 3 tests on main and has 5 with this change; the 3 pre-existing tests still pass.

What's your motivation?

Recipe: org.openrewrite.java.testing.mockito.MockUtilsToStatic.

Case 1: cross-file field use

Before

The recipe decides per file whether a MockUtil variable is still needed. It never sees uses from other compilation units. Given these two files in one run:

package mockito.example;

import org.mockito.internal.util.MockUtil;

public class MockitoMockUtils {
    public MockUtil util = new MockUtil();
}
package mockito.example;

public class MockitoMockUtilsUser {
    public boolean isMockUtilSet(MockitoMockUtils utils) {
        return utils.util != null;
    }
}

Actual after the recipe

Using current main. the first file becomes an empty class, public class MockitoMockUtils {\n}, with the field and the import removed. The second file is unchanged and still reads utils.util. Compiling the output pair with javac fails with:

error: cannot find symbol
  symbol:   variable util
  location: variable utils of type MockitoMockUtils

After the recipe runs, the code should still compile, so the field should stay when another file uses it. Test: doNotRemoveFieldUsedInAnotherClass.

Expected after the recipe

(unchanged)

Case 2: declaration under a case label

Before

Given an old-style switch:

switch (mode) {
    case 1:
        MockUtil util = new MockUtil();
        return util.isMock(value);
    default:
        return false;
}

Actual after the recipe

Using current main, the call is migrated to MockUtil.isMock(value), but the now-unused MockUtil util = new MockUtil(); line stays. The DeleteStatement scheduled from visitNewClass only removes statements whose parent is a J.Block; statements after case 1: hang off the J.Case instead, so the dead declaration is left behind. Test: mockUtilsVariableInSwitchCaseToStatic.

Expected after the recipe

The call MUST be migrated and the unused declaration MUST be removed.

Found while preparing #1084, which rewrites the removal logic in this recipe but deliberately does not fix these two behaviors, as its description discloses.

Anything in particular you'd like reviewers to focus on?

I think defect 1 is a genuine bug, because the recipe produces code that does not compile. Defect 2 is more of an improvement: the output compiles, it just keeps a dead statement. If you agree this should change, I would gladly prepare the fix. If this behavior is intended, feel free to close this and I know it is settled.

Any additional context

Pre-existing tests changed: None.

Related open PR of mine touching the same recipe: #1084. It does not fix either behavior here; its removal logic also handles only declarations whose parent is a block, so the case-label gap persists with it.

This reproduction was prepared with AI assistance (Claude Code). I reviewed the tests and this description.

The added reproduction tests and the existing suite together cover changed and unchanged behavior. The known-failing tests remain disabled until implementation. The formatter run was calibrated per file; untouched lines were not reformatted.

Checklist

…e-label declaration

doNotRemoveFieldUsedInAnotherClass pins the unsound single-file use
analysis: a MockUtil field referenced only from another source file is
removed, so that file stops compiling. mockUtilsVariableInSwitchCaseToStatic
pins the declaration left behind under a case label after its uses are
migrated. Both are marked @disabled as known-failing.
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Aug 11, 2026
@martinfrancois martinfrancois changed the title MockUtilsToStatic: add failing tests for cross-file field use and case-label declaration Keep MockUtil declarations used across files and switch labels Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant