IDEA-159541 Unstable API usage inspection

This commit is contained in:
Yaroslav Pankratyev
2018-04-18 15:38:45 +07:00
parent bf00d03ea4
commit 05f6f7eb91
9 changed files with 430 additions and 0 deletions
@@ -182,6 +182,9 @@
groupKey="inspections.group.name"
enabledByDefault="true" level="ERROR"
implementationClass="org.jetbrains.idea.devkit.inspections.PresentationAnnotationInspection"/>
<localInspection language="UAST" shortName="UnstableApiUsage" displayName="Unstable API usage"
groupKey="inspections.group.name" enabledByDefault="true" level="WARNING"
implementationClass="org.jetbrains.idea.devkit.inspections.UnstableApiUsageInspection"/>
<moduleConfigurationEditorProvider implementation="org.jetbrains.idea.devkit.module.PluginModuleEditorsProvider"/>
@@ -0,0 +1,5 @@
<html>
<body>
Reports unstable API (elements annotated with one of annotations from list) usages.
</body>
</html>
@@ -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 <id>'' or ''after <id>''
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}).
@@ -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<String> 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());
}
}
@@ -0,0 +1,82 @@
import pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>;
import static pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
import static pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.staticNonExperimentalMethodInExperimentalClass;
import static pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS</warning>;
import static pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'staticExperimentalMethodInExperimentalClass' is unstable">staticExperimentalMethodInExperimentalClass</warning>;
import pkg.NonExperimentalClass;
import static pkg.NonExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS;
import static pkg.NonExperimentalClass.staticNonExperimentalMethodInNonExperimentalClass;
import static pkg.NonExperimentalClass.<warning descr="'EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS</warning>;
import static pkg.NonExperimentalClass.<warning descr="'staticExperimentalMethodInNonExperimentalClass' is unstable">staticExperimentalMethodInNonExperimentalClass</warning>;
import pkg.<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>;
import pkg.NonExperimentalEnum;
import static pkg.<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
import static pkg.<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.<warning descr="'EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM</warning>;
import static pkg.NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
import static pkg.NonExperimentalEnum.<warning descr="'EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM</warning>;
import pkg.<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning>;
import pkg.NonExperimentalAnnotation;
import <warning descr="'unstablePkg' is unstable">unstablePkg</warning>.ClassInUnstablePkg;
public class UnstableElementsTest {
public void test() {
String s = <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.staticNonExperimentalMethodInExperimentalClass();
<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning> experimentalClassInstanceViaNonExperimentalConstructor = new ExperimentalClass();
s = experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalFieldInExperimentalClass;
experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalMethodInExperimentalClass();
s = NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS;
staticNonExperimentalMethodInExperimentalClass();
s = <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS</warning>;
<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'staticExperimentalMethodInExperimentalClass' is unstable">staticExperimentalMethodInExperimentalClass</warning>();
<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning> experimentalClassInstanceViaExperimentalConstructor = new <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>("");
s = experimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalFieldInExperimentalClass' is unstable">experimentalFieldInExperimentalClass</warning>;
experimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalMethodInExperimentalClass' is unstable">experimentalMethodInExperimentalClass</warning>();
s = <warning descr="'EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS</warning>;
<warning descr="'staticExperimentalMethodInExperimentalClass' is unstable">staticExperimentalMethodInExperimentalClass</warning>();
// ---------------------------------
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.<warning descr="'EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS</warning>;
NonExperimentalClass.<warning descr="'staticExperimentalMethodInNonExperimentalClass' is unstable">staticExperimentalMethodInNonExperimentalClass</warning>();
NonExperimentalClass nonExperimentalClassInstanceViaExperimentalConstructor = new <warning descr="'NonExperimentalClass' is unstable">NonExperimentalClass</warning>("");
s = nonExperimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalFieldInNonExperimentalClass' is unstable">experimentalFieldInNonExperimentalClass</warning>;
nonExperimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalMethodInNonExperimentalClass' is unstable">experimentalMethodInNonExperimentalClass</warning>();
s = <warning descr="'EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS</warning>;
<warning descr="'staticExperimentalMethodInNonExperimentalClass' is unstable">staticExperimentalMethodInNonExperimentalClass</warning>();
// ---------------------------------
<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning> nonExperimentalValueInExperimentalEnum = <warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
nonExperimentalValueInExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM;
<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning> experimentalValueInExperimentalEnum = <warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.<warning descr="'EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM</warning>;
experimentalValueInExperimentalEnum = <warning descr="'EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM</warning>;
NonExperimentalEnum nonExperimentalValueInNonExperimentalEnum = NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
nonExperimentalValueInNonExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM;
NonExperimentalEnum experimentalValueInNonExperimentalEnum = NonExperimentalEnum.<warning descr="'EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM</warning>;
experimentalValueInNonExperimentalEnum = <warning descr="'EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM</warning>;
// ---------------------------------
@<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning> class C1 {}
@<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning>(nonExperimentalAttributeInExperimentalAnnotation = "123") class C2 {}
@<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning>(<warning descr="'experimentalAttributeInExperimentalAnnotation' is unstable">experimentalAttributeInExperimentalAnnotation</warning> = "123") class C3 {}
@NonExperimentalAnnotation class C4 {}
@NonExperimentalAnnotation(nonExperimentalAttributeInNonExperimentalAnnotation = "123") class C5 {}
@NonExperimentalAnnotation(<warning descr="'experimentalAttributeInNonExperimentalAnnotation' is unstable">experimentalAttributeInNonExperimentalAnnotation</warning> = "123") class C6 {}
}
}
@@ -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")
}
}
@@ -0,0 +1,83 @@
import pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>
import pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
import pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.staticNonExperimentalMethodInExperimentalClass
import pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS</warning>
import pkg.<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'staticExperimentalMethodInExperimentalClass' is unstable">staticExperimentalMethodInExperimentalClass</warning>
import pkg.NonExperimentalClass
import pkg.NonExperimentalClass.NON_EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS
import pkg.NonExperimentalClass.staticNonExperimentalMethodInNonExperimentalClass
import pkg.NonExperimentalClass.<warning descr="'EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS</warning>
import pkg.NonExperimentalClass.<warning descr="'staticExperimentalMethodInNonExperimentalClass' is unstable">staticExperimentalMethodInNonExperimentalClass</warning>
import pkg.<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>
import pkg.NonExperimentalEnum
import pkg.<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
import pkg.<warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.<warning descr="'EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM</warning>
import pkg.NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
import pkg.NonExperimentalEnum.<warning descr="'EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM</warning>
import pkg.<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning>
import pkg.NonExperimentalAnnotation
import <warning descr="'unstablePkg' is unstable">unstablePkg</warning>.ClassInUnstablePkg
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", "UNUSED_VALUE")
class UnstableElementsTest {
fun test() {
var s = <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.staticNonExperimentalMethodInExperimentalClass()
val experimentalClassInstanceViaNonExperimentalConstructor : <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning> = ExperimentalClass()
s = experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalFieldInExperimentalClass
experimentalClassInstanceViaNonExperimentalConstructor.nonExperimentalMethodInExperimentalClass()
s = NON_EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS
staticNonExperimentalMethodInExperimentalClass()
s = <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS</warning>
<warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>.<warning descr="'staticExperimentalMethodInExperimentalClass' is unstable">staticExperimentalMethodInExperimentalClass</warning>()
val experimentalClassInstanceViaExperimentalConstructor : <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning> = <warning descr="'ExperimentalClass' is unstable">ExperimentalClass</warning>("")
s = experimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalFieldInExperimentalClass' is unstable">experimentalFieldInExperimentalClass</warning>
experimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalMethodInExperimentalClass' is unstable">experimentalMethodInExperimentalClass</warning>()
s = <warning descr="'EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_EXPERIMENTAL_CLASS</warning>
<warning descr="'staticExperimentalMethodInExperimentalClass' is unstable">staticExperimentalMethodInExperimentalClass</warning>()
// ---------------------------------
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.<warning descr="'EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS</warning>
NonExperimentalClass.<warning descr="'staticExperimentalMethodInNonExperimentalClass' is unstable">staticExperimentalMethodInNonExperimentalClass</warning>()
val nonExperimentalClassInstanceViaExperimentalConstructor = <warning descr="'NonExperimentalClass' is unstable">NonExperimentalClass</warning>("")
s = nonExperimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalFieldInNonExperimentalClass' is unstable">experimentalFieldInNonExperimentalClass</warning>
nonExperimentalClassInstanceViaExperimentalConstructor.<warning descr="'experimentalMethodInNonExperimentalClass' is unstable">experimentalMethodInNonExperimentalClass</warning>()
s = <warning descr="'EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS' is unstable">EXPERIMENTAL_CONSTANT_IN_NON_EXPERIMENTAL_CLASS</warning>
<warning descr="'staticExperimentalMethodInNonExperimentalClass' is unstable">staticExperimentalMethodInNonExperimentalClass</warning>()
// ---------------------------------
var nonExperimentalValueInExperimentalEnum : <warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning> = <warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
nonExperimentalValueInExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM
var experimentalValueInExperimentalEnum : <warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning> = <warning descr="'ExperimentalEnum' is unstable">ExperimentalEnum</warning>.<warning descr="'EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM</warning>
experimentalValueInExperimentalEnum = <warning descr="'EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_EXPERIMENTAL_ENUM</warning>
var nonExperimentalValueInNonExperimentalEnum = NonExperimentalEnum.NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
nonExperimentalValueInNonExperimentalEnum = NON_EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM
var experimentalValueInNonExperimentalEnum = NonExperimentalEnum.<warning descr="'EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM</warning>
experimentalValueInNonExperimentalEnum = <warning descr="'EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM' is unstable">EXPERIMENTAL_VALUE_IN_NON_EXPERIMENTAL_ENUM</warning>
// ---------------------------------
@<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning> class C1
@<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning>(nonExperimentalAttributeInExperimentalAnnotation = "123") class C2
@<warning descr="'ExperimentalAnnotation' is unstable">ExperimentalAnnotation</warning>(<warning descr="'experimentalAttributeInExperimentalAnnotation' is unstable">experimentalAttributeInExperimentalAnnotation</warning> = "123") class C3
@NonExperimentalAnnotation class C4
@NonExperimentalAnnotation(nonExperimentalAttributeInNonExperimentalAnnotation = "123") class C5
@NonExperimentalAnnotation(<warning descr="'experimentalAttributeInNonExperimentalAnnotation' is unstable">experimentalAttributeInNonExperimentalAnnotation</warning> = "123") class C6
}
}
@@ -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")
}
}
@@ -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 {}")
}
}