[java-highlighting] unhandled exceptions, string templates -> ExpressionChecker

Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only)

GitOrigin-RevId: 0172c8851d083ddc6ee5dad2a74fd27e7374e9ff
This commit is contained in:
Tagir Valeev
2025-01-21 09:12:08 +00:00
committed by intellij-monorepo-bot
parent ac754128ca
commit e77c362643
14 changed files with 181 additions and 162 deletions
@@ -229,6 +229,10 @@ pattern.type.pattern.expected=Type pattern expected
expression.expected=Expression expected
string.template.void.not.allowed.in.embedded=Expression with the 'void' type is not allowed as a string template embedded expression
string.template.processor.missing=Processor missing from string template expression
string.template.raw.processor=Raw processor type is not allowed: {0}
modifier.not.allowed=Modifier ''{0}'' not allowed here
modifier.not.allowed.local.class=Modifier ''{0}'' not allowed on local classes
modifier.not.allowed.non.sealed=Modifier 'non-sealed' is not allowed on classes that do not have a sealed superclass
@@ -1,16 +1,22 @@
// 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.codeInsight.ExceptionUtil;
import com.intellij.java.codeserver.highlighting.errors.JavaErrorKinds;
import com.intellij.java.codeserver.highlighting.errors.JavaIncompatibleTypeErrorContext;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.impl.IncompleteModelUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import static com.intellij.util.ObjectUtils.tryCast;
final class ExpressionChecker {
@@ -308,6 +314,8 @@ final class ExpressionChecker {
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (resolved instanceof PsiMethod psiMethod && resolveResult.isValidResult()) {
checkUnhandledExceptions(methodCall);
if (myVisitor.hasErrorResults()) return;
}
else {
@@ -325,6 +333,67 @@ final class ExpressionChecker {
}
}
void checkTemplateExpression(@NotNull PsiTemplateExpression templateExpression) {
myVisitor.checkFeature(templateExpression, JavaFeature.STRING_TEMPLATES);
if (myVisitor.hasErrorResults()) return;
PsiExpression processor = templateExpression.getProcessor();
if (processor == null) {
myVisitor.report(JavaErrorKinds.STRING_TEMPLATE_PROCESSOR_MISSING.create(templateExpression));
return;
}
PsiType type = processor.getType();
if (type == null) return;
PsiElementFactory factory = JavaPsiFacade.getElementFactory(processor.getProject());
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)) {
return;
}
myVisitor.report(JavaErrorKinds.TYPE_INCOMPATIBLE.create(processor, new JavaIncompatibleTypeErrorContext(processorType, type)));
return;
}
PsiClass processorClass = processorType.resolve();
if (processorClass == null) return;
for (PsiClassType classType : PsiTypesUtil.getClassTypeComponents(type)) {
if (!TypeConversionUtil.isAssignable(processorType, classType)) continue;
PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
PsiClass aClass = resolveResult.getElement();
if (aClass == null) continue;
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(processorClass, aClass, resolveResult.getSubstitutor());
if (substitutor == null) continue;
Map<PsiTypeParameter, PsiType> substitutionMap = substitutor.getSubstitutionMap();
if (substitutionMap.isEmpty() || substitutionMap.containsValue(null)) {
myVisitor.report(JavaErrorKinds.STRING_TEMPLATE_RAW_PROCESSOR.create(processor, type));
return;
}
}
}
private static boolean shouldHighlightUnhandledException(@NotNull PsiElement element) {
// JSP top-level errors are handled by UnhandledExceptionInJSP inspection
if (FileTypeUtils.isInServerPageFile(element)) {
PsiMethod targetMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class, true, PsiLambdaExpression.class);
if (targetMethod instanceof SyntheticElement) {
return false;
}
}
return true;
}
void checkUnhandledExceptions(@NotNull PsiElement element) {
List<PsiClassType> unhandled = ExceptionUtil.getOwnUnhandledExceptions(element);
if (unhandled.isEmpty()) return;
unhandled = ContainerUtil.filter(unhandled, type -> type.resolve() != null);
if (unhandled.isEmpty()) return;
if (!shouldHighlightUnhandledException(element)) return;
myVisitor.report(JavaErrorKinds.EXCEPTION_UNHANDLED.create(element, unhandled));
}
boolean isDummyConstructorCall(@NotNull PsiMethodCallExpression methodCall,
@NotNull PsiExpressionList list,
@NotNull PsiReferenceExpression referenceToMethod) {
@@ -171,6 +171,27 @@ final class JavaErrorVisitor extends JavaElementVisitor {
public void visitEnumConstant(@NotNull PsiEnumConstant enumConstant) {
super.visitEnumConstant(enumConstant);
if (!hasErrorResults()) myClassChecker.checkEnumWithAbstractMethods(enumConstant);
if (!hasErrorResults()) myExpressionChecker.checkUnhandledExceptions(enumConstant);
}
@Override
public void visitTemplateExpression(@NotNull PsiTemplateExpression expression) {
super.visitTemplateExpression(expression);
if (!hasErrorResults()) myExpressionChecker.checkTemplateExpression(expression);
if (!hasErrorResults()) myExpressionChecker.checkUnhandledExceptions(expression);
}
@Override
public void visitTemplate(@NotNull PsiTemplate template) {
super.visitTemplate(template);
checkFeature(template, JavaFeature.STRING_TEMPLATES);
if (hasErrorResults()) return;
for (PsiExpression embeddedExpression : template.getEmbeddedExpressions()) {
if (PsiTypes.voidType().equals(embeddedExpression.getType())) {
report(JavaErrorKinds.STRING_TEMPLATE_VOID_NOT_ALLOWED_IN_EMBEDDED.create(embeddedExpression));
}
}
}
@Override
@@ -186,6 +207,7 @@ final class JavaErrorVisitor extends JavaElementVisitor {
if (!hasErrorResults()) myClassChecker.checkAnonymousInheritProhibited(expression);
if (!hasErrorResults()) myClassChecker.checkAnonymousSealedProhibited(expression);
if (!hasErrorResults()) myExpressionChecker.checkQualifiedNew(expression, type, aClass);
if (!hasErrorResults()) myExpressionChecker.checkUnhandledExceptions(expression);
}
@Override
@@ -239,15 +261,8 @@ final class JavaErrorVisitor extends JavaElementVisitor {
PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null && !PsiTypesUtil.allTypeParametersResolved(expression, functionalInterfaceType)) return;
JavaResolveResult result;
JavaResolveResult[] results;
try {
results = expression.multiResolve(true);
result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
}
catch (IndexNotReadyException e) {
return;
}
JavaResolveResult[] results = expression.multiResolve(true);
JavaResolveResult result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
if (!hasErrorResults()) {
boolean resolvedButNonApplicable = results.length == 1 && results[0] instanceof MethodCandidateInfo methodInfo &&
!methodInfo.isApplicable() &&
@@ -262,6 +277,13 @@ final class JavaErrorVisitor extends JavaElementVisitor {
}
}
}
if (!hasErrorResults()) myExpressionChecker.checkUnhandledExceptions(expression);
}
@Override
public void visitThrowStatement(@NotNull PsiThrowStatement statement) {
myExpressionChecker.checkUnhandledExceptions(statement);
if (!hasErrorResults()) visitStatement(statement);
}
@Override
@@ -14,6 +14,7 @@ import com.intellij.psi.impl.source.tree.TreeUtil;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.psi.util.PsiFormatUtilBase;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,6 +52,29 @@ final class JavaErrorFormatUtil {
return PsiFormatUtil.formatVariable(field, PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME, PsiSubstitutor.EMPTY);
}
static @Nullable TextRange getRange(@NotNull PsiElement element) {
if (element instanceof PsiMember member) {
return getMemberDeclarationTextRange(member);
}
if (element instanceof PsiNewExpression newExpression) {
PsiJavaCodeReferenceElement reference = newExpression.getClassReference();
if (reference != null) {
return reference.getTextRangeInParent();
}
}
if (element instanceof PsiMethodCallExpression callExpression) {
PsiElement nameElement = callExpression.getMethodExpression().getReferenceNameElement();
if (nameElement != null) {
return nameElement.getTextRangeInParent();
}
}
PsiElement nextSibling = element.getNextSibling();
if (PsiUtil.isJavaToken(nextSibling, JavaTokenType.SEMICOLON)) {
return TextRange.create(0, element.getTextLength() + 1);
}
return null;
}
static @NotNull TextRange getMethodDeclarationTextRange(@NotNull PsiMethod method) {
if (method instanceof SyntheticElement) return TextRange.EMPTY_RANGE;
int start = stripAnnotationsFromModifierList(method.getModifierList());
@@ -18,5 +18,10 @@ public enum JavaErrorHighlightType {
/**
* Error highlighting for unresolved/unknown reference
*/
WRONG_REF
WRONG_REF,
/**
* Error highlighting for unhandled exception
*/
UNHANDLED_EXCEPTION
}
@@ -501,7 +501,7 @@ public final class JavaErrorKinds {
public static final Parameterized<PsiElement, Collection<PsiClassType>> EXCEPTION_UNHANDLED =
error(PsiElement.class, "exception.unhandled")
.withRange(psi -> psi instanceof PsiMember member ? getMemberDeclarationTextRange(member) : null)
.withRange(JavaErrorFormatUtil::getRange)
.<Collection<PsiClassType>>parameterized()
.withRawDescription((psi, unhandled) -> message("exception.unhandled", formatTypes(unhandled), unhandled.size()));
public static final Parameterized<PsiTypeElement, InvalidDisjointTypeContext> EXCEPTION_MUST_BE_DISJOINT =
@@ -635,6 +635,13 @@ public final class JavaErrorKinds {
.withRawDescription((psi, cls) -> message("call.super.qualifier.not.inner.class", formatClass(cls)));
public static final Simple<PsiMethodCallExpression> CALL_EXPECTED = error("call.expected");
public static final Simple<PsiExpression> STRING_TEMPLATE_VOID_NOT_ALLOWED_IN_EMBEDDED =
error("string.template.void.not.allowed.in.embedded");
public static final Simple<PsiTemplateExpression> STRING_TEMPLATE_PROCESSOR_MISSING =
error("string.template.processor.missing");
public static final Parameterized<PsiExpression, PsiType> STRING_TEMPLATE_RAW_PROCESSOR =
parameterized(PsiExpression.class, PsiType.class, "string.template.raw.processor")
.withRawDescription((psi, type) -> message("string.template.raw.processor", type.getPresentableText()));
private static @NotNull <Psi extends PsiElement> Simple<Psi> error(
@NotNull @PropertyKey(resourceBundle = JavaCompilationErrorBundle.BUNDLE) String key) {
@@ -4,7 +4,6 @@ package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeInsight.daemon.JavaErrorBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.intention.CommonIntentionAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.diagnostic.PluginException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.extensions.ExtensionPointName;
@@ -21,6 +20,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public final class ErrorFixExtensionPoint implements PluginAware {
private static final ExtensionPointName<ErrorFixExtensionPoint> ERROR_FIX_EXTENSION_POINT =
@@ -69,13 +69,18 @@ public final class ErrorFixExtensionPoint implements PluginAware {
return map;
}
public static void registerFixes(@NotNull Consumer<? super CommonIntentionAction> info,
@NotNull PsiElement context,
@NotNull @PropertyKey(resourceBundle = JavaErrorBundle.BUNDLE) String code) {
List<ErrorFixExtensionPoint> fixes = getCodeToFixMap().getOrDefault(code, Collections.emptyList());
for (ErrorFixExtensionPoint fix : fixes) {
info.accept(fix.instantiate(context));
}
}
public static void registerFixes(@NotNull HighlightInfo.Builder info,
@NotNull PsiElement context,
@NotNull @PropertyKey(resourceBundle = JavaErrorBundle.BUNDLE) String code) {
List<ErrorFixExtensionPoint> fixes = getCodeToFixMap().getOrDefault(code, Collections.emptyList());
for (ErrorFixExtensionPoint fix : fixes) {
IntentionAction action = fix.instantiate(context).asIntention();
info.registerFix(action, null, null, null, null);
}
registerFixes(HighlightUtil.asConsumer(info), context, code);
}
}
@@ -176,23 +176,13 @@ public final class HighlightFixUtil {
}
}
static void registerUnhandledExceptionFixes(@NotNull PsiElement element, @NotNull HighlightInfo.Builder info) {
static void registerUnhandledExceptionFixes(@NotNull PsiElement element, @NotNull Consumer<? super CommonIntentionAction> info) {
final QuickFixFactory quickFixFactory = QuickFixFactory.getInstance();
IntentionAction action4 = quickFixFactory.createAddExceptionFromFieldInitializerToConstructorThrowsFix(element);
info.registerFix(action4, null, null, null, null);
IntentionAction action3 = quickFixFactory.createAddExceptionToCatchFix();
info.registerFix(action3, null, null, null, null);
IntentionAction action2 = quickFixFactory.createAddExceptionToExistingCatch(element);
info.registerFix(action2, null, null, null, null);
IntentionAction action1 = quickFixFactory.createAddExceptionToThrowsFix(element);
info.registerFix(action1, null, null, null, null);
IntentionAction action = quickFixFactory.createSurroundWithTryCatchFix(element);
info.registerFix(action, null, null, null, null);
info.accept(quickFixFactory.createAddExceptionFromFieldInitializerToConstructorThrowsFix(element));
info.accept(quickFixFactory.createAddExceptionToCatchFix());
info.accept(quickFixFactory.createAddExceptionToExistingCatch(element));
info.accept(quickFixFactory.createAddExceptionToThrowsFix(element));
info.accept(quickFixFactory.createSurroundWithTryCatchFix(element));
}
static void registerStaticProblemQuickFixAction(@Nullable HighlightInfo.Builder info, @NotNull PsiElement refElement, @NotNull PsiJavaCodeReferenceElement place) {
@@ -209,12 +209,11 @@ public final class HighlightMethodUtil {
boolean isDummy = isDummyConstructorCall(methodCall, resolveHelper, list, referenceToMethod);
if (isDummy) return;
HighlightInfo.Builder builder;
HighlightInfo.Builder builder = null;
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (resolved instanceof PsiMethod psiMethod && resolveResult.isValidResult()) {
builder = HighlightUtil.checkUnhandledExceptions(methodCall);
if (builder == null && psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
PsiClass containingClass = psiMethod.getContainingClass();
if (containingClass != null && containingClass.isInterface()) {
PsiElement element = ObjectUtils.notNull(referenceToMethod.getReferenceNameElement(), referenceToMethod);
@@ -246,7 +245,6 @@ public final class HighlightMethodUtil {
PsiMethod resolvedMethod = candidateInfo != null ? candidateInfo.getElement() : null;
if (!resolveResult.isAccessible() || !resolveResult.isStaticsScopeCorrect()) {
builder = null;
}
else if (candidateInfo != null && !candidateInfo.isApplicable()) {
if (candidateInfo.isTypeArgumentsApplicable()) {
@@ -279,9 +277,6 @@ public final class HighlightMethodUtil {
}
}
}
else {
builder = null;
}
}
if (builder == null) {
builder = GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, referenceToMethod, substitutor, javaSdkVersion);
@@ -839,42 +839,6 @@ public final class HighlightUtil {
return PsiFormatUtil.formatVariable(field, PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME, PsiSubstitutor.EMPTY);
}
static HighlightInfo.Builder checkUnhandledExceptions(@NotNull PsiElement element) {
List<PsiClassType> unhandled = ExceptionUtil.getOwnUnhandledExceptions(element);
if (unhandled.isEmpty()) return null;
unhandled = ContainerUtil.filter(unhandled, type -> type.resolve() != null);
if (unhandled.isEmpty()) return null;
HighlightInfoType highlightType = getUnhandledExceptionHighlightType(element);
if (highlightType == null) return null;
TextRange textRange = computeRange(element);
String description = getUnhandledExceptionsDescriptor(unhandled);
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(highlightType).range(textRange).descriptionAndTooltip(description);
HighlightFixUtil.registerUnhandledExceptionFixes(element, info);
ErrorFixExtensionPoint.registerFixes(info, element, "unhandled.exceptions");
return info;
}
private static TextRange computeRange(@NotNull PsiElement element) {
if (element instanceof PsiNewExpression newExpression) {
PsiJavaCodeReferenceElement reference = newExpression.getClassReference();
if (reference != null) {
return reference.getTextRange();
}
}
if (element instanceof PsiEnumConstant constant) {
return constant.getNameIdentifier().getTextRange();
}
if (element instanceof PsiMethodCallExpression callExpression) {
PsiElement nameElement = callExpression.getMethodExpression().getReferenceNameElement();
if (nameElement != null) {
return nameElement.getTextRange();
}
}
return HighlightMethodUtil.getFixRange(element);
}
static HighlightInfo.Builder checkUnhandledCloserExceptions(@NotNull PsiResourceListElement resource) {
List<PsiClassType> unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null);
if (unhandled.isEmpty()) return null;
@@ -885,7 +849,7 @@ public final class HighlightUtil {
String description = JavaErrorBundle.message("unhandled.close.exceptions", formatTypes(unhandled), unhandled.size(),
JavaErrorBundle.message("auto.closeable.resource"));
HighlightInfo.Builder highlight = HighlightInfo.newHighlightInfo(highlightType).range(resource).descriptionAndTooltip(description);
HighlightFixUtil.registerUnhandledExceptionFixes(resource, highlight);
HighlightFixUtil.registerUnhandledExceptionFixes(resource, asConsumer(highlight));
return highlight;
}
@@ -1438,45 +1402,6 @@ public final class HighlightUtil {
return null;
}
static HighlightInfo.Builder checkTemplateExpression(@NotNull PsiTemplateExpression templateExpression) {
HighlightInfo.Builder builder = checkFeature(templateExpression, JavaFeature.STRING_TEMPLATES,
PsiUtil.getLanguageLevel(templateExpression), templateExpression.getContainingFile());
if (builder != null) return builder;
PsiExpression processor = templateExpression.getProcessor();
if (processor == null) {
String message = JavaErrorBundle.message("processor.missing.from.string.template.expression");
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(templateExpression).descriptionAndTooltip(message)
.registerFix(new MissingStrProcessorFix(templateExpression), null, null, null, null);
}
PsiType type = processor.getType();
if (type == null) return null;
PsiElementFactory factory = JavaPsiFacade.getElementFactory(processor.getProject());
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)) return null;
return createIncompatibleTypeHighlightInfo(processorType, type, processor.getTextRange(), 0);
}
PsiClass processorClass = processorType.resolve();
if (processorClass == null) return null;
for (PsiClassType classType : PsiTypesUtil.getClassTypeComponents(type)) {
if (!TypeConversionUtil.isAssignable(processorType, classType)) continue;
PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
PsiClass aClass = resolveResult.getElement();
if (aClass == null) continue;
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(processorClass, aClass, resolveResult.getSubstitutor());
if (substitutor == null) continue;
Map<PsiTypeParameter, PsiType> substitutionMap = substitutor.getSubstitutionMap();
if (substitutionMap.isEmpty() || substitutionMap.containsValue(null)) {
String text = JavaErrorBundle.message("raw.processor.type.not.allowed", type.getPresentableText());
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(processor).descriptionAndTooltip(text);
}
}
return null;
}
static HighlightInfo.Builder checkTryResourceIsAutoCloseable(@NotNull PsiResourceListElement resource) {
PsiType type = resource.getType();
if (type == null) return null;
@@ -229,6 +229,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
JavaErrorHighlightType javaHighlightType = error.highlightType();
HighlightInfoType type = switch (javaHighlightType) {
case ERROR, FILE_LEVEL_ERROR -> HighlightInfoType.ERROR;
case UNHANDLED_EXCEPTION -> HighlightInfoType.UNHANDLED_EXCEPTION;
case WRONG_REF -> HighlightInfoType.WRONG_REF;
};
TextRange range = error.range();
@@ -526,7 +527,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
HighlightMethodUtil.checkConstructorCall(getProject(), type.resolveGenerics(), enumConstant, type, null, myJavaSdkVersion,
enumConstant.getArgumentList(), myErrorSink);
}
if (!hasErrorResults()) add(HighlightUtil.checkUnhandledExceptions(enumConstant));
}
@Override
@@ -773,28 +773,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
}
@Override
public void visitTemplateExpression(@NotNull PsiTemplateExpression expression) {
super.visitTemplateExpression(expression);
add(HighlightUtil.checkTemplateExpression(expression));
if (!hasErrorResults()) add(HighlightUtil.checkUnhandledExceptions(expression));
}
@Override
public void visitTemplate(@NotNull PsiTemplate template) {
super.visitTemplate(template);
add(checkFeature(template, JavaFeature.STRING_TEMPLATES));
if (hasErrorResults()) return;
for (PsiExpression embeddedExpression : template.getEmbeddedExpressions()) {
if (PsiTypes.voidType().equals(embeddedExpression.getType())) {
String message = JavaErrorBundle.message("expression.with.type.void.not.allowed.as.string.template.embedded.expression");
add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(embeddedExpression).descriptionAndTooltip(message));
}
}
}
@Override
public void visitMethod(@NotNull PsiMethod method) {
super.visitMethod(method);
@@ -847,7 +825,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
@Override
public void visitNewExpression(@NotNull PsiNewExpression expression) {
PsiType type = expression.getType();
add(HighlightUtil.checkUnhandledExceptions(expression));
if (!hasErrorResults()) add(GenericsHighlightUtil.checkTypeParameterInstantiation(expression));
if (!hasErrorResults()) add(GenericsHighlightUtil.checkGenericArrayCreation(expression, type));
try {
@@ -1240,10 +1217,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
add(PsiMethodReferenceHighlightingUtil.checkRawConstructorReference(expression));
}
if (!hasErrorResults()) {
add(HighlightUtil.checkUnhandledExceptions(expression));
}
if (!hasErrorResults()) {
boolean resolvedButNonApplicable = results.length == 1 && results[0] instanceof MethodCandidateInfo methodInfo &&
!methodInfo.isApplicable() &&
@@ -1440,12 +1413,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
}
@Override
public void visitThrowStatement(@NotNull PsiThrowStatement statement) {
add(HighlightUtil.checkUnhandledExceptions(statement));
if (!hasErrorResults()) visitStatement(statement);
}
@Override
public void visitTryStatement(@NotNull PsiTryStatement statement) {
super.visitTryStatement(statement);
@@ -212,17 +212,22 @@ final class JavaErrorFixProvider {
fix(CONSTRUCTOR_AMBIGUOUS_IMPLICIT_CALL, error -> myFactory.createAddDefaultConstructorFix(
requireNonNull(error.context().psiClass().getSuperClass())));
fix(CONSTRUCTOR_NO_DEFAULT, error -> myFactory.createAddDefaultConstructorFix(error.context()));
fix(EXCEPTION_UNHANDLED, error -> {
PsiClass psiClass = error.psi() instanceof PsiClass cls ? cls :
error.psi() instanceof PsiMethod method ? method.getContainingClass() :
null;
return psiClass != null ? myFactory.createCreateConstructorMatchingSuperFix(psiClass) : null;
});
fix(EXCEPTION_UNHANDLED, error -> {
if (error.psi() instanceof PsiMethod method) {
return myFactory.createAddExceptionToThrowsFix(method, error.context());
multi(EXCEPTION_UNHANDLED, error -> {
List<CommonIntentionAction> registrar = new ArrayList<>();
PsiElement element = error.psi();
HighlightFixUtil.registerUnhandledExceptionFixes(element, registrar::add);
if (element instanceof PsiMethod method) {
registrar.add(myFactory.createAddExceptionToThrowsFix(method, error.context()));
PsiClass aClass = method.getContainingClass();
if (aClass != null) {
registrar.add(myFactory.createCreateConstructorMatchingSuperFix(aClass));
}
}
return null;
else if (element instanceof PsiClass cls) {
registrar.add(myFactory.createCreateConstructorMatchingSuperFix(cls));
}
ErrorFixExtensionPoint.registerFixes(registrar::add, element, "unhandled.exceptions");
return registrar;
});
}
@@ -274,6 +279,7 @@ final class JavaErrorFixProvider {
return registrar;
}
});
fix(STRING_TEMPLATE_PROCESSOR_MISSING, error -> new MissingStrProcessorFix(error.psi()));
}
private void createTypeFixes() {
@@ -119,7 +119,7 @@ class X {
}
public static void voidExpression() {
String a = STR."\{<error descr="Expression with type 'void' not allowed as string template embedded expression">voidExpression()</error>}";
String a = STR."\{<error descr="Expression with the 'void' type is not allowed as a string template embedded expression">voidExpression()</error>}";
System.out.println(a);
}
@@ -119,7 +119,7 @@ class X {
}
public static void voidExpression() {
String a = STR."\{<error descr="Expression with type 'void' not allowed as string template embedded expression">voidExpression()</error>}";
String a = STR."\{<error descr="Expression with the 'void' type is not allowed as a string template embedded expression">voidExpression()</error>}";
System.out.println(a);
}