CodeStyleManager.reformat produces corrupted output for injected content with inconsistent indentation
Summary
CodeStyleManager.reformat(PsiFile) produces corrupted output when formatting injected language content in Java text blocks and Kotlin raw strings where input lines have inconsistent indentation (i.e., lines need to be re-indented by the formatter). The workaround is to use CodeStyleManager.reformatText(PsiFile, List<TextRange>) instead, which works correctly.
Description
When using LightJavaCodeInsightFixtureTestCase with setCaresAboutInjection(true) to test formatting of injected language content, CodeStyleManager.reformat() produces incorrect results when the input content has lines at different indentation levels.
Trigger condition: Input content where lines have different indentation levels (i.e., the formatter needs to adjust indentation to align them).
Workaround: Using CodeStyleManager.reformatText() instead works correctly.
The same formatting works correctly:
- In the actual editor (tested via
runIde) - When using
reformatText()instead ofreformat()
Steps to reproduce
-
Create a custom language plugin with a
FormattingModelBuilderthat aligns content -
Configure language injection using
//language=customlangcomment -
Write a test extending
LightJavaCodeInsightFixtureTestCase:
// FAILS - produces corrupted output
public void testFormatter_reformat() {
myFixture.setCaresAboutInjection(true);
myFixture.configureByText("Test.java", """
public class Test {
//language=customlang
@MyAnnotation(\"""
header1 | header2
a|b<caret>
\""")
void test() {}
}
""");
WriteCommandAction.writeCommandAction(getProject())
.run(() -> CodeStyleManager.getInstance(getProject())
.reformat(myFixture.getFile()));
// Output is corrupted
}
// WORKS - produces correct output
public void testFormatter_reformatText() {
myFixture.setCaresAboutInjection(true);
myFixture.configureByText("Test.java", /* same content */);
WriteCommandAction.writeCommandAction(getProject())
.run(() -> CodeStyleManager.getInstance(getProject())
.reformatText(
myFixture.getFile(),
List.of(myFixture.getFile().getTextRange())
));
// Output is correct
}
Note: The input content has the header at one indentation level and the data row at a different indentation level. The formatter should align them, but reformat() corrupts the output.
- Run the test
Expected behaviour
Both methods should produce correctly formatted output matching editor behaviour:
header1 | header2
a | b
Actual behaviour with reformat()
The text is corrupted – spaces are inserted at wrong positions, rows may merge together, and characters may appear in wrong positions.
Actual behaviour with reformatText() (workaround)
Output is correct – matches editor behaviour.
Key observations
- Workaround exists:
reformatText()works correctly whilereformat()fails - Trigger: Input with inconsistent indentation (lines at different indent levels)
- Not triggered: When all input lines have the same indentation level
- Formatting works correctly in the actual editor (tested via
runIde) - The injection is detected correctly in tests
- The formatter is invoked (modifications occur, but at wrong offsets)
- Affects both Java text blocks and Kotlin raw strings
Environment
- IntelliJ IDEA 2025.2 (Community Edition)
- Test framework:
LightJavaCodeInsightFixtureTestCase - OS: macOS
- JDK: 21