diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 472ccc5a628..02740561bf7 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -1169,6 +1169,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt"); } + @Test + @TestMetadata("cycleInParameters_after.kt") + public void testCycleInParameters_after() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.kt"); + } + + @Test + @TestMetadata("cycleInParameters_before.kt") + public void testCycleInParameters_before() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.kt"); + } + @Test @TestMetadata("DanglingMixed.kt") public void testDanglingMixed() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 0d761c4f83f..379290d3726 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -1169,6 +1169,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt"); } + @Test + @TestMetadata("cycleInParameters_after.kt") + public void testCycleInParameters_after() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.kt"); + } + + @Test + @TestMetadata("cycleInParameters_before.kt") + public void testCycleInParameters_before() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.kt"); + } + @Test @TestMetadata("DanglingMixed.kt") public void testDanglingMixed() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 50de4b2d70d..dd5a4836930 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -1169,6 +1169,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt"); } + @Test + @TestMetadata("cycleInParameters_after.kt") + public void testCycleInParameters_after() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.kt"); + } + + @Test + @TestMetadata("cycleInParameters_before.kt") + public void testCycleInParameters_before() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.kt"); + } + @Test @TestMetadata("DanglingMixed.kt") public void testDanglingMixed() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 042a0f3ab3d..d909b6d5b6d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -300,6 +300,7 @@ public interface Errors { DiagnosticFactory0 ANNOTATIONS_ON_BLOCK_LEVEL_EXPRESSION_ON_THE_SAME_LINE = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 ANNOTATION_USED_AS_ANNOTATION_ARGUMENT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 ANNOTATION_ARGUMENT_IS_NON_CONST = DiagnosticFactory0.create(WARNING); + DiagnosticFactoryForDeprecation0 CYCLE_IN_ANNOTATION_PARAMETER = DiagnosticFactoryForDeprecation0.create(LanguageFeature.ProhibitCyclesInAnnotations); DiagnosticFactoryForDeprecation0 RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION = DiagnosticFactoryForDeprecation0.create(LanguageFeature.RestrictRetentionForExpressionAnnotations); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index c905fcc99d3..860e8aa3075 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1001,6 +1001,7 @@ public class DefaultErrorMessages { MAP.put(ANNOTATION_USED_AS_ANNOTATION_ARGUMENT, "An annotation can't be used as the annotations argument"); MAP.put(ANNOTATION_ARGUMENT_IS_NON_CONST, "An annotation argument must be a compile-time constant"); + MAP.put(CYCLE_IN_ANNOTATION_PARAMETER, "Type of this parameter is cyclic"); MAP.put(RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION, "Expression annotations with retention other than SOURCE are prohibited"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index 95ac5538457..13578df07b0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -49,6 +49,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( EnumCompanionInEnumConstructorCallChecker, ContextualDeclarationChecker, ValueParameterUsageInDefaultArgumentChecker, + CyclicAnnotationsChecker, ) private val DEFAULT_CALL_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/CyclicAnnotationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/CyclicAnnotationsChecker.kt new file mode 100644 index 00000000000..f9e5e43d659 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/CyclicAnnotationsChecker.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.checkers + +import org.jetbrains.kotlin.builtins.ReflectionTypes +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.diagnostics.Errors.CYCLE_IN_ANNOTATION_PARAMETER +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.types.UnwrappedType + +object CyclicAnnotationsChecker : DeclarationChecker { + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if ( + declaration !is KtClass || !declaration.isAnnotation() || + descriptor !is ClassDescriptor || descriptor.kind != ClassKind.ANNOTATION_CLASS + ) return + + val primaryConstructor = declaration.primaryConstructor ?: return + val primaryConstructorDescriptor = descriptor.unsubstitutedPrimaryConstructor ?: return + + val checker = Checker(descriptor) + + for ((parameter, parameterDescriptor) in primaryConstructor.valueParameters.zip(primaryConstructorDescriptor.valueParameters)) { + if (checker.parameterHasCycle(descriptor, parameterDescriptor)) { + context.trace.report(CYCLE_IN_ANNOTATION_PARAMETER.on(context.languageVersionSettings, parameter)) + } + } + } + + private class Checker(val targetAnnotation: ClassDescriptor) { + private val visitedAnnotationDescriptors = mutableSetOf(targetAnnotation) + private val annotationDescriptorsWithCycle = mutableSetOf(targetAnnotation) + + fun annotationHasCycle(annotationDescriptor: ClassDescriptor): Boolean { + val constructorDescriptor = annotationDescriptor.unsubstitutedPrimaryConstructor ?: return false + + for (parameterDescriptor in constructorDescriptor.valueParameters) { + if (parameterHasCycle(annotationDescriptor, parameterDescriptor)) { + return true + } + } + return false + } + + fun parameterHasCycle(ownedAnnotation: ClassDescriptor, parameterDescriptor: ValueParameterDescriptor): Boolean { + val returnType = parameterDescriptor.returnType?.unwrap() ?: return false + return when { + returnType.arguments.isNotEmpty() && !ReflectionTypes.isKClassType(returnType) -> { + for (argument in returnType.arguments) { + if (!argument.isStarProjection) { + if (typeHasCycle(ownedAnnotation, argument.type.unwrap())) return true + } + } + false + } + else -> typeHasCycle(ownedAnnotation, returnType) + } + } + + fun typeHasCycle(ownedAnnotation: ClassDescriptor, type: UnwrappedType): Boolean { + val referencedAnnotationDescriptor = (type.constructor.declarationDescriptor as? ClassDescriptor) + ?.takeIf { it.kind == ClassKind.ANNOTATION_CLASS } + ?: return false + if (!visitedAnnotationDescriptors.add(referencedAnnotationDescriptor)) { + return (referencedAnnotationDescriptor in annotationDescriptorsWithCycle).also { + if (it) { + annotationDescriptorsWithCycle += ownedAnnotation + } + } + } + if (referencedAnnotationDescriptor == targetAnnotation) { + annotationDescriptorsWithCycle += ownedAnnotation + return true + } + return annotationHasCycle(referencedAnnotationDescriptor) + } + } +} + diff --git a/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.fir.kt b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.fir.kt new file mode 100644 index 00000000000..0998cff629d --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.fir.kt @@ -0,0 +1,15 @@ +// WITH_REFLECT +// LANGUAGE: +ProhibitCyclesInAnnotations +// ISSUE: KT-47932 + +import kotlin.reflect.KClass + +annotation class X(val value: X) // error +annotation class Y(val value: Array) // error + +annotation class Z1(val a: Z2, val b: Z2) // error +annotation class Z2(val value: Z1) // error + +annotation class A(val x: KClass) // OK +annotation class B(val x: KClass) // OK +annotation class C(val b: B) // OK \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.kt b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.kt new file mode 100644 index 00000000000..3d2891e8e96 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.kt @@ -0,0 +1,15 @@ +// WITH_REFLECT +// LANGUAGE: +ProhibitCyclesInAnnotations +// ISSUE: KT-47932 + +import kotlin.reflect.KClass + +annotation class X(val value: X) // error +annotation class Y(val value: Array) // error + +annotation class Z1(val a: Z2, val b: Z2) // error +annotation class Z2(val value: Z1) // error + +annotation class A(val x: KClass) // OK +annotation class B(val x: KClass) // OK +annotation class C(val b: B) // OK diff --git a/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.txt b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.txt new file mode 100644 index 00000000000..6c28e920c7b --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.txt @@ -0,0 +1,58 @@ +package + +public final annotation class A : kotlin.Annotation { + public constructor A(/*0*/ x: kotlin.reflect.KClass) + public final val x: kotlin.reflect.KClass + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class B : kotlin.Annotation { + public constructor B(/*0*/ x: kotlin.reflect.KClass) + public final val x: kotlin.reflect.KClass + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class C : kotlin.Annotation { + public constructor C(/*0*/ b: B) + public final val b: B + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class X : kotlin.Annotation { + public constructor X(/*0*/ value: X) + public final val value: X + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class Y : kotlin.Annotation { + public constructor Y(/*0*/ value: kotlin.Array) + public final val value: kotlin.Array + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class Z1 : kotlin.Annotation { + public constructor Z1(/*0*/ a: Z2, /*1*/ b: Z2) + public final val a: Z2 + public final val b: Z2 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class Z2 : kotlin.Annotation { + public constructor Z2(/*0*/ value: Z1) + public final val value: Z1 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.fir.kt b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.fir.kt new file mode 100644 index 00000000000..9c9f5d1f0be --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.fir.kt @@ -0,0 +1,15 @@ +// WITH_REFLECT +// LANGUAGE: -ProhibitCyclesInAnnotations +// ISSUE: KT-47932 + +import kotlin.reflect.KClass + +annotation class X(val value: X) // error +annotation class Y(val value: Array) // error + +annotation class Z1(val a: Z2, val b: Z2) // error +annotation class Z2(val value: Z1) // error + +annotation class A(val x: KClass) // OK +annotation class B(val x: KClass) // OK +annotation class C(val b: B) // OK \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.kt b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.kt new file mode 100644 index 00000000000..370b7b19e95 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.kt @@ -0,0 +1,15 @@ +// WITH_REFLECT +// LANGUAGE: -ProhibitCyclesInAnnotations +// ISSUE: KT-47932 + +import kotlin.reflect.KClass + +annotation class X(val value: X) // error +annotation class Y(val value: Array) // error + +annotation class Z1(val a: Z2, val b: Z2) // error +annotation class Z2(val value: Z1) // error + +annotation class A(val x: KClass) // OK +annotation class B(val x: KClass) // OK +annotation class C(val b: B) // OK diff --git a/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.txt b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.txt new file mode 100644 index 00000000000..34a35e278d7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.txt @@ -0,0 +1,59 @@ +package + +public final annotation class A : kotlin.Annotation { + public constructor A(/*0*/ x: kotlin.reflect.KClass) + public final val x: kotlin.reflect.KClass + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class B : kotlin.Annotation { + public constructor B(/*0*/ x: kotlin.reflect.KClass) + public final val x: kotlin.reflect.KClass + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class C : kotlin.Annotation { + public constructor C(/*0*/ b: B) + public final val b: B + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class X : kotlin.Annotation { + public constructor X(/*0*/ value: X) + public final val value: X + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class Y : kotlin.Annotation { + public constructor Y(/*0*/ value: kotlin.Array) + public final val value: kotlin.Array + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class Z1 : kotlin.Annotation { + public constructor Z1(/*0*/ a: Z2, /*1*/ b: Z2) + public final val a: Z2 + public final val b: Z2 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final annotation class Z2 : kotlin.Annotation { + public constructor Z2(/*0*/ value: Z1) + public final val value: Z1 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 6e34a8278e4..2d43c2e2808 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -1169,6 +1169,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/annotations/ConstructorCallAllowed.kt"); } + @Test + @TestMetadata("cycleInParameters_after.kt") + public void testCycleInParameters_after() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_after.kt"); + } + + @Test + @TestMetadata("cycleInParameters_before.kt") + public void testCycleInParameters_before() throws Exception { + runTest("compiler/testData/diagnostics/tests/annotations/cycleInParameters_before.kt"); + } + @Test @TestMetadata("DanglingInScript.kts") public void testDanglingInScript() throws Exception { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 1983c476493..3122b0e1535 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -259,6 +259,7 @@ enum class LanguageFeature( ProhibitIllegalValueParameterUsageInDefaultArguments(KOTLIN_1_9, kind = BUG_FIX), // KT-25694 ProhibitConstructorCallOnFunctionalSupertype(KOTLIN_1_9, kind = BUG_FIX), // KT-46344 ProhibitArrayLiteralsInCompanionOfAnnotation(KOTLIN_1_9, kind = BUG_FIX), // KT-39041 + ProhibitCyclesInAnnotations(KOTLIN_1_9, kind = BUG_FIX), // KT-49110 // Temporarily disabled, see KT-27084/KT-22379 SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX), diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt index e3ebee3d3d4..f3691402d75 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/ReflectionTypes.kt @@ -17,7 +17,9 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly @@ -99,6 +101,11 @@ class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: Not return containingPackage != null && containingPackage.fqName == KOTLIN_REFLECT_FQ_NAME } + fun isKClassType(type: KotlinType): Boolean { + val descriptor = type.unwrap().constructor.declarationDescriptor ?: return false + return descriptor.classId == StandardClassIds.KClass + } + fun isCallableType(type: KotlinType): Boolean = type.isFunctionTypeOrSubtype || type.isSuspendFunctionTypeOrSubtype || isKCallableType(type)