IDEA-305079 show usages for record fields using lombok @Builder and @With #2252

GitOrigin-RevId: fae916295f1a3cc40d759bf10a995446aa43a7ca
This commit is contained in:
Henri Viik
2022-11-27 20:49:28 +01:00
committed by intellij-monorepo-bot
parent c072a65cd8
commit 2504ec6d32
6 changed files with 81 additions and 17 deletions

View File

@@ -6,6 +6,8 @@ import com.intellij.openapi.project.DumbService;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMember;
import com.intellij.psi.PsiRecordComponent;
import com.intellij.psi.util.PsiUtilCore;
import de.plushnikov.intellij.plugin.psi.LombokLightClassBuilder;
import de.plushnikov.intellij.plugin.psi.LombokLightFieldBuilder;
@@ -26,9 +28,9 @@ public class LombokFieldFindUsagesHandlerFactory extends FindUsagesHandlerFactor
@Override
public boolean canFindUsages(@NotNull PsiElement element) {
if (element instanceof PsiField && !DumbService.isDumb(element.getProject())) {
final PsiField psiField = (PsiField) element;
final PsiClass containingClass = psiField.getContainingClass();
if ((element instanceof PsiField || element instanceof PsiRecordComponent) && !DumbService.isDumb(element.getProject())) {
final PsiMember psiMember = (PsiMember) element;
final PsiClass containingClass = psiMember.getContainingClass();
if (containingClass != null) {
return Arrays.stream(containingClass.getMethods()).anyMatch(LombokLightMethodBuilder.class::isInstance) ||
Arrays.stream(containingClass.getInnerClasses()).anyMatch(LombokLightClassBuilder.class::isInstance);
@@ -42,34 +44,34 @@ public class LombokFieldFindUsagesHandlerFactory extends FindUsagesHandlerFactor
return new FindUsagesHandler(element) {
@Override
public PsiElement @NotNull [] getSecondaryElements() {
final PsiField psiField = (PsiField) getPsiElement();
final PsiClass containingClass = psiField.getContainingClass();
final PsiMember psiMember = (PsiMember) getPsiElement();
final PsiClass containingClass = psiMember.getContainingClass();
if (containingClass != null) {
final Collection<PsiElement> elements = new ArrayList<>();
processClass(containingClass, psiField, elements);
processClass(containingClass, psiMember, elements);
Arrays.stream(containingClass.getInnerClasses())
.forEach(psiClass -> processClass(psiClass, psiField, elements));
.forEach(psiClass -> processClass(psiClass, psiMember, elements));
return PsiUtilCore.toPsiElementArray(elements);
}
return PsiElement.EMPTY_ARRAY;
}
private static void processClass(PsiClass containingClass, PsiField refPsiField, Collection<PsiElement> collector) {
private static void processClass(PsiClass containingClass, PsiMember refPsiField, Collection<PsiElement> collector) {
processClassMethods(containingClass, refPsiField, collector);
processClassFields(containingClass, refPsiField, collector);
}
private static void processClassFields(PsiClass containingClass, PsiField refPsiField, Collection<PsiElement> collector) {
private static void processClassFields(PsiClass containingClass, PsiMember refPsiField, Collection<PsiElement> collector) {
Arrays.stream(containingClass.getFields())
.filter(LombokLightFieldBuilder.class::isInstance)
.filter(psiField -> psiField.getNavigationElement() == refPsiField)
.forEach(collector::add);
}
private static void processClassMethods(PsiClass containingClass, PsiField refPsiField, Collection<PsiElement> collector) {
private static void processClassMethods(PsiClass containingClass, PsiMember refPsiField, Collection<PsiElement> collector) {
Arrays.stream(containingClass.getMethods())
.filter(LombokLightMethodBuilder.class::isInstance)
.filter(psiMethod -> psiMethod.getNavigationElement() == refPsiField)

View File

@@ -83,12 +83,14 @@ public class BuilderProcessor extends AbstractClassProcessor {
@Override
protected void generatePsiElements(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation, @NotNull List<? super PsiElement> target) {
if (PsiAnnotationSearchUtil.isNotAnnotatedWith(psiClass, LombokClassNames.ALL_ARGS_CONSTRUCTOR,
LombokClassNames.REQUIRED_ARGS_CONSTRUCTOR, LombokClassNames.NO_ARGS_CONSTRUCTOR)) {
// Create all args constructor only if there is no declared constructors and no lombok constructor annotations
final Collection<PsiMethod> definedConstructors = PsiClassUtil.collectClassConstructorIntern(psiClass);
if (definedConstructors.isEmpty()) {
target.addAll(getAllArgsConstructorProcessor().createAllArgsConstructor(psiClass, PsiModifier.PACKAGE_LOCAL, psiAnnotation));
if (!psiClass.isRecord()) {
if (PsiAnnotationSearchUtil.isNotAnnotatedWith(psiClass, LombokClassNames.ALL_ARGS_CONSTRUCTOR,
LombokClassNames.REQUIRED_ARGS_CONSTRUCTOR, LombokClassNames.NO_ARGS_CONSTRUCTOR)) {
// Create all args constructor only if there is no declared constructors and no lombok constructor annotations
final Collection<PsiMethod> definedConstructors = PsiClassUtil.collectClassConstructorIntern(psiClass);
if (definedConstructors.isEmpty()) {
target.addAll(getAllArgsConstructorProcessor().createAllArgsConstructor(psiClass, PsiModifier.PACKAGE_LOCAL, psiAnnotation));
}
}
}

View File

@@ -3,6 +3,7 @@ package de.plushnikov.intellij.plugin.processor.clazz.constructor;
import com.intellij.codeInsight.daemon.impl.quickfix.SafeDeleteFix;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.RecordAugmentProvider;
import com.intellij.psi.impl.light.LightReferenceListBuilder;
import com.intellij.psi.impl.light.LightTypeParameterBuilder;
import com.intellij.psi.util.PsiTypesUtil;
@@ -182,7 +183,9 @@ public abstract class AbstractConstructorClassProcessor extends AbstractClassPro
protected static Collection<PsiField> getAllNotInitializedAndNotStaticFields(@NotNull PsiClass psiClass) {
Collection<PsiField> allNotInitializedNotStaticFields = new ArrayList<>();
final boolean classAnnotatedWithValue = PsiAnnotationSearchUtil.isAnnotatedWith(psiClass, LombokClassNames.VALUE);
for (PsiField psiField : PsiClassUtil.collectClassFieldsIntern(psiClass)) {
Collection<PsiField> fields = psiClass.isRecord() ? RecordAugmentProvider.getFieldAugments(psiClass)
: PsiClassUtil.collectClassFieldsIntern(psiClass);
for (PsiField psiField : fields) {
// skip fields named $
boolean addField = !psiField.getName().startsWith(LombokUtils.LOMBOK_INTERN_FIELD_MARKER);

View File

@@ -7,9 +7,11 @@ import com.intellij.find.findUsages.JavaClassFindUsagesOptions;
import com.intellij.find.impl.FindManagerImpl;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.CommonProcessors;
import de.plushnikov.intellij.plugin.AbstractLombokLightCodeInsightTestCase;
import de.plushnikov.intellij.plugin.LombokTestUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -21,6 +23,12 @@ import java.util.List;
*/
public class LombokUsageTest extends AbstractLombokLightCodeInsightTestCase {
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return LombokTestUtil.LOMBOK_NEW_DESCRIPTOR;
}
public void testFindUsageGetterSetter() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "findUsageGetterSetter.setBar", "findUsageGetterSetter.getBar");
@@ -36,11 +44,21 @@ public class LombokUsageTest extends AbstractLombokLightCodeInsightTestCase {
assertUsages(usages, "findUsageWither.withBar", "findUsageWither.getBar");
}
public void testFindUsageWitherRecord() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "findUsageWitherRecord.withBar", "findUsageWitherRecord.bar");
}
public void testFindUsageBuilder() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "FindUsageBuilder.builder().bar", "findUsageBuilder.getBar");
}
public void testFindUsageBuilderRecord() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "FindUsageBuilderRecord.builder().bar", "findUsageBuilderRecord.bar");
}
public void testFindUsageSingularBuilder() {
final Collection<UsageInfo> usages = loadTestClass();
assertUsages(usages, "FindUsageSingularBuilder.builder().bar", "FindUsageSingularBuilder.builder().bars",

View File

@@ -0,0 +1,19 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
import lombok.Builder;
@Builder
public record FindUsageBuilderRecord(
int foo,
String b<caret>ar
) {
public static void main(String[] args) {
FindUsageBuilderRecord findUsageBuilderRecord = FindUsageBuilderRecord.builder()
.bar("bar")
.foo(1981)
.build();
System.out.println("Bar is: " + findUsageBuilderRecord.bar());
System.out.println("Foo is: " + findUsageBuilderRecord.foo());
}
}

View File

@@ -0,0 +1,20 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
import lombok.Value;
import lombok.experimental.Wither;
@Wither
@Value
public record FindUsageWitherRecord(
int foo,
String b<caret>ar
) {
public static void main(String[] args) {
FindUsageWitherRecord findUsageWitherRecord = new FindUsageWitherRecord(1, "bar");
findUsageWitherRecord
.withBar("myBar")
.withFoo(1981);
System.out.println("Bar is: " + findUsageWitherRecord.bar());
System.out.println("Foo is: " + findUsageWitherRecord.foo());
}
}