mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
add assert if no accessors found for binding
disabled for inspection since all inspections serialized by platform by default but not all inspections are state-full
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2017 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-2018 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.codeInspection;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.xmlb.annotations.Property;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.intellij.lang.annotations.Pattern;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -14,9 +15,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
@Property(assertIfNoBindings = false)
|
||||
public abstract class LocalInspectionTool extends InspectionProfileEntry {
|
||||
public static final LocalInspectionTool[] EMPTY_ARRAY = new LocalInspectionTool[0];
|
||||
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2018 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.configurationStore.xml
|
||||
|
||||
import com.intellij.configurationStore.AState
|
||||
import com.intellij.configurationStore.deserialize
|
||||
import com.intellij.openapi.components.BaseState
|
||||
import com.intellij.util.loadElement
|
||||
import com.intellij.util.xmlb.annotations.MapAnnotation
|
||||
import com.intellij.util.xmlb.annotations.Property
|
||||
import com.intellij.util.xmlb.annotations.Tag
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
@@ -39,6 +27,35 @@ class KotlinXmlSerializerTest {
|
||||
</bean>""", data)
|
||||
}
|
||||
|
||||
@Tag("profile-state")
|
||||
private class VisibleTreeState : BaseState() {
|
||||
internal var foo by string()
|
||||
}
|
||||
|
||||
private class VisibleTreeStateComponent : BaseState() {
|
||||
// we do not support private accessors
|
||||
@get:Property(surroundWithTag = false)
|
||||
@get:MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
|
||||
var profileNameToState by map<String, VisibleTreeState>()
|
||||
|
||||
fun getVisibleTreeState(profile: String) = profileNameToState.getOrPut(profile) {
|
||||
incrementModificationCount()
|
||||
VisibleTreeState()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test fun `private map`() {
|
||||
val data = VisibleTreeStateComponent()
|
||||
data.getVisibleTreeState("new")
|
||||
testSerializer("""
|
||||
<VisibleTreeStateComponent>
|
||||
<entry key="new">
|
||||
<profile-state />
|
||||
</entry>
|
||||
</VisibleTreeStateComponent>""", data)
|
||||
}
|
||||
|
||||
@Test fun floatProperty() {
|
||||
val state = AState()
|
||||
state.floatProperty = 3.4f
|
||||
|
||||
@@ -41,7 +41,7 @@ internal class XmlSerializerTest {
|
||||
@Test fun annotatedInternalVar() {
|
||||
class Bean {
|
||||
@MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
|
||||
internal var PLACES_MAP = TreeMap<String, String>()
|
||||
var PLACES_MAP = TreeMap<String, String>()
|
||||
}
|
||||
|
||||
val data = Bean()
|
||||
@@ -61,19 +61,27 @@ internal class XmlSerializerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun emptyBeanSerialization() {
|
||||
// commented for now, error level changed to WARN
|
||||
// @Test fun emptyBeanSerialization() {
|
||||
// class EmptyBean
|
||||
//
|
||||
// try {
|
||||
// testSerializer("<EmptyBean />", EmptyBean())
|
||||
// }
|
||||
// catch (e: AssertionError) {
|
||||
// assertThat(e.message).startsWith("no accessors for class ")
|
||||
// }
|
||||
//
|
||||
// Assertions.fail("error expected")
|
||||
// }
|
||||
|
||||
@Test fun `supress no accessors warn`() {
|
||||
@Property(assertIfNoBindings = false)
|
||||
class EmptyBean
|
||||
|
||||
testSerializer("<EmptyBean />", EmptyBean())
|
||||
}
|
||||
|
||||
@Tag("Bean")
|
||||
private class EmptyBeanWithCustomName
|
||||
|
||||
@Test fun emptyBeanSerializationWithCustomName() {
|
||||
testSerializer("<Bean />", EmptyBeanWithCustomName())
|
||||
}
|
||||
|
||||
@Test fun publicFieldSerialization() {
|
||||
val bean = BeanWithPublicFields()
|
||||
|
||||
@@ -107,17 +115,43 @@ internal class XmlSerializerTest {
|
||||
}
|
||||
|
||||
private class BeanWithSubBean {
|
||||
var BEAN1: EmptyBeanWithCustomName? = EmptyBeanWithCustomName()
|
||||
var BEAN2: BeanWithPublicFields? = BeanWithPublicFields()
|
||||
var bean1: BeanWithPublicFields? = BeanWithPublicFields()
|
||||
var bean2: BeanWithPublicFields? = BeanWithPublicFields()
|
||||
}
|
||||
|
||||
@Test fun subBeanSerialization() {
|
||||
val bean = BeanWithSubBean()
|
||||
testSerializer("<BeanWithSubBean>\n" + " <option name=\"BEAN1\">\n" + " <Bean />\n" + " </option>\n" + " <option name=\"BEAN2\">\n" + " <BeanWithPublicFields>\n" + " <option name=\"INT_V\" value=\"1\" />\n" + " <option name=\"STRING_V\" value=\"hello\" />\n" + " </BeanWithPublicFields>\n" + " </option>\n" + "</BeanWithSubBean>", bean)
|
||||
bean.BEAN2!!.INT_V = 2
|
||||
bean.BEAN2!!.STRING_V = "bye"
|
||||
testSerializer("""<BeanWithSubBean>
|
||||
<option name="bean1">
|
||||
<BeanWithPublicFields>
|
||||
<option name="INT_V" value="1" />
|
||||
<option name="STRING_V" value="hello" />
|
||||
</BeanWithPublicFields>
|
||||
</option>
|
||||
<option name="bean2">
|
||||
<BeanWithPublicFields>
|
||||
<option name="INT_V" value="1" />
|
||||
<option name="STRING_V" value="hello" />
|
||||
</BeanWithPublicFields>
|
||||
</option>
|
||||
</BeanWithSubBean>""", bean)
|
||||
bean.bean2!!.INT_V = 2
|
||||
bean.bean2!!.STRING_V = "bye"
|
||||
|
||||
testSerializer("<BeanWithSubBean>\n" + " <option name=\"BEAN1\">\n" + " <Bean />\n" + " </option>\n" + " <option name=\"BEAN2\">\n" + " <BeanWithPublicFields>\n" + " <option name=\"INT_V\" value=\"2\" />\n" + " <option name=\"STRING_V\" value=\"bye\" />\n" + " </BeanWithPublicFields>\n" + " </option>\n" + "</BeanWithSubBean>", bean)
|
||||
testSerializer("""<BeanWithSubBean>
|
||||
<option name="bean1">
|
||||
<BeanWithPublicFields>
|
||||
<option name="INT_V" value="1" />
|
||||
<option name="STRING_V" value="hello" />
|
||||
</BeanWithPublicFields>
|
||||
</option>
|
||||
<option name="bean2">
|
||||
<BeanWithPublicFields>
|
||||
<option name="INT_V" value="2" />
|
||||
<option name="STRING_V" value="bye" />
|
||||
</BeanWithPublicFields>
|
||||
</option>
|
||||
</BeanWithSubBean>""", bean)
|
||||
}
|
||||
|
||||
@Test fun subBeanSerializationAndSkipDefaults() {
|
||||
@@ -140,7 +174,7 @@ internal class XmlSerializerTest {
|
||||
@Tag("bean")
|
||||
class BeanWithSubBeanWithEquals {
|
||||
@Suppress("unused")
|
||||
var bean1: EmptyBeanWithCustomName = EmptyBeanWithCustomName()
|
||||
var bean1: BeanWithPublicFields = BeanWithPublicFields()
|
||||
var bean2: BeanWithEquals = BeanWithEquals()
|
||||
}
|
||||
|
||||
@@ -155,17 +189,26 @@ internal class XmlSerializerTest {
|
||||
@Test fun nullFieldValue() {
|
||||
val bean1 = BeanWithPublicFields()
|
||||
|
||||
testSerializer("<BeanWithPublicFields>\n" + " <option name=\"INT_V\" value=\"1\" />\n" + " <option name=\"STRING_V\" value=\"hello\" />\n" + "</BeanWithPublicFields>", bean1)
|
||||
testSerializer("""<BeanWithPublicFields>
|
||||
<option name="INT_V" value="1" />
|
||||
<option name="STRING_V" value="hello" />
|
||||
</BeanWithPublicFields>""", bean1)
|
||||
|
||||
bean1.STRING_V = null
|
||||
|
||||
testSerializer("<BeanWithPublicFields>\n" + " <option name=\"INT_V\" value=\"1\" />\n" + " <option name=\"STRING_V\" />\n" + "</BeanWithPublicFields>", bean1)
|
||||
testSerializer("""<BeanWithPublicFields>
|
||||
<option name="INT_V" value="1" />
|
||||
<option name="STRING_V" />
|
||||
</BeanWithPublicFields>""", bean1)
|
||||
|
||||
val bean2 = BeanWithSubBean()
|
||||
bean2.BEAN1 = null
|
||||
bean2.BEAN2 = null
|
||||
bean2.bean1 = null
|
||||
bean2.bean2 = null
|
||||
|
||||
testSerializer("<BeanWithSubBean>\n" + " <option name=\"BEAN1\" />\n" + " <option name=\"BEAN2\" />\n" + "</BeanWithSubBean>", bean2)
|
||||
testSerializer("""<BeanWithSubBean>
|
||||
<option name="bean1" />
|
||||
<option name="bean2" />
|
||||
</BeanWithSubBean>""", bean2)
|
||||
}
|
||||
|
||||
private data class BeanWithOption(@OptionTag("path") var PATH: String? = null)
|
||||
@@ -270,9 +313,13 @@ internal class XmlSerializerTest {
|
||||
@Suppress("unused")
|
||||
@Transient
|
||||
fun getValue(): String = "foo"
|
||||
|
||||
var foo: String? = null
|
||||
}
|
||||
|
||||
testSerializer("<Bean />", Bean())
|
||||
testSerializer("""<Bean>
|
||||
<option name="foo" />
|
||||
</Bean>""", Bean())
|
||||
}
|
||||
|
||||
@Test fun propertyWithoutTagWithPrimitiveType() {
|
||||
@@ -447,10 +494,18 @@ internal class XmlSerializerTest {
|
||||
val element = BeanWithJDOMElement()
|
||||
element.STRING_V = "a"
|
||||
element.actions = Element("x").addContent(Element("a")).addContent(Element("b"))
|
||||
assertSerializer(element, "<BeanWithJDOMElement>\n" + " <option name=\"STRING_V\" value=\"a\" />\n" + " <actions>\n" + " <a />\n" + " <b />\n" + " </actions>\n" + "</BeanWithJDOMElement>", null)
|
||||
assertSerializer(element, """<BeanWithJDOMElement>
|
||||
<option name="STRING_V" value="a" />
|
||||
<actions>
|
||||
<a />
|
||||
<b />
|
||||
</actions>
|
||||
</BeanWithJDOMElement>""", null)
|
||||
|
||||
element.actions = null
|
||||
assertSerializer(element, "<BeanWithJDOMElement>\n" + " <option name=\"STRING_V\" value=\"a\" />\n" + "</BeanWithJDOMElement>", null)
|
||||
assertSerializer(element, """<BeanWithJDOMElement>
|
||||
<option name="STRING_V" value="a" />
|
||||
</BeanWithJDOMElement>""", null)
|
||||
}
|
||||
|
||||
@Test fun deserializeJDOMElementField() {
|
||||
@@ -541,7 +596,7 @@ internal class XmlSerializerTest {
|
||||
testSerializer("<bean>\n <condition expression=\"2+2\" />\n" + "</bean>", bean)
|
||||
}
|
||||
|
||||
@Test fun `no_wrap`() {
|
||||
@Test fun `no wrap`() {
|
||||
@Tag("bean")
|
||||
class Bean {
|
||||
@Property(flat = true)
|
||||
|
||||
+3
-2
@@ -3,6 +3,7 @@ package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.*;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.pico.CachingConstructorInjectionComponentAdapter;
|
||||
@@ -170,7 +171,7 @@ public class ExtensionsAreaImpl implements ExtensionsArea {
|
||||
adapter = new ExtensionComponentAdapter(implClass, extensionElement, myPicoContainer, pluginDescriptor, shouldDeserializeInstance(extensionElement));
|
||||
}
|
||||
else {
|
||||
adapter = new ExtensionComponentAdapter(extensionPoint.getClassName(), extensionElement, myPicoContainer, pluginDescriptor, true);
|
||||
adapter = new ExtensionComponentAdapter(extensionPoint.getClassName(), extensionElement, myPicoContainer, pluginDescriptor, !JDOMUtil.isEmpty(extensionElement));
|
||||
}
|
||||
myPicoContainer.registerComponent(adapter);
|
||||
((ExtensionPointImpl)extensionPoint).registerExtensionAdapter(adapter);
|
||||
@@ -182,7 +183,7 @@ public class ExtensionsAreaImpl implements ExtensionsArea {
|
||||
// has custom attributes
|
||||
for (Attribute attribute : extensionElement.getAttributes()) {
|
||||
final String name = attribute.getName();
|
||||
if (!"implementation".equals(name) && !"id".equals(name) && !"order".equals(name)) {
|
||||
if (!"implementation".equals(name) && !"id".equals(name) && !"order".equals(name) && !"os".equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,8 @@ fun PersistentStateComponent<*>.serializeStateInto(element: Element) {
|
||||
state?.let { serializeObjectInto(it, element) }
|
||||
}
|
||||
|
||||
fun serializeObjectInto(o: Any, target: Element) {
|
||||
@JvmOverloads
|
||||
fun serializeObjectInto(o: Any, target: Element, filter: SerializationFilter? = null) {
|
||||
if (o is Element) {
|
||||
val iterator = o.children.iterator()
|
||||
for (child in iterator) {
|
||||
@@ -134,7 +135,7 @@ fun serializeObjectInto(o: Any, target: Element) {
|
||||
}
|
||||
|
||||
val binding = serializer.getClassBinding(o.javaClass)
|
||||
(binding as BeanBinding).serializeInto(o, target, if (o is BaseState) null else getDefaultSerializationFilter())
|
||||
(binding as BeanBinding).serializeInto(o, target, if (o is BaseState) null else (filter ?: getDefaultSerializationFilter()))
|
||||
}
|
||||
|
||||
private val serializer = object : XmlSerializerImpl.XmlSerializerBase() {
|
||||
|
||||
@@ -306,8 +306,8 @@ public class BeanBinding extends NotNullDeserializeBinding {
|
||||
}
|
||||
}
|
||||
|
||||
if (accessors.isEmpty()) {
|
||||
LOG.error("no accessors for " + aClass);
|
||||
if (accessors.isEmpty() && !isAssertBindings(aClass)) {
|
||||
LOG.warn("no accessors for " + aClass);
|
||||
}
|
||||
|
||||
ourAccessorCache.put(aClass, accessors);
|
||||
@@ -315,11 +315,23 @@ public class BeanBinding extends NotNullDeserializeBinding {
|
||||
return accessors;
|
||||
}
|
||||
|
||||
// avoid assert for OCInspections.Properties
|
||||
private static boolean isAssertBindings(@NotNull Class<?> aClass) {
|
||||
do {
|
||||
Property property = aClass.getAnnotation(Property.class);
|
||||
if (property != null && !property.assertIfNoBindings()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while ((aClass = aClass.getSuperclass()) != null);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class NameAndIsSetter {
|
||||
final String name;
|
||||
final boolean isSetter;
|
||||
|
||||
public NameAndIsSetter(String name, boolean isSetter) {
|
||||
private NameAndIsSetter(String name, boolean isSetter) {
|
||||
this.name = name;
|
||||
this.isSetter = isSetter;
|
||||
}
|
||||
@@ -462,26 +474,31 @@ public class BeanBinding extends NotNullDeserializeBinding {
|
||||
|
||||
@NotNull
|
||||
private static Binding createBinding(@NotNull MutableAccessor accessor, @NotNull Serializer serializer, @NotNull Property.Style propertyStyle) {
|
||||
Binding binding = serializer.getBinding(accessor);
|
||||
if (binding instanceof JDOMElementBinding) {
|
||||
return binding;
|
||||
}
|
||||
|
||||
Attribute attribute = accessor.getAnnotation(Attribute.class);
|
||||
if (attribute != null) {
|
||||
return new AttributeBinding(accessor, attribute);
|
||||
}
|
||||
|
||||
Tag tag = accessor.getAnnotation(Tag.class);
|
||||
if (tag != null) {
|
||||
return new TagBinding(accessor, tag);
|
||||
}
|
||||
|
||||
Text text = accessor.getAnnotation(Text.class);
|
||||
if (text != null) {
|
||||
return new TextBinding(accessor);
|
||||
}
|
||||
|
||||
OptionTag optionTag = accessor.getAnnotation(OptionTag.class);
|
||||
if (optionTag != null && optionTag.converter() != Converter.class) {
|
||||
return new OptionTagBinding(accessor, optionTag);
|
||||
}
|
||||
|
||||
Binding binding = serializer.getBinding(accessor);
|
||||
if (binding instanceof JDOMElementBinding) {
|
||||
return binding;
|
||||
}
|
||||
|
||||
Tag tag = accessor.getAnnotation(Tag.class);
|
||||
if (tag != null) {
|
||||
return new TagBinding(accessor, tag);
|
||||
}
|
||||
|
||||
if (binding instanceof CompactCollectionBinding) {
|
||||
return new AccessorBindingWrapper(accessor, binding, false, Property.Style.OPTION_TAG);
|
||||
}
|
||||
@@ -509,8 +526,6 @@ public class BeanBinding extends NotNullDeserializeBinding {
|
||||
return new TagBinding(accessor, xCollection.propertyElementName());
|
||||
}
|
||||
|
||||
OptionTag optionTag = accessor.getAnnotation(OptionTag.class);
|
||||
|
||||
if (optionTag == null) {
|
||||
XMap xMap = accessor.getAnnotation(XMap.class);
|
||||
if (xMap != null) {
|
||||
|
||||
@@ -40,4 +40,6 @@ public @interface Property {
|
||||
* Applicable only on class level.
|
||||
*/
|
||||
Style style() default Style.OPTION_TAG;
|
||||
|
||||
boolean assertIfNoBindings() default true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user