mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[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:
committed by
intellij-monorepo-bot
parent
ac754128ca
commit
e77c362643
@@ -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
|
||||
|
||||
+69
@@ -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) {
|
||||
|
||||
+31
-9
@@ -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
|
||||
|
||||
+24
@@ -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());
|
||||
|
||||
+6
-1
@@ -18,5 +18,10 @@ public enum JavaErrorHighlightType {
|
||||
/**
|
||||
* Error highlighting for unresolved/unknown reference
|
||||
*/
|
||||
WRONG_REF
|
||||
WRONG_REF,
|
||||
|
||||
/**
|
||||
* Error highlighting for unhandled exception
|
||||
*/
|
||||
UNHANDLED_EXCEPTION
|
||||
}
|
||||
|
||||
+8
-1
@@ -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) {
|
||||
|
||||
+11
-6
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-16
@@ -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) {
|
||||
|
||||
+2
-7
@@ -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);
|
||||
|
||||
+1
-76
@@ -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;
|
||||
|
||||
+1
-34
@@ -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);
|
||||
|
||||
+16
-10
@@ -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() {
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user