mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +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
@@ -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