Skip to content
This repository has been archived by the owner on Nov 3, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into backport_intellij_2019.2
Browse files Browse the repository at this point in the history
# Conflicts:
#	.travis.yml
#	gradle.properties
  • Loading branch information
mplushnikov committed Dec 1, 2019
2 parents a59854c + cbed337 commit 015cb6f
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 32 deletions.
1 change: 1 addition & 0 deletions parts/pluginChanges.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<ul>
<li>0.28
<ol>
<li>Fixed #394: New feature request: Add SneakyThrows QuickFix, thanks to @Lekanich (Aleksandr Lekanich)</li>
<li>Fixed #440: NPE inspection false positive with lazy getters, thanks to @Lekanich (Aleksandr Lekanich)</li>
<li>Fixed #633: @Builder.Default causes a warning message, thanks to @Lekanich (Aleksandr Lekanich)</li>
<li>Fixed #672: Add support for @CustomLog, thanks to @juriad (Adam Juraszek)</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@

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.util.text.StringUtil;
import com.intellij.psi.PsiClassInitializer;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiLambdaExpression;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiMethodReferenceExpression;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.util.PsiTreeUtil;
import de.plushnikov.intellij.plugin.handler.BuilderHandler;
import de.plushnikov.intellij.plugin.handler.EqualsAndHashCodeCallSuperHandler;
import de.plushnikov.intellij.plugin.handler.LazyGetterHandler;
import de.plushnikov.intellij.plugin.handler.OnXAnnotationHandler;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -24,19 +31,25 @@


public class LombokHighlightErrorFilter implements HighlightInfoFilter {

private static final Pattern UNINITIALIZED_MESSAGE = Pattern.compile("Variable '.+' might not have been initialized");
private static final Pattern LOMBOK_ANY_ANNOTATION_REQUIRED = Pattern.compile("Incompatible types\\. Found: '__*', required: 'lombok.*AnyAnnotation\\[\\]'");

private final Map<HighlightSeverity, Map<TextAttributesKey, List<LombokHighlightFilter>>> registeredFilters;
private final Map<HighlightSeverity, Map<TextAttributesKey, List<LombokHighlightFixHook>>> registeredHooks;

public LombokHighlightErrorFilter() {
registeredFilters = new HashMap<>();
registeredHooks = new HashMap<>();

for (LombokHighlightFilter highlightFilter : LombokHighlightFilter.values()) {
registeredFilters.computeIfAbsent(highlightFilter.severity, s -> new HashMap<>())
.computeIfAbsent(highlightFilter.key, k -> new ArrayList<>())
.add(highlightFilter);
}

for (LombokHighlightFilter value : LombokHighlightFilter.values()) {
registeredFilters.computeIfAbsent(value.severity, s -> new HashMap<>())
.computeIfAbsent(value.key, k -> new ArrayList<>())
.add(value);
for (LombokHighlightFixHook highlightFixHook : LombokHighlightFixHook.values()) {
registeredHooks.computeIfAbsent(highlightFixHook.severity, s -> new HashMap<>())
.computeIfAbsent(highlightFixHook.key, k -> new ArrayList<>())
.add(highlightFixHook);
}
}

Expand All @@ -51,30 +64,97 @@ public boolean accept(@NotNull HighlightInfo highlightInfo, @Nullable PsiFile fi
return true;
}

String description = StringUtil.notNullize(highlightInfo.getDescription());
if (HighlightSeverity.ERROR.equals(highlightInfo.getSeverity())) {
// check exceptions for highlights
boolean acceptHighlight = registeredFilters
.getOrDefault(highlightInfo.getSeverity(), Collections.emptyMap())
.getOrDefault(highlightInfo.type.getAttributesKey(), Collections.emptyList())
.stream()
.filter(filter -> filter.descriptionCheck(highlightInfo.getDescription()))
.allMatch(filter -> filter.accept(highlightedElement));

// check if highlight was filtered
if (!acceptHighlight) {
return false;
}

// Handling LazyGetter
if (uninitializedField(description) && LazyGetterHandler.isLazyGetterHandled(highlightedElement)) {
// handle rest cases
String description = highlightInfo.getDescription();
if (HighlightSeverity.ERROR.equals(highlightInfo.getSeverity())) {
//Handling onX parameters
if (OnXAnnotationHandler.isOnXParameterAnnotation(highlightInfo, file)
|| OnXAnnotationHandler.isOnXParameterValue(highlightInfo, file)
|| (description != null && LOMBOK_ANY_ANNOTATION_REQUIRED.matcher(description).matches())) {
return false;
}
}

//Handling onX parameters
return !OnXAnnotationHandler.isOnXParameterAnnotation(highlightInfo, file)
&& !OnXAnnotationHandler.isOnXParameterValue(highlightInfo, file)
&& !LOMBOK_ANY_ANNOTATION_REQUIRED.matcher(description).matches();
// register different quick fix for highlight
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 = Pattern.compile("Unhandled exception: .+");

@Override
public boolean descriptionCheck(@Nullable String description) {
return description != null && pattern.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 = new AddAnnotationFix(SneakyThrows.class.getCanonicalName(), (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;
}

// check other exceptions for highlights
Map<TextAttributesKey, List<LombokHighlightFilter>> severityMap = registeredFilters
.getOrDefault(highlightInfo.getSeverity(), Collections.emptyMap());
abstract public boolean descriptionCheck(@Nullable String description);

return severityMap.getOrDefault(highlightInfo.type.getAttributesKey(), Collections.emptyList()).stream()
.filter(filter -> filter.descriptionCheck(description))
.allMatch(filter -> filter.accept(highlightedElement));
abstract public void processHook(@NotNull PsiElement highlightedElement, @NotNull HighlightInfo highlightInfo);
}

private enum LombokHighlightFilter {
// ERROR HANDLERS

VARIABLE_MIGHT_NOT_BEEN_INITIALIZED(HighlightSeverity.ERROR, CodeInsightColors.ERRORS_ATTRIBUTES) {
private final Pattern pattern = Pattern.compile("Variable '.+' might not have been initialized");

@Override
public boolean descriptionCheck(@Nullable String description) {
return description != null && pattern.matcher(description).matches();
}

@Override
public boolean accept(@NotNull PsiElement highlightedElement) {
return !LazyGetterHandler.isLazyGetterHandled(highlightedElement);
}
},

// WARNINGS HANDLERS

VARIABLE_INITIALIZER_IS_REDUNDANT(HighlightSeverity.WARNING, CodeInsightColors.NOT_USED_ELEMENT_ATTRIBUTES) {
private final Pattern pattern = Pattern.compile("Variable '.+' initializer '.+' is redundant");

Expand Down Expand Up @@ -130,8 +210,4 @@ public boolean accept(@NotNull PsiElement highlightedElement) {

abstract public boolean accept(@NotNull PsiElement highlightedElement);
}

private boolean uninitializedField(String description) {
return UNINITIALIZED_MESSAGE.matcher(description).matches();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.regex.Pattern;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.With;
import lombok.experimental.Wither;


public class OnXAnnotationHandler {
private static final Pattern UNDERSCORES = Pattern.compile("__*");
Expand All @@ -21,13 +30,14 @@ public class OnXAnnotationHandler {
private static final String CANNOT_FIND_METHOD_VALUE_MESSAGE = "Cannot find method 'value'";

private static final Collection<String> ONXABLE_ANNOTATIONS = Arrays.asList(
"lombok.Getter",
"lombok.Setter",
"lombok.experimental.Wither",
"lombok.NoArgsConstructor",
"lombok.RequiredArgsConstructor",
"lombok.AllArgsConstructor",
"lombok.EqualsAndHashCode"
Getter.class.getCanonicalName(),
Setter.class.getCanonicalName(),
With.class.getCanonicalName(),
Wither.class.getCanonicalName(),
NoArgsConstructor.class.getCanonicalName(),
RequiredArgsConstructor.class.getCanonicalName(),
AllArgsConstructor.class.getCanonicalName(),
EqualsAndHashCode.class.getCanonicalName()
);
private static final Collection<String> ONX_PARAMETERS = Arrays.asList(
"onConstructor",
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/messages/lombokBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ daemon.donate.title=Lombok support plugin updated to v{0}
daemon.donate.content=<br/>\
Helpful? <b><a href="https://www.paypal.me/mplushnikov">Donate with PayPal</a></b><br/><br/>\
Fixes:<br/>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/394">#394</a>): New feature request: Add SneakyThrows QuickFix, thanks to @Lekanich (Aleksandr Lekanich)<br>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/440">#440</a>): NPE inspection false positive with lazy getters, thanks to @Lekanich (Aleksandr Lekanich)<br>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/633">#633</a>): @Builder.Default causes a warning message, thanks to @Lekanich (Aleksandr Lekanich)<br>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/672">#672</a>): Add support for @CustomLog, thanks to @juriad (Adam Juraszek)<br>\
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package de.plushnikov.intellij.plugin.extension;

import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import de.plushnikov.intellij.plugin.AbstractLombokLightCodeInsightTestCase;

import java.util.List;

public class SneakyThrowsExceptionAddQuickFixTest extends AbstractLombokLightCodeInsightTestCase {

@Override
protected String getBasePath() {
return super.getBasePath() + "/extension";
}

public void testCheckedExeptionQuickFixExample() {
myFixture.configureByFile(getBasePath() + '/' + getTestName(false) + ".java");

final List<IntentionAction> availableActions = getAvailableActions();
assertTrue("Intention to add @SneakyThrows was not presented",
availableActions.stream().anyMatch(action -> action.getText().contains("@SneakyThrows")));
}

protected List<IntentionAction> getAvailableActions() {
final Editor editor = getEditor();
final PsiFile file = getFile();
CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, new int[0], false);
return CodeInsightTestFixtureImpl.getAvailableIntentions(editor, file);
}

}
21 changes: 21 additions & 0 deletions test-manual/src/main/java/de/plushnikov/findusages/Issue645.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package de.plushnikov.findusages;

import lombok.Builder;

public class Issue645 {
@Builder
public static class SomeDataClass {
public static class SomeDataClassBuilder {
private void buildWithJSON() {
this.jsonObject = "test";
}
}

public final String jsonObject;
}

public static void main(String[] args) {
SomeDataClass dataClass = SomeDataClass.builder().jsonObject("sdsdsd").build();
System.out.println(dataClass.jsonObject);
}
}
18 changes: 18 additions & 0 deletions test-manual/src/main/java/de/plushnikov/sneakythrows/Issue394.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.plushnikov.sneakythrows;

import lombok.SneakyThrows;

import java.io.File;

public class Issue394 {

// @SneakyThrows
public String calcString() {
new File("somePath").createNewFile();
return "";
}

public static void main(String[] args) {
new Issue394().calcString();
}
}
14 changes: 14 additions & 0 deletions testData/extension/CheckedExeptionQuickFixExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package extension;

import java.io.IOException;

public class CheckedExeptionQuickFixExample {

public int calcSomething() {
<caret>throw new IOException();
}

public static void main(String[] args) {
System.out.println(new CheckedExeptionQuickFixExample().calcSomething());
}
}

0 comments on commit 015cb6f

Please sign in to comment.