diff --git a/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java b/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java index 88c71c3cd9ec..d09f68861ce9 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java @@ -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]; diff --git a/platform/configuration-store-impl/testSrc/xml/KotlinXmlSerializerTest.kt b/platform/configuration-store-impl/testSrc/xml/KotlinXmlSerializerTest.kt index d82b1e74e62a..fd7bfecb19eb 100644 --- a/platform/configuration-store-impl/testSrc/xml/KotlinXmlSerializerTest.kt +++ b/platform/configuration-store-impl/testSrc/xml/KotlinXmlSerializerTest.kt @@ -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 { """, 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() + + fun getVisibleTreeState(profile: String) = profileNameToState.getOrPut(profile) { + incrementModificationCount() + VisibleTreeState() + } + } + + + @Test fun `private map`() { + val data = VisibleTreeStateComponent() + data.getVisibleTreeState("new") + testSerializer(""" + + + + +""", data) + } + @Test fun floatProperty() { val state = AState() state.floatProperty = 3.4f diff --git a/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt b/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt index adefad8786bb..7073fca34139 100644 --- a/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt +++ b/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt @@ -41,7 +41,7 @@ internal class XmlSerializerTest { @Test fun annotatedInternalVar() { class Bean { @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false) - internal var PLACES_MAP = TreeMap() + var PLACES_MAP = TreeMap() } 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()) +// } +// 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()) } - @Tag("Bean") - private class EmptyBeanWithCustomName - - @Test fun emptyBeanSerializationWithCustomName() { - testSerializer("", 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("\n" + " \n" + " \n" + "", bean) - bean.BEAN2!!.INT_V = 2 - bean.BEAN2!!.STRING_V = "bye" + testSerializer(""" + + +""", bean) + bean.bean2!!.INT_V = 2 + bean.bean2!!.STRING_V = "bye" - testSerializer("\n" + " \n" + " \n" + "", bean) + testSerializer(""" + + +""", 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("\n" + " ", bean1) + testSerializer(""" + """, bean1) bean1.STRING_V = null - testSerializer("\n" + " ", bean1) + testSerializer(""" + """, bean1) val bean2 = BeanWithSubBean() - bean2.BEAN1 = null - bean2.BEAN2 = null + bean2.bean1 = null + bean2.bean2 = null - testSerializer("\n" + " ", bean2) + testSerializer(""" + """, 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()) + testSerializer(""" + """, 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, "\n" + " ", null) + assertSerializer(element, """ + + + +""", null) element.actions = null - assertSerializer(element, "\n" + " ", null) + assertSerializer(element, """ + """, null) } @Test fun deserializeJDOMElementField() { @@ -541,7 +596,7 @@ internal class XmlSerializerTest { testSerializer("\n \n" + "", bean) } - @Test fun `no_wrap`() { + @Test fun `no wrap`() { @Tag("bean") class Bean { @Property(flat = true) diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionsAreaImpl.java b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionsAreaImpl.java index 95ad27950663..f619475e0ed2 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionsAreaImpl.java +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionsAreaImpl.java @@ -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; } } diff --git a/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt b/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt index dfcbfb018e13..4f2295dafd69 100644 --- a/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt +++ b/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt @@ -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() { diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index 5a1c83084423..ee23db452f6b 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -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) { diff --git a/platform/util/src/com/intellij/util/xmlb/annotations/Property.java b/platform/util/src/com/intellij/util/xmlb/annotations/Property.java index 65f9c58d915e..c3244055fcb2 100644 --- a/platform/util/src/com/intellij/util/xmlb/annotations/Property.java +++ b/platform/util/src/com/intellij/util/xmlb/annotations/Property.java @@ -40,4 +40,6 @@ public @interface Property { * Applicable only on class level. */ Style style() default Style.OPTION_TAG; + + boolean assertIfNoBindings() default true; }