[FIR] Implement deprecation for accessing private operators from public inline function

This only affects delegation operators as well as the for-loop-related
next and hasNext operators.
All the other operators worked correctly before.
In K2, the previously mentioned operator calls will be flagged with a
deprecation error and will become and error in 2.1.

#KT-59782 Fixed
This commit is contained in:
Kirill Rakhman
2024-02-02 14:23:10 +01:00
committed by Space Team
parent 58c03e021b
commit 376a9b8ace
17 changed files with 370 additions and 1 deletions
@@ -1651,6 +1651,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<Symbol>("referencedDeclaration")
}
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE_DEPRECATION by warning<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("inlineDeclaration")
parameter<Symbol>("referencedDeclaration")
}
val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<Symbol>("inlineDeclaration")
parameter<Symbol>("referencedDeclaration")
@@ -833,6 +833,7 @@ object FirErrors {
val NULLABLE_INLINE_PARAMETER: KtDiagnosticFactory2<FirValueParameterSymbol, FirBasedSymbol<*>> by error2<KtDeclaration, FirValueParameterSymbol, FirBasedSymbol<*>>()
val RECURSION_IN_INLINE: KtDiagnosticFactory1<FirBasedSymbol<*>> by error1<KtElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE: KtDiagnosticFactory2<FirBasedSymbol<*>, FirBasedSymbol<*>> by error2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE_DEPRECATION: KtDiagnosticFactory2<FirBasedSymbol<*>, FirBasedSymbol<*>> by warning2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE: KtDiagnosticFactory2<FirBasedSymbol<*>, FirBasedSymbol<*>> by error2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR: KtDiagnosticFactory2<FirBasedSymbol<*>, FirBasedSymbol<*>> by error2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val PROTECTED_CALL_FROM_PUBLIC_INLINE: KtDiagnosticFactory2<FirBasedSymbol<*>, FirBasedSymbol<*>> by warning2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory2
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.references.symbol
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.publishedApiEffectiveVisibility
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -91,7 +93,7 @@ object FirInlineDeclarationChecker : FirFunctionChecker(MppCheckerKind.Common) {
) {
reporter.reportOn(
source,
FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE,
getNonPublicCallFromPublicInlineFactory(accessExpression, source, context),
inlineFunction.symbol,
accessedSymbol,
context
@@ -106,6 +108,24 @@ object FirInlineDeclarationChecker : FirFunctionChecker(MppCheckerKind.Common) {
)
}
private fun getNonPublicCallFromPublicInlineFactory(
accessExpression: FirStatement,
source: KtSourceElement,
context: CheckerContext,
): KtDiagnosticFactory2<FirBasedSymbol<*>, FirBasedSymbol<*>> {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitPrivateOperatorCallInInline)) {
val isDelegatedPropertyAccessor = source.kind == KtFakeSourceElementKind.DelegatedPropertyAccessor
val isForLoopButNotIteratorCall = source.kind == KtFakeSourceElementKind.DesugaredForLoop &&
accessExpression.toReference(context.session)?.symbol?.memberDeclarationNameOrNull != OperatorNameConventions.ITERATOR
if (isDelegatedPropertyAccessor || isForLoopButNotIteratorCall) {
return FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE_DEPRECATION
}
}
return FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE
}
private fun EffectiveVisibility.isReachableDueToLocalDispatchReceiver(access: FirStatement, context: CheckerContext): Boolean {
val receiverType = access.localDispatchReceiver(context) ?: return false
val receiverProtected = EffectiveVisibility.Protected(receiverType.typeConstructor(context.session.typeContext))
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderers.CLASS_ID
import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderers.COLLECTION
@@ -504,6 +505,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PLATFORM_CLASS_MA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPILER_REQUIRED_ANNOTATION_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_LABELS_ARE_FORBIDDEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE_DEPRECATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.POTENTIALLY_NON_REPORTED_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRE_RELEASE_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED
@@ -2427,6 +2429,13 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
map.put(RECURSION_IN_INLINE, "Inline function ''{0}'' cannot be recursive.", SYMBOL)
map.put(NON_PUBLIC_CALL_FROM_PUBLIC_INLINE, "Public-API inline function cannot access non-public-API ''{0}''.", SYMBOL, SYMBOL)
map.put(
NON_PUBLIC_CALL_FROM_PUBLIC_INLINE_DEPRECATION,
"Public-API inline function cannot access non-public-API ''{0}''. " +
"This will become an error in Kotlin ${LanguageFeature.ProhibitPrivateOperatorCallInInline.sinceVersion?.versionString}.",
SYMBOL,
SYMBOL
)
map.put(
PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE,
"Protected constructor call from public-API inline function is deprecated.",