IDEA-228949 plugin.xml: fix resolving <with> "attribute" when @Attribute is defined on field

GitOrigin-RevId: ccad63d0367f0dc75bdccf5137f408817101e018
This commit is contained in:
Yann Cébron
2019-12-11 16:08:36 +01:00
committed by intellij-monorepo-bot
parent 355bdf075d
commit 3adc832826
10 changed files with 82 additions and 19 deletions

View File

@@ -26,12 +26,12 @@
beanClass="com.intellij.openapi.options.ConfigurableEP"
area="IDEA_PROJECT"
dynamic="true">
<with attribute="instanceClass" implements="com.intellij.openapi.options.Configurable"/>
<with attribute="instance" implements="com.intellij.openapi.options.Configurable"/>
</extensionPoint>
<extensionPoint name="applicationConfigurable"
beanClass="com.intellij.openapi.options.ConfigurableEP">
<with attribute="instanceClass" implements="com.intellij.openapi.options.Configurable"/>
<with attribute="instance" implements="com.intellij.openapi.options.Configurable"/>
</extensionPoint>
<extensionPoint name="fileType"

View File

@@ -32,7 +32,7 @@ public interface With extends DomElement {
@NotNull
@Attribute("tag")
@Convert(PluginFieldNameConverter.class)
@Convert(PluginFieldNameConverter.class) // todo .ForTag variante!!! sucht nacht @Tag statt Attribute
GenericAttributeValue<PsiField> getTag();
@NotNull

View File

@@ -7,7 +7,6 @@ import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.compiler.CompileTaskBean;
import com.intellij.openapi.extensions.RequiredElement;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PropertyUtilBase;
@@ -97,10 +96,11 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
}
@Nullable
static With findWithElement(List<? extends With> elements, PsiField field) {
for (With element : elements) {
if (Comparing.equal(field.getName(), element.getAttribute().getStringValue())) {
return element;
static With findWithElement(List<? extends With> withElements, PsiField field) {
for (With with : withElements) {
PsiField withPsiField = DomUtil.hasXml(with.getTag()) ? with.getTag().getValue() : with.getAttribute().getValue();
if (field.getManager().areElementsEquivalent(field, withPsiField)) {
return with;
}
}
return null;
@@ -113,12 +113,12 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
return;
}
final String fieldName = field.getName();
final PsiAnnotation attrAnno = PsiUtil.findAnnotation(Attribute.class, field, getter, setter);
String fieldName = field.getName();
final PsiAnnotation attributeAnnotation = PsiUtil.findAnnotation(Attribute.class, field, getter, setter);
final PsiType fieldType = field.getType();
if (attrAnno != null) {
final String attrName = getStringAttribute(attrAnno, "value", fieldName);
if (attrName != null) {
if (attributeAnnotation != null) {
fieldName = getStringAttribute(attributeAnnotation, "value", fieldName);
if (fieldName != null) {
Class clazz = String.class;
if (withElement != null || Extension.isClassField(fieldName)) {
clazz = PsiClass.class;
@@ -131,7 +131,7 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
clazz = Integer.class;
}
final DomExtension extension =
registrar.registerGenericAttributeValueChildExtension(new XmlName(attrName), clazz).setDeclaringElement(field);
registrar.registerGenericAttributeValueChildExtension(new XmlName(fieldName), clazz).setDeclaringElement(field);
if (PsiUtil.findAnnotation(RequiredElement.class, field) != null) {
extension.addCustomAnnotation(MyRequired.INSTANCE);
}

View File

@@ -16,8 +16,11 @@
package org.jetbrains.idea.devkit.dom.impl;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.completion.JavaLookupElementBuilder;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.*;
import com.intellij.psi.util.PropertyUtilBase;
import com.intellij.util.ObjectUtils;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.ResolvingConverter;
import com.intellij.util.xmlb.annotations.Attribute;
@@ -36,6 +39,12 @@ import java.util.List;
* @author yole
*/
public class PluginFieldNameConverter extends ResolvingConverter<PsiField> {
@Override
public String getErrorMessage(@Nullable String s, ConvertContext context) {
return "Cannot resolve extension point property '" + s + "'";
}
@NotNull
@Override
public Collection<? extends PsiField> getVariants(ConvertContext context) {
@@ -56,6 +65,13 @@ public class PluginFieldNameConverter extends ResolvingConverter<PsiField> {
return result;
}
@Nullable
@Override
public LookupElement createLookupElement(PsiField field) {
final String fieldName = ObjectUtils.chooseNotNull(getAttributeAnnotationValue(field), field.getName());
return JavaLookupElementBuilder.forField(field, fieldName, null);
}
@Nullable
@Override
public PsiField fromString(@Nullable @NonNls String s, ConvertContext context) {
@@ -63,14 +79,18 @@ public class PluginFieldNameConverter extends ResolvingConverter<PsiField> {
PsiClass value = getEPBeanClass(context);
if (value == null) return null;
PsiField field = value.findFieldByName(s, true);
if (field != null) {
if (field != null && getAttributeAnnotationValue(field) == null) {
return field;
}
return findFieldByAttributeValue(value, s);
}
@Nullable
private static PsiField findFieldByAttributeValue(PsiClass psiClass, @NotNull String attrNameToFind) {
for (PsiField psiField : psiClass.getAllFields()) {
if (psiField.hasModifierProperty(PsiModifier.STATIC)) continue;
if (attrNameToFind.equals(getAttributeAnnotationValue(psiField))) {
return psiField;
}

View File

@@ -0,0 +1,7 @@
public class ExtensionDefinesWithAttributeViaAnnotation {
@com.intellij.util.xmlb.annotations.Attribute("customAttributeName")
private String myAttribute;
private String myAttributeWithoutAnnotation;
}

View File

@@ -0,0 +1,11 @@
<idea-plugin>
<id>my.plugin</id>
<vendor>DevKit</vendor>
<extensionPoints>
<extensionPoint name="viaAttribute" beanClass="ExtensionDefinesWithAttributeViaAnnotation">
<with attribute="<caret>" />
</extensionPoint>
</extensionPoints>
</idea-plugin>

View File

@@ -0,0 +1,15 @@
<idea-plugin>
<id>my.plugin</id>
<vendor>DevKit</vendor>
<extensionPoints>
<extensionPoint name="viaAttribute" beanClass="ExtensionDefinesWithAttributeViaAnnotation">
<with attribute="customAttributeName" implements="java.lang.Runnable"/>
<with attribute="myAttributeWithoutAnnotation" implements="java.lang.Runnable"/>
<with attribute="<error descr="Cannot resolve extension point property 'myAttribute'">myAttribute</error>" implements="java.lang.Runnable"/>
</extensionPoint>
</extensionPoints>
</idea-plugin>

View File

@@ -21,7 +21,7 @@
<extensionPoint name="projectConfigurable"
beanClass="com.intellij.openapi.options.ConfigurableEP"
area="IDEA_PROJECT">
<with attribute="instanceClass" implements="com.intellij.openapi.options.Configurable"/>
<with attribute="instance" implements="com.intellij.openapi.options.Configurable"/>
</extensionPoint>
<extensionPoint name="generalOptionsProvider" beanClass="com.intellij.ide.GeneralSettingsConfigurableEP">
<with attribute="instance" implements="com.intellij.openapi.options.SearchableConfigurable"/>

View File

@@ -360,6 +360,16 @@ class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase {
doHighlightingTest("extensionWithDefaultValuesInAnnotations.xml", "ExtBeanWithDefaultValuesInAnnotations.java")
}
void testExtensionDefinesWithAttributeViaAnnotation() {
doHighlightingTest("extensionDefinesWithAttributeViaAnnotation.xml", "ExtensionDefinesWithAttributeViaAnnotation.java")
}
void testExtensionDefinesWithAttributeViaAnnotationCompletion() {
myFixture.copyFileToProject("ExtensionDefinesWithAttributeViaAnnotation.java")
myFixture.testCompletionVariants("extensionDefinesWithAttributeViaAnnotation-completion.xml",
"customAttributeName", "myAttributeWithoutAnnotation")
}
void testLanguageAttributeHighlighting() {
configureLanguageAttributeTest()
doHighlightingTest("languageAttribute.xml", "MyLanguageAttributeEPBean.java")

View File

@@ -12,8 +12,8 @@
<extensionPoint name="dom.implementation"
beanClass="com.intellij.util.xml.impl.DomImplementationClassEP"
dynamic="true">
<with attribute="interfaceName" implements="com.intellij.util.xml.DomElement"/>
<with attribute="implementationName" implements="com.intellij.util.xml.DomElement"/>
<with attribute="interfaceClass" implements="com.intellij.util.xml.DomElement"/>
<with attribute="implementationClass" implements="com.intellij.util.xml.DomElement"/>
</extensionPoint>
<extensionPoint name="dom.converter"
@@ -23,7 +23,7 @@
<extensionPoint name="dom.extender"
beanClass="com.intellij.util.xml.reflect.DomExtenderEP"
dynamic="true">
<with attribute="domClassName" implements="com.intellij.util.xml.DomElement"/>
<with attribute="domClass" implements="com.intellij.util.xml.DomElement"/>
<with attribute="extenderClass" implements="com.intellij.util.xml.reflect.DomExtender"/>
</extensionPoint>