mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] remaining must-be-throwable checks moved
Also: JavaErrorVisitor.factory() method Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: 1b006957d8e98ef4817a08232374d2504fb46b30
This commit is contained in:
committed by
intellij-monorepo-bot
parent
98ea5917a1
commit
9ac8f167bd
@@ -340,3 +340,5 @@ return.before.explicit.constructor.call='return' not allowed before ''{0}'' call
|
||||
return.value.missing=Missing return value
|
||||
return.from.void.method=Cannot return a value from a method with void result type
|
||||
return.from.constructor=Cannot return a value from a constructor
|
||||
|
||||
catch.type.parameter=Cannot catch type parameters
|
||||
|
||||
+1
-1
@@ -740,7 +740,7 @@ final class ClassChecker {
|
||||
if (isRealInnerClass(targetClass)) {
|
||||
PsiClass outerClass = targetClass.getContainingClass();
|
||||
if (outerClass != null) {
|
||||
PsiClassType outerType = JavaPsiFacade.getElementFactory(myVisitor.project()).createType(outerClass);
|
||||
PsiClassType outerType = myVisitor.factory().createType(outerClass);
|
||||
myVisitor.myExpressionChecker.checkAssignability(outerType, null, qualifier, qualifier);
|
||||
}
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -433,7 +433,7 @@ final class ExpressionChecker {
|
||||
PsiType type = processor.getType();
|
||||
if (type == null) return;
|
||||
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(processor.getProject());
|
||||
PsiElementFactory factory = myVisitor.factory();
|
||||
PsiClassType processorType = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING_TEMPLATE_PROCESSOR, processor.getResolveScope());
|
||||
if (!TypeConversionUtil.isAssignable(processorType, type)) {
|
||||
if (IncompleteModelUtil.isIncompleteModel(templateExpression) && IncompleteModelUtil.isPotentiallyConvertible(processorType, processor)) {
|
||||
|
||||
+15
-3
@@ -20,6 +20,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Objects.*;
|
||||
|
||||
final class GenericsChecker {
|
||||
private final @NotNull JavaErrorVisitor myVisitor;
|
||||
|
||||
@@ -146,11 +148,10 @@ final class GenericsChecker {
|
||||
PsiClass superClass = result.getElement();
|
||||
if (superClass == null || visited.contains(superClass)) continue;
|
||||
PsiSubstitutor superTypeSubstitutor = result.getSubstitutor();
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(aClass.getProject());
|
||||
//JLS 4.8 The superclasses (respectively, superinterfaces) of a raw type are the erasures
|
||||
// of the superclasses (superinterfaces) of any of the parameterizations of the generic type.
|
||||
superTypeSubstitutor = PsiUtil.isRawSubstitutor(aClass, derivedSubstitutor)
|
||||
? elementFactory.createRawSubstitutor(superClass)
|
||||
? myVisitor.factory().createRawSubstitutor(superClass)
|
||||
: MethodSignatureUtil.combineSubstitutors(superTypeSubstitutor, derivedSubstitutor);
|
||||
|
||||
PsiSubstitutor inheritedSubstitutor = inheritedClasses.get(superClass);
|
||||
@@ -372,8 +373,19 @@ final class GenericsChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkCatchParameterIsClass(@NotNull PsiParameter parameter) {
|
||||
if (!(parameter.getDeclarationScope() instanceof PsiCatchSection)) return;
|
||||
|
||||
List<PsiTypeElement> typeElements = PsiUtil.getParameterTypeElements(parameter);
|
||||
for (PsiTypeElement typeElement : typeElements) {
|
||||
if (PsiUtil.resolveClassInClassTypeOnly(typeElement.getType()) instanceof PsiTypeParameter) {
|
||||
myVisitor.report(JavaErrorKinds.CATCH_TYPE_PARAMETER.create(typeElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiType detectExpectedType(@NotNull PsiReferenceParameterList referenceParameterList) {
|
||||
PsiNewExpression newExpression = Objects.requireNonNull(PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class));
|
||||
PsiNewExpression newExpression = requireNonNull(PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class));
|
||||
PsiElement parent = newExpression.getParent();
|
||||
PsiType expectedType = null;
|
||||
if (parent instanceof PsiVariable psiVariable && newExpression.equals(psiVariable.getInitializer())) {
|
||||
|
||||
+13
-2
@@ -40,6 +40,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
private final @NotNull Consumer<JavaCompilationError<?, ?>> myErrorConsumer;
|
||||
private final @NotNull Project myProject;
|
||||
private final @NotNull PsiFile myFile;
|
||||
private final @NotNull PsiElementFactory myFactory;
|
||||
private final @NotNull LanguageLevel myLanguageLevel;
|
||||
private final @NotNull AnnotationChecker myAnnotationChecker = new AnnotationChecker(this);
|
||||
final @NotNull ClassChecker myClassChecker = new ClassChecker(this);
|
||||
@@ -64,6 +65,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
myJavaModule = module;
|
||||
myJavaSdkVersion = ObjectUtils
|
||||
.notNull(JavaVersionService.getInstance().getJavaSdkVersion(file), JavaSdkVersion.fromLanguageLevel(myLanguageLevel));
|
||||
myFactory = JavaPsiFacade.getElementFactory(myProject);
|
||||
}
|
||||
|
||||
void report(@NotNull JavaCompilationError<?, ?> error) {
|
||||
@@ -83,6 +85,10 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
@NotNull Project project() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
@NotNull PsiElementFactory factory() {
|
||||
return myFactory;
|
||||
}
|
||||
|
||||
@NotNull LanguageLevel languageLevel() {
|
||||
return myLanguageLevel;
|
||||
@@ -154,7 +160,9 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
if (!hasErrorResults() && parameter.getType() instanceof PsiDisjunctionType) {
|
||||
checkFeature(parameter, JavaFeature.MULTI_CATCH);
|
||||
}
|
||||
if (!hasErrorResults()) myStatementChecker.checkMustBeThrowable(parameter, parameter.getType());
|
||||
if (!hasErrorResults()) myStatementChecker.checkCatchTypeIsDisjoint(parameter);
|
||||
if (!hasErrorResults()) myGenericsChecker.checkCatchParameterIsClass(parameter);
|
||||
}
|
||||
else if (parent instanceof PsiForeachStatement forEach) {
|
||||
checkFeature(forEach, JavaFeature.FOR_EACH);
|
||||
@@ -194,8 +202,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
if (!hasErrorResults()) myClassChecker.checkEnumWithAbstractMethods(enumConstant);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkUnhandledExceptions(enumConstant);
|
||||
if (!hasErrorResults()) {
|
||||
PsiClass containingClass = requireNonNull(enumConstant.getContainingClass());
|
||||
PsiClassType type = JavaPsiFacade.getElementFactory(myProject).createType(containingClass);
|
||||
PsiClassType type = factory().createType(requireNonNull(enumConstant.getContainingClass()));
|
||||
myExpressionChecker.checkConstructorCall(type.resolveGenerics(), enumConstant, type, null);
|
||||
}
|
||||
}
|
||||
@@ -738,6 +745,9 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
@Override
|
||||
public void visitExpression(@NotNull PsiExpression expression) {
|
||||
super.visitExpression(expression);
|
||||
PsiElement parent = expression.getParent();
|
||||
// Method expression of the call should not be especially processed
|
||||
if (parent instanceof PsiMethodCallExpression) return;
|
||||
if (!hasErrorResults()) myAnnotationChecker.checkConstantExpression(expression);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkMustBeBoolean(expression);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkAssertOperatorTypes(expression);
|
||||
@@ -748,6 +758,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
if (!hasErrorResults() && expression instanceof PsiArrayAccessExpression accessExpression) {
|
||||
myExpressionChecker.checkValidArrayAccessExpression(accessExpression);
|
||||
}
|
||||
if (!hasErrorResults()) myStatementChecker.checkThrowExceptionType(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-5
@@ -49,11 +49,11 @@ final class MethodChecker {
|
||||
return signatures;
|
||||
}
|
||||
|
||||
void checkMustBeThrowable(@NotNull PsiClass aClass, @NotNull PsiElement context) {
|
||||
PsiClassType type = JavaPsiFacade.getElementFactory(aClass.getProject()).createType(aClass);
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject());
|
||||
PsiClassType throwable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, context.getResolveScope());
|
||||
if (!TypeConversionUtil.isAssignable(throwable, type)) {
|
||||
void checkMustBeThrowable(@NotNull PsiClass aClass, @NotNull PsiJavaCodeReferenceElement context) {
|
||||
if (!InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_LANG_THROWABLE)) {
|
||||
PsiElementFactory factory = myVisitor.factory();
|
||||
PsiClassType type = factory.createType(aClass);
|
||||
PsiClassType throwable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, context.getResolveScope());
|
||||
if (IncompleteModelUtil.isIncompleteModel(context) && IncompleteModelUtil.isPotentiallyConvertible(throwable, type, context)) return;
|
||||
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(context, new JavaIncompatibleTypeErrorContext(throwable, type)));
|
||||
}
|
||||
|
||||
+19
-1
@@ -195,7 +195,7 @@ final class StatementChecker {
|
||||
PsiType type = resource.getType();
|
||||
if (type == null) return;
|
||||
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(resource.getProject());
|
||||
PsiElementFactory factory = myVisitor.factory();
|
||||
PsiClassType autoCloseable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE, resource.getResolveScope());
|
||||
if (TypeConversionUtil.isAssignable(autoCloseable, type)) return;
|
||||
if (IncompleteModelUtil.isIncompleteModel(resource) && IncompleteModelUtil.isPotentiallyConvertible(autoCloseable, type, resource)) return;
|
||||
@@ -338,4 +338,22 @@ final class StatementChecker {
|
||||
var kind = isDeclarationNotAllowed ? JavaErrorKinds.STATEMENT_DECLARATION_NOT_ALLOWED : JavaErrorKinds.STATEMENT_BAD_EXPRESSION;
|
||||
myVisitor.report(kind.create(statement));
|
||||
}
|
||||
|
||||
void checkThrowExceptionType(@NotNull PsiExpression expression) {
|
||||
if (expression.getParent() instanceof PsiThrowStatement statement && statement.getException() == expression) {
|
||||
PsiType type = expression.getType();
|
||||
checkMustBeThrowable(expression, type);
|
||||
}
|
||||
}
|
||||
|
||||
void checkMustBeThrowable(@NotNull PsiElement context, PsiType type) {
|
||||
if (type != null && !InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_THROWABLE)) {
|
||||
PsiElementFactory factory = myVisitor.factory();
|
||||
PsiClassType throwable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, context.getResolveScope());
|
||||
if (!(IncompleteModelUtil.isIncompleteModel(context) &&
|
||||
IncompleteModelUtil.isPotentiallyConvertible(throwable, type, context))) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(context, new JavaIncompatibleTypeErrorContext(throwable, type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -629,6 +629,8 @@ public final class JavaErrorKinds {
|
||||
public static final Simple<PsiBreakStatement> BREAK_OUT_OF_SWITCH_EXPRESSION = error("break.out.of.switch.expression");
|
||||
public static final Simple<PsiContinueStatement> CONTINUE_OUTSIDE_LOOP = error("continue.outside.loop");
|
||||
public static final Simple<PsiContinueStatement> CONTINUE_OUT_OF_SWITCH_EXPRESSION = error("continue.out.of.switch.expression");
|
||||
|
||||
public static final Simple<PsiTypeElement> CATCH_TYPE_PARAMETER = error("catch.type.parameter");
|
||||
|
||||
public static final Parameterized<PsiExpression, PsiType> ARRAY_ILLEGAL_INITIALIZER =
|
||||
parameterized(PsiExpression.class, PsiType.class, "array.illegal.initializer")
|
||||
|
||||
-13
@@ -778,19 +778,6 @@ public final class GenericsHighlightUtil {
|
||||
return enumClass != null && enumClass.isEnum() ? enumClass : null;
|
||||
}
|
||||
|
||||
static void checkCatchParameterIsClass(@NotNull PsiParameter parameter, @NotNull Consumer<? super HighlightInfo.Builder> errorSink) {
|
||||
if (!(parameter.getDeclarationScope() instanceof PsiCatchSection)) return;
|
||||
|
||||
List<PsiTypeElement> typeElements = PsiUtil.getParameterTypeElements(parameter);
|
||||
for (PsiTypeElement typeElement : typeElements) {
|
||||
PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(typeElement.getType());
|
||||
if (aClass instanceof PsiTypeParameter) {
|
||||
String message = JavaErrorBundle.message("generics.cannot.catch.type.parameters");
|
||||
errorSink.accept(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkInstanceOfGenericType(@NotNull LanguageLevel languageLevel, @NotNull PsiInstanceOfExpression expression) {
|
||||
PsiTypeElement checkTypeElement = InstanceOfUtils.findCheckTypeElement(expression);
|
||||
if (checkTypeElement == null) return null;
|
||||
|
||||
-32
@@ -761,14 +761,6 @@ public final class HighlightUtil {
|
||||
return container == null ? "?" : HighlightMessageUtil.getSymbolName(container, substitutor);
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkCatchParameterIsThrowable(@NotNull PsiParameter parameter) {
|
||||
if (parameter.getDeclarationScope() instanceof PsiCatchSection) {
|
||||
PsiType type = parameter.getType();
|
||||
return checkMustBeThrowable(type, parameter, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkResourceVariableIsFinal(@NotNull PsiResourceExpression resource) {
|
||||
PsiExpression expression = resource.getExpression();
|
||||
|
||||
@@ -1357,30 +1349,6 @@ public final class HighlightUtil {
|
||||
}
|
||||
|
||||
|
||||
static HighlightInfo.Builder checkMustBeThrowable(@NotNull PsiType type, @NotNull PsiElement context, boolean addCastIntention) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject());
|
||||
PsiClassType throwable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, context.getResolveScope());
|
||||
if (!TypeConversionUtil.isAssignable(throwable, type)) {
|
||||
if (IncompleteModelUtil.isIncompleteModel(context) && IncompleteModelUtil.isPotentiallyConvertible(throwable, type, context)) return null;
|
||||
HighlightInfo.Builder highlightInfo = createIncompatibleTypeHighlightInfo(throwable, type, context.getTextRange(), 0);
|
||||
if (addCastIntention && TypeConversionUtil.areTypesConvertible(type, throwable)) {
|
||||
if (context instanceof PsiExpression) {
|
||||
IntentionAction action = getFixFactory().createAddTypeCastFix(throwable, (PsiExpression)context);
|
||||
highlightInfo.registerFix(action, null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(type);
|
||||
if (aClass != null) {
|
||||
IntentionAction action = getFixFactory().createExtendsListFix(aClass, throwable, true);
|
||||
highlightInfo.registerFix(action, null, null, null, null);
|
||||
}
|
||||
return highlightInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static HighlightInfo.Builder checkReference(@NotNull PsiJavaCodeReferenceElement ref,
|
||||
@NotNull JavaResolveResult result,
|
||||
@NotNull PsiFile containingFile,
|
||||
|
||||
-17
@@ -478,12 +478,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (!hasErrorResults()) add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression, myFile));
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkVariableExpected(expression));
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkConditionalExpressionBranchTypesMatch(expression, type));
|
||||
if (!hasErrorResults() &&
|
||||
parent instanceof PsiThrowStatement statement &&
|
||||
statement.getException() == expression &&
|
||||
type != null) {
|
||||
add(HighlightUtil.checkMustBeThrowable(type, expression, true));
|
||||
}
|
||||
if (!hasErrorResults() && shouldReportForeachNotApplicable(expression)) {
|
||||
add(GenericsHighlightUtil.checkForeachExpressionTypeIsIterable(expression));
|
||||
}
|
||||
@@ -680,17 +674,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
if (!hasErrorResults()) add(HighlightControlFlowUtil.checkRecordComponentInitialized(recordComponent));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParameter(@NotNull PsiParameter parameter) {
|
||||
super.visitParameter(parameter);
|
||||
|
||||
PsiElement parent = parameter.getParent();
|
||||
if (parent instanceof PsiCatchSection) {
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkCatchParameterIsThrowable(parameter));
|
||||
if (!hasErrorResults()) GenericsHighlightUtil.checkCatchParameterIsClass(parameter, myErrorSink);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) {
|
||||
super.visitReferenceElement(ref);
|
||||
|
||||
+7
-7
@@ -23,16 +23,16 @@ class a60
|
||||
{
|
||||
public void test() throws <error descr="Incompatible types. Found: 'MyException', required: 'java.lang.Throwable'">MyException</error>
|
||||
{
|
||||
throw <error descr="Incompatible types. Found: 'MyException', required: 'java.lang.Throwable'">new MyException()</error>;
|
||||
throw new <error descr="Incompatible types. Found: 'MyException', required: 'java.lang.Throwable'">MyException</error>();
|
||||
}
|
||||
public void test(int i) {
|
||||
switch (i) {
|
||||
case 1: throw <error descr="Incompatible types. Found: 'boolean', required: 'java.lang.Throwable'">false</error>;
|
||||
case 2: throw <error descr="Incompatible types. Found: 'int', required: 'java.lang.Throwable'">1</error>;
|
||||
case 3: throw <error descr="Incompatible types. Found: 'double', required: 'java.lang.Throwable'">1.0</error>;
|
||||
case 4: throw <error descr="Incompatible types. Found: 'char', required: 'java.lang.Throwable'">'a'</error>;
|
||||
case 5: throw <error descr="Incompatible types. Found: 'long', required: 'java.lang.Throwable'">1L</error>;
|
||||
case 6: throw <error descr="Incompatible types. Found: 'float', required: 'java.lang.Throwable'">1.0f</error>;
|
||||
case 1: throw <error descr="Incompatible types. Found: 'boolean', required: 'java.lang.Throwable'">false;</error>
|
||||
case 2: throw <error descr="Incompatible types. Found: 'int', required: 'java.lang.Throwable'">1;</error>
|
||||
case 3: throw <error descr="Incompatible types. Found: 'double', required: 'java.lang.Throwable'">1.0;</error>
|
||||
case 4: throw <error descr="Incompatible types. Found: 'char', required: 'java.lang.Throwable'">'a';</error>
|
||||
case 5: throw <error descr="Incompatible types. Found: 'long', required: 'java.lang.Throwable'">1L;</error>
|
||||
case 6: throw <error descr="Incompatible types. Found: 'float', required: 'java.lang.Throwable'">1.0f;</error>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user