mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
[java] warn on non-instantiatable intersection types (IDEA-277529)
extend for any context GitOrigin-RevId: d6f499348c8278bcb58951900ebf116440719082
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c752c69914
commit
1f0f1acfbc
@@ -557,7 +557,7 @@ type.constraint.assignability.explanation.subtype.of.subtype={0} is already know
|
||||
type.constraint.assignability.explanation.not.instance.of={0} is known to be not {1}
|
||||
type.constraint.assignability.explanation.not.instance.of.supertype={0} is known to be not {1} which is a supertype of {2}
|
||||
type.constraint.assignability.explanation.definitely.inconvertible={0} is known to be {1} which is definitely incompatible with {2}
|
||||
inspection.message.javac.quick.intersection.type.problem=Though assignment is formal correct, it could lead to ClassCastException at runtime. Expected: ''{0}'', actual: ''{1}''
|
||||
inspection.message.javac.quick.intersection.type.problem=Intersection type ''{0}'' cannot be instantiated, because ''{1}'' is final
|
||||
suggest.package.private.visibility.level.for.classes.in.exported.packages.java.9=Suggest package-private visibility level for classes in exported packages (Java 9+)
|
||||
generate.members.position.at.caret=At caret
|
||||
generate.members.position.after.equals.and.hashcode=After equals() and hashCode()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInspection.compiler;
|
||||
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
@@ -25,11 +25,15 @@ import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
|
||||
public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
|
||||
@@ -82,7 +86,6 @@ public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
|
||||
final PsiExpression rExpression = assignment.getRExpression();
|
||||
if (rExpression == null) return;
|
||||
PsiJavaToken operationSign = assignment.getOperationSign();
|
||||
checkIntersectionType(lType, rExpression.getType(), operationSign);
|
||||
|
||||
IElementType eqOpSign = operationSign.getTokenType();
|
||||
IElementType opSign = TypeConversionUtil.convertEQtoOperation(eqOpSign);
|
||||
@@ -100,44 +103,16 @@ public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVariable(PsiVariable variable) {
|
||||
super.visitVariable(variable);
|
||||
final PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer != null) {
|
||||
final PsiElement assignmentToken = PsiTreeUtil.skipWhitespacesBackward(initializer);
|
||||
if (assignmentToken != null) {
|
||||
checkIntersectionType(variable.getType(), initializer.getType(), assignmentToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIntersectionType(@NotNull PsiType lType, @Nullable PsiType rType, @NotNull PsiElement elementToHighlight) {
|
||||
if (rType instanceof PsiIntersectionType && TypeConversionUtil.isAssignable(lType, rType)) {
|
||||
final PsiClass psiClass = PsiUtil.resolveClassInType(lType);
|
||||
if (psiClass != null && psiClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
final PsiType[] conjuncts = ((PsiIntersectionType)rType).getConjuncts();
|
||||
for (PsiType conjunct : conjuncts) {
|
||||
if (!TypeConversionUtil.isAssignable(conjunct, lType)) {
|
||||
final String descriptionTemplate =
|
||||
JavaAnalysisBundle.message("inspection.message.javac.quick.intersection.type.problem", lType.getPresentableText(),rType.getPresentableText());
|
||||
myHolder.registerProblem(elementToHighlight, descriptionTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
if (PsiUtil.isLanguageLevel8OrHigher(expression) && expression.getTypeArguments().length == 0) {
|
||||
if (expression.getTypeArguments().length == 0) {
|
||||
PsiExpression[] args = expression.getArgumentList().getExpressions();
|
||||
JavaResolveResult resolveResult = expression.resolveMethodGenerics();
|
||||
if (resolveResult instanceof MethodCandidateInfo) {
|
||||
PsiMethod method = ((MethodCandidateInfo)resolveResult).getElement();
|
||||
if (method.isVarArgs() && method.hasTypeParameters() && args.length > method.getParameterList().getParametersCount() + 50) {
|
||||
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
|
||||
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
|
||||
if (PsiUtil.isLanguageLevel8OrHigher(expression) && method.isVarArgs() && method.hasTypeParameters() && args.length > method.getParameterList().getParametersCount() + 50) {
|
||||
for (PsiTypeParameter typeParameter : method.getTypeParameters()) {
|
||||
if (!PsiTypesUtil.isDenotableType(substitutor.substitute(typeParameter), expression)) {
|
||||
return;
|
||||
@@ -155,6 +130,31 @@ public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resolveResult.isValidResult()) {
|
||||
for (PsiType value : substitutor.getSubstitutionMap().values()) {
|
||||
if (value instanceof PsiIntersectionType) {
|
||||
PsiClass aClass = Arrays.stream(((PsiIntersectionType)value).getConjuncts())
|
||||
.map(PsiUtil::resolveClassInClassTypeOnly)
|
||||
.filter(_aClass -> _aClass != null && _aClass.hasModifierProperty(PsiModifier.FINAL))
|
||||
.findFirst().orElse(null);
|
||||
if (aClass != null && aClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
for (PsiType conjunct : ((PsiIntersectionType)value).getConjuncts()) {
|
||||
PsiClass currentClass = PsiUtil.resolveClassInClassTypeOnly(conjunct);
|
||||
if (currentClass != null &&
|
||||
!aClass.equals(currentClass) &&
|
||||
!aClass.isInheritor(currentClass, true)) {
|
||||
final String descriptionTemplate =
|
||||
JavaAnalysisBundle.message("inspection.message.javac.quick.intersection.type.problem",
|
||||
value.getPresentableText(), ObjectUtils.notNull(aClass.getQualifiedName(),
|
||||
Objects.requireNonNull(aClass.getName())));
|
||||
myHolder.registerProblem(expression.getMethodExpression(), descriptionTemplate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ class Test {
|
||||
}
|
||||
|
||||
{
|
||||
String m <warning descr="Though assignment is formal correct, it could lead to ClassCastException at runtime. Expected: 'String', actual: 'Runnable & String'">=</warning> f();
|
||||
String m = <warning descr="Intersection type 'Runnable & String' cannot be instantiated, because 'java.lang.String' is final">f</warning>();
|
||||
System.out.println(m);
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ Boolean.class, Boolean.TYPE /*,String[].class */ /*,BigDecimal.class*/);
|
||||
///////////////////////
|
||||
class Axx {
|
||||
<T extends Runnable> T a() {
|
||||
String s <warning descr="Though assignment is formal correct, it could lead to ClassCastException at runtime. Expected: 'String', actual: 'Runnable & String'">=</warning> a();
|
||||
String s = <warning descr="Intersection type 'Runnable & String' cannot be instantiated, because 'java.lang.String' is final">a</warning>();
|
||||
s.hashCode();
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user