mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +07:00
UnstableTypeUsedInSignatureInspection: do not report if declaration is not accessible (private), or in the same package
GitOrigin-RevId: ac1182eefc5894b9893481015d3b3355785b37a0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7d53c40603
commit
c9eae61072
@@ -4,10 +4,9 @@ package com.intellij.codeInspection
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.codeInspection.UnstableApiUsageInspection.Companion.DEFAULT_UNSTABLE_API_ANNOTATIONS
|
||||
import com.intellij.codeInspection.util.SpecialAnnotationsUtil
|
||||
import com.intellij.psi.PsiClassType
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.PsiTypeParameterListOwner
|
||||
import com.intellij.psi.PsiWildcardType
|
||||
import com.intellij.lang.jvm.JvmModifier
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PropertyUtil
|
||||
import com.intellij.uast.UastVisitorAdapter
|
||||
import com.intellij.util.ui.FormBuilder
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet
|
||||
@@ -37,7 +36,7 @@ class UnstableTypeUsedInSignatureInspection : LocalInspectionTool() {
|
||||
) : AbstractUastNonRecursiveVisitor() {
|
||||
|
||||
override fun visitClass(node: UClass): Boolean {
|
||||
if (isMarkedUnstable(node)) {
|
||||
if (!isAccessibleDeclaration(node) || isMarkedUnstable(node)) {
|
||||
return true
|
||||
}
|
||||
checkTypeParameters(node.javaPsi, node)
|
||||
@@ -45,7 +44,7 @@ class UnstableTypeUsedInSignatureInspection : LocalInspectionTool() {
|
||||
}
|
||||
|
||||
override fun visitMethod(node: UMethod): Boolean {
|
||||
if (isMarkedUnstable(node)) {
|
||||
if (!isAccessibleDeclaration(node) || isMarkedUnstable(node)) {
|
||||
return true
|
||||
}
|
||||
for (uastParameter in node.uastParameters) {
|
||||
@@ -61,7 +60,7 @@ class UnstableTypeUsedInSignatureInspection : LocalInspectionTool() {
|
||||
}
|
||||
|
||||
override fun visitField(node: UField): Boolean {
|
||||
if (isMarkedUnstable(node)) {
|
||||
if (!isAccessibleDeclaration(node) || isMarkedUnstable(node)) {
|
||||
return true
|
||||
}
|
||||
checkReferencesUnstableType(node.type, node)
|
||||
@@ -80,12 +79,46 @@ class UnstableTypeUsedInSignatureInspection : LocalInspectionTool() {
|
||||
return false
|
||||
}
|
||||
|
||||
private tailrec fun isMarkedUnstable(node: UDeclaration): Boolean {
|
||||
if (node.annotations.any { it.qualifiedName in unstableApiAnnotations }) {
|
||||
private fun isAccessibleDeclaration(node: UDeclaration): Boolean {
|
||||
if (node.visibility == UastVisibility.PRIVATE) {
|
||||
if (node is UField) {
|
||||
//Kotlin properties are UField with accompanying getters\setters.
|
||||
val psiField = node.javaPsi
|
||||
if (psiField is PsiField) {
|
||||
val getter = PropertyUtil.findGetterForField(psiField)
|
||||
val setter = PropertyUtil.findSetterForField(psiField)
|
||||
return getter != null && !getter.hasModifier(JvmModifier.PRIVATE) || setter != null && !setter.hasModifier(JvmModifier.PRIVATE)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
val containingUClass = node.getContainingUClass()
|
||||
if (containingUClass != null) {
|
||||
return isAccessibleDeclaration(containingUClass)
|
||||
}
|
||||
return true
|
||||
}
|
||||
val containingClass = node.getContainingUClass() ?: return false
|
||||
return isMarkedUnstable(containingClass)
|
||||
|
||||
private fun isMarkedUnstable(node: UDeclaration) = findUnstableAnnotation(node) != null
|
||||
|
||||
private fun findUnstableAnnotation(node: UDeclaration): String? {
|
||||
val unstableAnnotation = node.annotations.find { it.qualifiedName in unstableApiAnnotations }
|
||||
if (unstableAnnotation != null) {
|
||||
return unstableAnnotation.qualifiedName
|
||||
}
|
||||
val containingClass = node.getContainingUClass()
|
||||
if (containingClass != null) {
|
||||
return findUnstableAnnotation(containingClass)
|
||||
}
|
||||
val containingUFile = node.getContainingUFile()
|
||||
if (containingUFile != null) {
|
||||
val packageName = containingUFile.packageName
|
||||
val psiPackage = JavaPsiFacade.getInstance(problemsHolder.project).findPackage(packageName)
|
||||
if (psiPackage != null) {
|
||||
return unstableApiAnnotations.find { psiPackage.hasAnnotation(it) }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun checkReferencesUnstableType(psiType: PsiType, declaration: UDeclaration): Boolean {
|
||||
@@ -103,11 +136,11 @@ class UnstableTypeUsedInSignatureInspection : LocalInspectionTool() {
|
||||
//Returns <class name> and <unstable annotation name>
|
||||
private fun findReferencedUnstableType(psiType: PsiType): Pair<String, String>? {
|
||||
if (psiType is PsiClassType) {
|
||||
val psiClass = psiType.resolve()
|
||||
if (psiClass != null) {
|
||||
val unstableApiAnnotation = unstableApiAnnotations.find { psiClass.hasAnnotation(it) }
|
||||
val uClass = psiType.resolve()?.toUElement(UClass::class.java)
|
||||
if (uClass != null) {
|
||||
val unstableApiAnnotation = findUnstableAnnotation(uClass)
|
||||
if (unstableApiAnnotation != null) {
|
||||
val className = psiClass.qualifiedName ?: psiType.className
|
||||
val className = uClass.qualifiedName ?: psiType.className
|
||||
return className to unstableApiAnnotation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package experimentalPackage;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public class ClassInExperimentalPackage {
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package experimentalPackage;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
class ExperimentalClass { }
|
||||
|
||||
// No warnings because the 'experimentalPackage', to which this class belongs, is also experimental.
|
||||
|
||||
class NoWarnings {
|
||||
public ExperimentalClass field;
|
||||
|
||||
public void methodWithParam(ExperimentalClass param) {}
|
||||
|
||||
public ExperimentalClass methodWithReturnType() { return null; }
|
||||
|
||||
|
||||
public ClassInExperimentalPackage fieldWithSamePackageType;
|
||||
|
||||
public void methodWithSamePackageParam(ClassInExperimentalPackage param) {}
|
||||
|
||||
public ClassInExperimentalPackage methodWithSamePackageReturnType() { return null; }
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
@org.jetbrains.annotations.ApiStatus.Experimental
|
||||
package experimentalPackage;
|
||||
@@ -2,7 +2,7 @@ package test;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import experimentalPackage.ClassInExperimentalPackage;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
class ExperimentalClass { }
|
||||
@@ -45,6 +45,12 @@ class Warnings {
|
||||
|
||||
public void <warning descr="Method must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its signature references unstable type 'test.ExperimentalClass'">methodWithUnstableTypeParameterSuperWildcard</warning>(List<? super ExperimentalClass> list) {
|
||||
}
|
||||
|
||||
public ClassInExperimentalPackage <warning descr="Field must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its type references unstable type 'experimentalPackage.ClassInExperimentalPackage'">fieldWithTypeFromExperimentalPackage</warning>;
|
||||
|
||||
public void <warning descr="Method must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its signature references unstable type 'experimentalPackage.ClassInExperimentalPackage'">methodWithParamTypeFromExperimentalPackage</warning>(ClassInExperimentalPackage param) { }
|
||||
|
||||
public ClassInExperimentalPackage <warning descr="Method must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its signature references unstable type 'experimentalPackage.ClassInExperimentalPackage'">methodWithReturnTypeFromExperimentalPackage</warning>() { return null; }
|
||||
}
|
||||
|
||||
class <warning descr="Class must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its declaration references unstable type 'test.ExperimentalClass'">WarningTypeParameter</warning><T extends ExperimentalClass> {
|
||||
@@ -65,7 +71,7 @@ class NoWarningsClassLevel {
|
||||
}
|
||||
}
|
||||
|
||||
// No warnings should be produced because methods and fields are already marked with @ApiStatus.Experimental annotation.
|
||||
// No warnings should be produced because methods and fields are already marked with @ApiStatus.Experimental annotation or are inaccessible.
|
||||
|
||||
class NoWarnings {
|
||||
|
||||
@@ -80,4 +86,11 @@ class NoWarnings {
|
||||
public ExperimentalClass methodWithExperimentalReturnType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ExperimentalClass privateField;
|
||||
|
||||
private void privateMethodWithParam(ExperimentalClass param) {
|
||||
}
|
||||
|
||||
private ExperimentalClass privateMethodWithReturnType() { return null; }
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
package test
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import experimentalPackage.ClassInExperimentalPackage
|
||||
|
||||
@ApiStatus.Experimental
|
||||
open class ExperimentalClass
|
||||
@@ -40,6 +41,12 @@ class Warnings {
|
||||
fun <warning descr="Method must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its signature references unstable type 'test.ExperimentalClass'">methodWithUnstableTypeParameterExtendsWildcard</warning>(list: List<ExperimentalClass>) {}
|
||||
|
||||
fun <warning descr="Method must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its signature references unstable type 'test.ExperimentalClass'">methodWithUnstableTypeParameterSuperWildcard</warning>(list: List<ExperimentalClass>) {}
|
||||
|
||||
var <warning descr="Field must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its type references unstable type 'experimentalPackage.ClassInExperimentalPackage'">fieldWithTypeFromExperimentalPackage</warning>: ClassInExperimentalPackage? = null
|
||||
|
||||
fun <warning descr="Method must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its signature references unstable type 'experimentalPackage.ClassInExperimentalPackage'">methodWithParamTypeFromExperimentalPackage</warning>(param: ClassInExperimentalPackage) {}
|
||||
|
||||
fun <warning descr="Method must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its signature references unstable type 'experimentalPackage.ClassInExperimentalPackage'">methodWithReturnTypeFromExperimentalPackage</warning>(): ClassInExperimentalPackage? = null
|
||||
}
|
||||
|
||||
class <warning descr="Class must be marked with '@org.jetbrains.annotations.ApiStatus.Experimental' annotation because its declaration references unstable type 'test.ExperimentalClass'">WarningTypeParameter</warning><T : ExperimentalClass>
|
||||
@@ -58,7 +65,7 @@ class NoWarningsClassLevel {
|
||||
}
|
||||
}
|
||||
|
||||
// No warnings should be produced because methods and fields are already marked with @ApiStatus.Experimental annotation.
|
||||
// No warnings should be produced because methods and fields are already marked with @ApiStatus.Experimental annotation or are inaccessible.
|
||||
|
||||
class NoWarnings {
|
||||
|
||||
@@ -73,4 +80,10 @@ class NoWarnings {
|
||||
fun methodWithExperimentalReturnType(): ExperimentalClass? {
|
||||
return null
|
||||
}
|
||||
|
||||
private val privateField: ExperimentalClass? = null
|
||||
|
||||
private fun privateMethodWithParam(param: ExperimentalClass) {}
|
||||
|
||||
private fun privateMethodWithReturnType(): ExperimentalClass? = null
|
||||
}
|
||||
@@ -18,6 +18,15 @@ class UnstableTypeUsedInSignatureTest : JavaCodeInsightFixtureTestCase() {
|
||||
inspection.unstableApiAnnotations.clear()
|
||||
inspection.unstableApiAnnotations.add(ApiStatus.Experimental::class.java.canonicalName)
|
||||
myFixture.enableInspections(inspection)
|
||||
configureAnnotatedFiles()
|
||||
}
|
||||
|
||||
private fun configureAnnotatedFiles() {
|
||||
listOf(
|
||||
"experimentalPackage/ClassInExperimentalPackage.java",
|
||||
"experimentalPackage/package-info.java",
|
||||
"experimentalPackage/NoWarnings.java"
|
||||
).forEach { myFixture.copyFileToProject(it) }
|
||||
}
|
||||
|
||||
override fun tuneFixture(moduleBuilder: JavaModuleFixtureBuilder<*>) {
|
||||
@@ -32,4 +41,8 @@ class UnstableTypeUsedInSignatureTest : JavaCodeInsightFixtureTestCase() {
|
||||
myFixture.testHighlighting("unstableTypeUsedInSignature.java")
|
||||
}
|
||||
|
||||
fun `test no warnings produced in experimental package`() {
|
||||
myFixture.testHighlighting("experimentalPackage/NoWarnings.java")
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user