diff --git a/plugins/devkit/devkit-core/resources/META-INF/plugin.xml b/plugins/devkit/devkit-core/resources/META-INF/plugin.xml
index c16651089337..c1b12a009bba 100644
--- a/plugins/devkit/devkit-core/resources/META-INF/plugin.xml
+++ b/plugins/devkit/devkit-core/resources/META-INF/plugin.xml
@@ -182,6 +182,9 @@
groupKey="inspections.group.name"
enabledByDefault="true" level="ERROR"
implementationClass="org.jetbrains.idea.devkit.inspections.PresentationAnnotationInspection"/>
+
diff --git a/plugins/devkit/devkit-core/resources/inspectionDescriptions/UnstableApiUsage.html b/plugins/devkit/devkit-core/resources/inspectionDescriptions/UnstableApiUsage.html
new file mode 100644
index 000000000000..215128f7ae6e
--- /dev/null
+++ b/plugins/devkit/devkit-core/resources/inspectionDescriptions/UnstableApiUsage.html
@@ -0,0 +1,5 @@
+
+
+Reports unstable API (elements annotated with one of annotations from list) usages.
+
+
\ No newline at end of file
diff --git a/plugins/devkit/devkit-core/resources/org/jetbrains/idea/devkit/DevKitBundle.properties b/plugins/devkit/devkit-core/resources/org/jetbrains/idea/devkit/DevKitBundle.properties
index 00fa9b6e88eb..93773c949b82 100644
--- a/plugins/devkit/devkit-core/resources/org/jetbrains/idea/devkit/DevKitBundle.properties
+++ b/plugins/devkit/devkit-core/resources/org/jetbrains/idea/devkit/DevKitBundle.properties
@@ -186,6 +186,9 @@ inspections.presentation.cannot.resolve.icon=Cannot resolve icon ''{0}''
inspections.plugin.xml.invalid.order.attribute=Invalid 'order' attribute value
invalid.order.attribute.part=Invalid ''order'' attribute value part: ''{0}'', must be ''first'', ''last'', ''before '' or ''after ''
+inspections.unstable.api.usage.annotations.list=Unstable API annotations
+inspections.unstable.api.usage.description=''{0}'' is unstable
+
ant.build.jar.comment=Build archive for plugin ''{0}''
ant.build.jar.description=Build plugin archive for module ''{0}''
no.java.sdk.for.idea.sdk.found=No Java SDK of appropriate version found. In addition to the IntelliJ Platform Plugin SDK, you need to define a JDK with the same Java version ({0}).
diff --git a/plugins/devkit/devkit-core/src/inspections/UnstableApiUsageInspection.java b/plugins/devkit/devkit-core/src/inspections/UnstableApiUsageInspection.java
new file mode 100644
index 000000000000..ee7d04417669
--- /dev/null
+++ b/plugins/devkit/devkit-core/src/inspections/UnstableApiUsageInspection.java
@@ -0,0 +1,109 @@
+// 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 org.jetbrains.idea.devkit.inspections;
+
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.codeInspection.util.SpecialAnnotationsUtil;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.siyeh.ig.ui.ExternalizableStringSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.idea.devkit.DevKitBundle;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.List;
+
+public class UnstableApiUsageInspection extends LocalInspectionTool {
+ public final List unstableApiAnnotations = new ExternalizableStringSet(
+ "org.jetbrains.annotations.ApiStatus.Experimental",
+ "com.google.common.annotations.Beta",
+ "io.reactivex.annotations.Beta",
+ "io.reactivex.annotations.Experimental"
+ );
+
+ @Nullable
+ @Override
+ public JComponent createOptionsPanel() {
+ JPanel panel = new JPanel(new GridBagLayout());
+ //TODO in add annotation window "Include non-project items" should be enabled by default
+ JPanel annotationsListControl = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(
+ unstableApiAnnotations, DevKitBundle.message("inspections.unstable.api.usage.annotations.list"));
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.weighty = 1.0;
+ constraints.weightx = 1.0;
+ constraints.anchor = GridBagConstraints.CENTER;
+ constraints.fill = GridBagConstraints.BOTH;
+ panel.add(annotationsListControl, constraints);
+ return panel;
+ }
+
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
+ return new PsiElementVisitor() {
+ @Override
+ public void visitElement(PsiElement element) {
+ super.visitElement(element);
+
+ // Java constructors must be handled a bit differently (works fine with Kotlin)
+ PsiMethod resolvedConstructor = null;
+ PsiElement elementParent = element.getParent();
+ if (elementParent instanceof PsiConstructorCall) {
+ resolvedConstructor = ((PsiConstructorCall)elementParent).resolveConstructor();
+ }
+
+ for (PsiReference reference : element.getReferences()) {
+ PsiElement resolvedElement = resolvedConstructor != null ? resolvedConstructor : reference.resolve();
+ if (!(resolvedElement instanceof PsiModifierListOwner) || !isLibraryElement(resolvedElement)) {
+ continue;
+ }
+
+ PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)resolvedElement;
+ for (String annotation : unstableApiAnnotations) {
+ if (modifierListOwner.hasAnnotation(annotation)) {
+ holder.registerProblem(reference,
+ DevKitBundle.message("inspections.unstable.api.usage.description", getReferenceText(reference)),
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
+ }
+ }
+ }
+ }
+ };
+ }
+
+ private static boolean isLibraryElement(@NotNull PsiElement element) {
+ if (ApplicationManager.getApplication().isUnitTestMode()) {
+ return true;
+ }
+
+ PsiFile containingPsiFile = element.getContainingFile();
+ if (containingPsiFile == null) {
+ return false;
+ }
+ VirtualFile containingVirtualFile = containingPsiFile.getVirtualFile();
+ if (containingVirtualFile == null) {
+ return false;
+ }
+ return ProjectFileIndex.getInstance(element.getProject()).isInLibrary(containingVirtualFile);
+ }
+
+ @NotNull
+ private static String getReferenceText(@NotNull PsiReference reference) {
+ if (reference instanceof PsiQualifiedReference) {
+ String referenceName = ((PsiQualifiedReference)reference).getReferenceName();
+ if (referenceName != null) {
+ return referenceName;
+ }
+ }
+ // references are not PsiQualifiedReference for annotation attributes
+ return StringUtil.getShortName(reference.getCanonicalText());
+ }
+}
diff --git a/plugins/devkit/devkit-java-tests/testData/inspections/unstableApiUsage/UnstableElementsTest.java b/plugins/devkit/devkit-java-tests/testData/inspections/unstableApiUsage/UnstableElementsTest.java
new file mode 100644
index 000000000000..c6f5c4801f4d
--- /dev/null
+++ b/plugins/devkit/devkit-java-tests/testData/inspections/unstableApiUsage/UnstableElementsTest.java
@@ -0,0 +1,82 @@
+import pkg.ExperimentalClass;
+import static pkg.ExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
+import static pkg.ExperimentalClass.staticNonExperimentalMethodInExperimentalClass;
+import static pkg.ExperimentalClass.EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
+import static pkg.ExperimentalClass.staticExperimentalMethodInExperimentalClass;
+
+import pkg.NonExperimentalClass;
+import static pkg.NonExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS;
+import static pkg.NonExperimentalClass.staticNonExperimentalMethodInNonExperimentalClass;
+import static pkg.NonExperimentalClass.EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS;
+import static pkg.NonExperimentalClass.staticExperimentalMethodInNonExperimentalClass;
+
+import pkg.ExperimentalEnum;
+import pkg.NonExperimentalEnum;
+import static pkg.ExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
+import static pkg.ExperimentalEnum.EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
+import static pkg.NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
+import static pkg.NonExperimentalEnum.EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
+
+import pkg.ExperimentalAnnotation;
+import pkg.NonExperimentalAnnotation;
+
+import unstablePkg.ClassInUnstablePkg;
+
+public class UnstableElementsTest {
+ public void test() {
+ String s = ExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
+ ExperimentalClass.staticNonExperimentalMethodInExperimentalClass();
+ ExperimentalClass experimentalClassInstanceViaNonExperimentalConstructor = new ExperimentalClass();
+ s = experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalFieldInExperimentalClass;
+ experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalMethodInExperimentalClass();
+ s = NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
+ staticNonExperimentalMethodInExperimentalClass();
+
+ s = ExperimentalClass.EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
+ ExperimentalClass.staticExperimentalMethodInExperimentalClass();
+ ExperimentalClass experimentalClassInstanceViaExperimentalConstructor = new ExperimentalClass("");
+ s = experimentalClassInstanceViaExperimentalConstructor.experimentalFieldInExperimentalClass;
+ experimentalClassInstanceViaExperimentalConstructor.experimentalMethodInExperimentalClass();
+ s = EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
+ staticExperimentalMethodInExperimentalClass();
+
+ // ---------------------------------
+
+ s = NonExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS;
+ NonExperimentalClass.staticNonExperimentalMethodInNonExperimentalClass();
+ NonExperimentalClass nonExperimentalClassInstanceViaNonExperimentalConstructor = new NonExperimentalClass();
+ s = nonExperimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalFieldInNonExperimentalClass;
+ nonExperimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalMethodInNonExperimentalClass();
+ s = NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS;
+ staticNonExperimentalMethodInNonExperimentalClass();
+
+ s = NonExperimentalClass.EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS;
+ NonExperimentalClass.staticExperimentalMethodInNonExperimentalClass();
+ NonExperimentalClass nonExperimentalClassInstanceViaExperimentalConstructor = new NonExperimentalClass("");
+ s = nonExperimentalClassInstanceViaExperimentalConstructor.experimentalFieldInNonExperimentalClass;
+ nonExperimentalClassInstanceViaExperimentalConstructor.experimentalMethodInNonExperimentalClass();
+ s = EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS;
+ staticExperimentalMethodInNonExperimentalClass();
+
+ // ---------------------------------
+
+ ExperimentalEnum nonExperimentalValueInExperimentalEnum = ExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
+ nonExperimentalValueInExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
+ ExperimentalEnum experimentalValueInExperimentalEnum = ExperimentalEnum.EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
+ experimentalValueInExperimentalEnum = EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
+
+ NonExperimentalEnum nonExperimentalValueInNonExperimentalEnum = NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
+ nonExperimentalValueInNonExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
+ NonExperimentalEnum experimentalValueInNonExperimentalEnum = NonExperimentalEnum.EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
+ experimentalValueInNonExperimentalEnum = EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
+
+ // ---------------------------------
+
+ @ExperimentalAnnotation class C1 {}
+ @ExperimentalAnnotation(nonExperimentalAttributeInExperimentalAnnotation = "123") class C2 {}
+ @ExperimentalAnnotation(experimentalAttributeInExperimentalAnnotation = "123") class C3 {}
+ @NonExperimentalAnnotation class C4 {}
+ @NonExperimentalAnnotation(nonExperimentalAttributeInNonExperimentalAnnotation = "123") class C5 {}
+ @NonExperimentalAnnotation(experimentalAttributeInNonExperimentalAnnotation = "123") class C6 {}
+ }
+}
\ No newline at end of file
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/UnstableApiUsageInspectionTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/UnstableApiUsageInspectionTest.kt
new file mode 100644
index 000000000000..32a892cce600
--- /dev/null
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/UnstableApiUsageInspectionTest.kt
@@ -0,0 +1,14 @@
+// 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 org.jetbrains.idea.devkit.inspections
+
+import com.intellij.testFramework.TestDataPath
+import org.jetbrains.idea.devkit.DevkitJavaTestsUtil
+
+@TestDataPath("\$CONTENT_ROOT/testData/inspections/unstableApiUsage")
+class UnstableApiUsageInspectionTest : UnstableApiUsageInspectionTestBase() {
+ override fun getBasePath() = "${DevkitJavaTestsUtil.TESTDATA_PATH}inspections/unstableApiUsage"
+
+ fun testInspection() {
+ myFixture.testHighlighting(true, false, false, "UnstableElementsTest.java")
+ }
+}
diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/unstableApiUsage/UnstableElementsTest.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/unstableApiUsage/UnstableElementsTest.kt
new file mode 100644
index 000000000000..fa6360fc4083
--- /dev/null
+++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/unstableApiUsage/UnstableElementsTest.kt
@@ -0,0 +1,83 @@
+import pkg.ExperimentalClass
+import pkg.ExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
+import pkg.ExperimentalClass.staticNonExperimentalMethodInExperimentalClass
+import pkg.ExperimentalClass.EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
+import pkg.ExperimentalClass.staticExperimentalMethodInExperimentalClass
+
+import pkg.NonExperimentalClass
+import pkg.NonExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS
+import pkg.NonExperimentalClass.staticNonExperimentalMethodInNonExperimentalClass
+import pkg.NonExperimentalClass.EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS
+import pkg.NonExperimentalClass.staticExperimentalMethodInNonExperimentalClass
+
+import pkg.ExperimentalEnum
+import pkg.NonExperimentalEnum
+import pkg.ExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
+import pkg.ExperimentalEnum.EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
+import pkg.NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
+import pkg.NonExperimentalEnum.EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
+
+import pkg.ExperimentalAnnotation
+import pkg.NonExperimentalAnnotation
+
+import unstablePkg.ClassInUnstablePkg
+
+@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", "UNUSED_VALUE")
+class UnstableElementsTest {
+ fun test() {
+ var s = ExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
+ ExperimentalClass.staticNonExperimentalMethodInExperimentalClass()
+ val experimentalClassInstanceViaNonExperimentalConstructor : ExperimentalClass = ExperimentalClass()
+ s = experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalFieldInExperimentalClass
+ experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalMethodInExperimentalClass()
+ s = NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
+ staticNonExperimentalMethodInExperimentalClass()
+
+ s = ExperimentalClass.EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
+ ExperimentalClass.staticExperimentalMethodInExperimentalClass()
+ val experimentalClassInstanceViaExperimentalConstructor : ExperimentalClass = ExperimentalClass("")
+ s = experimentalClassInstanceViaExperimentalConstructor.experimentalFieldInExperimentalClass
+ experimentalClassInstanceViaExperimentalConstructor.experimentalMethodInExperimentalClass()
+ s = EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
+ staticExperimentalMethodInExperimentalClass()
+
+ // ---------------------------------
+
+ s = NonExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS
+ NonExperimentalClass.staticNonExperimentalMethodInNonExperimentalClass()
+ val nonExperimentalClassInstanceViaNonExperimentalConstructor = NonExperimentalClass()
+ s = nonExperimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalFieldInNonExperimentalClass
+ nonExperimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalMethodInNonExperimentalClass()
+ s = NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS
+ staticNonExperimentalMethodInNonExperimentalClass()
+
+ s = NonExperimentalClass.EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS
+ NonExperimentalClass.staticExperimentalMethodInNonExperimentalClass()
+ val nonExperimentalClassInstanceViaExperimentalConstructor = NonExperimentalClass("")
+ s = nonExperimentalClassInstanceViaExperimentalConstructor.experimentalFieldInNonExperimentalClass
+ nonExperimentalClassInstanceViaExperimentalConstructor.experimentalMethodInNonExperimentalClass()
+ s = EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS
+ staticExperimentalMethodInNonExperimentalClass()
+
+ // ---------------------------------
+
+ var nonExperimentalValueInExperimentalEnum : ExperimentalEnum = ExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
+ nonExperimentalValueInExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
+ var experimentalValueInExperimentalEnum : ExperimentalEnum = ExperimentalEnum.EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
+ experimentalValueInExperimentalEnum = EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
+
+ var nonExperimentalValueInNonExperimentalEnum = NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
+ nonExperimentalValueInNonExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
+ var experimentalValueInNonExperimentalEnum = NonExperimentalEnum.EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
+ experimentalValueInNonExperimentalEnum = EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
+
+ // ---------------------------------
+
+ @ExperimentalAnnotation class C1
+ @ExperimentalAnnotation(nonExperimentalAttributeInExperimentalAnnotation = "123") class C2
+ @ExperimentalAnnotation(experimentalAttributeInExperimentalAnnotation = "123") class C3
+ @NonExperimentalAnnotation class C4
+ @NonExperimentalAnnotation(nonExperimentalAttributeInNonExperimentalAnnotation = "123") class C5
+ @NonExperimentalAnnotation(experimentalAttributeInNonExperimentalAnnotation = "123") class C6
+ }
+}
\ No newline at end of file
diff --git a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtUnstableApiUsageInspectionTest.kt b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtUnstableApiUsageInspectionTest.kt
new file mode 100644
index 000000000000..4c45b43ae490
--- /dev/null
+++ b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtUnstableApiUsageInspectionTest.kt
@@ -0,0 +1,22 @@
+// 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 org.jetbrains.idea.devkit.kotlin.inspections
+
+import com.intellij.openapi.vfs.VirtualFileFilter
+import com.intellij.testFramework.TestDataPath
+import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
+import org.jetbrains.idea.devkit.inspections.UnstableApiUsageInspectionTestBase
+import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil
+
+@TestDataPath("\$CONTENT_ROOT/testData/inspections/unstableApiUsage")
+class KtUnstableApiUsageInspectionTest : UnstableApiUsageInspectionTestBase() {
+ override fun getBasePath() = "${DevkitKtTestsUtil.TESTDATA_PATH}inspections/unstableApiUsage"
+
+ override fun performAdditionalSetUp() {
+ // otherwise assertion in PsiFileImpl ("Access to tree elements not allowed") will not pass
+ (myFixture as CodeInsightTestFixtureImpl).setVirtualFileFilter(VirtualFileFilter.NONE)
+ }
+
+ fun testInspection() {
+ myFixture.testHighlighting("UnstableElementsTest.kt")
+ }
+}
\ No newline at end of file
diff --git a/plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/UnstableApiUsageInspectionTestBase.kt b/plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/UnstableApiUsageInspectionTestBase.kt
new file mode 100644
index 000000000000..793259a9b869
--- /dev/null
+++ b/plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/UnstableApiUsageInspectionTestBase.kt
@@ -0,0 +1,109 @@
+// 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 org.jetbrains.idea.devkit.inspections
+
+import com.intellij.testFramework.builders.JavaModuleFixtureBuilder
+import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
+import com.intellij.util.PathUtil
+import org.jetbrains.annotations.ApiStatus
+
+abstract class UnstableApiUsageInspectionTestBase : JavaCodeInsightFixtureTestCase() {
+ abstract override fun getBasePath(): String
+
+ override fun tuneFixture(moduleBuilder: JavaModuleFixtureBuilder<*>) {
+ moduleBuilder.addLibrary("util", PathUtil.getJarPathForClass(ApiStatus.Experimental::class.java))
+ }
+
+ open fun performAdditionalSetUp() {}
+
+ override fun setUp() {
+ super.setUp()
+ performAdditionalSetUp()
+
+ myFixture.enableInspections(UnstableApiUsageInspection::class.java)
+
+ myFixture.addFileToProject(
+ "pkg/ExperimentalAnnotation.java",
+ "package pkg;\n" +
+ "import org.jetbrains.annotations.ApiStatus;\n" +
+ "@ApiStatus.Experimental public @interface ExperimentalAnnotation {\n" +
+ " String nonExperimentalAttributeInExperimentalAnnotation() default \"\";\n" +
+ " @ApiStatus.Experimental String experimentalAttributeInExperimentalAnnotation() default \"\";\n" +
+ "}"
+ )
+ myFixture.addFileToProject(
+ "pkg/ExperimentalEnum.java",
+ "package pkg;\n" +
+ "\n" +
+ "import org.jetbrains.annotations.ApiStatus;\n" +
+ "\n" +
+ "@ApiStatus.Experimental public enum ExperimentalEnum {\n" +
+ " NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM,\n" +
+ " @ApiStatus.Experimental EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM\n" +
+ "}"
+ )
+ myFixture.addFileToProject(
+ "pkg/ExperimentalClass.java",
+ "package pkg;\n" +
+ "import org.jetbrains.annotations.ApiStatus;\n" +
+ "@ApiStatus.Experimental public class ExperimentalClass {\n" +
+ " public static final String NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS = \"\";\n" +
+ " public String nonExperimentalFieldInExperimentalClass = \"\";\n" +
+ " public ExperimentalClass() {}\n" +
+ " public static void staticNonExperimentalMethodInExperimentalClass() {}\n" +
+ " public void nonExperimentalMethodInExperimentalClass() {}\n" +
+ "\n" +
+ " @ApiStatus.Experimental public static final String EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS = \"\";\n" +
+ " @ApiStatus.Experimental public String experimentalFieldInExperimentalClass = \"\";\n" +
+ " @ApiStatus.Experimental public ExperimentalClass(String s) {}\n" +
+ " @ApiStatus.Experimental public static void staticExperimentalMethodInExperimentalClass() {}\n" +
+ " @ApiStatus.Experimental public void experimentalMethodInExperimentalClass() {}\n" +
+ "}"
+ )
+
+
+ myFixture.addFileToProject(
+ "pkg/NonExperimentalAnnotation.java",
+ "package pkg;\n" +
+ "import org.jetbrains.annotations.ApiStatus;\n" +
+ "public @interface NonExperimentalAnnotation {\n" +
+ " String nonExperimentalAttributeInNonExperimentalAnnotation() default \"\";\n" +
+ " @ApiStatus.Experimental String experimentalAttributeInNonExperimentalAnnotation() default \"\";\n" +
+ "}"
+ )
+ myFixture.addFileToProject(
+ "pkg/NonExperimentalEnum.java",
+ "package pkg;\n" +
+ "import org.jetbrains.annotations.ApiStatus;\n" +
+ "public enum NonExperimentalEnum {\n" +
+ " NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM,\n" +
+ " @ApiStatus.Experimental EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM\n" +
+ "}"
+ )
+ myFixture.addFileToProject(
+ "pkg/NonExperimentalClass.java",
+ "package pkg;\n" +
+ "import org.jetbrains.annotations.ApiStatus;\n" +
+ "public class NonExperimentalClass {\n" +
+ " public static final String NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS = \"\";\n" +
+ " public String nonExperimentalFieldInNonExperimentalClass = \"\";\n" +
+ " public NonExperimentalClass() {}\n" +
+ " public static void staticNonExperimentalMethodInNonExperimentalClass() {}\n" +
+ " public void nonExperimentalMethodInNonExperimentalClass() {}\n" +
+ "\n" +
+ " @ApiStatus.Experimental public static final String EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS = \"\";\n" +
+ " @ApiStatus.Experimental public String experimentalFieldInNonExperimentalClass = \"\";\n" +
+ " @ApiStatus.Experimental public NonExperimentalClass(String s) {}\n" +
+ " @ApiStatus.Experimental public static void staticExperimentalMethodInNonExperimentalClass() {}\n" +
+ " @ApiStatus.Experimental public void experimentalMethodInNonExperimentalClass() {}\n" +
+ "}"
+ )
+
+
+ myFixture.addFileToProject("unstablePkg/package-info.java",
+ "@org.jetbrains.annotations.ApiStatus.Experimental\n" +
+ "package unstablePkg;")
+ myFixture.addFileToProject("unstablePkg/ClassInUnstablePkg.java",
+ "package unstablePkg;\n" +
+ "public class ClassInUnstablePkg {}")
+ }
+}
\ No newline at end of file