package com.intellij.codeInspection.tests.java
import com.intellij.jvm.analysis.internal.testFramework.UnstableApiUsageInspectionTestBase
import com.intellij.jvm.analysis.testFramework.JvmLanguage
class JavaUnstableApiUsageInspectionTest : UnstableApiUsageInspectionTestBase() {
fun `test java experimental api usages`() {
inspection.myIgnoreInsideImports = false
myFixture.testHighlighting(JvmLanguage.JAVA, """
import experimental.pkg.AnnotatedClass;
import experimental.pkg.ClassWithExperimentalTypeInSignature;
import experimental.pkg.OwnerOfMembersWithExperimentalTypesInSignature;
import static experimental.pkg.AnnotatedClass.NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
import static experimental.pkg.AnnotatedClass.staticNonAnnotatedMethodInAnnotatedClass;
import static experimental.pkg.AnnotatedClass.ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
import static experimental.pkg.AnnotatedClass.staticAnnotatedMethodInAnnotatedClass;
import experimental.pkg.NonAnnotatedClass;
import static experimental.pkg.NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
import static experimental.pkg.NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass;
import static experimental.pkg.NonAnnotatedClass.ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
import static experimental.pkg.NonAnnotatedClass.staticAnnotatedMethodInNonAnnotatedClass;
import experimental.pkg.AnnotatedEnum;
import experimental.pkg.NonAnnotatedEnum;
import static experimental.pkg.AnnotatedEnum.NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
import static experimental.pkg.AnnotatedEnum.ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
import static experimental.pkg.NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
import static experimental.pkg.NonAnnotatedEnum.ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
import experimental.pkg.AnnotatedAnnotation;
import experimental.pkg.NonAnnotatedAnnotation;
import experimental.annotatedPkg.ClassInAnnotatedPkg;
class UnstableElementsTest {
public void test() {
String s = AnnotatedClass.NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
AnnotatedClass.staticNonAnnotatedMethodInAnnotatedClass();
AnnotatedClass annotatedClassInstanceViaNonAnnotatedConstructor = new AnnotatedClass();
s = annotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedFieldInAnnotatedClass;
annotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedMethodInAnnotatedClass();
s = NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
staticNonAnnotatedMethodInAnnotatedClass();
s = AnnotatedClass.ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
AnnotatedClass.staticAnnotatedMethodInAnnotatedClass();
AnnotatedClass annotatedClassInstanceViaAnnotatedConstructor = new AnnotatedClass("");
s = annotatedClassInstanceViaAnnotatedConstructor.annotatedFieldInAnnotatedClass;
annotatedClassInstanceViaAnnotatedConstructor.annotatedMethodInAnnotatedClass();
s = ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
staticAnnotatedMethodInAnnotatedClass();
// ---------------------------------
s = NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass();
NonAnnotatedClass nonAnnotatedClassInstanceViaNonAnnotatedConstructor = new NonAnnotatedClass();
s = nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedFieldInNonAnnotatedClass;
nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedMethodInNonAnnotatedClass();
s = NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
staticNonAnnotatedMethodInNonAnnotatedClass();
s = NonAnnotatedClass.ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
NonAnnotatedClass.staticAnnotatedMethodInNonAnnotatedClass();
NonAnnotatedClass nonAnnotatedClassInstanceViaAnnotatedConstructor = new NonAnnotatedClass("");
s = nonAnnotatedClassInstanceViaAnnotatedConstructor.annotatedFieldInNonAnnotatedClass;
nonAnnotatedClassInstanceViaAnnotatedConstructor.annotatedMethodInNonAnnotatedClass();
s = ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
staticAnnotatedMethodInNonAnnotatedClass();
// ---------------------------------
AnnotatedEnum nonAnnotatedValueInAnnotatedEnum = AnnotatedEnum.NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
nonAnnotatedValueInAnnotatedEnum = NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
AnnotatedEnum annotatedValueInAnnotatedEnum = AnnotatedEnum.ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
annotatedValueInAnnotatedEnum = ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
NonAnnotatedEnum nonAnnotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
nonAnnotatedValueInNonAnnotatedEnum = NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
NonAnnotatedEnum annotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
annotatedValueInNonAnnotatedEnum = ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
// ---------------------------------
@AnnotatedAnnotation class C1 {}
@AnnotatedAnnotation(nonAnnotatedAttributeInAnnotatedAnnotation = "123") class C2 {}
@AnnotatedAnnotation(annotatedAttributeInAnnotatedAnnotation = "123") class C3 {}
@NonAnnotatedAnnotation class C4 {}
@NonAnnotatedAnnotation(nonAnnotatedAttributeInNonAnnotatedAnnotation = "123") class C5 {}
@NonAnnotatedAnnotation(annotatedAttributeInNonAnnotatedAnnotation = "123") class C6 {}
}
}
class DirectOverrideAnnotatedMethod extends NonAnnotatedClass {
@Override
public void annotatedMethodInNonAnnotatedClass() {}
}
class IndirectOverrideAnnotatedMethod extends DirectOverrideAnnotatedMethod {
@Override
public void annotatedMethodInNonAnnotatedClass() {}
}
class DirectOverrideNonAnnotatedMethodInAnnotatedClass extends AnnotatedClass {
@Override
public void nonAnnotatedMethodInAnnotatedClass() {}
}
class DirectOverrideAnnotatedMethodInAnnotatedClass extends AnnotatedClass {
@Override
public void annotatedMethodInAnnotatedClass() {}
}
//No warning should be produced.
class WarningsOfExperimentalTypesInSignature {
public void classUsage() {
new ClassWithExperimentalTypeInSignature<AnnotatedClass>();
}
public void membersUsages(OwnerOfMembersWithExperimentalTypesInSignature owner) {
Object field = owner.field;
owner.parameterType(null);
owner.returnType();
Object fieldPkg = owner.field;
owner.parameterTypePkg(null);
owner.returnTypePkg();
}
}
""".trimIndent())
}
fun `test java do not report unstable api usages inside import statements`() {
inspection.myIgnoreInsideImports = true
myFixture.testHighlighting(JvmLanguage.JAVA, """
import experimental.pkg.AnnotatedClass;
import static experimental.pkg.AnnotatedClass.NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
import static experimental.pkg.AnnotatedClass.staticNonAnnotatedMethodInAnnotatedClass;
import static experimental.pkg.AnnotatedClass.ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
import static experimental.pkg.AnnotatedClass.staticAnnotatedMethodInAnnotatedClass;
import experimental.pkg.NonAnnotatedClass;
import static experimental.pkg.NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
import static experimental.pkg.NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass;
import static experimental.pkg.NonAnnotatedClass.ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
import static experimental.pkg.NonAnnotatedClass.staticAnnotatedMethodInNonAnnotatedClass;
import experimental.pkg.AnnotatedEnum;
import experimental.pkg.NonAnnotatedEnum;
import static experimental.pkg.AnnotatedEnum.NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
import static experimental.pkg.AnnotatedEnum.ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
import static experimental.pkg.NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
import static experimental.pkg.NonAnnotatedEnum.ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
import experimental.pkg.AnnotatedAnnotation;
import experimental.pkg.NonAnnotatedAnnotation;
import experimental.annotatedPkg.ClassInAnnotatedPkg;
""".trimIndent())
}
fun `test java no warnings on access to members of the same file`() {
myFixture.testHighlighting(JvmLanguage.JAVA, """
package test;
import experimental.pkg.AnnotatedClass;
@SuppressWarnings({"SameParameterValue", "unused", "UnusedReturnValue", "ResultOfMethodCallIgnored", "MethodMayBeStatic", "ObjectToString"})
class NoWarningsMembersOfTheSameFile {
private AnnotatedClass field;
private static AnnotatedClass staticField;
private AnnotatedClass returnType() { return null; }
private void paramType(AnnotatedClass param) { }
private static AnnotatedClass staticReturnType() { return null; }
private static void staticParamType(AnnotatedClass a) { }
void testNoWarningsProducedForMembersOfTheSameClass() {
field.toString();
staticField.toString();
returnType();
paramType(null);
staticReturnType();
staticParamType(null);
}
private class InnerClass {
void testNoWarningsProducedForMembersEnclosingClass() {
field.toString();
staticField.toString();
returnType();
paramType(null);
staticReturnType();
staticParamType(null);
}
}
}
""".trimIndent())
}
fun `test highlighting scheduled for removal`() {
inspection.myIgnoreInsideImports = false
myFixture.testHighlighting(JvmLanguage.JAVA, """
// 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.
import scheduledForRemoval.pkg.AnnotatedClass;
import scheduledForRemoval.pkg.ClassWithScheduledForRemovalTypeInSignature;
import scheduledForRemoval.pkg.OwnerOfMembersWithScheduledForRemovalTypesInSignature;
import static scheduledForRemoval.pkg.AnnotatedClass.NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
import static scheduledForRemoval.pkg.AnnotatedClass.staticNonAnnotatedMethodInAnnotatedClass;
import static scheduledForRemoval.pkg.AnnotatedClass.ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
import static scheduledForRemoval.pkg.AnnotatedClass.staticAnnotatedMethodInAnnotatedClass;
import scheduledForRemoval.pkg.NonAnnotatedClass;
import static scheduledForRemoval.pkg.NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
import static scheduledForRemoval.pkg.NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass;
import static scheduledForRemoval.pkg.NonAnnotatedClass.ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
import static scheduledForRemoval.pkg.NonAnnotatedClass.staticAnnotatedMethodInNonAnnotatedClass;
import scheduledForRemoval.pkg.AnnotatedEnum;
import scheduledForRemoval.pkg.NonAnnotatedEnum;
import static scheduledForRemoval.pkg.AnnotatedEnum.NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
import static scheduledForRemoval.pkg.AnnotatedEnum.ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
import static scheduledForRemoval.pkg.NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
import static scheduledForRemoval.pkg.NonAnnotatedEnum.ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
import scheduledForRemoval.pkg.AnnotatedAnnotation;
import scheduledForRemoval.pkg.NonAnnotatedAnnotation;
import scheduledForRemoval.annotatedPkg.ClassInAnnotatedPkg;
class ScheduledForRemovalElementsTest {
public void test() {
String s = AnnotatedClass.NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
AnnotatedClass.staticNonAnnotatedMethodInAnnotatedClass();
AnnotatedClass annotatedClassInstanceViaNonAnnotatedConstructor = new AnnotatedClass();
s = annotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedFieldInAnnotatedClass;
annotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedMethodInAnnotatedClass();
s = NON_ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
staticNonAnnotatedMethodInAnnotatedClass();
s = AnnotatedClass.ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
AnnotatedClass.staticAnnotatedMethodInAnnotatedClass();
AnnotatedClass annotatedClassInstanceViaAnnotatedConstructor = new AnnotatedClass("");
s = annotatedClassInstanceViaAnnotatedConstructor.annotatedFieldInAnnotatedClass;
annotatedClassInstanceViaAnnotatedConstructor.annotatedMethodInAnnotatedClass();
s = ANNOTATED_CONSTANT_IN_ANNOTATED_CLASS;
staticAnnotatedMethodInAnnotatedClass();
// ---------------------------------
s = NonAnnotatedClass.NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
NonAnnotatedClass.staticNonAnnotatedMethodInNonAnnotatedClass();
NonAnnotatedClass nonAnnotatedClassInstanceViaNonAnnotatedConstructor = new NonAnnotatedClass();
s = nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedFieldInNonAnnotatedClass;
nonAnnotatedClassInstanceViaNonAnnotatedConstructor.nonAnnotatedMethodInNonAnnotatedClass();
s = NON_ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
staticNonAnnotatedMethodInNonAnnotatedClass();
s = NonAnnotatedClass.ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
NonAnnotatedClass.staticAnnotatedMethodInNonAnnotatedClass();
NonAnnotatedClass nonAnnotatedClassInstanceViaAnnotatedConstructor = new NonAnnotatedClass("");
s = nonAnnotatedClassInstanceViaAnnotatedConstructor.annotatedFieldInNonAnnotatedClass;
nonAnnotatedClassInstanceViaAnnotatedConstructor.annotatedMethodInNonAnnotatedClass();
s = ANNOTATED_CONSTANT_IN_NON_ANNOTATED_CLASS;
staticAnnotatedMethodInNonAnnotatedClass();
// ---------------------------------
AnnotatedEnum nonAnnotatedValueInAnnotatedEnum = AnnotatedEnum.NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
nonAnnotatedValueInAnnotatedEnum = NON_ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
AnnotatedEnum annotatedValueInAnnotatedEnum = AnnotatedEnum.ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
annotatedValueInAnnotatedEnum = ANNOTATED_VALUE_IN_ANNOTATED_ENUM;
NonAnnotatedEnum nonAnnotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
nonAnnotatedValueInNonAnnotatedEnum = NON_ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
NonAnnotatedEnum annotatedValueInNonAnnotatedEnum = NonAnnotatedEnum.ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
annotatedValueInNonAnnotatedEnum = ANNOTATED_VALUE_IN_NON_ANNOTATED_ENUM;
// ---------------------------------
@AnnotatedAnnotation class C1 {}
@AnnotatedAnnotation(nonAnnotatedAttributeInAnnotatedAnnotation = "123") class C2 {}
@AnnotatedAnnotation(annotatedAttributeInAnnotatedAnnotation = "123") class C3 {}
@NonAnnotatedAnnotation class C4 {}
@NonAnnotatedAnnotation(nonAnnotatedAttributeInNonAnnotatedAnnotation = "123") class C5 {}
@NonAnnotatedAnnotation(annotatedAttributeInNonAnnotatedAnnotation = "123") class C6 {}
}
}
class DirectOverrideAnnotatedMethod extends NonAnnotatedClass {
@Override
public void annotatedMethodInNonAnnotatedClass() {}
}
class IndirectOverrideAnnotatedMethod extends DirectOverrideAnnotatedMethod {
@Override
public void annotatedMethodInNonAnnotatedClass() {}
}
class WarningsOfScheduledForRemovalTypesInSignature {
public void classUsage() {
new ClassWithScheduledForRemovalTypeInSignature<AnnotatedClass>();
}
public void membersUsages(OwnerOfMembersWithScheduledForRemovalTypesInSignature owner) {
Object field = owner.field;
owner.parameterType(null);
owner.returnType();
Object fieldPkg = owner.field;
owner.parameterTypePkg(null);
owner.returnTypePkg();
}
}
""".trimIndent())
}
fun `test scheduled for removal fix`() {
inspection.myIgnoreInsideImports = false
inspection.myIgnoreApiDeclaredInThisProject = false
myFixture.testQuickFix(JvmLanguage.JAVA, before = """
package org.jetbrains.annotations;
final class ApiStatus {
public @interface ScheduledForRemoval { }
}
class X {
/**
* @deprecated use {@link #bar()}
*/
@Deprecated
@ApiStatus.ScheduledForRemoval
public static void foo() { }
public static void bar() { }
}
class Use {
void test() {
X.foo();
}
}
""".trimIndent(), after = """
package org.jetbrains.annotations;
final class ApiStatus {
public @interface ScheduledForRemoval { }
}
class X {
/**
* @deprecated use {@link #bar()}
*/
@Deprecated
@ApiStatus.ScheduledForRemoval
public static void foo() { }
public static void bar() { }
}
class Use {
void test() {
X.bar();
}
}
""".trimIndent(), hint = "Replace method call with 'X.bar()'", testPreview = true)
}
}