Skip to content

Commit

Permalink
Implemented Reference-Searcher for fields and lombok generated method…
Browse files Browse the repository at this point in the history
…s like setter/getter/builder/wither

fixed #144
fixed #186
  • Loading branch information
mplushnikov committed Jul 15, 2018
1 parent 769c9ba commit 57c46f6
Show file tree
Hide file tree
Showing 25 changed files with 450 additions and 92 deletions.
2 changes: 2 additions & 0 deletions parts/pluginChanges.html
@@ -1,6 +1,8 @@
<ul>
<li>0.20
<ol>
<li>Fixed #144: Find usages on field should find usages of builder/wither methods</li>
<li>Fixed #186: Find usages doesn't work (for example Accessors with Setter/Getter)</li>
<li>Fixed #450: @Builder doesn't mark generated builder 'setters' as @Deprecated if the source field is deprecated</li>
<li>Fixed #497: Lombok plugin breaks creating Intellij IDEA postfix expressions</li>
<li>Fixed #499: @Builder does not respect @Accessors on fields</li>
Expand Down

This file was deleted.

@@ -0,0 +1,51 @@
package de.plushnikov.intellij.plugin.extension;

import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.SearchRequestCollector;
import com.intellij.psi.search.UsageSearchContext;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.Processor;
import de.plushnikov.intellij.plugin.psi.LombokLightMethodBuilder;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;

public class LombokReferenceSearcher extends QueryExecutorBase<PsiReference, ReferencesSearch.SearchParameters> {

public LombokReferenceSearcher() {
super(true);
}

@Override
public void processQuery(@NotNull ReferencesSearch.SearchParameters queryParameters, @NotNull Processor<PsiReference> consumer) {
PsiElement refElement = queryParameters.getElementToSearch();

if (refElement instanceof PsiField) {
processPsiField((PsiField) refElement, queryParameters.getOptimizer());
}
}

private void processPsiField(final PsiField refPsiField, final SearchRequestCollector collector) {
final PsiClass containingClass = refPsiField.getContainingClass();
if (null != containingClass) {
processClassMethods(refPsiField, collector, containingClass);

Arrays.stream(containingClass.getInnerClasses())
.forEach(psiClass -> processClassMethods(refPsiField, collector, psiClass));
}
}

private void processClassMethods(PsiField refPsiField, SearchRequestCollector collector, PsiClass containingClass) {
Arrays.stream(containingClass.getMethods())
.filter(LombokLightMethodBuilder.class::isInstance)
.filter(psiMethod -> psiMethod.getNavigationElement() == refPsiField)
.forEach(psiMethod -> {
collector.searchWord(psiMethod.getName(), psiMethod.getUseScope(), UsageSearchContext.IN_CODE, true, psiMethod);
});
}

}
@@ -1,16 +1,17 @@
package de.plushnikov.intellij.plugin.extension;

import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import com.intellij.refactoring.rename.RenameJavaVariableProcessor;
import de.plushnikov.intellij.plugin.processor.field.AccessorsInfo;
import de.plushnikov.intellij.plugin.psi.LombokLightMethodBuilder;
import de.plushnikov.intellij.plugin.thirdparty.LombokUtils;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Map;

public class LombokRenameFieldReferenceProcessor extends RenameJavaVariableProcessor {
Expand All @@ -20,39 +21,41 @@ public LombokRenameFieldReferenceProcessor() {

@Override
public boolean canProcessElement(@NotNull PsiElement element) {
final boolean isPsiJavaField = element instanceof PsiField && StdFileTypes.JAVA.getLanguage().equals(element.getLanguage());
if (isPsiJavaField) {
if (element instanceof PsiField) {
final PsiField psiField = (PsiField) element;
AccessorsInfo accessorsInfo = AccessorsInfo.build(psiField);
final String accessorFieldName = accessorsInfo.removePrefix(psiField.getName());
if (!psiField.getName().equals(accessorFieldName)) {
return true;
final PsiClass containingClass = psiField.getContainingClass();
if (null != containingClass) {
return Arrays.stream(containingClass.getAllMethods())
.filter(LombokLightMethodBuilder.class::isInstance)
.anyMatch(psiMethod -> psiMethod.getNavigationElement() == psiField);
}
}
return false;
}

@Override
public void prepareRenaming(PsiElement element, String newName, Map<PsiElement, String> allRenames) {
public void prepareRenaming(@NotNull PsiElement element, @NotNull String newName, @NotNull Map<PsiElement, String> allRenames) {
final PsiField psiField = (PsiField) element;
final PsiClass containingClass = psiField.getContainingClass();
if (null != containingClass) {
final AccessorsInfo accessorsInfo = AccessorsInfo.build(psiField);
final String psiFieldName = psiField.getName();

final String currentFieldName = psiField.getName();
final boolean isBoolean = PsiType.BOOLEAN.equals(psiField.getType());

final String getterName = LombokUtils.toGetterName(accessorsInfo, psiFieldName, isBoolean);
final String setterName = LombokUtils.toSetterName(accessorsInfo, psiFieldName, isBoolean);
final String getterName = LombokUtils.toGetterName(accessorsInfo, currentFieldName, isBoolean);
final String setterName = LombokUtils.toSetterName(accessorsInfo, currentFieldName, isBoolean);

final PsiMethod[] psiGetterMethods = containingClass.findMethodsByName(getterName, false);
final PsiMethod[] psiSetterMethods = containingClass.findMethodsByName(setterName, false);

String newFieldName = accessorsInfo.removePrefix(newName);
for (PsiMethod psiMethod : psiGetterMethods) {
allRenames.put(psiMethod, LombokUtils.toGetterName(accessorsInfo, newName, isBoolean));
allRenames.put(psiMethod, LombokUtils.toGetterName(accessorsInfo, newFieldName, isBoolean));
}

for (PsiMethod psiMethod : psiSetterMethods) {
allRenames.put(psiMethod, LombokUtils.toSetterName(accessorsInfo, newName, isBoolean));
allRenames.put(psiMethod, LombokUtils.toSetterName(accessorsInfo, newFieldName, isBoolean));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/META-INF/plugin.xml
Expand Up @@ -66,7 +66,7 @@

<custom.exception.handler implementation="de.plushnikov.intellij.plugin.handler.SneakyThrowsExceptionHandler"/>

<findUsagesHandlerFactory implementation="de.plushnikov.intellij.plugin.extension.LombokFieldFindUsagesHandlerFactory"/>
<referencesSearch implementation="de.plushnikov.intellij.plugin.extension.LombokReferenceSearcher"/>
<renamePsiElementProcessor implementation="de.plushnikov.intellij.plugin.extension.LombokRenameFieldReferenceProcessor"/>

<java.elementFinder implementation="de.plushnikov.intellij.plugin.extension.LombokElementFinder" order="last"/>
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages/lombokBundle.properties
Expand Up @@ -20,6 +20,8 @@ config.warn.dependency.outdated.message=<br>\

daemon.donate.title=Lombok support plugin updated to v{0}
daemon.donate.content=\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/144">#144</a>): Find usages on field should find usages of builder/wither methods<br>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/186">#186</a>): Find usages doesn't work (for example Accessors with Setter/Getter)<br>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/450">#450</a>): @Builder doesn't mark generated builder 'setters' as @Deprecated if the source field is deprecated<br>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/497">#497</a>): Lombok plugin breaks creating Intellij IDEA postfix expressions<br>\
- Fixed (<a href="https://github.com/mplushnikov/lombok-intellij-plugin/issues/499">#499</a>): @Builder does not respect @Accessors on fields<br>\
Expand Down
@@ -0,0 +1,55 @@
package de.plushnikov.intellij.plugin.usage;

import com.intellij.usageView.UsageInfo;
import de.plushnikov.intellij.plugin.AbstractLombokLightCodeInsightTestCase;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
* Test for lombok find usage extension
*/
public class LombokUsageTest extends AbstractLombokLightCodeInsightTestCase {

public void testFindUsageGetterSetter() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "findUsageGetterSetter.setBar", "findUsageGetterSetter.getBar");
}

public void testFindUsageAccessors() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "findUsageAccessors.setBar", "findUsageAccessors.getBar");
}

public void testFindUsageWither() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "findUsageWither\n .withBar", "findUsageWither.getBar");
}

public void testFindUsageBuilder() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "FindUsageBuilder.builder()\n .bar", "findUsageBuilder.getBar");
}

private void assertUsages(Collection<UsageInfo> usages, String... usageTexts) {
assertEquals(usageTexts.length, usages.size());
List<UsageInfo> sortedUsages = new ArrayList<UsageInfo>(usages);
Collections.sort(sortedUsages, UsageInfo::compareToByStartOffset);
for (int i = 0; i < usageTexts.length; i++) {
assertEquals(usageTexts[i], sortedUsages.get(i).getElement().getText());
}
}

@NotNull
private Collection<UsageInfo> loadTestClass() {
return myFixture.testFindUsages(getBasePath() + getTestName(false) + ".java");
}

@Override
protected String getBasePath() {
return super.getBasePath() + "/usage/";
}
}
@@ -0,0 +1,21 @@
package de.plushnikov.builder.issue450;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@lombok.Builder
public class BuilderWithDeprecatedField {
private String bar;

@Deprecated
private String foo;

@Deprecated
private List<String> xyzs;

public static void main(String[] args) {
System.out.println(BuilderWithDeprecatedField.builder().bar("bar").foo("foo").xyzs(Collections.singletonList("yxzx")).clearXyzs().xyz("xyz").build());
}
}
@@ -0,0 +1,13 @@
package de.plushnikov.builder.issue450;

public class BuilderWithDeprecatedParam {

@lombok.Builder
private static java.util.Collection<String> creator(String bar, @Deprecated String foo) {
return java.util.Arrays.asList(bar, foo);
}

public static void main(String[] args) {
System.out.println(BuilderWithDeprecatedParam.builder().bar("bar").foo("foo").build());
}
}
@@ -0,0 +1,15 @@
package de.plushnikov.builder.issue499;

import lombok.Builder;
import lombok.experimental.Accessors;

@Builder
public class TestClass {
@Accessors(prefix = "m")
private String mSample = "sample 1";

public static void main(String[] args) {
TestClass.builder().sample("sample 2").build();
builder().sample("").build();
}
}
37 changes: 37 additions & 0 deletions test-manual/src/main/java/de/plushnikov/findusages/DataItem.java
@@ -0,0 +1,37 @@
package de.plushnikov.findusages;

import lombok.*;
import lombok.experimental.Accessors;
import sun.security.util.Password;

import java.time.Instant;

@Value
@ToString
@Accessors(fluent = true)
@Builder
public class DataItem {
@NonNull
String name;
String anotherName;
@NonNull
Instant createTimestamp;
@NonNull
String content;

@Getter
@Accessors(fluent = true)
final Password password;

public static void main(String[] args) {
DataItem item = DataItem.builder()
.name("a")
.anotherName("a")
.createTimestamp(Instant.now())
.content("content")
.build();
System.out.println("Item.name = " + item.name());
System.out.println("Item.name = " + item.anotherName());
System.out.println(item.password());
}
}
@@ -0,0 +1,23 @@
package de.plushnikov.findusages;

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(prefix = "m", fluent = true)
public class FindUsageAccessors {
private int mFoo;

@Accessors(prefix = "_")
private String _Bar;

private String bMar;

public static void main(String[] args) {
FindUsageAccessors findUsageAccessors = new FindUsageAccessors();
findUsageAccessors.setBar("myBar");
findUsageAccessors.foo(1981);
System.out.println("Bar is: " + findUsageAccessors.getBar());
System.out.println("Foo is: " + findUsageAccessors.foo());
}
}

0 comments on commit 57c46f6

Please sign in to comment.