mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-242833 EP attribute marked with com.intellij.openapi.extensions.RequiredElement needs ability to specify nonEmpty=false
GitOrigin-RevId: 7a1bf8484fc6069041e34d20d3c4245d3eb4eda2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
16344fc69a
commit
1f38e71591
@@ -17,7 +17,7 @@ public final class PsiSymbolReferenceProviderBean extends CustomLoadingExtension
|
||||
* The references will be provided for the specified language and its {@linkplain Language#getBaseLanguage() base languages}.
|
||||
*/
|
||||
@Attribute
|
||||
@RequiredElement
|
||||
@RequiredElement(allowEmpty = true)
|
||||
public String hostLanguage;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
import com.intellij.util.xmlb.annotations.Attribute;
|
||||
@@ -16,4 +16,9 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface RequiredElement {
|
||||
|
||||
/**
|
||||
* @return {@code true} if the specified property value can be empty.
|
||||
*/
|
||||
boolean allowEmpty() default false;
|
||||
}
|
||||
|
||||
@@ -550,6 +550,7 @@ inspections.IncorrectParentDisposableInspection.do.not.use.as.disposable=Don''t
|
||||
inspections.IncorrectParentDisposableInspection.documentation.link.title=Choosing a Disposable Parent
|
||||
|
||||
extension.point.documentation.field.required.suffix=(required)
|
||||
extension.point.documentation.field.required.can.be.empty.suffix=(required, empty allowed)
|
||||
extension.point.documentation.implementation.section=Extension Point Implementation
|
||||
|
||||
gutter.related.option.description=Description
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
|
||||
binding.visit(new ExtensionPointBinding.BindingVisitor() {
|
||||
|
||||
@Override
|
||||
public void visitAttribute(@NotNull PsiField field, @NotNull @NonNls String attributeName, boolean required) {
|
||||
public void visitAttribute(@NotNull PsiField field, @NotNull @NonNls String attributeName, RequiredFlag required) {
|
||||
final With withElement = findWithElement(elements, field);
|
||||
final PsiType fieldType = field.getType();
|
||||
Class<?> clazz = String.class;
|
||||
@@ -122,7 +122,7 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTagOrProperty(@NotNull PsiField field, @NotNull String tagName, boolean required) {
|
||||
public void visitTagOrProperty(@NotNull PsiField field, @NotNull String tagName, RequiredFlag required) {
|
||||
final DomExtension extension =
|
||||
registrar.registerFixedNumberChildExtension(new XmlName(tagName), SimpleTagValue.class)
|
||||
.setDeclaringElement(field);
|
||||
@@ -139,7 +139,7 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
|
||||
public void visitXCollection(@NotNull PsiField field,
|
||||
@Nullable String tagName,
|
||||
@NotNull PsiAnnotation collectionAnnotation,
|
||||
boolean required) {
|
||||
RequiredFlag required) {
|
||||
if (tagName == null) {
|
||||
registerCollectionBinding(field, registrar, collectionAnnotation, required);
|
||||
return;
|
||||
@@ -181,14 +181,19 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
|
||||
}
|
||||
}
|
||||
|
||||
private static void markAsRequired(DomExtension extension, boolean required) {
|
||||
if (required) extension.addCustomAnnotation(MyRequired.INSTANCE);
|
||||
private static void markAsRequired(DomExtension extension, ExtensionPointBinding.BindingVisitor.RequiredFlag required) {
|
||||
if (required == ExtensionPointBinding.BindingVisitor.RequiredFlag.REQUIRED) {
|
||||
extension.addCustomAnnotation(MyRequired.INSTANCE);
|
||||
}
|
||||
else if (required == ExtensionPointBinding.BindingVisitor.RequiredFlag.REQUIRED_ALLOW_EMPTY) {
|
||||
extension.addCustomAnnotation(MyRequiredCanBeEmpty.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerCollectionBinding(PsiField field,
|
||||
DomExtensionsRegistrar registrar,
|
||||
PsiAnnotation collectionAnnotation,
|
||||
boolean required) {
|
||||
ExtensionPointBinding.BindingVisitor.RequiredFlag required) {
|
||||
final boolean surroundWithTag = PsiUtil.getAnnotationBooleanAttribute(collectionAnnotation, "surroundWithTag");
|
||||
if (surroundWithTag) return; // todo Set, List, Array
|
||||
|
||||
@@ -292,6 +297,32 @@ public class ExtensionDomExtender extends DomExtender<Extension> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ClassExplicitlyAnnotation")
|
||||
private static class MyRequiredCanBeEmpty implements Required {
|
||||
|
||||
private static final MyRequiredCanBeEmpty INSTANCE = new MyRequiredCanBeEmpty();
|
||||
|
||||
@Override
|
||||
public boolean value() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nonEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean identifier() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Required.class;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MyImplementationExtendClass extends ExtendClassImpl {
|
||||
private final String myInterfaceName;
|
||||
|
||||
|
||||
@@ -40,7 +40,13 @@ public class ExtensionPointBinding {
|
||||
final PsiMethod setter = PropertyUtilBase.findSetterForField(field);
|
||||
if ((getter == null || setter == null) && !field.hasModifierProperty(PsiModifier.PUBLIC)) continue;
|
||||
|
||||
boolean required = PsiUtil.findAnnotation(RequiredElement.class, field, getter, setter) != null;
|
||||
final PsiAnnotation requiredAnnotation = PsiUtil.findAnnotation(RequiredElement.class, field, getter, setter);
|
||||
BindingVisitor.RequiredFlag required = BindingVisitor.RequiredFlag.NOT_REQUIRED;
|
||||
if (requiredAnnotation != null) {
|
||||
required = PsiUtil.getAnnotationBooleanAttribute(requiredAnnotation, "allowEmpty") ?
|
||||
BindingVisitor.RequiredFlag.REQUIRED_ALLOW_EMPTY : BindingVisitor.RequiredFlag.REQUIRED;
|
||||
}
|
||||
|
||||
final PsiAnnotation attributeAnnotation = PsiUtil.findAnnotation(Attribute.class, field, getter, setter);
|
||||
if (attributeAnnotation != null) {
|
||||
String fieldName = PsiUtil.getAnnotationStringAttribute(attributeAnnotation, "value", field.getName());
|
||||
@@ -75,10 +81,19 @@ public class ExtensionPointBinding {
|
||||
|
||||
public interface BindingVisitor {
|
||||
|
||||
void visitAttribute(@NotNull PsiField field, @NotNull @NonNls String attributeName, boolean required);
|
||||
enum RequiredFlag {
|
||||
NOT_REQUIRED,
|
||||
REQUIRED,
|
||||
REQUIRED_ALLOW_EMPTY
|
||||
}
|
||||
|
||||
void visitTagOrProperty(@NotNull PsiField field, @NotNull @NonNls String tagName, boolean required);
|
||||
void visitAttribute(@NotNull PsiField field, @NotNull @NonNls String attributeName, RequiredFlag required);
|
||||
|
||||
void visitXCollection(@NotNull PsiField field, @Nullable @NonNls String tagName, @NotNull PsiAnnotation collectionAnnotation, boolean required);
|
||||
void visitTagOrProperty(@NotNull PsiField field, @NotNull @NonNls String tagName, RequiredFlag required);
|
||||
|
||||
void visitXCollection(@NotNull PsiField field,
|
||||
@Nullable @NonNls String tagName,
|
||||
@NotNull PsiAnnotation collectionAnnotation,
|
||||
RequiredFlag required);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-5
@@ -75,12 +75,12 @@ public class ExtensionPointDocumentationProvider implements DocumentationProvide
|
||||
|
||||
new ExtensionPointBinding(beanClass).visit(new ExtensionPointBinding.BindingVisitor() {
|
||||
@Override
|
||||
public void visitAttribute(@NotNull PsiField field, @NotNull String attributeName, boolean required) {
|
||||
public void visitAttribute(@NotNull PsiField field, @NotNull String attributeName, RequiredFlag required) {
|
||||
appendFieldBindingText(field, attributeName, required);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTagOrProperty(@NotNull PsiField field, @NotNull String tagName, boolean required) {
|
||||
public void visitTagOrProperty(@NotNull PsiField field, @NotNull String tagName, RequiredFlag required) {
|
||||
visitAttribute(field, "<" + tagName + ">", required);
|
||||
}
|
||||
|
||||
@@ -88,15 +88,21 @@ public class ExtensionPointDocumentationProvider implements DocumentationProvide
|
||||
public void visitXCollection(@NotNull PsiField field,
|
||||
@Nullable String tagName,
|
||||
@NotNull PsiAnnotation collectionAnnotation,
|
||||
boolean required) {
|
||||
RequiredFlag required) {
|
||||
visitAttribute(field, "<" + tagName + ">...", required);
|
||||
}
|
||||
|
||||
private void appendFieldBindingText(@NotNull PsiField field, @NotNull @NlsSafe String displayName, boolean required) {
|
||||
private void appendFieldBindingText(@NotNull PsiField field, @NotNull @NlsSafe String displayName, RequiredFlag required) {
|
||||
HtmlChunk hyperLink = createLink(JavaDocUtil.getReferenceText(field.getProject(), field), displayName);
|
||||
|
||||
final String typeText = field.getType().getPresentableText();
|
||||
final String requiredText = required ? " " + DevKitBundle.message("extension.point.documentation.field.required.suffix") : "";
|
||||
String requiredText = "";
|
||||
if (required == RequiredFlag.REQUIRED) {
|
||||
requiredText = " " + DevKitBundle.message("extension.point.documentation.field.required.suffix");
|
||||
}
|
||||
else if (required == RequiredFlag.REQUIRED_ALLOW_EMPTY) {
|
||||
requiredText = " " + DevKitBundle.message("extension.point.documentation.field.required.can.be.empty.suffix");
|
||||
}
|
||||
final String initializer = field.getInitializer() != null ? " = " + field.getInitializer().getText() : "";
|
||||
bindingRows.append(createSectionRow(hyperLink, typeText + requiredText + initializer));
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
forClass="<error descr="Cannot resolve symbol 'INVALID_VALUE'">INVALID_VALUE</error>"
|
||||
/>
|
||||
|
||||
<myService serviceImplementation="foo.MyRunnable"
|
||||
canBeEmptyString=""/>
|
||||
|
||||
<myPlugin.foo.bar implementation="java.util.ArrayList" os="<error descr="Unknown enum value 'INVALID_VALUE'">INVALID_VALUE</error>"/>
|
||||
<completion.contributor/>
|
||||
<custom.custom/>
|
||||
|
||||
+4
@@ -13,6 +13,10 @@ public class MyExtensionPoint {
|
||||
@Attribute
|
||||
public String implementationClass;
|
||||
|
||||
@RequiredElement(allowEmpty = true)
|
||||
@Attribute
|
||||
public String stringCanBeEmpty;
|
||||
|
||||
@Tag
|
||||
public Integer intValue;
|
||||
}
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
* Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
package org.jetbrains.idea.devkit.codeInsight
|
||||
|
||||
@@ -143,11 +143,13 @@ class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase {
|
||||
"}")
|
||||
myFixture.addClass("package foo; " +
|
||||
"import com.intellij.util.xmlb.annotations.Attribute; " +
|
||||
"import com.intellij.openapi.extensions.RequiredElement; " +
|
||||
"public class MyServiceDescriptor { " +
|
||||
" @Attribute public String serviceImplementation; " +
|
||||
" @Attribute public java.util.concurrent.TimeUnit timeUnit; " +
|
||||
" @Attribute public java.lang.Integer integerNullable; " +
|
||||
" @Attribute public int intPropertyForClass; " +
|
||||
" @Attribute @RequiredElement(allowEmpty=true) public String canBeEmptyString; " +
|
||||
" @Attribute public boolean forClass; " +
|
||||
"}")
|
||||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ public class ExtensionPointDocumentationProviderTest extends LightJavaCodeInsigh
|
||||
"<div class='definition'><pre>bar<br>public class <b>MyExtensionPoint</b>\n" +
|
||||
"extends <a href=\"psi_element://java.lang.Object\"><code>Object</code></a></pre></div><div class='content'>\n" +
|
||||
" MyExtensionPoint JavaDoc.\n" +
|
||||
" </div><table class='sections'><p></table><table class=\"sections\"><tr><td class=\"section\" valign=\"top\"><p><a href=\"psi_element://bar.MyExtensionPoint#implementationClass\"><code>implementationClass</code></a></p></td><td valign=\"top\">String (required)</td></tr><tr><td class=\"section\" valign=\"top\"><p><a href=\"psi_element://bar.MyExtensionPoint#intValue\"><code><intValue></code></a></p></td><td valign=\"top\">Integer</td></tr><br/></table></pre></div><div class=\"content\"><h2>Extension Point Implementation</h2><div class='definition'><pre>bar<br>public interface <b>MyExtension</b></pre></div><div class='content'>\n" +
|
||||
" </div><table class='sections'><p></table><table class=\"sections\"><tr><td class=\"section\" valign=\"top\"><p><a href=\"psi_element://bar.MyExtensionPoint#implementationClass\"><code>implementationClass</code></a></p></td><td valign=\"top\">String (required)</td></tr><tr><td class=\"section\" valign=\"top\"><p><a href=\"psi_element://bar.MyExtensionPoint#stringCanBeEmpty\"><code>stringCanBeEmpty</code></a></p></td><td valign=\"top\">String (required, empty allowed)</td></tr><tr><td class=\"section\" valign=\"top\"><p><a href=\"psi_element://bar.MyExtensionPoint#intValue\"><code><intValue></code></a></p></td><td valign=\"top\">Integer</td></tr><br/></table></pre></div><div class=\"content\"><h2>Extension Point Implementation</h2><div class='definition'><pre>bar<br>public interface <b>MyExtension</b></pre></div><div class='content'>\n" +
|
||||
" My Extension Javadoc.\n" +
|
||||
" </div><table class='sections'><p></table></div>",
|
||||
provider.generateDoc(docElement, getOriginalElement()));
|
||||
|
||||
Reference in New Issue
Block a user