mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
[lombok] IDEA-255688 Get rid of LombokHighlightFixHook-Filter
GitOrigin-RevId: d050c269d3fcedcdcc21429e83604688c50b6b60
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c5257f0fea
commit
6f95b21eeb
@@ -37,6 +37,7 @@
|
||||
<extensionPoint qualifiedName="com.intellij.javaLanguageLevelPusherCustomizer" interface="com.intellij.openapi.roots.impl.JavaLanguageLevelPusherCustomizer" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.propertyAccessorDetector" interface="com.intellij.psi.util.PropertyAccessorDetector" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.virtualManifestProvider" interface="com.intellij.codeInsight.daemon.impl.analysis.VirtualManifestProvider" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.unhandledExceptionFixProvider" interface="com.intellij.codeInsight.daemon.impl.analysis.UnhandledExceptionFixProvider" dynamic="true"/>
|
||||
|
||||
<extensionPoint qualifiedName="com.intellij.injectedLanguageJavaReferenceSupplier"
|
||||
beanClass="com.intellij.codeInsight.daemon.impl.analysis.InjectedLanguageJavaReferenceSupplier" dynamic="true"/>
|
||||
|
||||
@@ -176,26 +176,29 @@ public final class HighlightFixUtil {
|
||||
}
|
||||
}
|
||||
|
||||
static void registerUnhandledExceptionFixes(@NotNull PsiElement element, @Nullable HighlightInfo.Builder info) {
|
||||
IntentionAction action4 = QuickFixFactory.getInstance().createAddExceptionFromFieldInitializerToConstructorThrowsFix(element);
|
||||
static void registerUnhandledExceptionFixes(@NotNull PsiElement element, @Nullable HighlightInfo.Builder info,
|
||||
@NotNull List<PsiClassType> unhandledExceptions) {
|
||||
if (info != null) {
|
||||
final QuickFixFactory quickFixFactory = QuickFixFactory.getInstance();
|
||||
|
||||
IntentionAction action4 = quickFixFactory.createAddExceptionFromFieldInitializerToConstructorThrowsFix(element);
|
||||
info.registerFix(action4, null, null, null, null);
|
||||
}
|
||||
IntentionAction action3 = QuickFixFactory.getInstance().createAddExceptionToCatchFix();
|
||||
if (info != null) {
|
||||
|
||||
IntentionAction action3 = quickFixFactory.createAddExceptionToCatchFix();
|
||||
info.registerFix(action3, null, null, null, null);
|
||||
}
|
||||
IntentionAction action2 = QuickFixFactory.getInstance().createAddExceptionToExistingCatch(element);
|
||||
if (info != null) {
|
||||
|
||||
IntentionAction action2 = quickFixFactory.createAddExceptionToExistingCatch(element);
|
||||
info.registerFix(action2, null, null, null, null);
|
||||
}
|
||||
IntentionAction action1 = QuickFixFactory.getInstance().createAddExceptionToThrowsFix(element);
|
||||
if (info != null) {
|
||||
|
||||
IntentionAction action1 = quickFixFactory.createAddExceptionToThrowsFix(element);
|
||||
info.registerFix(action1, null, null, null, null);
|
||||
}
|
||||
IntentionAction action = QuickFixFactory.getInstance().createSurroundWithTryCatchFix(element);
|
||||
if (info != null) {
|
||||
|
||||
IntentionAction action = quickFixFactory.createSurroundWithTryCatchFix(element);
|
||||
info.registerFix(action, null, null, null, null);
|
||||
|
||||
for (UnhandledExceptionFixProvider provider : UnhandledExceptionFixProvider.EP_NAME.getExtensionList()) {
|
||||
provider.registerUnhandledExceptionFixes(info, element, unhandledExceptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -925,7 +925,7 @@ public final class HighlightUtil {
|
||||
TextRange textRange = computeRange(element);
|
||||
String description = getUnhandledExceptionsDescriptor(unhandled);
|
||||
HighlightInfo.Builder info = HighlightInfo.newHighlightInfo(highlightType).range(textRange).descriptionAndTooltip(description);
|
||||
HighlightFixUtil.registerUnhandledExceptionFixes(element, info);
|
||||
HighlightFixUtil.registerUnhandledExceptionFixes(element, info, unhandled);
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -958,7 +958,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, highlight, unhandled);
|
||||
return highlight;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The UnhandledExceptionFixProvider interface provides a way to register fixes for unhandled exceptions.
|
||||
*/
|
||||
public interface UnhandledExceptionFixProvider {
|
||||
ExtensionPointName<UnhandledExceptionFixProvider> EP_NAME = new ExtensionPointName<>("com.intellij.unhandledExceptionFixProvider");
|
||||
|
||||
/**
|
||||
* Registers fixes for unhandled exceptions.
|
||||
* <p>
|
||||
* This method is responsible for registering fixes for unhandled exceptions in the provided {@link HighlightInfo.Builder} instance.
|
||||
*
|
||||
* @param info the {@link HighlightInfo.Builder} instance to register the fixes into
|
||||
* @param element the {@link PsiElement} representing the location of the unhandled exception
|
||||
* @param unhandledExceptions the list of unhandled exception types
|
||||
*/
|
||||
void registerUnhandledExceptionFixes(@NotNull HighlightInfo.Builder info, @NotNull PsiElement element,
|
||||
@NotNull List<PsiClassType> unhandledExceptions);
|
||||
}
|
||||
@@ -1,41 +1,18 @@
|
||||
package de.plushnikov.intellij.plugin.extension;
|
||||
|
||||
import com.intellij.codeInsight.daemon.JavaErrorBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoFilter;
|
||||
import com.intellij.codeInsight.intention.AddAnnotationFix;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import de.plushnikov.intellij.plugin.LombokClassNames;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import de.plushnikov.intellij.plugin.handler.OnXAnnotationHandler;
|
||||
import de.plushnikov.intellij.plugin.quickfix.PsiQuickFixFactory;
|
||||
import de.plushnikov.intellij.plugin.util.LombokLibraryUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class LombokHighlightErrorFilter implements HighlightInfoFilter {
|
||||
|
||||
private static final class Holder {
|
||||
static final Map<HighlightSeverity, Map<TextAttributesKey, List<LombokHighlightFixHook>>> registeredHooks;
|
||||
|
||||
static {
|
||||
registeredHooks = new HashMap<>();
|
||||
|
||||
for (LombokHighlightFixHook highlightFixHook : LombokHighlightFixHook.values()) {
|
||||
registeredHooks.computeIfAbsent(highlightFixHook.severity, s -> new HashMap<>())
|
||||
.computeIfAbsent(highlightFixHook.key, k -> new ArrayList<>())
|
||||
.add(highlightFixHook);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LombokHighlightErrorFilter() {
|
||||
}
|
||||
|
||||
@@ -63,59 +40,6 @@ public class LombokHighlightErrorFilter implements HighlightInfoFilter {
|
||||
}
|
||||
}
|
||||
|
||||
// register different quick fix for highlight
|
||||
Holder.registeredHooks
|
||||
.getOrDefault(highlightInfo.getSeverity(), Collections.emptyMap())
|
||||
.getOrDefault(highlightInfo.type.getAttributesKey(), Collections.emptyList())
|
||||
.stream()
|
||||
.filter(filter -> filter.descriptionCheck(highlightInfo.getDescription()))
|
||||
.forEach(filter -> filter.processHook(highlightedElement, highlightInfo));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private enum LombokHighlightFixHook {
|
||||
|
||||
UNHANDLED_EXCEPTION(HighlightSeverity.ERROR, CodeInsightColors.ERRORS_ATTRIBUTES) {
|
||||
private final Pattern pattern = preparePattern(1);
|
||||
private final Pattern pattern2 = preparePattern(2);
|
||||
|
||||
@NotNull
|
||||
private static Pattern preparePattern(int count) {
|
||||
return Pattern.compile(JavaErrorBundle.message("unhandled.exceptions", ".*", count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean descriptionCheck(@Nullable String description) {
|
||||
return description != null && (pattern.matcher(description).matches() || pattern2.matcher(description).matches());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processHook(@NotNull PsiElement highlightedElement, @NotNull HighlightInfo highlightInfo) {
|
||||
PsiElement importantParent = PsiTreeUtil.getParentOfType(highlightedElement,
|
||||
PsiMethod.class, PsiLambdaExpression.class,
|
||||
PsiMethodReferenceExpression.class, PsiClassInitializer.class
|
||||
);
|
||||
|
||||
// applicable only for methods
|
||||
if (importantParent instanceof PsiMethod) {
|
||||
AddAnnotationFix fix =
|
||||
PsiQuickFixFactory.createAddAnnotationFix(LombokClassNames.SNEAKY_THROWS, (PsiModifierListOwner)importantParent);
|
||||
highlightInfo.registerFix(fix, null, null, null, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final HighlightSeverity severity;
|
||||
private final TextAttributesKey key;
|
||||
|
||||
LombokHighlightFixHook(@NotNull HighlightSeverity severity, @Nullable TextAttributesKey key) {
|
||||
this.severity = severity;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
abstract public boolean descriptionCheck(@Nullable String description);
|
||||
|
||||
abstract public void processHook(@NotNull PsiElement highlightedElement, @NotNull HighlightInfo highlightInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class SneakyThrowsExceptionHandler extends CustomExceptionHandler {
|
||||
@Override
|
||||
public boolean isHandled(@Nullable PsiElement element, @NotNull PsiClassType exceptionType, PsiElement topElement) {
|
||||
final PsiCodeBlock containingCodeBlock = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class, false);
|
||||
if (isCodeBlockWithExceptionInConstructorCall(containingCodeBlock, exceptionType)) {
|
||||
if (isCodeBlockWithExceptionInConstructorCall(containingCodeBlock, Collections.singleton(exceptionType))) {
|
||||
// call to a sibling or super constructor is excluded from the @SneakyThrows treatment
|
||||
return false;
|
||||
}
|
||||
@@ -50,20 +50,25 @@ public class SneakyThrowsExceptionHandler extends CustomExceptionHandler {
|
||||
}
|
||||
|
||||
private static boolean isCodeBlockWithExceptionInConstructorCall(@Nullable PsiCodeBlock codeBlock,
|
||||
@NotNull PsiClassType exceptionType) {
|
||||
@NotNull Collection<PsiClassType> exceptionTypes) {
|
||||
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(codeBlock, PsiMethod.class);
|
||||
if (null != containingMethod) {
|
||||
final PsiMethodCallExpression thisOrSuperCallInConstructor =
|
||||
JavaPsiConstructorUtil.findThisOrSuperCallInConstructor(containingMethod);
|
||||
if (null != thisOrSuperCallInConstructor) {
|
||||
ExceptionTypesCollector visitor = new ExceptionTypesCollector();
|
||||
thisOrSuperCallInConstructor.accept(visitor);
|
||||
return visitor.exceptionTypes.contains(exceptionType);
|
||||
return throwsExceptionsTypes(thisOrSuperCallInConstructor, exceptionTypes);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean throwsExceptionsTypes(@NotNull PsiMethodCallExpression thisOrSuperCallInConstructor,
|
||||
@NotNull Collection<PsiClassType> exceptionTypes) {
|
||||
ExceptionTypesCollector visitor = new ExceptionTypesCollector();
|
||||
thisOrSuperCallInConstructor.accept(visitor);
|
||||
return ContainerUtil.intersects(visitor.exceptionTypes, exceptionTypes);
|
||||
}
|
||||
|
||||
private static class ExceptionTypesCollector extends JavaRecursiveElementWalkingVisitor {
|
||||
private final Collection<PsiClassType> exceptionTypes = new HashSet<>();
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.plushnikov.intellij.plugin.handler;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.UnhandledExceptionFixProvider;
|
||||
import com.intellij.codeInsight.intention.AddAnnotationFix;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.JavaPsiConstructorUtil;
|
||||
import de.plushnikov.intellij.plugin.LombokClassNames;
|
||||
import de.plushnikov.intellij.plugin.quickfix.PsiQuickFixFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adds @SneakyThrows Annotation as Fix to handle unhandled exceptions
|
||||
*/
|
||||
public class SneakyThrowsUnhandledExceptionFixProvider implements UnhandledExceptionFixProvider {
|
||||
@Override
|
||||
public void registerUnhandledExceptionFixes(@NotNull HighlightInfo.Builder info,
|
||||
@NotNull PsiElement element,
|
||||
@NotNull List<PsiClassType> unhandledExceptions) {
|
||||
PsiElement importantParent = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiLambdaExpression.class,
|
||||
PsiMethodReferenceExpression.class, PsiClassInitializer.class);
|
||||
|
||||
// applicable only for methods
|
||||
if (importantParent instanceof PsiMethod psiMethod) {
|
||||
final PsiMethodCallExpression thisOrSuperCallInConstructor = JavaPsiConstructorUtil.findThisOrSuperCallInConstructor(psiMethod);
|
||||
if (null == thisOrSuperCallInConstructor ||
|
||||
!SneakyThrowsExceptionHandler.throwsExceptionsTypes(thisOrSuperCallInConstructor, unhandledExceptions)) {
|
||||
|
||||
AddAnnotationFix fix = PsiQuickFixFactory.createAddAnnotationFix(LombokClassNames.SNEAKY_THROWS, psiMethod);
|
||||
info.registerFix(fix, null, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,7 @@
|
||||
<fileBasedIndex implementation="de.plushnikov.intellij.plugin.lombokconfig.LombokConfigIndex"/>
|
||||
|
||||
<custom.exception.handler implementation="de.plushnikov.intellij.plugin.handler.SneakyThrowsExceptionHandler"/>
|
||||
<unhandledExceptionFixProvider implementation="de.plushnikov.intellij.plugin.handler.SneakyThrowsUnhandledExceptionFixProvider"/>
|
||||
|
||||
<implicit.resource.closer
|
||||
implementation="de.plushnikov.intellij.plugin.extension.LombokCleanUpImplicitResourceCloser"/>
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package de.plushnikov.intellij.plugin.highlights;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import de.plushnikov.intellij.plugin.AbstractLombokLightCodeInsightTestCase;
|
||||
import de.plushnikov.intellij.plugin.inspection.LombokInspection;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SneakyThrowsQuickFixTest extends AbstractLombokLightCodeInsightTestCase {
|
||||
|
||||
public void testSneakyThrowsInvalidQuickFix() {
|
||||
myFixture.enableInspections(LombokInspection.class);
|
||||
|
||||
@Language("JAVA") final String text = """
|
||||
import lombok.SneakyThrows;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestSneakyThrow {
|
||||
|
||||
@SneakyThrows<caret>
|
||||
public TestSneakyThrow(String s) {
|
||||
this(throwException());
|
||||
}
|
||||
|
||||
public TestSneakyThrow(int i) {
|
||||
}
|
||||
|
||||
private static int throwException() throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
""";
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, text);
|
||||
|
||||
myFixture.launchAction("Remove annotation");
|
||||
|
||||
@Language("JAVA") final String expectedText = """
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestSneakyThrow {
|
||||
|
||||
public TestSneakyThrow(String s) {
|
||||
this(throwException());
|
||||
}
|
||||
|
||||
public TestSneakyThrow(int i) {
|
||||
}
|
||||
|
||||
private static int throwException() throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
""";
|
||||
myFixture.checkResult(expectedText, true);
|
||||
}
|
||||
|
||||
public void testSneakyThrowsUnhandledExceptionWithoutQuickFix() {
|
||||
@Language("JAVA") final String text = """
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestSneakyThrow {
|
||||
|
||||
public TestSneakyThrow(String s) {
|
||||
this(<caret>throwException());
|
||||
}
|
||||
|
||||
public TestSneakyThrow(int i) {
|
||||
}
|
||||
|
||||
private static int throwException() throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
""";
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, text);
|
||||
|
||||
List<IntentionAction> actions = myFixture.filterAvailableIntentions("Annotate constructor 'TestSneakyThrow()' as '@SneakyThrows'");
|
||||
assertEmpty(actions);
|
||||
}
|
||||
|
||||
public void testSneakyThrowsUnhandledExceptionWithQuickFix() {
|
||||
@Language("JAVA") final String text = """
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestSneakyThrow {
|
||||
|
||||
public TestSneakyThrow(String s) {
|
||||
this(throwException());
|
||||
if (1 == 1) {
|
||||
throw new <caret>Exception("123");
|
||||
}
|
||||
}
|
||||
|
||||
public TestSneakyThrow(int i) {
|
||||
}
|
||||
|
||||
private static int throwException() throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
""";
|
||||
myFixture.configureByText(JavaFileType.INSTANCE, text);
|
||||
|
||||
myFixture.launchAction("Annotate constructor 'TestSneakyThrow()' as '@SneakyThrows'");
|
||||
|
||||
@Language("JAVA") final String expectedText = """
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestSneakyThrow {
|
||||
|
||||
@SneakyThrows
|
||||
public TestSneakyThrow(String s) {
|
||||
this(throwException());
|
||||
if (1 == 1) {
|
||||
throw new Exception("123");
|
||||
}
|
||||
}
|
||||
|
||||
public TestSneakyThrow(int i) {
|
||||
}
|
||||
|
||||
private static int throwException() throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
""";
|
||||
myFixture.checkResult(expectedText, true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user