diff --git a/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt b/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt index fc39efde491ba..c780c751e7a59 100644 --- a/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDataClassConverters.kt @@ -1126,6 +1126,12 @@ private fun KaDiagnosticConverterBuilder.addConversions20() { token, ) } + add(FirJvmErrors.JAVA_CLASS_PROPERTY_REFERENCE.warningFactory) { firDiagnostic -> + JavaClassPropertyReferenceWarningImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirWebCommonErrors.NESTED_JS_EXPORT) { firDiagnostic -> NestedJsExportImpl( firDiagnostic as KtPsiDiagnostic, @@ -6580,6 +6586,12 @@ private fun KaDiagnosticConverterBuilder.addConversions144() { token, ) } + add(FirJvmErrors.JAVA_CLASS_PROPERTY_REFERENCE.errorFactory) { firDiagnostic -> + JavaClassPropertyReferenceErrorImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } } private fun KaDiagnosticConverterBuilder.addConversions145() { diff --git a/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt b/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt index c48bc6444b32c..2248b2440e7b5 100644 --- a/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt +++ b/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt @@ -4985,6 +4985,14 @@ sealed interface KaFirDiagnostic : KaDiagnosticWithPsi { val expectedType: KaType } + interface JavaClassPropertyReferenceError : KaFirDiagnostic { + override val diagnosticClass get() = JavaClassPropertyReferenceError::class + } + + interface JavaClassPropertyReferenceWarning : KaFirDiagnostic { + override val diagnosticClass get() = JavaClassPropertyReferenceWarning::class + } + interface UnexhaustiveWhenBasedOnJavaAnnotations : KaFirDiagnostic { override val diagnosticClass get() = UnexhaustiveWhenBasedOnJavaAnnotations::class val subjectType: KaType diff --git a/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt index d334f2458ef32..ce26f4398edf1 100644 --- a/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/gen/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt @@ -5986,6 +5986,16 @@ internal class JavaClassOnCompanionImpl( token: KaLifetimeToken, ) : KaAbstractFirDiagnostic(firDiagnostic, token), KaFirDiagnostic.JavaClassOnCompanion +internal class JavaClassPropertyReferenceErrorImpl( + firDiagnostic: KtPsiDiagnostic, + token: KaLifetimeToken, +) : KaAbstractFirDiagnostic(firDiagnostic, token), KaFirDiagnostic.JavaClassPropertyReferenceError + +internal class JavaClassPropertyReferenceWarningImpl( + firDiagnostic: KtPsiDiagnostic, + token: KaLifetimeToken, +) : KaAbstractFirDiagnostic(firDiagnostic, token), KaFirDiagnostic.JavaClassPropertyReferenceWarning + internal class UnexhaustiveWhenBasedOnJavaAnnotationsImpl( override val subjectType: KaType, firDiagnostic: KtPsiDiagnostic, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt index d61684f9d26be..7c28a8922f3b4 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirJvmDiagnosticsList.kt @@ -117,6 +117,10 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") { parameter("actualType") parameter("expectedType") } + val JAVA_CLASS_PROPERTY_REFERENCE by deprecationError( + featureForError = ForbidJavaClassPropertyReferences, + positioningStrategy = PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED, + ) val UNEXHAUSTIVE_WHEN_BASED_ON_JAVA_ANNOTATIONS by warning(PositioningStrategy.WHEN_EXPRESSION) { parameter("subjectType") diff --git a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt index 149cf5bf9e828..4d75150dbbf9d 100644 --- a/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt +++ b/compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature.ForbidImplementationByDelegationWithDifferentGenericSignature +import org.jetbrains.kotlin.config.LanguageFeature.ForbidJavaClassPropertyReferences import org.jetbrains.kotlin.config.LanguageFeature.ForbidJvmAnnotationsOnAnnotationParameters import org.jetbrains.kotlin.config.LanguageFeature.ForbidJvmSerializableLambdaOnInlinedFunctionLiterals import org.jetbrains.kotlin.config.LanguageFeature.ProhibitSynchronizationByValueClassesAndPrimitives @@ -86,6 +87,7 @@ object FirJvmErrors : KtDiagnosticsContainer() { val NULLABILITY_MISMATCH_BASED_ON_EXPLICIT_TYPE_ARGUMENTS_FOR_JAVA: KtDiagnosticFactory3 = KtDiagnosticFactory3("NULLABILITY_MISMATCH_BASED_ON_EXPLICIT_TYPE_ARGUMENTS_FOR_JAVA", WARNING, SourceElementPositioningStrategies.DEFAULT, PsiElement::class, getRendererFactory()) val TYPE_MISMATCH_WHEN_FLEXIBILITY_CHANGES: KtDiagnosticFactory2 = KtDiagnosticFactory2("TYPE_MISMATCH_WHEN_FLEXIBILITY_CHANGES", WARNING, SourceElementPositioningStrategies.DEFAULT, PsiElement::class, getRendererFactory()) val JAVA_CLASS_ON_COMPANION: KtDiagnosticFactory2 = KtDiagnosticFactory2("JAVA_CLASS_ON_COMPANION", WARNING, SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED, PsiElement::class, getRendererFactory()) + val JAVA_CLASS_PROPERTY_REFERENCE: KtDiagnosticFactoryForDeprecation0 = KtDiagnosticFactoryForDeprecation0("JAVA_CLASS_PROPERTY_REFERENCE", ForbidJavaClassPropertyReferences, SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED, PsiElement::class, getRendererFactory()) val UNEXHAUSTIVE_WHEN_BASED_ON_JAVA_ANNOTATIONS: KtDiagnosticFactory1 = KtDiagnosticFactory1("UNEXHAUSTIVE_WHEN_BASED_ON_JAVA_ANNOTATIONS", WARNING, SourceElementPositioningStrategies.WHEN_EXPRESSION, PsiElement::class, getRendererFactory()) // Type parameters diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt index aed07561a8176..d24b00f601404 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt @@ -49,6 +49,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INNER_JVM_ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_CLASS_INHERITS_KT_PRIVATE_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_CLASS_ON_COMPANION +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_CLASS_PROPERTY_REFERENCE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_FIELD_SHADOWED_BY_KOTLIN_PROPERTY import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE @@ -185,6 +186,10 @@ object FirJvmErrorsDefaultMessages : BaseDiagnosticRendererFactory() { RENDER_TYPE, RENDER_TYPE, ) + map.put( + JAVA_CLASS_PROPERTY_REFERENCE, + "Property references to 'javaClass' are error-prone: '::javaClass' creates a property reference, not the Java class of the receiver. Use '.javaClass' or '::class.java' instead.", + ) map.put( UNEXHAUSTIVE_WHEN_BASED_ON_JAVA_ANNOTATIONS, diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt index dc62a8b7896fb..f77603c50fc2f 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/JvmExpressionCheckers.kt @@ -38,6 +38,7 @@ object JvmExpressionCheckers : ExpressionCheckers() { FirUnsupportedSyntheticCallableReferenceChecker, FirFieldReferenceShadowedByInvisibleKotlinProperty, FirJavaSamInterfaceConstructorReferenceChecker, + FirJavaClassPropertyReferenceChecker, ) override val functionCallCheckers: Set diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaClassPropertyReferenceChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaClassPropertyReferenceChecker.kt new file mode 100644 index 0000000000000..c47bcff28b416 --- /dev/null +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/expression/FirJavaClassPropertyReferenceChecker.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2026 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.fir.analysis.jvm.checkers.expression + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirCallableReferenceAccessChecker +import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors +import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess +import org.jetbrains.kotlin.fir.expressions.toResolvedCallableReference +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.name.JvmStandardClassIds + +object FirJavaClassPropertyReferenceChecker : FirCallableReferenceAccessChecker(MppCheckerKind.Common) { + context(context: CheckerContext, reporter: DiagnosticReporter) + override fun check(expression: FirCallableReferenceAccess) { + val resolvedSymbol = expression.toResolvedCallableReference()?.resolvedSymbol as? FirCallableSymbol<*> ?: return + if (resolvedSymbol.callableId != JvmStandardClassIds.Callables.JavaClass) return + + reporter.reportOn(expression.calleeReference.source, FirJvmErrors.JAVA_CLASS_PROPERTY_REFERENCE) + } +} diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt index 11c8db5025be0..e0912c2d6663b 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt @@ -776,6 +776,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set = setOf( "IMPLEMENTATION_BY_DELEGATION_WITH_DIFFERENT_GENERIC_SIGNATURE_ERROR", "NOT_YET_SUPPORTED_LOCAL_INLINE_FUNCTION", "JAVA_TYPE_MISMATCH", + "JAVA_CLASS_PROPERTY_REFERENCE_ERROR", "UPPER_BOUND_CANNOT_BE_ARRAY", "STRICTFP_ON_CLASS", "SYNCHRONIZED_ON_ABSTRACT", diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReferences/javaClassPropertyReference.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReferences/javaClassPropertyReference.kt new file mode 100644 index 0000000000000..4dc28c1160865 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReferences/javaClassPropertyReference.kt @@ -0,0 +1,16 @@ +// RUN_PIPELINE_TILL: FRONTEND +// ISSUE: KTLC-375, KT-81931 +// LATEST_LV_DIFFERENCE + +fun test(x: Any) { + val a = x::javaClass + val b = Any()::javaClass + val c = 2::javaClass + val d = x::javaClass.get() + + val direct = x.javaClass + val literal = Any::class.java +} + +/* GENERATED_FIR_TAGS: callableReference, classReference, functionDeclaration, integerLiteral, localProperty, +propertyDeclaration */ diff --git a/compiler/testData/diagnostics/testsWithStdLib/callableReferences/javaClassPropertyReference.latestLV.kt b/compiler/testData/diagnostics/testsWithStdLib/callableReferences/javaClassPropertyReference.latestLV.kt new file mode 100644 index 0000000000000..d41da2e4723eb --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/callableReferences/javaClassPropertyReference.latestLV.kt @@ -0,0 +1,16 @@ +// RUN_PIPELINE_TILL: FRONTEND +// ISSUE: KTLC-375, KT-81931 +// LATEST_LV_DIFFERENCE + +fun test(x: Any) { + val a = x::javaClass + val b = Any()::javaClass + val c = 2::javaClass + val d = x::javaClass.get() + + val direct = x.javaClass + val literal = Any::class.java +} + +/* GENERATED_FIR_TAGS: callableReference, classReference, functionDeclaration, integerLiteral, localProperty, +propertyDeclaration */ diff --git a/core/language.version-settings/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/core/language.version-settings/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index efff8a278453e..0c64b34ce57d9 100644 --- a/core/language.version-settings/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/core/language.version-settings/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -552,6 +552,7 @@ enum class LanguageFeature( // 2.6 ReportReificationProblemsInDnnAndFlexible(sinceVersion = KOTLIN_2_6, enabledInProgressiveMode = true, "KTLC-399"), + ForbidJavaClassPropertyReferences(sinceVersion = KOTLIN_2_6, enabledInProgressiveMode = true, "KTLC-375"), // End of 2.* language features --------------------------------------------------