[java] IDEA-371865 Inspection to convert 'System.out'<->'IO'

GitOrigin-RevId: fdb87ffc06388bd022224000c7b4e8d9e2013e9d
This commit is contained in:
Mikhail Pyltsin
2025-07-02 17:32:09 +00:00
committed by intellij-monorepo-bot
parent 59422d6662
commit 3a52f8601c
31 changed files with 522 additions and 20 deletions
@@ -3,6 +3,7 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.codeInsight.daemon.impl.UnusedSymbolUtil;
import com.intellij.codeInspection.options.OptPane;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.java.JavaBundle;
import com.intellij.java.codeserver.core.JavaPsiModuleUtil;
@@ -22,6 +23,7 @@ import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiMethodUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.VariableAccessUtils;
@@ -35,11 +37,21 @@ import java.util.Set;
public final class ExplicitToImplicitClassMigrationInspection extends AbstractBaseJavaLocalInspectionTool {
public boolean convertToIo = true;
@Override
public @NotNull Set<@NotNull JavaFeature> requiredFeatures() {
return Set.of(JavaFeature.IMPLICIT_CLASSES);
}
@Override
public @NotNull OptPane getOptionsPane() {
return OptPane.pane(
OptPane.checkbox("convertToIo",
JavaBundle.message("inspection.explicit.to.implicit.convert.to.io"))
);
}
@Override
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@@ -159,14 +171,14 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
if (underRoot) {
holder.registerProblem(aClass, new TextRange(0, classIdentifier.getTextRangeInParent().getEndOffset()),
JavaBundle.message("inspection.explicit.to.implicit.class.migration.name"),
new ReplaceWithImplicitClassFix());
new ReplaceWithImplicitClassFix(convertToIo));
}
else {
holder.registerProblem(aClass,
JavaBundle.message("inspection.explicit.to.implicit.class.migration.name"),
ProblemHighlightType.INFORMATION,
new TextRange(0, classIdentifier.getTextRangeInParent().getEndOffset()),
new ReplaceWithImplicitClassFix());
new ReplaceWithImplicitClassFix(convertToIo));
}
}
@@ -181,6 +193,10 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
private static class ReplaceWithImplicitClassFix extends ModCommandQuickFix {
private final boolean myConvertToIo;
private ReplaceWithImplicitClassFix(boolean io) { myConvertToIo = io; }
@Override
public @Nls(capitalization = Nls.Capitalization.Sentence) @NotNull String getFamilyName() {
return JavaBundle.message("inspection.explicit.to.implicit.class.migration.fix.name");
@@ -206,7 +222,7 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
);
}
private static @NotNull ModCommandAction getCommandActionWithMovingToRoot(@NotNull Project project) {
private @NotNull ModCommandAction getCommandActionWithMovingToRoot(@NotNull Project project) {
return new ModCommandAction() {
@Override
public Presentation getPresentation(@NotNull ActionContext context) {
@@ -243,7 +259,7 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
};
}
private static void applyFix(@NotNull Project project, @NotNull PsiElement element) {
private void applyFix(@NotNull Project project, @NotNull PsiElement element) {
PsiFile containingFile = element.getContainingFile();
if (!(containingFile instanceof PsiJavaFile javaFile)) {
return;
@@ -281,9 +297,9 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
CommentTracker tracker = new CommentTracker();
String body = tracker.rangeText(lBrace.getNextSibling(), rBrace.getPrevSibling());
PsiImplicitClass newClass = PsiElementFactory.getInstance(project).createImplicitClassFromText(body, psiClass);
if(!(newClass.getContainingFile() instanceof PsiJavaFile dummyFile) ||
dummyFile.getImportList() == null ||
javaFile.getImportList() == null) {
if (!(newClass.getContainingFile() instanceof PsiJavaFile dummyFile) ||
dummyFile.getImportList() == null ||
javaFile.getImportList() == null) {
return;
}
//it is necessary to resolve accurately inside a new implicit class
@@ -299,8 +315,32 @@ public final class ExplicitToImplicitClassMigrationInspection extends AbstractBa
cleanMainMethod(implicitClass);
PsiFile replacedContainingFile = replaced.getContainingFile();
if (replacedContainingFile != null) {
JavaCodeStyleManager.getInstance(project).optimizeImports(replacedContainingFile);
if (replacedContainingFile == null) return;
if (myConvertToIo && PsiUtil.isAvailable(JavaFeature.JAVA_LANG_IO, replacedContainingFile)) {
convertToIOMethods(replacedContainingFile);
}
JavaCodeStyleManager.getInstance(project).optimizeImports(replacedContainingFile);
}
private static void convertToIOMethods(@NotNull PsiFile file) {
if (!(file instanceof PsiJavaFile javaFile)) {
return;
}
List<PsiMethodCallExpression> systemOutPrints = new ArrayList<>();
javaFile.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
if (MigrateToJavaLangIoInspection.isSystemOutPrintln(expression)) {
systemOutPrints.add(expression);
return;
}
super.visitMethodCallExpression(expression);
}
});
for (PsiMethodCallExpression print : systemOutPrints) {
MigrateToJavaLangIoInspection.replaceToIO(print);
}
}
@@ -0,0 +1,104 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection;
import com.intellij.java.JavaBundle;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.CommentTracker;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import java.util.stream.Collectors;
public final class MigrateFromJavaLangIoInspection extends AbstractBaseJavaLocalInspectionTool {
private static final CallMatcher IO_PRINT =
CallMatcher.anyOf(
CallMatcher.staticCall("java.lang.IO", "println").parameterCount(0),
CallMatcher.staticCall("java.lang.IO", "println", "print").parameterCount(1)
);
private static final Set<String> IO_PRINT_NAMES = IO_PRINT.names().collect(Collectors.toSet());
@Override
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override
public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
String referenceName = expression.getMethodExpression().getReferenceName();
if (referenceName == null) return;
if (!isIOPrint(expression)) return;
PsiReferenceExpression methodExpression = expression.getMethodExpression();
holder.registerProblem(methodExpression,
JavaBundle.message("inspection.migrate.from.java.lang.io.name"),
new ConvertIOToSystemOutFix(referenceName));
}
};
}
private static class ConvertIOToSystemOutFix extends PsiUpdateModCommandQuickFix {
@NotNull
private final String methodName;
private ConvertIOToSystemOutFix(@NotNull String name) { methodName = name; }
@Override
public @NotNull String getFamilyName() {
return JavaBundle.message("inspection.migrate.from.java.lang.io.fix.family");
}
@Override
public @NotNull String getName() {
return JavaBundle.message("inspection.migrate.from.java.lang.io.fix.name", "System.out." + methodName + "()");
}
@Override
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
PsiElement parent = element.getParent();
if (!(parent instanceof PsiMethodCallExpression methodCall)) return;
replaceToSystemOut(methodCall);
}
}
static void replaceToSystemOut(@NotNull PsiMethodCallExpression methodCall) {
PsiReferenceExpression methodExpr = methodCall.getMethodExpression();
String methodName = methodExpr.getReferenceName();
if (methodName == null) return;
PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
StringBuilder replacement = new StringBuilder("System.out.").append(methodName).append("(");
if (arguments.length == 1) {
replacement.append(arguments[0].getText());
}
replacement.append(')');
PsiElementFactory factory = JavaPsiFacade.getElementFactory(methodCall.getProject());
PsiExpression expr = factory.createExpressionFromText(replacement.toString(), methodCall);
new CommentTracker().replace(methodCall, expr);
}
private static boolean isIOPrint(@NotNull PsiMethodCallExpression expression) {
boolean isResolvedIO = IO_PRINT.test(expression);
if (isResolvedIO) return true;
String name = expression.getMethodExpression().getReferenceName();
if (!IO_PRINT_NAMES.contains(name)) return false;
PsiExpression[] args = expression.getArgumentList().getExpressions();
if (!(args.length == 0 || args.length == 1)) return false;
PsiMethod method = expression.resolveMethod();
if (method != null) return false;
PsiExpression qualifierExpression = expression.getMethodExpression().getQualifierExpression();
if (!(qualifierExpression instanceof PsiReferenceExpression qualifierRefExpression)) return false;
if (qualifierRefExpression.getQualifierExpression() != null) return false;
String referenceName = qualifierRefExpression.getReferenceName();
if (!"IO".equals(referenceName)) return false;
PsiElement resolvedQualifier = qualifierRefExpression.resolve();
if (resolvedQualifier != null) return false;
return true;
}
}
@@ -0,0 +1,143 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection;
import com.intellij.codeInspection.options.OptPane;
import com.intellij.java.JavaBundle;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.CommentTracker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public final class MigrateToJavaLangIoInspection extends AbstractBaseJavaLocalInspectionTool {
public boolean processImplicitClasses = true;
public boolean processOrdinaryClasses = true;
private static final CallMatcher PRINT_STREAM_PRINT =
CallMatcher.anyOf(
CallMatcher.instanceCall("java.io.PrintStream", "println").parameterCount(0),
CallMatcher.instanceCall("java.io.PrintStream", "println", "print").parameterCount(1)
);
@Override
public @NotNull Set<@NotNull JavaFeature> requiredFeatures() {
return Set.of(JavaFeature.JAVA_LANG_IO);
}
@Override
public @NotNull OptPane getOptionsPane() {
return OptPane.pane(
OptPane.checkbox("processOrdinaryClasses",
JavaBundle.message("inspection.migrate.to.java.lang.io.option.ordinary")),
OptPane.checkbox("processImplicitClasses",
JavaBundle.message("inspection.migrate.to.java.lang.io.option.implicit"))
);
}
@Override
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override
public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
String referenceName = expression.getMethodExpression().getReferenceName();
if (referenceName == null) return;
if (!isSystemOutPrintln(expression)) return;
PsiClass topClass = PsiTreeUtil.getTopmostParentOfType(expression, PsiClass.class);
if (topClass == null) return;
boolean applicableForClass = isApplicableForClass(topClass);
PsiReferenceExpression methodExpression = expression.getMethodExpression();
if (applicableForClass) {
holder.registerProblem(methodExpression,
JavaBundle.message("inspection.migrate.to.java.lang.io.name"),
new ConvertSystemOutPrintlnFix(referenceName));
}
else {
holder.registerProblem(methodExpression,
JavaBundle.message("inspection.migrate.to.java.lang.io.name"),
ProblemHighlightType.INFORMATION,
new ConvertSystemOutPrintlnFix(referenceName));
}
}
private boolean isApplicableForClass(@Nullable PsiClass psiClass) {
if (psiClass == null) {
return false;
}
if (PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true) != null) {
return false;
}
if (psiClass instanceof PsiImplicitClass) {
return processImplicitClasses;
}
return processOrdinaryClasses;
}
};
}
private static class ConvertSystemOutPrintlnFix extends PsiUpdateModCommandQuickFix {
@NotNull
private final String methodName;
private ConvertSystemOutPrintlnFix(@NotNull String name) { methodName = name; }
@Override
public @NotNull String getFamilyName() {
return JavaBundle.message("inspection.migrate.to.java.lang.io.fix.family");
}
@Override
public @NotNull String getName() {
return JavaBundle.message("inspection.migrate.to.java.lang.io.fix.name", "IO." + methodName + "()");
}
@Override
protected void applyFix(@NotNull Project project, @NotNull PsiElement element, @NotNull ModPsiUpdater updater) {
PsiElement parent = element.getParent();
if (!(parent instanceof PsiMethodCallExpression methodCall)) return;
replaceToIO(methodCall);
}
}
static void replaceToIO(@NotNull PsiMethodCallExpression methodCall) {
PsiReferenceExpression methodExpr = methodCall.getMethodExpression();
String methodName = methodExpr.getReferenceName();
if (methodName == null) return;
PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
StringBuilder replacement = new StringBuilder("IO.").append(methodName).append("(");
if (arguments.length == 1) {
replacement.append(arguments[0].getText());
}
replacement.append(')');
PsiElementFactory factory = JavaPsiFacade.getElementFactory(methodCall.getProject());
PsiExpression expr = factory.createExpressionFromText(replacement.toString(), methodCall);
new CommentTracker().replace(methodCall, expr);
}
static boolean isSystemOutPrintln(@NotNull PsiMethodCallExpression expression) {
if (!PRINT_STREAM_PRINT.test(expression)) return false;
PsiReferenceExpression methodExpression = expression.getMethodExpression();
PsiExpression qualifier = methodExpression.getQualifierExpression();
if (!(qualifier instanceof PsiReferenceExpression ref)) return false;
PsiElement resolved = ref.resolve();
if (!(resolved instanceof PsiField field)) return false;
if (!field.getName().equals("out")) return false;
PsiClass containingClass = field.getContainingClass();
if (containingClass == null) return false;
if (!CommonClassNames.JAVA_LANG_SYSTEM.equals(containingClass.getQualifiedName())) return false;
return true;
}
}
@@ -1705,6 +1705,18 @@
bundle="messages.JavaBundle"
editorAttributes="NOT_USED_ELEMENT_ATTRIBUTES"
key="inspection.explicit.to.implicit.class.migration.name"/>
<localInspection groupPathKey="group.path.names.java.language.level.specific.issues.and.migration.aids" language="JAVA"
groupBundle="messages.InspectionsBundle"
groupKey="group.names.language.level.specific.issues.and.migration.aids25" enabledByDefault="true" level="INFORMATION"
implementationClass="com.intellij.codeInspection.MigrateToJavaLangIoInspection"
bundle="messages.JavaBundle"
key="inspection.migrate.to.java.lang.io.name"/>
<localInspection groupPathKey="group.path.names.java.language.level.specific.issues.and.migration.aids" language="JAVA"
groupBundle="messages.InspectionsBundle"
groupKey="group.names.language.level.specific.issues.and.migration.aids25" enabledByDefault="true" level="INFORMATION"
implementationClass="com.intellij.codeInspection.MigrateFromJavaLangIoInspection"
bundle="messages.JavaBundle"
key="inspection.migrate.from.java.lang.io.name"/>
<localInspection groupPathKey="group.path.names.java.language.level.specific.issues.and.migration.aids" language="JAVA"
shortName="TextBlockBackwardMigration"
groupBundle="messages.InspectionsBundle"
@@ -5,17 +5,21 @@ Reports ordinary classes, which can be converted into compact source files
<pre><code>
public class Sample {
public static void main(String[] args) {
String a = "Hello, world!";
System.out.println("Hello, world!");
}
}
</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>
void main() {
String a = "Hello, world!";
IO.println("Hello, world!");
}
</code></pre>
<!-- tooltip end -->
<p>Configure the inspection:</p>
<ul>
<li>Select <b>Replace 'System.out.print()' and 'System.out.println()' with methods from 'java.lang.IO' class</b> to convert these calls to IO methods.</li>
</ul>
<p><small>New in 2024.1</small></p>
</body>
</html>
@@ -0,0 +1,18 @@
<html>
<body>
Reports <code>IO.println()</code> and <code>IO.print()</code> calls and suggests replacing them with <code>System.out</code> methods.
<p>
This inspection helps migrate code from <code>java.lang.IO</code> class back to traditional <code>System.out</code> calls.</p>
<p>
<b>Example:</b>
</p>
<pre><code>IO.println("Hello, World!");</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>System.out.println("Hello, World!");</code></pre>
<!-- tooltip end -->
<p>
This inspection can help to downgrade for backward compatibility with earlier Java versions.
</p>
<p><small>New in 2025.2</small></p>
</body>
</html>
@@ -0,0 +1,20 @@
<html>
<body>
Reports <code>System.out.println()</code> and <code>System.out.print()</code> calls and suggests replacing them with methods from <code>java.lang.IO</code> class.
<p>
This inspection helps migrate code to use the newer <code>java.lang.IO</code> class</p>
<p>
<b>Example:</b>
</p>
<pre><code>System.out.println("Hello, World!");</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>IO.println("Hello, World!");</code></pre>
<!-- tooltip end -->
<p>Configure the inspection:</p>
<ul>
<li>Use the <b>Report in regular classes</b> option to report and suggest fixes in regular classes</li>
<li>Use the <b>Report in compact source files</b> option to report and suggest fixes in compact source files</li>
</ul>
<p><small>New in 2025.2</small></p>
</body>
</html>
@@ -1,3 +1,3 @@
void main() {
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
@@ -1,3 +1,3 @@
void main() {
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
@@ -1,4 +1,4 @@
void main() {
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
@@ -4,6 +4,6 @@
*/ /*comments2*/ /*comments3*/
void main(/*test*/) {
//comments4
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
//comments5
@@ -1,3 +1,3 @@
void main() {
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
@@ -1,3 +1,3 @@
void main() {
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
@@ -2,5 +2,5 @@ import p.List;
void main(String[] args) {
List <caret>a = null;
System.out.println("Hello, world!" + args);
IO.println("Hello, world!" + args);
}
@@ -2,5 +2,5 @@ import p.List;
void ma<caret>in() {
List a = null;
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
@@ -1,3 +1,3 @@
void main() {
System.out.println("Hello, world!");
IO.println("Hello, world!");
}
@@ -0,0 +1,7 @@
void main() {
I<caret>O.println("Hello, world!");
IO.println("Hello, world!");
IO.println("Hello, world!");
IO.print("Hello, world!");
}
@@ -0,0 +1,9 @@
<warning descr="Explicit class declaration can be converted into a compact source file">public class before<caret>WithSeveralIO</warning> {
public static void main(String[] args) {
System.out.println("Hello, world!");
System.out.println("Hello, world!");
System.out.println("Hello, world!");
System.out.print("Hello, world!");
}
}
@@ -0,0 +1,3 @@
void main() {
Sy<caret>stem.out.print("Hello");
}
@@ -0,0 +1,5 @@
class Test {
public static void main(String[] args) {
System.out<caret>.println("Hello");
}
}
@@ -0,0 +1,3 @@
void main() {
<error descr="Cannot resolve symbol 'IO'">IO<caret></error>/*some*/.print("Hello");
}
@@ -0,0 +1,5 @@
class Test {
public static void main(String[] args) {
IO<caret>.println("Hello");
}
}
@@ -0,0 +1,5 @@
class Test {
public static void main(String[] args) {
IO.<caret>print("Hello");
}
}
@@ -0,0 +1,3 @@
public static void main(String[] args) {
IO.<caret>println("Hello");
}
@@ -0,0 +1,5 @@
class Test {
public static void main(String[] args) {
System./*some comment*/out.<caret>print("Hello");
}
}
@@ -0,0 +1,3 @@
public static void main(String[] args) {
System.out.<caret>printf("Hello");
}
@@ -0,0 +1,3 @@
public static void main(String[] args) {
System.out.<caret>println("Hello");
}
@@ -94,6 +94,8 @@ public class ExplicitToImplicitClassMigrationInspectionInspectionTest extends Li
);
}
public void testWithSeveralIO() { doTest(); }
private void doNotFind() {
myFixture.enableInspections(new ExplicitToImplicitClassMigrationInspection());
myFixture.testHighlighting(true, false, true, "before" + getTestName(false) + ".java");
@@ -103,6 +105,7 @@ public class ExplicitToImplicitClassMigrationInspectionInspectionTest extends Li
}
private void doTest() {
MigrateToJavaLangIoInspectionTest.addIOClass(myFixture);
myFixture.enableInspections(new ExplicitToImplicitClassMigrationInspection());
myFixture.testHighlighting(true, false, true, "before" + getTestName(false) + ".java");
myFixture.checkPreviewAndLaunchAction(myFixture.findSingleIntention(
@@ -0,0 +1,36 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInspection.MigrateFromJavaLangIoInspection;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
public class MigrateFromJavaLangIoInspectionTest extends LightJavaCodeInsightFixtureTestCase {
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_LATEST_WITH_LATEST_JDK;
}
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath() + "/inspection/migrateFromJavaLangIo/";
}
public void testPrintlnResolved() {
MigrateToJavaLangIoInspectionTest.addIOClass(myFixture);
doTest("Replace with 'System.out.println()'");
}
public void testPrintUnresolved() { doTest("Replace with 'System.out.print()'"); }
private void doTest(String message) {
myFixture.enableInspections(new MigrateFromJavaLangIoInspection());
myFixture.testHighlighting(true, true, true, "before" + getTestName(false) + ".java");
myFixture.checkPreviewAndLaunchAction(myFixture.findSingleIntention(message));
myFixture.checkResultByFile("after" + getTestName(false) + ".java");
}
}
@@ -0,0 +1,62 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.MigrateToJavaLangIoInspection;
import com.intellij.java.JavaBundle;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
public class MigrateToJavaLangIoInspectionTest extends LightJavaCodeInsightFixtureTestCase {
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_LATEST_WITH_LATEST_JDK;
}
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath() + "/inspection/migrateToJavaLangIo/";
}
public void testPrintlnImplicitClass() { doTest("Replace with 'IO.println()'"); }
public void testPrintRegularClass() { doTest("Replace with 'IO.print()'"); }
public void testPrintf() {
doNotFind(InspectionsBundle.message("fix.all.inspection.problems.in.file", JavaBundle.message("inspection.migrate.to.java.lang.io.name")));
}
private void doNotFind(String message) {
addIOClass(myFixture);
MigrateToJavaLangIoInspection inspection = new MigrateToJavaLangIoInspection();
myFixture.enableInspections(inspection);
myFixture.testHighlighting(true, true, true, "before" + getTestName(false) + ".java");
IntentionAction intention = myFixture.getAvailableIntention(message);
assertNull(intention);
}
private void doTest(String message) {
addIOClass(myFixture);
myFixture.enableInspections(new MigrateToJavaLangIoInspection());
myFixture.testHighlighting(true, true, true, "before" + getTestName(false) + ".java");
myFixture.checkPreviewAndLaunchAction(myFixture.findSingleIntention(message));
myFixture.checkResultByFile("after" + getTestName(false) + ".java");
}
static void addIOClass(@NotNull JavaCodeInsightTestFixture fixture) {
fixture.addClass("""
package java.lang;
public final class IO {
public static void println(Object obj) {}
public static void println() {}
public static void print(Object obj) {}
}
""");
}
}
@@ -733,6 +733,15 @@ inspection.explicit.to.implicit.class.migration.fix.name=Convert into compact so
inspection.explicit.to.implicit.move.to.root.title=Move Simple Source File
inspection.explicit.to.implicit.move.to.root.move=Move under the project root
inspection.explicit.to.implicit.move.to.root.delete.package=Don't move, only delete package statement
inspection.explicit.to.implicit.convert.to.io=Replace 'System.out.print()' and 'System.out.println()' with methods from 'java.lang.IO' class
inspection.migrate.from.java.lang.io.name=Method from 'System.out' can be used instead of 'java.lang.IO'
inspection.migrate.from.java.lang.io.fix.family=Replace with 'System.out' methods
inspection.migrate.from.java.lang.io.fix.name=Replace with ''{0}''
inspection.migrate.to.java.lang.io.name=Method from 'java.lang.IO' class can be used
inspection.migrate.to.java.lang.io.fix.name=Replace with ''{0}''
inspection.migrate.to.java.lang.io.fix.family=Use method from 'java.lang.IO' class
inspection.migrate.to.java.lang.io.option.ordinary=Report in regular classes
inspection.migrate.to.java.lang.io.option.implicit=Report in compact source files
inspection.inconsistent.text.block.indent.name=Inconsistent whitespace indentation in text block
inspection.inconsistent.text.block.indent.message=Text block indent consists of mixed tabs and spaces
inspection.inconsistent.text.block.indent.spaces=Indent text block with spaces only