Fix accessibility check for experimental declarations from default scope

#KT-40919 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2020-08-07 14:04:10 +03:00
parent b403b63f48
commit 0c13a7f89a
12 changed files with 73 additions and 7 deletions
@@ -80,6 +80,7 @@ class KotlinResolutionStatelessCallbacksImpl(
kotlinCallArgument.psiCallArgument.psiExpression, kotlinCallArgument.psiCallArgument.psiExpression,
(resolutionCallbacks as? KotlinResolutionCallbacksImpl)?.trace?.bindingContext, (resolutionCallbacks as? KotlinResolutionCallbacksImpl)?.trace?.bindingContext,
isSuperCall = false, isSuperCall = false,
fromImportingScope = false
) )
override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean = override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean =
@@ -64,15 +64,17 @@ class DeprecationResolver(
descriptor: DeclarationDescriptor, descriptor: DeclarationDescriptor,
call: Call? = null, call: Call? = null,
bindingContext: BindingContext? = null, bindingContext: BindingContext? = null,
isSuperCall: Boolean = false isSuperCall: Boolean = false,
fromImportingScope: Boolean = false
): Boolean = ): Boolean =
isHiddenInResolution(descriptor, call?.callElement, bindingContext, isSuperCall) isHiddenInResolution(descriptor, call?.callElement, bindingContext, isSuperCall, fromImportingScope)
fun isHiddenInResolution( fun isHiddenInResolution(
descriptor: DeclarationDescriptor, descriptor: DeclarationDescriptor,
callElement: KtElement?, callElement: KtElement?,
bindingContext: BindingContext?, bindingContext: BindingContext?,
isSuperCall: Boolean isSuperCall: Boolean,
fromImportingScope: Boolean
): Boolean { ): Boolean {
if (descriptor is FunctionDescriptor) { if (descriptor is FunctionDescriptor) {
if (descriptor.isHiddenToOvercomeSignatureClash) return true if (descriptor.isHiddenToOvercomeSignatureClash) return true
@@ -83,14 +85,17 @@ class DeprecationResolver(
if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessible) return true if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessible) return true
if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessibleButWasExperimental) { if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessibleButWasExperimental) {
if (callElement != null && bindingContext != null) { return if (callElement != null && bindingContext != null) {
return with(ExperimentalUsageChecker) { with(ExperimentalUsageChecker) {
sinceKotlinAccessibility.markerClasses.any { classDescriptor -> sinceKotlinAccessibility.markerClasses.any { classDescriptor ->
!callElement.isExperimentalityAccepted(classDescriptor.fqNameSafe, languageVersionSettings, bindingContext) !callElement.isExperimentalityAccepted(classDescriptor.fqNameSafe, languageVersionSettings, bindingContext)
} }
} }
} else {
// We need a softer check for descriptors from importing scope as there is no access to PSI elements
// It's fine to return false here as there will be additional checks for accessibility later
!fromImportingScope
} }
return true
} }
return isDeprecatedHidden(descriptor) return isDeprecatedHidden(descriptor)
@@ -235,7 +235,8 @@ class LazyImportScope(
private fun LazyImportResolver<*>.isClassifierVisible(descriptor: ClassifierDescriptor): Boolean { private fun LazyImportResolver<*>.isClassifierVisible(descriptor: ClassifierDescriptor): Boolean {
if (filteringKind == FilteringKind.ALL) return true if (filteringKind == FilteringKind.ALL) return true
if (components.deprecationResolver.isHiddenInResolution(descriptor)) return false // TODO: do not perform this check here because for correct work it requires corresponding PSI element
if (components.deprecationResolver.isHiddenInResolution(descriptor, fromImportingScope = true)) return false
val visibility = (descriptor as DeclarationDescriptorWithVisibility).visibility val visibility = (descriptor as DeclarationDescriptorWithVisibility).visibility
val includeVisible = filteringKind == FilteringKind.VISIBLE_CLASSES val includeVisible = filteringKind == FilteringKind.VISIBLE_CLASSES
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/useDeclarationThatWasExperimentalWithoutExplicitImport.kt
-d
$TEMP_DIR$
-language-version
1.3
@@ -0,0 +1,7 @@
@ExperimentalStdlibApi
fun test(s: ArrayDeque<Int>): ArrayDeque<Int>? {
ArrayDeque<Int>(42)
val x: ArrayDeque<Int>? = null
return x ?: s
}
@@ -0,0 +1,6 @@
$TESTDATA_DIR$/useDeclarationThatWasExperimentalWithoutMarker.kt
-d
$TEMP_DIR$
-language-version
1.3
-Xopt-in=kotlin.ExperimentalStdlibApi
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/useDeclarationThatWasExperimentalWithoutMarker.kt
-d
$TEMP_DIR$
-language-version
1.3
@@ -0,0 +1,6 @@
fun test(s: ArrayDeque<Int>): ArrayDeque<Int>? {
ArrayDeque<Int>(42)
val x: ArrayDeque<Int>? = null
return x ?: s
}
@@ -0,0 +1,13 @@
compiler/testData/cli/jvm/useDeclarationThatWasExperimentalWithoutMarker.kt:1:13: error: this declaration is experimental and its usage must be marked with '@kotlin.ExperimentalStdlibApi' or '@OptIn(kotlin.ExperimentalStdlibApi::class)'
fun test(s: ArrayDeque<Int>): ArrayDeque<Int>? {
^
compiler/testData/cli/jvm/useDeclarationThatWasExperimentalWithoutMarker.kt:1:31: error: this declaration is experimental and its usage must be marked with '@kotlin.ExperimentalStdlibApi' or '@OptIn(kotlin.ExperimentalStdlibApi::class)'
fun test(s: ArrayDeque<Int>): ArrayDeque<Int>? {
^
compiler/testData/cli/jvm/useDeclarationThatWasExperimentalWithoutMarker.kt:2:5: error: unresolved reference: ArrayDeque
ArrayDeque<Int>(42)
^
compiler/testData/cli/jvm/useDeclarationThatWasExperimentalWithoutMarker.kt:4:12: error: this declaration is experimental and its usage must be marked with '@kotlin.ExperimentalStdlibApi' or '@OptIn(kotlin.ExperimentalStdlibApi::class)'
val x: ArrayDeque<Int>? = null
^
COMPILATION_ERROR
@@ -720,6 +720,21 @@ public class CliTestGenerated extends AbstractCliTest {
runTest("compiler/testData/cli/jvm/unknownExtraFlags.args"); runTest("compiler/testData/cli/jvm/unknownExtraFlags.args");
} }
@TestMetadata("useDeclarationThatWasExperimentalWithoutExplicitImport.args")
public void testUseDeclarationThatWasExperimentalWithoutExplicitImport() throws Exception {
runTest("compiler/testData/cli/jvm/useDeclarationThatWasExperimentalWithoutExplicitImport.args");
}
@TestMetadata("useDeclarationThatWasExperimentalWithoutExplicitImportCommandLine.args")
public void testUseDeclarationThatWasExperimentalWithoutExplicitImportCommandLine() throws Exception {
runTest("compiler/testData/cli/jvm/useDeclarationThatWasExperimentalWithoutExplicitImportCommandLine.args");
}
@TestMetadata("useDeclarationThatWasExperimentalWithoutMarker.args")
public void testUseDeclarationThatWasExperimentalWithoutMarker() throws Exception {
runTest("compiler/testData/cli/jvm/useDeclarationThatWasExperimentalWithoutMarker.args");
}
@TestMetadata("useMixedNamedArgumentsFlag.args") @TestMetadata("useMixedNamedArgumentsFlag.args")
public void testUseMixedNamedArgumentsFlag() throws Exception { public void testUseMixedNamedArgumentsFlag() throws Exception {
runTest("compiler/testData/cli/jvm/useMixedNamedArgumentsFlag.args"); runTest("compiler/testData/cli/jvm/useMixedNamedArgumentsFlag.args");