mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[lombok] IDEA-305806 IDEA-301687 provided new extension point for custom property group handling : added support to "structure tool tab" to show lombok's @With methods and @Accessors(fluent = true) in properties (together with getters and setter)
GitOrigin-RevId: f7baae1c9c5690c2b0002d3b1276b7d25ec83040
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b62f68a267
commit
50788430bd
@@ -0,0 +1,42 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi.util;
|
||||
|
||||
import com.intellij.lang.java.beans.PropertyKind;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class DefaultPropertyAccessorDetector implements PropertyAccessorDetector {
|
||||
private static final ExtensionPointName<PropertyAccessorDetector> EP_NAME = ExtensionPointName.create("com.intellij.propertyAccessorDetector");
|
||||
|
||||
public static @Nullable PropertyAccessorInfo detectFrom(@NotNull PsiMethod method) {
|
||||
for (PropertyAccessorDetector detector : EP_NAME.getExtensions()) {
|
||||
PropertyAccessorInfo accessorInfo = detector.detectPropertyAccessor(method);
|
||||
if (accessorInfo != null) {
|
||||
return accessorInfo;
|
||||
}
|
||||
}
|
||||
return getAccessorInfo(method);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PropertyAccessorInfo getAccessorInfo(@NotNull PsiMethod method) {
|
||||
if (PropertyUtilBase.isSimplePropertyGetter(method)) {
|
||||
return new PropertyAccessorInfo(PropertyUtilBase.getPropertyNameByGetter(method),
|
||||
method.getReturnType(),
|
||||
PropertyKind.GETTER);
|
||||
}
|
||||
else if (PropertyUtilBase.isSimplePropertySetter(method)) {
|
||||
return new PropertyAccessorInfo(PropertyUtilBase.getPropertyNameBySetter(method),
|
||||
method.getParameterList().getParameters()[0].getType(),
|
||||
PropertyKind.SETTER);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PropertyAccessorInfo detectPropertyAccessor(@NotNull PsiMethod method) {
|
||||
return getAccessorInfo(method);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi.util;
|
||||
|
||||
import com.intellij.lang.java.beans.PropertyKind;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface PropertyAccessorDetector {
|
||||
/**
|
||||
* Detects property access information if any, or results to null
|
||||
*/
|
||||
@Nullable PropertyAccessorInfo detectPropertyAccessor(@NotNull PsiMethod method);
|
||||
|
||||
class PropertyAccessorInfo {
|
||||
private final @NotNull String propertyName;
|
||||
private final @NotNull PsiType propertyType;
|
||||
private final @NotNull PropertyKind kind;
|
||||
|
||||
public PropertyAccessorInfo(@NotNull String propertyName, @NotNull PsiType propertyType, @NotNull PropertyKind kind) {
|
||||
this.propertyName = propertyName;
|
||||
this.propertyType = propertyType;
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
public @NotNull String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public @NotNull PsiType getPropertyType() {
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
public @NotNull PropertyKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public boolean isKindOf(PropertyKind other) {
|
||||
return this.kind == other;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
<extensionPoint qualifiedName="com.intellij.jvm.elementProvider" area="IDEA_PROJECT" interface="com.intellij.lang.jvm.facade.JvmElementProvider" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.java.elementFinder" area="IDEA_PROJECT" interface="com.intellij.psi.PsiElementFinder" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.classTypePointerFactory" interface="com.intellij.psi.ClassTypePointerFactory" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.propertyAccessorDetector" interface="com.intellij.psi.util.PropertyAccessorDetector" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.customJavadocTagProvider" interface="com.intellij.psi.javadoc.CustomJavadocTagProvider" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.javadocTagInfo" area="IDEA_PROJECT" interface="com.intellij.psi.javadoc.JavadocTagInfo" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.importFilter" interface="com.intellij.codeInsight.ImportFilter" dynamic="true"/>
|
||||
|
||||
+18
-18
@@ -5,6 +5,7 @@ import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.treeView.WeighedItem;
|
||||
import com.intellij.ide.util.treeView.smartTree.Group;
|
||||
import com.intellij.ide.util.treeView.smartTree.TreeElement;
|
||||
import com.intellij.lang.java.beans.PropertyKind;
|
||||
import com.intellij.navigation.ColoredItemPresentation;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
@@ -12,6 +13,8 @@ import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.DefaultPropertyAccessorDetector;
|
||||
import com.intellij.psi.util.PropertyAccessorDetector;
|
||||
import com.intellij.psi.util.PropertyUtilBase;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -48,28 +51,26 @@ public final class PropertyGroup implements Group, ColoredItemPresentation, Acce
|
||||
}
|
||||
|
||||
public static PropertyGroup createOn(PsiElement object, final TreeElement treeElement) {
|
||||
if (object instanceof PsiField) {
|
||||
PsiField field = (PsiField)object;
|
||||
if (object instanceof PsiField field) {
|
||||
PropertyGroup group = new PropertyGroup(PropertyUtilBase.suggestPropertyName(field), field.getType(),
|
||||
field.hasModifierProperty(PsiModifier.STATIC), object.getProject());
|
||||
field.hasModifierProperty(PsiModifier.STATIC), field.getProject());
|
||||
group.setField(field);
|
||||
group.myChildren.add(treeElement);
|
||||
return group;
|
||||
}
|
||||
else if (object instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)object;
|
||||
if (PropertyUtilBase.isSimplePropertyGetter(method)) {
|
||||
PropertyGroup group = new PropertyGroup(PropertyUtilBase.getPropertyNameByGetter(method), method.getReturnType(),
|
||||
method.hasModifierProperty(PsiModifier.STATIC), object.getProject());
|
||||
group.setGetter(method);
|
||||
group.myChildren.add(treeElement);
|
||||
return group;
|
||||
}
|
||||
else if (PropertyUtilBase.isSimplePropertySetter(method)) {
|
||||
PropertyGroup group =
|
||||
new PropertyGroup(PropertyUtilBase.getPropertyNameBySetter(method), method.getParameterList().getParameters()[0].getType(),
|
||||
method.hasModifierProperty(PsiModifier.STATIC), object.getProject());
|
||||
group.setSetter(method);
|
||||
else if (object instanceof PsiMethod method) {
|
||||
final PropertyAccessorDetector.PropertyAccessorInfo accessorInfo = DefaultPropertyAccessorDetector.detectFrom(method);
|
||||
if (null != accessorInfo &&
|
||||
(accessorInfo.isKindOf(PropertyKind.GETTER) || accessorInfo.isKindOf(PropertyKind.SETTER))) {
|
||||
|
||||
PropertyGroup group = new PropertyGroup(accessorInfo.getPropertyName(), accessorInfo.getPropertyType(),
|
||||
method.hasModifierProperty(PsiModifier.STATIC), method.getProject());
|
||||
if (accessorInfo.isKindOf(PropertyKind.GETTER)) {
|
||||
group.setGetter(method);
|
||||
}
|
||||
else {
|
||||
group.setSetter(method);
|
||||
}
|
||||
group.myChildren.add(treeElement);
|
||||
return group;
|
||||
}
|
||||
@@ -113,7 +114,6 @@ public final class PropertyGroup implements Group, ColoredItemPresentation, Acce
|
||||
return PROPERTY_WRITE_ICON;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isStatic() {
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package de.plushnikov.intellij.plugin.extension;
|
||||
|
||||
import com.intellij.lang.java.beans.PropertyKind;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiField;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.PropertyAccessorDetector;
|
||||
import com.intellij.psi.util.PropertyUtilBase;
|
||||
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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class LombokPropertyAccessorDetector implements PropertyAccessorDetector {
|
||||
|
||||
@Override
|
||||
public @Nullable PropertyAccessorInfo detectPropertyAccessor(@NotNull PsiMethod method) {
|
||||
if (method instanceof LombokLightMethodBuilder methodBuilder) {
|
||||
final PsiElement navigationElement = methodBuilder.getNavigationElement();
|
||||
if (navigationElement instanceof PsiField originalField) {
|
||||
final AccessorsInfo accessorsInfo = AccessorsInfo.buildFor(originalField);
|
||||
|
||||
final boolean lombokPropertySetterOrWither = isLombokPropertySetterOrWither(methodBuilder, originalField, accessorsInfo);
|
||||
final boolean lombokPropertyGetter = isLombokPropertyGetter(methodBuilder, originalField, accessorsInfo);
|
||||
|
||||
|
||||
if (lombokPropertySetterOrWither || lombokPropertyGetter) {
|
||||
return new PropertyAccessorInfo(PropertyUtilBase.suggestPropertyName(originalField),
|
||||
originalField.getType(),
|
||||
lombokPropertyGetter?PropertyKind.GETTER:PropertyKind.SETTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isLombokPropertyGetter(LombokLightMethodBuilder method, PsiField originalField, AccessorsInfo accessorsInfo) {
|
||||
return !method.hasParameters() && method.getName().equals(LombokUtils.getGetterName(originalField, accessorsInfo));
|
||||
}
|
||||
|
||||
private static boolean isLombokPropertySetterOrWither(LombokLightMethodBuilder method,
|
||||
PsiField originalField,
|
||||
AccessorsInfo accessorsInfo) {
|
||||
return method.getParameterList().getParameters().length == 1 &&
|
||||
(method.getName().equals(LombokUtils.getSetterName(originalField, accessorsInfo)) ||
|
||||
method.getName().equals(LombokUtils.getWitherName(originalField, accessorsInfo)));
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,7 @@
|
||||
<treeGenerator implementation="de.plushnikov.intellij.plugin.extension.LombokLightMethodTreeGenerator"/>
|
||||
|
||||
<lang.structureViewExtension implementation="de.plushnikov.intellij.plugin.extension.LombokStructureViewExtension"/>
|
||||
<propertyAccessorDetector implementation="de.plushnikov.intellij.plugin.extension.LombokPropertyAccessorDetector"/>
|
||||
|
||||
<daemon.highlightInfoFilter implementation="de.plushnikov.intellij.plugin.extension.LombokHighlightErrorFilter"/>
|
||||
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package de.plushnikov.intellij.plugin.extension;
|
||||
|
||||
import com.intellij.ide.structureView.impl.java.JavaAnonymousClassesNodeProvider;
|
||||
import com.intellij.ide.structureView.impl.java.PropertiesGrouper;
|
||||
import com.intellij.ide.structureView.impl.java.SuperTypesGrouper;
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
import de.plushnikov.intellij.plugin.AbstractLombokLightCodeInsightTestCase;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class LombokStructureViewExtensionTest extends AbstractLombokLightCodeInsightTestCase {
|
||||
|
||||
@Language("JAVA")
|
||||
private static final String LOMBOKED_TEST_CLASS = """
|
||||
@lombok.Data
|
||||
@lombok.NoArgsConstructor
|
||||
@lombok.AllArgsConstructor
|
||||
@lombok.experimental.Accessors(fluent = true, prefix = "my")
|
||||
public class Test {
|
||||
private float fff;
|
||||
private String myString;
|
||||
@lombok.With
|
||||
private Boolean myActive;
|
||||
@lombok.experimental.Accessors(fluent = false)
|
||||
private int myX;
|
||||
}""";
|
||||
|
||||
|
||||
public void testLombokPropertiesGrouping() {
|
||||
doPropertiesTest(LOMBOKED_TEST_CLASS,
|
||||
"""
|
||||
-Test.java
|
||||
-Test
|
||||
Test(float, String, Boolean, int)
|
||||
Test()
|
||||
equals(Object): boolean
|
||||
canEqual(Object): boolean
|
||||
hashCode(): int
|
||||
toString(): String
|
||||
-fff: float
|
||||
fff(): float
|
||||
fff(float): Test
|
||||
fff: float
|
||||
-myString: String
|
||||
string(): String
|
||||
string(String): Test
|
||||
myString: String
|
||||
-myActive: Boolean
|
||||
active(): Boolean
|
||||
active(Boolean): Test
|
||||
withActive(Boolean): Test
|
||||
myActive: Boolean
|
||||
-myX: int
|
||||
getX(): int
|
||||
setX(int): void
|
||||
myX: int
|
||||
""");
|
||||
}
|
||||
|
||||
private void doPropertiesTest(String classText, String expected) {
|
||||
doTest(classText, expected, false, true);
|
||||
}
|
||||
|
||||
private void doTest(String classText,
|
||||
String expected,
|
||||
boolean showInterfaces,
|
||||
boolean showProperties) {
|
||||
myFixture.configureByText("Test.java", classText);
|
||||
myFixture.testStructureView(svc -> {
|
||||
svc.setActionActive(SuperTypesGrouper.ID, showInterfaces);
|
||||
svc.setActionActive(PropertiesGrouper.ID, showProperties);
|
||||
svc.setActionActive(JavaAnonymousClassesNodeProvider.ID, true);
|
||||
JTree tree = svc.getTree();
|
||||
PlatformTestUtil.waitWhileBusy(tree);
|
||||
PlatformTestUtil.expandAll(tree);
|
||||
PlatformTestUtil.assertTreeEqual(tree, expected);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user