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

- extract "java.lang.IO"
- tests for allowUnresolved
- more reliable works with varargs

(cherry picked from commit 8376baaa86afa3806cb096cffd42e9ed0db0d451)


(cherry picked from commit 78c8b1aed86c1414989a5a83b9e7d54ca5ed83e0)

IJ-MR-169535

GitOrigin-RevId: 704e1b94c19dbf07d5371b8989164070db2cd860
This commit is contained in:
Mikhail Pyltsin
2025-07-08 18:13:27 +02:00
committed by intellij-monorepo-bot
parent 01c7dc6dd8
commit cae5987ba6
11 changed files with 279 additions and 11 deletions

View File

@@ -23,6 +23,9 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.intellij.psi.CommonClassNames.JAVA_LANG_OBJECT;
import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
/**
* This interface represents a condition upon method call
*
@@ -342,11 +345,13 @@ public interface CallMatcher extends Predicate<PsiMethodCallExpression> {
if (method != null) return false;
PsiExpression qualifierExpression = call.getMethodExpression().getQualifierExpression();
if (!(qualifierExpression instanceof PsiReferenceExpression qualifierRefExpression)) return false;
if (qualifierRefExpression.getQualifierExpression() != null) return false;
String referenceName = qualifierRefExpression.getReferenceName();
if (referenceName == null && myClassName.isEmpty()) return true;
if (referenceName == null) return false;
if (!myClassName.endsWith(referenceName)) return false;
if (!(myClassName.endsWith("." + referenceName) ||
myClassName.equals(referenceName))) {
return false;
}
PsiElement resolvedQualifier = qualifierRefExpression.resolve();
if (resolvedQualifier != null) return false;
return true;
@@ -413,9 +418,16 @@ public interface CallMatcher extends Predicate<PsiMethodCallExpression> {
private static boolean expressionTypeMatches(@Nullable String type, @NotNull PsiExpression argument) {
if (type == null) return true;
if (type.endsWith("...")) {
type = type.substring(0, type.length() - 3);
}
PsiType psiType = argument.getType();
if (psiType == null) return false;
return psiType.equalsToText(type) || PsiTypesUtil.classNameEquals(psiType, type);
return psiType.equalsToText(type) ||
PsiTypesUtil.classNameEquals(psiType, type) ||
JAVA_LANG_OBJECT.equals(type) ||
//small optimization, because it can be slow and String is popular
(!JAVA_LANG_STRING.equals(type) && InheritanceUtil.isInheritor(psiType, type));
}
@Contract(pure = true)
@@ -458,12 +470,25 @@ public interface CallMatcher extends Predicate<PsiMethodCallExpression> {
private boolean unresolvedArgumentListMatch(@NotNull PsiExpressionList expressionList) {
if (myParameters == null) return true;
PsiExpression[] args = expressionList.getExpressions();
if (myParameters.length == 0 && args.length != 0) return false;
if (myParameters.length > 0) {
if (args.length < myParameters.length - 1) return false;
String lastParameter = myParameters[myParameters.length - 1];
if (lastParameter != null && lastParameter.endsWith("...")) {
if (args.length < myParameters.length - 1) return false;
}
else {
if (args.length != myParameters.length) return false;
}
}
for (int i = 0; i < Math.min(myParameters.length, args.length); i++) {
for (int i = 0; i < args.length; i++) {
PsiExpression arg = args[i];
String parameter = myParameters[i];
String parameter;
if (i < myParameters.length) {
parameter = myParameters[i];
}
else {
parameter = myParameters[myParameters.length - 1];
}
if (!expressionTypeMatches(parameter, arg)) return false;
}
return true;

View File

@@ -1483,7 +1483,7 @@ public final class ExpressionUtils {
yield (!hasCharArrayParameter(method) && (JAVA_UTIL_FORMATTER.equals(className) ||
InheritanceUtil.isInheritor(containingClass, JAVA_IO_PRINT_STREAM) ||
InheritanceUtil.isInheritor(containingClass, JAVA_IO_PRINT_WRITER))) ||
"java.lang.IO".equals(className);
JAVA_LANG_IO.equals(className);
}
case "printf", "format" -> {
if (arguments.length < 1) yield false;