mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] type-related errors, lvti-related errors, TypeChecker introduced
Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: 126dfbfe5a1046072d520e9a8f57261ff7add384
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f912c93cec
commit
a157ee801e
@@ -186,6 +186,18 @@ type.incompatible.reason.inference=<br/>reason: {0}
|
||||
type.void.not.allowed='void' type is not allowed here
|
||||
type.void.illegal=Illegal type: 'void'
|
||||
type.inaccessible=''{0}'' is inaccessible here
|
||||
type.unknown.class=Unknown class: ''{0}''
|
||||
type.argument.primitive=Type argument cannot be of a primitive type
|
||||
type.wildcard.cannot.be.instantiated=Wildcard type ''{0}'' cannot be instantiated directly
|
||||
type.wildcard.not.expected=No wildcard expected
|
||||
type.wildcard.may.be.used.only.as.reference.parameters=Wildcards may be used only as reference parameters
|
||||
|
||||
lvti.no.initializer=Cannot infer type: 'var' on variable without initializer
|
||||
lvti.lambda=Cannot infer type: lambda expression requires an explicit target type
|
||||
lvti.method.reference=Cannot infer type: method reference requires an explicit target type
|
||||
lvti.array='var' is not allowed as an element type of an array
|
||||
lvti.null=Cannot infer type: variable initializer is 'null'
|
||||
lvti.void=Cannot infer type: variable initializer is 'void'
|
||||
|
||||
label.without.statement=Label without statement
|
||||
label.duplicate=Label ''{0}'' already in use
|
||||
@@ -197,6 +209,8 @@ break.out.of.switch.expression=Break out of switch expression is not allowed
|
||||
continue.outside.loop='continue' statement outside of loop
|
||||
continue.out.of.switch.expression=Continue out of switch expression is not allowed
|
||||
|
||||
foreach.not.applicable=Foreach not applicable to type ''{0}''
|
||||
|
||||
new.expression.qualified.malformed=Invalid qualified new
|
||||
new.expression.qualified.static.class=Qualified new of static class
|
||||
new.expression.qualified.anonymous.implements.interface=Anonymous class implements interface; cannot have qualifier for new
|
||||
@@ -282,6 +296,7 @@ array.type.expected=Array type expected; found: ''{0}''
|
||||
array.generic=Generic array creation not allowed
|
||||
array.empty.diamond=Array creation with '<>' not allowed
|
||||
array.type.arguments=Array creation with type arguments not allowed
|
||||
array.too.many.dimensions=Too many array dimensions
|
||||
|
||||
pattern.type.pattern.expected=Type pattern expected
|
||||
|
||||
|
||||
+1
-51
@@ -155,31 +155,6 @@ final class ExpressionChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkIllegalVoidType(@NotNull PsiKeyword type) {
|
||||
if (!PsiKeyword.VOID.equals(type.getText())) return;
|
||||
|
||||
PsiElement parent = type.getParent();
|
||||
if (parent instanceof PsiErrorElement) return;
|
||||
if (parent instanceof PsiTypeElement) {
|
||||
PsiElement typeOwner = parent.getParent();
|
||||
if (typeOwner != null) {
|
||||
// do not highlight incomplete declarations
|
||||
if (PsiUtilCore.hasErrorElementChild(typeOwner)) return;
|
||||
}
|
||||
|
||||
if (typeOwner instanceof PsiMethod method) {
|
||||
if (method.getReturnTypeElement() == parent && PsiTypes.voidType().equals(method.getReturnType())) return;
|
||||
}
|
||||
else if (typeOwner instanceof PsiClassObjectAccessExpression classAccess) {
|
||||
if (TypeConversionUtil.isVoidType(classAccess.getOperand().getType())) return;
|
||||
}
|
||||
else if (typeOwner instanceof JavaCodeFragment) {
|
||||
if (typeOwner.getUserData(PsiUtil.VALID_VOID_TYPE_IN_CODE_FRAGMENT) != null) return;
|
||||
}
|
||||
}
|
||||
myVisitor.report(JavaErrorKinds.TYPE_VOID_ILLEGAL.create(type));
|
||||
}
|
||||
|
||||
void checkMustBeBoolean(@NotNull PsiExpression expr) {
|
||||
PsiElement parent = expr.getParent();
|
||||
if (parent instanceof PsiIfStatement ||
|
||||
@@ -199,31 +174,6 @@ final class ExpressionChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkAssertOperatorTypes(@NotNull PsiExpression expression) {
|
||||
if (!(expression.getParent() instanceof PsiAssertStatement assertStatement)) return;
|
||||
PsiType type = expression.getType();
|
||||
if (type == null) return;
|
||||
if (expression == assertStatement.getAssertCondition() && !TypeConversionUtil.isBooleanType(type)) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
|
||||
expression, new JavaIncompatibleTypeErrorContext(PsiTypes.booleanType(), type)));
|
||||
}
|
||||
else if (expression == assertStatement.getAssertDescription() && TypeConversionUtil.isVoidType(type)) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_VOID_NOT_ALLOWED.create(expression));
|
||||
}
|
||||
}
|
||||
|
||||
void checkSynchronizedExpressionType(@NotNull PsiExpression expression) {
|
||||
if (expression.getParent() instanceof PsiSynchronizedStatement synchronizedStatement &&
|
||||
expression == synchronizedStatement.getLockExpression()) {
|
||||
PsiType type = expression.getType();
|
||||
if (type == null) return;
|
||||
if (type instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(type)) {
|
||||
PsiClassType objectType = PsiType.getJavaLangObject(myVisitor.file().getManager(), expression.getResolveScope());
|
||||
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(expression, new JavaIncompatibleTypeErrorContext(objectType, type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkArrayInitializer(@NotNull PsiExpression initializer, @NotNull PsiArrayInitializerExpression initializerList) {
|
||||
PsiType arrayType = initializerList.getType();
|
||||
if (!(arrayType instanceof PsiArrayType theArrayType)) return;
|
||||
@@ -754,7 +704,7 @@ final class ExpressionChecker {
|
||||
myVisitor.report(JavaErrorKinds.EXCEPTION_UNHANDLED_CLOSE.create(resource, unhandled));
|
||||
}
|
||||
|
||||
private static boolean isArrayDeclaration(@NotNull PsiVariable variable) {
|
||||
static boolean isArrayDeclaration(@NotNull PsiVariable variable) {
|
||||
// Java-style 'var' arrays are prohibited by the parser; for C-style ones, looking for a bracket is enough
|
||||
return ContainerUtil.or(variable.getChildren(), e -> PsiUtil.isJavaToken(e, JavaTokenType.LBRACKET));
|
||||
}
|
||||
|
||||
+36
@@ -384,6 +384,42 @@ final class GenericsChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkReferenceTypeUsedAsTypeArgument(@NotNull PsiTypeElement typeElement) {
|
||||
PsiType type = typeElement.getType();
|
||||
PsiType wildCardBind = type instanceof PsiWildcardType wildcardType ? wildcardType.getBound() : null;
|
||||
if (type != PsiTypes.nullType() && type instanceof PsiPrimitiveType || wildCardBind instanceof PsiPrimitiveType) {
|
||||
if (!(typeElement.getParent() instanceof PsiReferenceParameterList list)) return;
|
||||
PsiElement parent = list.getParent();
|
||||
if (!(parent instanceof PsiJavaCodeReferenceElement) && !(parent instanceof PsiNewExpression)) return;
|
||||
myVisitor.report(JavaErrorKinds.TYPE_ARGUMENT_PRIMITIVE.create(typeElement));
|
||||
}
|
||||
}
|
||||
|
||||
void checkWildcardUsage(@NotNull PsiTypeElement typeElement) {
|
||||
PsiType type = typeElement.getType();
|
||||
if (type instanceof PsiWildcardType) {
|
||||
if (typeElement.getParent() instanceof PsiReferenceParameterList) {
|
||||
PsiElement parent = typeElement.getParent().getParent();
|
||||
PsiElement refParent = parent.getParent();
|
||||
if (refParent instanceof PsiAnonymousClass) refParent = refParent.getParent();
|
||||
if (refParent instanceof PsiNewExpression newExpression) {
|
||||
if (!(newExpression.getType() instanceof PsiArrayType)) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_WILDCARD_CANNOT_BE_INSTANTIATED.create(typeElement));
|
||||
}
|
||||
}
|
||||
else if (refParent instanceof PsiReferenceList) {
|
||||
PsiElement refPParent = refParent.getParent();
|
||||
if (!(refPParent instanceof PsiTypeParameter typeParameter) || refParent != typeParameter.getExtendsList()) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_WILDCARD_NOT_EXPECTED.create(typeElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!typeElement.isInferredType()){
|
||||
myVisitor.report(JavaErrorKinds.TYPE_WILDCARD_MAY_BE_USED_ONLY_AS_REFERENCE_PARAMETERS.create(typeElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiType detectExpectedType(@NotNull PsiReferenceParameterList referenceParameterList) {
|
||||
PsiNewExpression newExpression = requireNonNull(PsiTreeUtil.getParentOfType(referenceParameterList, PsiNewExpression.class));
|
||||
PsiElement parent = newExpression.getParent();
|
||||
|
||||
+19
-5
@@ -47,6 +47,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
private final @NotNull RecordChecker myRecordChecker = new RecordChecker(this);
|
||||
private final @NotNull ImportChecker myImportChecker = new ImportChecker(this);
|
||||
final @NotNull GenericsChecker myGenericsChecker = new GenericsChecker(this);
|
||||
final @NotNull TypeChecker myTypeChecker = new TypeChecker(this);
|
||||
final @NotNull MethodChecker myMethodChecker = new MethodChecker(this);
|
||||
private final @NotNull ReceiverChecker myReceiverChecker = new ReceiverChecker(this);
|
||||
final @NotNull ModifierChecker myModifierChecker = new ModifierChecker(this);
|
||||
@@ -147,6 +148,16 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
if (!hasErrorResults()) myStatementChecker.checkContinueTarget(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeElement(@NotNull PsiTypeElement type) {
|
||||
super.visitTypeElement(type);
|
||||
if (!hasErrorResults()) myTypeChecker.checkIllegalType(type);
|
||||
if (!hasErrorResults()) myTypeChecker.checkVarTypeApplicability(type);
|
||||
if (!hasErrorResults()) myTypeChecker.checkArrayType(type);
|
||||
if (!hasErrorResults()) myGenericsChecker.checkReferenceTypeUsedAsTypeArgument(type);
|
||||
if (!hasErrorResults()) myGenericsChecker.checkWildcardUsage(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitParameter(@NotNull PsiParameter parameter) {
|
||||
super.visitParameter(parameter);
|
||||
@@ -160,7 +171,7 @@ 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()) myTypeChecker.checkMustBeThrowable(parameter, parameter.getType());
|
||||
if (!hasErrorResults()) myStatementChecker.checkCatchTypeIsDisjoint(parameter);
|
||||
if (!hasErrorResults()) myGenericsChecker.checkCatchParameterIsClass(parameter);
|
||||
}
|
||||
@@ -461,7 +472,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
public void visitKeyword(@NotNull PsiKeyword keyword) {
|
||||
super.visitKeyword(keyword);
|
||||
if (!hasErrorResults()) myClassChecker.checkStaticDeclarationInInnerClass(keyword);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkIllegalVoidType(keyword);
|
||||
if (!hasErrorResults()) myTypeChecker.checkIllegalVoidType(keyword);
|
||||
PsiElement parent = keyword.getParent();
|
||||
if (parent instanceof PsiModifierList psiModifierList) {
|
||||
if (!hasErrorResults()) myModifierChecker.checkNotAllowedModifier(keyword, psiModifierList);
|
||||
@@ -750,15 +761,18 @@ final class JavaErrorVisitor extends JavaElementVisitor {
|
||||
if (parent instanceof PsiMethodCallExpression) return;
|
||||
if (!hasErrorResults()) myAnnotationChecker.checkConstantExpression(expression);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkMustBeBoolean(expression);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkAssertOperatorTypes(expression);
|
||||
if (!hasErrorResults()) myExpressionChecker.checkSynchronizedExpressionType(expression);
|
||||
if (!hasErrorResults()) myStatementChecker.checkAssertStatementTypes(expression);
|
||||
if (!hasErrorResults()) myStatementChecker.checkSynchronizedStatementType(expression);
|
||||
if (expression.getParent() instanceof PsiArrayInitializerExpression arrayInitializer) {
|
||||
if (!hasErrorResults()) myExpressionChecker.checkArrayInitializer(expression, arrayInitializer);
|
||||
}
|
||||
if (!hasErrorResults() && expression instanceof PsiArrayAccessExpression accessExpression) {
|
||||
myExpressionChecker.checkValidArrayAccessExpression(accessExpression);
|
||||
}
|
||||
if (!hasErrorResults()) myStatementChecker.checkThrowExceptionType(expression);
|
||||
if (!hasErrorResults() && expression.getParent() instanceof PsiThrowStatement statement && statement.getException() == expression) {
|
||||
myTypeChecker.checkMustBeThrowable(expression, expression.getType());
|
||||
}
|
||||
if (!hasErrorResults()) myStatementChecker.checkForeachExpressionTypeIsIterable(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+39
-11
@@ -2,6 +2,7 @@
|
||||
package com.intellij.java.codeserver.highlighting;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.core.JavaPsiBundle;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
|
||||
@@ -81,6 +82,26 @@ final class StatementChecker {
|
||||
}
|
||||
}
|
||||
|
||||
void checkForeachExpressionTypeIsIterable(@NotNull PsiExpression expression) {
|
||||
if (!shouldReportForeachNotApplicable(expression)) return;
|
||||
if (expression.getType() == null) return;
|
||||
PsiType itemType = JavaGenericsUtil.getCollectionItemType(expression);
|
||||
if (itemType == null) {
|
||||
myVisitor.report(JavaErrorKinds.FOREACH_NOT_APPLICABLE.create(expression));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldReportForeachNotApplicable(@NotNull PsiExpression expression) {
|
||||
if (!(expression.getParent() instanceof PsiForeachStatementBase parentForEach)) return false;
|
||||
|
||||
PsiExpression iteratedValue = parentForEach.getIteratedValue();
|
||||
if (iteratedValue != expression) return false;
|
||||
|
||||
// Ignore if the type of the value which is being iterated over is not resolved yet
|
||||
PsiType iteratedValueType = iteratedValue.getType();
|
||||
return iteratedValueType == null || !PsiTypesUtil.hasUnresolvedComponents(iteratedValueType);
|
||||
}
|
||||
|
||||
void checkCatchTypeIsDisjoint(@NotNull PsiParameter parameter) {
|
||||
if (!(parameter.getType() instanceof PsiDisjunctionType)) return;
|
||||
|
||||
@@ -339,20 +360,27 @@ final class StatementChecker {
|
||||
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 checkAssertStatementTypes(@NotNull PsiExpression expression) {
|
||||
if (!(expression.getParent() instanceof PsiAssertStatement assertStatement)) return;
|
||||
PsiType type = expression.getType();
|
||||
if (type == null) return;
|
||||
if (expression == assertStatement.getAssertCondition() && !TypeConversionUtil.isBooleanType(type)) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(
|
||||
expression, new JavaIncompatibleTypeErrorContext(PsiTypes.booleanType(), type)));
|
||||
}
|
||||
else if (expression == assertStatement.getAssertDescription() && TypeConversionUtil.isVoidType(type)) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_VOID_NOT_ALLOWED.create(expression));
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
void checkSynchronizedStatementType(@NotNull PsiExpression expression) {
|
||||
if (expression.getParent() instanceof PsiSynchronizedStatement synchronizedStatement &&
|
||||
expression == synchronizedStatement.getLockExpression()) {
|
||||
PsiType type = expression.getType();
|
||||
if (type == null) return;
|
||||
if (type instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(type)) {
|
||||
PsiClassType objectType = PsiType.getJavaLangObject(myVisitor.file().getManager(), expression.getResolveScope());
|
||||
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(expression, new JavaIncompatibleTypeErrorContext(objectType, type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
// 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.codeserver.highlighting;
|
||||
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
|
||||
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.IncompleteModelUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
|
||||
final class TypeChecker {
|
||||
private final @NotNull JavaErrorVisitor myVisitor;
|
||||
|
||||
TypeChecker(@NotNull JavaErrorVisitor visitor) { myVisitor = visitor; }
|
||||
|
||||
void checkIllegalType(@NotNull PsiTypeElement typeElement) {
|
||||
PsiElement parent = typeElement.getParent();
|
||||
if (parent instanceof PsiTypeElement) return;
|
||||
|
||||
if (PsiUtil.isInsideJavadocComment(typeElement)) return;
|
||||
|
||||
PsiType type = typeElement.getType();
|
||||
PsiType componentType = type.getDeepComponentType();
|
||||
if (componentType instanceof PsiClassType) {
|
||||
PsiClass aClass = PsiUtil.resolveClassInType(componentType);
|
||||
if (aClass == null) {
|
||||
if (typeElement.isInferredType() && parent instanceof PsiLocalVariable localVariable) {
|
||||
PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(localVariable.getInitializer());
|
||||
if (initializer instanceof PsiNewExpression) {
|
||||
// The problem is already reported on the initializer
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (IncompleteModelUtil.isIncompleteModel(myVisitor.file())) return;
|
||||
myVisitor.report(JavaErrorKinds.TYPE_UNKNOWN_CLASS.create(typeElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkVarTypeApplicability(@NotNull PsiTypeElement typeElement) {
|
||||
if (!typeElement.isInferredType()) return;
|
||||
PsiElement parent = typeElement.getParent();
|
||||
PsiVariable variable = tryCast(parent, PsiVariable.class);
|
||||
if (variable instanceof PsiLocalVariable localVariable) {
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer == null) {
|
||||
if (PsiUtilCore.hasErrorElementChild(variable)) return;
|
||||
myVisitor.report(JavaErrorKinds.LVTI_NO_INITIALIZER.create(localVariable));
|
||||
return;
|
||||
}
|
||||
PsiExpression deparen = PsiUtil.skipParenthesizedExprDown(initializer);
|
||||
if (deparen instanceof PsiFunctionalExpression) {
|
||||
var kind = deparen instanceof PsiLambdaExpression ? JavaErrorKinds.LVTI_LAMBDA : JavaErrorKinds.LVTI_METHOD_REFERENCE;
|
||||
myVisitor.report(kind.create(localVariable));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ExpressionChecker.isArrayDeclaration(variable)) {
|
||||
myVisitor.report(JavaErrorKinds.LVTI_ARRAY.create(localVariable));
|
||||
return;
|
||||
}
|
||||
|
||||
PsiType lType = variable.getType();
|
||||
if (PsiTypes.nullType().equals(lType) && allChildrenAreNullLiterals(initializer)) {
|
||||
myVisitor.report(JavaErrorKinds.LVTI_NULL.create(localVariable));
|
||||
return;
|
||||
}
|
||||
if (PsiTypes.voidType().equals(lType)) {
|
||||
myVisitor.report(JavaErrorKinds.LVTI_VOID.create(localVariable));
|
||||
}
|
||||
}
|
||||
else if (variable instanceof PsiParameter && variable.getParent() instanceof PsiParameterList &&
|
||||
ExpressionChecker.isArrayDeclaration(variable)) {
|
||||
myVisitor.report(JavaErrorKinds.LVTI_ARRAY.create(variable));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean allChildrenAreNullLiterals(PsiExpression expression) {
|
||||
expression = PsiUtil.skipParenthesizedExprDown(expression);
|
||||
if (expression == null) return false;
|
||||
if (expression instanceof PsiLiteralExpression literal && PsiTypes.nullType().equals(literal.getType())) return true;
|
||||
if (expression instanceof PsiTypeCastExpression cast) {
|
||||
return allChildrenAreNullLiterals(cast.getOperand());
|
||||
}
|
||||
if (expression instanceof PsiConditionalExpression conditional) {
|
||||
return allChildrenAreNullLiterals(conditional.getThenExpression()) &&
|
||||
allChildrenAreNullLiterals(conditional.getElseExpression());
|
||||
}
|
||||
if (expression instanceof PsiSwitchExpression switchExpression) {
|
||||
PsiCodeBlock switchBody = switchExpression.getBody();
|
||||
if (switchBody == null) return false;
|
||||
PsiStatement[] statements = switchBody.getStatements();
|
||||
for (PsiStatement statement : statements) {
|
||||
if (statement instanceof PsiSwitchLabeledRuleStatement rule) {
|
||||
PsiStatement ruleBody = rule.getBody();
|
||||
if (ruleBody instanceof PsiBlockStatement blockStatement) {
|
||||
for (PsiYieldStatement yield : PsiTreeUtil.findChildrenOfType(blockStatement, PsiYieldStatement.class)) {
|
||||
if (yield.findEnclosingExpression() == switchExpression && !allChildrenAreNullLiterals(yield.getExpression())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ruleBody instanceof PsiExpressionStatement expr) {
|
||||
if (!allChildrenAreNullLiterals(expr.getExpression())) return false;
|
||||
}
|
||||
}
|
||||
else if (statement instanceof PsiYieldStatement yield) {
|
||||
if (!allChildrenAreNullLiterals(yield.getExpression())) return false;
|
||||
}
|
||||
else {
|
||||
for (PsiYieldStatement yield : PsiTreeUtil.findChildrenOfType(statement, PsiYieldStatement.class)) {
|
||||
if (yield.findEnclosingExpression() == switchExpression && !allChildrenAreNullLiterals(yield.getExpression())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void checkArrayType(@NotNull PsiTypeElement type) {
|
||||
int dimensions = 0;
|
||||
for (PsiElement child = type.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (PsiUtil.isJavaToken(child, JavaTokenType.LBRACKET)) {
|
||||
dimensions++;
|
||||
}
|
||||
}
|
||||
if (dimensions > 255) {
|
||||
// JVM Specification, 4.3.2: no more than 255 dimensions allowed
|
||||
myVisitor.report(JavaErrorKinds.ARRAY_TOO_MANY_DIMENSIONS.create(type));
|
||||
}
|
||||
}
|
||||
|
||||
void checkIllegalVoidType(@NotNull PsiKeyword type) {
|
||||
if (!PsiKeyword.VOID.equals(type.getText())) return;
|
||||
|
||||
PsiElement parent = type.getParent();
|
||||
if (parent instanceof PsiErrorElement) return;
|
||||
if (parent instanceof PsiTypeElement) {
|
||||
PsiElement typeOwner = parent.getParent();
|
||||
if (typeOwner != null) {
|
||||
// do not highlight incomplete declarations
|
||||
if (PsiUtilCore.hasErrorElementChild(typeOwner)) return;
|
||||
}
|
||||
|
||||
if (typeOwner instanceof PsiMethod method) {
|
||||
if (method.getReturnTypeElement() == parent && PsiTypes.voidType().equals(method.getReturnType())) return;
|
||||
}
|
||||
else if (typeOwner instanceof PsiClassObjectAccessExpression classAccess) {
|
||||
if (TypeConversionUtil.isVoidType(classAccess.getOperand().getType())) return;
|
||||
}
|
||||
else if (typeOwner instanceof JavaCodeFragment) {
|
||||
if (typeOwner.getUserData(PsiUtil.VALID_VOID_TYPE_IN_CODE_FRAGMENT) != null) return;
|
||||
}
|
||||
}
|
||||
myVisitor.report(JavaErrorKinds.TYPE_VOID_ILLEGAL.create(type));
|
||||
}
|
||||
|
||||
void checkMustBeThrowable(@NotNull PsiElement context, PsiType type) {
|
||||
PsiElementFactory factory = myVisitor.factory();
|
||||
PsiClassType throwable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_THROWABLE, context.getResolveScope());
|
||||
if (type != null && !TypeConversionUtil.isAssignable(throwable, type)) {
|
||||
if (!(IncompleteModelUtil.isIncompleteModel(context) &&
|
||||
IncompleteModelUtil.isPotentiallyConvertible(throwable, type, context))) {
|
||||
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(context, new JavaIncompatibleTypeErrorContext(throwable, type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -8,6 +8,8 @@ import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A concrete instance of a Java compilation error. Note that the instance is bound to a PSI element, so it should not
|
||||
* outlive the read-action. Otherwise it may become invalid.
|
||||
@@ -75,4 +77,23 @@ public record JavaCompilationError<Psi extends PsiElement, Context>(@NotNull Jav
|
||||
public @NotNull HtmlChunk tooltip() {
|
||||
return kind.tooltip(psi, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to match wanted error message and extract PSI without doing unchecked casts in client code.
|
||||
*
|
||||
* @param kinds wanted error kinds
|
||||
* @return an optional containing typed {@link #psi()} if the current error is one of supplied kinds;
|
||||
* empty optional otherwise
|
||||
* @param <WantedPsi> the common PSI type of wanted kinds
|
||||
*/
|
||||
@SafeVarargs
|
||||
public final <WantedPsi extends PsiElement> @NotNull Optional<WantedPsi> psiForKind(JavaErrorKind<? extends WantedPsi, ?>... kinds) {
|
||||
for (JavaErrorKind<? extends WantedPsi, ?> errorKind : kinds) {
|
||||
if (errorKind.equals(kind)) {
|
||||
//noinspection unchecked
|
||||
return Optional.of((WantedPsi)psi);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -613,6 +613,31 @@ public final class JavaErrorKinds {
|
||||
public static final Parameterized<PsiElement, PsiClass> TYPE_INACCESSIBLE =
|
||||
parameterized(PsiElement.class, PsiClass.class, "type.inaccessible")
|
||||
.withRawDescription((psi, cls) -> message("type.inaccessible", formatClass(cls)));
|
||||
public static final Simple<PsiTypeElement> TYPE_UNKNOWN_CLASS = error(PsiTypeElement.class, "type.unknown.class")
|
||||
.withRawDescription(type -> message("type.unknown.class", type.getType().getDeepComponentType().getCanonicalText()));
|
||||
public static final Simple<PsiTypeElement> TYPE_ARGUMENT_PRIMITIVE = error(PsiTypeElement.class, "type.argument.primitive");
|
||||
public static final Simple<PsiTypeElement> TYPE_WILDCARD_NOT_EXPECTED = error(PsiTypeElement.class, "type.wildcard.not.expected");
|
||||
public static final Simple<PsiTypeElement> TYPE_WILDCARD_MAY_BE_USED_ONLY_AS_REFERENCE_PARAMETERS =
|
||||
error(PsiTypeElement.class, "type.wildcard.may.be.used.only.as.reference.parameters");
|
||||
public static final Simple<PsiTypeElement> TYPE_WILDCARD_CANNOT_BE_INSTANTIATED =
|
||||
error(PsiTypeElement.class, "type.wildcard.cannot.be.instantiated")
|
||||
.withRawDescription(type -> message("type.wildcard.cannot.be.instantiated", formatType(type.getType())));
|
||||
|
||||
public static final Simple<PsiExpression> FOREACH_NOT_APPLICABLE = error(PsiExpression.class, "foreach.not.applicable")
|
||||
.withRawDescription(expression -> message("foreach.not.applicable", formatType(expression.getType())));
|
||||
|
||||
public static final Simple<PsiLocalVariable> LVTI_NO_INITIALIZER = error(PsiLocalVariable.class, "lvti.no.initializer")
|
||||
.withAnchor(var -> var.getTypeElement());
|
||||
public static final Simple<PsiLocalVariable> LVTI_VOID = error(PsiLocalVariable.class, "lvti.void")
|
||||
.withAnchor(var -> var.getTypeElement());
|
||||
public static final Simple<PsiLocalVariable> LVTI_NULL = error(PsiLocalVariable.class, "lvti.null")
|
||||
.withAnchor(var -> var.getTypeElement());
|
||||
public static final Simple<PsiLocalVariable> LVTI_LAMBDA = error(PsiLocalVariable.class, "lvti.lambda")
|
||||
.withAnchor(var -> var.getTypeElement());
|
||||
public static final Simple<PsiLocalVariable> LVTI_METHOD_REFERENCE = error(PsiLocalVariable.class, "lvti.method.reference")
|
||||
.withAnchor(var -> var.getTypeElement());
|
||||
public static final Simple<PsiVariable> LVTI_ARRAY = error(PsiVariable.class, "lvti.array")
|
||||
.withAnchor(var -> var.getTypeElement());
|
||||
|
||||
public static final Simple<PsiLabeledStatement> LABEL_WITHOUT_STATEMENT = error(PsiLabeledStatement.class, "label.without.statement")
|
||||
.withAnchor(label -> label.getLabelIdentifier());
|
||||
@@ -642,6 +667,7 @@ public final class JavaErrorKinds {
|
||||
public static final Simple<PsiElement> ARRAY_GENERIC = error("array.generic");
|
||||
public static final Simple<PsiReferenceParameterList> ARRAY_EMPTY_DIAMOND = error("array.empty.diamond");
|
||||
public static final Simple<PsiReferenceParameterList> ARRAY_TYPE_ARGUMENTS = error("array.type.arguments");
|
||||
public static final Simple<PsiTypeElement> ARRAY_TOO_MANY_DIMENSIONS = error("array.too.many.dimensions");
|
||||
|
||||
public static final Parameterized<PsiReferenceExpression, PsiClass> PATTERN_TYPE_PATTERN_EXPECTED =
|
||||
parameterized("pattern.type.pattern.expected");
|
||||
|
||||
-73
@@ -644,79 +644,6 @@ public final class GenericsHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkWildcardUsage(@NotNull PsiTypeElement typeElement) {
|
||||
PsiType type = typeElement.getType();
|
||||
if (type instanceof PsiWildcardType) {
|
||||
if (typeElement.getParent() instanceof PsiReferenceParameterList) {
|
||||
PsiElement parent = typeElement.getParent().getParent();
|
||||
LOG.assertTrue(parent instanceof PsiJavaCodeReferenceElement, parent);
|
||||
PsiElement refParent = parent.getParent();
|
||||
if (refParent instanceof PsiAnonymousClass) refParent = refParent.getParent();
|
||||
if (refParent instanceof PsiNewExpression newExpression) {
|
||||
if (!(newExpression.getType() instanceof PsiArrayType)) {
|
||||
String description = JavaErrorBundle.message("wildcard.type.cannot.be.instantiated", JavaHighlightUtil.formatType(type));
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description);
|
||||
}
|
||||
}
|
||||
else if (refParent instanceof PsiReferenceList) {
|
||||
PsiElement refPParent = refParent.getParent();
|
||||
if (!(refPParent instanceof PsiTypeParameter typeParameter) || refParent != typeParameter.getExtendsList()) {
|
||||
String description = JavaErrorBundle.message("generics.wildcard.not.expected");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!typeElement.isInferredType()){
|
||||
String description = JavaErrorBundle.message("generics.wildcards.may.be.used.only.as.reference.parameters");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkReferenceTypeUsedAsTypeArgument(@NotNull PsiTypeElement typeElement) {
|
||||
PsiType type = typeElement.getType();
|
||||
PsiType wildCardBind = type instanceof PsiWildcardType wildcardType ? wildcardType.getBound() : null;
|
||||
if (type != PsiTypes.nullType() && type instanceof PsiPrimitiveType || wildCardBind instanceof PsiPrimitiveType) {
|
||||
PsiElement element = new PsiMatcherImpl(typeElement)
|
||||
.parent(PsiMatchers.hasClass(PsiReferenceParameterList.class))
|
||||
.parent(PsiMatchers.hasClass(PsiJavaCodeReferenceElement.class, PsiNewExpression.class))
|
||||
.getElement();
|
||||
if (element == null) return null;
|
||||
|
||||
String text = JavaErrorBundle.message("generics.type.argument.cannot.be.of.primitive.type");
|
||||
HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(text);
|
||||
|
||||
PsiPrimitiveType toConvert = (PsiPrimitiveType)(type instanceof PsiWildcardType ? wildCardBind : type);
|
||||
PsiClassType boxedType = toConvert.getBoxedType(typeElement);
|
||||
if (boxedType != null) {
|
||||
IntentionAction action = QuickFixFactory.getInstance().createReplacePrimitiveWithBoxedTypeAction(
|
||||
typeElement, toConvert.getPresentableText(), toConvert.getBoxedTypeName());
|
||||
builder.registerFix(action, null, null, null, null);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkForeachExpressionTypeIsIterable(@NotNull PsiExpression expression) {
|
||||
if (expression.getType() == null) return null;
|
||||
PsiType itemType = JavaGenericsUtil.getCollectionItemType(expression);
|
||||
if (itemType == null) {
|
||||
String description = JavaErrorBundle.message("foreach.not.applicable",
|
||||
JavaHighlightUtil.formatType(expression.getType()));
|
||||
HighlightInfo.Builder builder = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(description);
|
||||
IntentionAction action = QuickFixFactory.getInstance().createNotIterableForEachLoopFix(expression);
|
||||
if (action != null) {
|
||||
builder.registerFix(action, null, null, null, null);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2
|
||||
static HighlightInfo.Builder checkAccessStaticFieldFromEnumConstructor(@NotNull PsiReferenceExpression expr,
|
||||
@NotNull JavaResolveResult result) {
|
||||
|
||||
+2
-3
@@ -417,7 +417,7 @@ public final class HighlightFixUtil {
|
||||
return copyType != null && returnType.isAssignableFrom(copyType);
|
||||
}
|
||||
|
||||
static void registerSpecifyVarTypeFix(@NotNull PsiLocalVariable variable, @NotNull HighlightInfo.Builder info) {
|
||||
static void registerSpecifyVarTypeFix(@NotNull PsiLocalVariable variable, @NotNull Consumer<? super CommonIntentionAction> info) {
|
||||
PsiElement block = PsiUtil.getVariableCodeBlock(variable, null);
|
||||
if (block == null) return;
|
||||
PsiTreeUtil.processElements(block, PsiReferenceExpression.class, ref -> {
|
||||
@@ -435,8 +435,7 @@ public final class HighlightFixUtil {
|
||||
if (type != null) {
|
||||
type = GenericsUtil.getVariableTypeByExpressionType(type);
|
||||
if (PsiTypesUtil.isDenotableType(type, variable) && !PsiTypes.voidType().equals(type)) {
|
||||
IntentionAction fix = QuickFixFactory.getInstance().createSetVariableTypeFix(variable, type);
|
||||
info.registerFix(fix, null, null, null, null);
|
||||
info.accept(QuickFixFactory.getInstance().createSetVariableTypeFix(variable, type));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
-106
@@ -51,7 +51,6 @@ import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.NamedColorUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.InstanceOfUtils;
|
||||
import com.siyeh.ig.psiutils.VariableAccessUtils;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -297,61 +296,6 @@ public final class HighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkVarTypeApplicability(@NotNull PsiTypeElement typeElement) {
|
||||
if (!typeElement.isInferredType()) {
|
||||
return null;
|
||||
}
|
||||
PsiElement parent = typeElement.getParent();
|
||||
PsiVariable variable = tryCast(parent, PsiVariable.class);
|
||||
if (variable instanceof PsiLocalVariable localVariable) {
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer == null) {
|
||||
if (PsiUtilCore.hasErrorElementChild(variable)) return null;
|
||||
String message = JavaErrorBundle.message("lvti.no.initializer");
|
||||
HighlightInfo.Builder info =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(typeElement);
|
||||
HighlightFixUtil.registerSpecifyVarTypeFix(localVariable, info);
|
||||
return info;
|
||||
}
|
||||
PsiExpression deparen = PsiUtil.skipParenthesizedExprDown(initializer);
|
||||
if (deparen instanceof PsiFunctionalExpression) {
|
||||
boolean lambda = deparen instanceof PsiLambdaExpression;
|
||||
String message = JavaErrorBundle.message(lambda ? "lvti.lambda" : "lvti.method.ref");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(typeElement);
|
||||
}
|
||||
|
||||
if (isArrayDeclaration(variable)) {
|
||||
String message = JavaErrorBundle.message("lvti.array");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(typeElement);
|
||||
}
|
||||
|
||||
PsiType lType = variable.getType();
|
||||
if (PsiTypes.nullType().equals(lType) &&
|
||||
ExpressionUtils.nonStructuralChildren(initializer).allMatch(ExpressionUtils::isNullLiteral)) {
|
||||
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
|
||||
.descriptionAndTooltip(JavaErrorBundle.message("lvti.null"))
|
||||
.range(typeElement);
|
||||
HighlightFixUtil.registerSpecifyVarTypeFix(localVariable, info);
|
||||
return info;
|
||||
}
|
||||
if (PsiTypes.voidType().equals(lType)) {
|
||||
String message = JavaErrorBundle.message("lvti.void");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(typeElement);
|
||||
}
|
||||
}
|
||||
else if (variable instanceof PsiParameter && variable.getParent() instanceof PsiParameterList && isArrayDeclaration(variable)) {
|
||||
String message = JavaErrorBundle.message("lvti.array");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(message).range(typeElement);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isArrayDeclaration(@NotNull PsiVariable variable) {
|
||||
// Java-style 'var' arrays are prohibited by the parser; for C-style ones, looking for a bracket is enough
|
||||
return ContainerUtil.or(variable.getChildren(), e -> PsiUtil.isJavaToken(e, JavaTokenType.LBRACKET));
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkAssignability(@Nullable PsiType lType,
|
||||
@Nullable PsiType rType,
|
||||
@Nullable PsiExpression expression,
|
||||
@@ -870,41 +814,6 @@ public final class HighlightUtil {
|
||||
}
|
||||
|
||||
|
||||
static HighlightInfo.Builder checkIllegalType(@NotNull PsiTypeElement typeElement, @NotNull PsiFile containingFile) {
|
||||
PsiElement parent = typeElement.getParent();
|
||||
if (parent instanceof PsiTypeElement) return null;
|
||||
|
||||
if (PsiUtil.isInsideJavadocComment(typeElement)) return null;
|
||||
|
||||
PsiType type = typeElement.getType();
|
||||
PsiType componentType = type.getDeepComponentType();
|
||||
if (componentType instanceof PsiClassType) {
|
||||
PsiClass aClass = PsiUtil.resolveClassInType(componentType);
|
||||
if (aClass == null) {
|
||||
if (typeElement.isInferredType() && parent instanceof PsiLocalVariable localVariable) {
|
||||
PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(localVariable.getInitializer());
|
||||
if (initializer instanceof PsiNewExpression) {
|
||||
// The problem is already reported on the initializer
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (IncompleteModelUtil.isIncompleteModel(containingFile)) {
|
||||
return null;
|
||||
}
|
||||
String canonicalText = componentType.getCanonicalText();
|
||||
String description = JavaErrorBundle.message("unknown.class", canonicalText);
|
||||
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description);
|
||||
PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement();
|
||||
if (referenceElement != null) {
|
||||
UnresolvedReferenceQuickFixUpdater.getInstance(containingFile.getProject()).registerQuickFixesLater(referenceElement, info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkMemberReferencedBeforeConstructorCalled(@NotNull PsiElement expression,
|
||||
@Nullable PsiElement resolved,
|
||||
@NotNull Function<? super PsiElement, ? extends PsiMethod> surroundingConstructor) {
|
||||
@@ -1191,21 +1100,6 @@ public final class HighlightUtil {
|
||||
.navigationShift(navigationShift);
|
||||
}
|
||||
|
||||
public static HighlightInfo.Builder checkArrayType(PsiTypeElement type) {
|
||||
int dimensions = 0;
|
||||
for (PsiElement child = type.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (PsiUtil.isJavaToken(child, JavaTokenType.LBRACKET)) {
|
||||
dimensions++;
|
||||
}
|
||||
}
|
||||
if (dimensions > 255) {
|
||||
// JVM Specification, 4.3.2: no more than 255 dimensions allowed
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(type.getTextRange())
|
||||
.description(JavaErrorBundle.message("too.many.array.dimensions"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkExtraSemicolonBetweenImportStatements(@NotNull PsiJavaToken token,
|
||||
IElementType type,
|
||||
@NotNull LanguageLevel level) {
|
||||
|
||||
+7
-25
@@ -64,6 +64,7 @@ import java.util.function.Function;
|
||||
|
||||
import static com.intellij.psi.PsiModifier.SEALED;
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
import static java.util.Objects.*;
|
||||
|
||||
// java highlighting: problems in java code like unresolved/incompatible symbols/methods etc.
|
||||
public class HighlightVisitorImpl extends JavaElementVisitor implements HighlightVisitor {
|
||||
@@ -250,10 +251,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
info.range(anchor);
|
||||
}
|
||||
errorFixProvider.processFixes(error, fix -> info.registerFix(fix.asIntention(), null, null, null, null));
|
||||
if (error.kind() == JavaErrorKinds.EXPRESSION_EXPECTED || error.kind() == JavaErrorKinds.REFERENCE_UNRESOLVED ||
|
||||
error.kind() == JavaErrorKinds.REFERENCE_AMBIGUOUS) {
|
||||
UnresolvedReferenceQuickFixUpdater.getInstance(getProject()).registerQuickFixesLater((PsiReference)error.psi(), info);
|
||||
}
|
||||
error.psiForKind(JavaErrorKinds.EXPRESSION_EXPECTED, JavaErrorKinds.REFERENCE_UNRESOLVED, JavaErrorKinds.REFERENCE_AMBIGUOUS)
|
||||
.or(() -> error.psiForKind(JavaErrorKinds.TYPE_UNKNOWN_CLASS).map(PsiTypeElement::getInnermostComponentReferenceElement))
|
||||
.ifPresent(ref -> UnresolvedReferenceQuickFixUpdater.getInstance(getProject()).registerQuickFixesLater(ref, info));
|
||||
add(info);
|
||||
}
|
||||
|
||||
@@ -478,20 +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() && shouldReportForeachNotApplicable(expression)) {
|
||||
add(GenericsHighlightUtil.checkForeachExpressionTypeIsIterable(expression));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldReportForeachNotApplicable(@NotNull PsiExpression expression) {
|
||||
if (!(expression.getParent() instanceof PsiForeachStatementBase parentForEach)) return false;
|
||||
|
||||
PsiExpression iteratedValue = parentForEach.getIteratedValue();
|
||||
if (iteratedValue != expression) return false;
|
||||
|
||||
// Ignore if the type of the value which is being iterated over is not resolved yet
|
||||
PsiType iteratedValueType = iteratedValue.getType();
|
||||
return iteratedValueType == null || !PsiTypesUtil.hasUnresolvedComponents(iteratedValueType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1024,8 +1010,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
IncompleteModelUtil.isUnresolvedClassType(functionalInterfaceType)) {
|
||||
return;
|
||||
}
|
||||
String t1 = HighlightUtil.format(Objects.requireNonNull(results[0].getElement()));
|
||||
String t2 = HighlightUtil.format(Objects.requireNonNull(results[1].getElement()));
|
||||
String t1 = HighlightUtil.format(requireNonNull(results[0].getElement()));
|
||||
String t2 = HighlightUtil.format(requireNonNull(results[1].getElement()));
|
||||
description = JavaErrorBundle.message("ambiguous.reference", expression.getReferenceName(), t1, t2);
|
||||
}
|
||||
else {
|
||||
@@ -1148,11 +1134,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
|
||||
@Override
|
||||
public void visitTypeElement(@NotNull PsiTypeElement type) {
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkIllegalType(type, myFile));
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkVarTypeApplicability(type));
|
||||
if (!hasErrorResults()) add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type));
|
||||
if (!hasErrorResults()) add(GenericsHighlightUtil.checkWildcardUsage(type));
|
||||
if (!hasErrorResults()) add(HighlightUtil.checkArrayType(type));
|
||||
super.visitTypeElement(type);
|
||||
if (!hasErrorResults()) {
|
||||
PreviewFeatureUtil.checkPreviewFeature(type, myPreviewFeatureVisitor);
|
||||
}
|
||||
|
||||
+15
@@ -158,6 +158,7 @@ final class JavaErrorFixProvider {
|
||||
}
|
||||
}
|
||||
});
|
||||
fix(FOREACH_NOT_APPLICABLE, error -> myFactory.createNotIterableForEachLoopFix(error.psi()));
|
||||
}
|
||||
|
||||
private void createMethodFixes() {
|
||||
@@ -302,6 +303,8 @@ final class JavaErrorFixProvider {
|
||||
private void createVariableFixes() {
|
||||
fix(UNNAMED_VARIABLE_BRACKETS, error -> new NormalizeBracketsFix(error.psi()));
|
||||
fix(UNNAMED_VARIABLE_WITHOUT_INITIALIZER, error -> myFactory.createAddVariableInitializerFix(error.psi()));
|
||||
fixes(LVTI_NO_INITIALIZER, (error, sink) -> HighlightFixUtil.registerSpecifyVarTypeFix(error.psi(), sink));
|
||||
fixes(LVTI_NULL, (error, sink) -> HighlightFixUtil.registerSpecifyVarTypeFix(error.psi(), sink));
|
||||
}
|
||||
|
||||
private void createExpressionFixes() {
|
||||
@@ -545,6 +548,18 @@ final class JavaErrorFixProvider {
|
||||
HighlightFixUtil.registerMethodReturnFixAction(sink, candidate, constructorCall);
|
||||
}
|
||||
});
|
||||
fix(TYPE_ARGUMENT_PRIMITIVE, error -> {
|
||||
PsiTypeElement typeElement = error.psi();
|
||||
PsiType type = typeElement.getType();
|
||||
PsiPrimitiveType toConvert =
|
||||
(PsiPrimitiveType)(type instanceof PsiWildcardType wildcardType ? requireNonNull(wildcardType.getBound()) : type);
|
||||
PsiClassType boxedType = toConvert.getBoxedType(typeElement);
|
||||
if (boxedType != null) {
|
||||
return QuickFixFactory.getInstance().createReplacePrimitiveWithBoxedTypeAction(
|
||||
typeElement, toConvert.getPresentableText(), boxedType.getCanonicalText());
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void createClassFixes() {
|
||||
|
||||
@@ -24,7 +24,6 @@ generics.methods.have.same.erasure.hide={0}; both methods have same erasure, yet
|
||||
generics.type.parameter.cannot.be.instantiated=Type parameter ''{0}'' cannot be instantiated directly
|
||||
wildcard.type.cannot.be.instantiated=Wildcard type ''{0}'' cannot be instantiated directly
|
||||
generics.wildcard.not.expected=No wildcard expected
|
||||
generics.wildcards.may.be.used.only.as.reference.parameters=Wildcards may be used only as reference parameters
|
||||
generics.type.argument.cannot.be.of.primitive.type=Type argument cannot be of primitive type
|
||||
generics.unchecked.assignment=Unchecked assignment: ''{0}'' to ''{1}''
|
||||
generics.unchecked.cast=Unchecked cast: ''{0}'' to ''{1}''
|
||||
@@ -371,11 +370,9 @@ module.bad.name=Module ''{0}'' has an invalid name
|
||||
restricted.identifier=''{0}'' is a restricted identifier and cannot be used for type declarations
|
||||
restricted.identifier.reference=Illegal reference to restricted type ''{0}''
|
||||
|
||||
lvti.no.initializer=Cannot infer type: 'var' on variable without initializer
|
||||
lvti.lambda=Cannot infer type: lambda expression requires an explicit target type
|
||||
lvti.method.ref=Cannot infer type: method reference requires an explicit target type
|
||||
lvti.compound='var' is not allowed in a compound declaration
|
||||
lvti.array='var' is not allowed as an element type of an array
|
||||
lvti.null=Cannot infer type: variable initializer is 'null'
|
||||
lvti.void=Cannot infer type: variable initializer is 'void'
|
||||
lvti.selfReferenced=Cannot infer type for ''{0}'', it is used in its own variable initializer
|
||||
|
||||
+3
-3
@@ -2,14 +2,14 @@ class A {
|
||||
<T> A() {}
|
||||
|
||||
{
|
||||
new <<error descr="Type argument cannot be of primitive type">int</error>>A();
|
||||
new <<error descr="Type argument cannot be of a primitive type">int</error>>A();
|
||||
}
|
||||
}
|
||||
|
||||
class B<T> {
|
||||
{
|
||||
new B<<error descr="Type argument cannot be of primitive type">int</error>>();
|
||||
B.<<error descr="Type argument cannot be of primitive type">int</error>>m();
|
||||
new B<<error descr="Type argument cannot be of a primitive type">int</error>>();
|
||||
B.<<error descr="Type argument cannot be of a primitive type">int</error>>m();
|
||||
}
|
||||
|
||||
<S> void m(){}
|
||||
|
||||
+4
-4
@@ -27,10 +27,10 @@ class D<T extends C> {
|
||||
}
|
||||
|
||||
class Primitives<T> {
|
||||
Object a = new Primitives<<error descr="Type argument cannot be of primitive type">? extends int</error>>();
|
||||
Object o = new Primitives<<error descr="Type argument cannot be of primitive type">int</error>>();
|
||||
void f(Primitives<<error descr="Type argument cannot be of primitive type">boolean</error>> param) {
|
||||
if (this instanceof Primitives<<error descr="Type argument cannot be of primitive type">double</error>>) {
|
||||
Object a = new Primitives<<error descr="Type argument cannot be of a primitive type">? extends int</error>>();
|
||||
Object o = new Primitives<<error descr="Type argument cannot be of a primitive type">int</error>>();
|
||||
void f(Primitives<<error descr="Type argument cannot be of a primitive type">boolean</error>> param) {
|
||||
if (this instanceof Primitives<<error descr="Type argument cannot be of a primitive type">double</error>>) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -2,14 +2,14 @@ class A {
|
||||
<T> A() {}
|
||||
|
||||
{
|
||||
new <<error descr="Type argument cannot be of primitive type">int</error>>A();
|
||||
new <<error descr="Type argument cannot be of a primitive type">int</error>>A();
|
||||
}
|
||||
}
|
||||
|
||||
class B<T> {
|
||||
{
|
||||
new B<<error descr="Type argument cannot be of primitive type">int</error>>();
|
||||
B.<<error descr="Type argument cannot be of primitive type">int</error>>m();
|
||||
new B<<error descr="Type argument cannot be of a primitive type">int</error>>();
|
||||
B.<<error descr="Type argument cannot be of a primitive type">int</error>>m();
|
||||
}
|
||||
|
||||
<S> void m(){}
|
||||
|
||||
+4
-4
@@ -27,10 +27,10 @@ class D<T extends C> {
|
||||
}
|
||||
|
||||
class Primitives<T> {
|
||||
Object a = new Primitives<<error descr="Type argument cannot be of primitive type">? extends int</error>>();
|
||||
Object o = new Primitives<<error descr="Type argument cannot be of primitive type">int</error>>();
|
||||
void f(Primitives<<error descr="Type argument cannot be of primitive type">boolean</error>> param) {
|
||||
if (this instanceof Primitives<<error descr="Type argument cannot be of primitive type">double</error>>) {
|
||||
Object a = new Primitives<<error descr="Type argument cannot be of a primitive type">? extends int</error>>();
|
||||
Object o = new Primitives<<error descr="Type argument cannot be of a primitive type">int</error>>();
|
||||
void f(Primitives<<error descr="Type argument cannot be of a primitive type">boolean</error>> param) {
|
||||
if (this instanceof Primitives<<error descr="Type argument cannot be of a primitive type">double</error>>) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user