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