Add internal WasExperimental for stdlib
Usages of declarations annotated with WasExperimental are allowed even if the API version requirement is not satisfied, provided that the opt-in to all mentioned markers is given. This is needed for smooth graduation of API in kotlin-stdlib
This commit is contained in:
+6
-3
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.API_NOT_AVAILABLE
|
import org.jetbrains.kotlin.diagnostics.Errors.API_NOT_AVAILABLE
|
||||||
|
import org.jetbrains.kotlin.resolve.SinceKotlinAccessibility
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||||
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
||||||
@@ -34,13 +35,15 @@ object ApiVersionCallChecker : CallChecker {
|
|||||||
// Objects will be checked by ApiVersionClassifierUsageChecker
|
// Objects will be checked by ApiVersionClassifierUsageChecker
|
||||||
if (targetDescriptor is FakeCallableDescriptorForObject) return
|
if (targetDescriptor is FakeCallableDescriptorForObject) return
|
||||||
|
|
||||||
val accessible = targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) { version ->
|
val accessibility = targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings)
|
||||||
|
if (accessibility is SinceKotlinAccessibility.NotAccessible) {
|
||||||
context.trace.report(
|
context.trace.report(
|
||||||
API_NOT_AVAILABLE.on(element, version.versionString, context.languageVersionSettings.apiVersion.versionString)
|
API_NOT_AVAILABLE.on(element, accessibility.version.versionString, context.languageVersionSettings.apiVersion.versionString)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessible && targetDescriptor is PropertyDescriptor && DeprecatedCallChecker.shouldCheckPropertyGetter(element)) {
|
if (accessibility == SinceKotlinAccessibility.Accessible &&
|
||||||
|
targetDescriptor is PropertyDescriptor && DeprecatedCallChecker.shouldCheckPropertyGetter(element)) {
|
||||||
targetDescriptor.getter?.let { check(it, context, element) }
|
targetDescriptor.getter?.let { check(it, context, element) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isConventionCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isSuperOrDelegatingConstructorCall
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isSuperOrDelegatingConstructorCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionStatelessCallbacks
|
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionStatelessCallbacks
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.isCoroutineCallWithAdditionalInference
|
import org.jetbrains.kotlin.resolve.calls.inference.isCoroutineCallWithAdditionalInference
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
|
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
|
||||||
@@ -51,8 +52,15 @@ class KotlinResolutionStatelessCallbacksImpl(
|
|||||||
override fun isSuperOrDelegatingConstructorCall(kotlinCall: KotlinCall) =
|
override fun isSuperOrDelegatingConstructorCall(kotlinCall: KotlinCall) =
|
||||||
kotlinCall is PSIKotlinCallImpl && isSuperOrDelegatingConstructorCall(kotlinCall.psiCall)
|
kotlinCall is PSIKotlinCallImpl && isSuperOrDelegatingConstructorCall(kotlinCall.psiCall)
|
||||||
|
|
||||||
override fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall) =
|
override fun isHiddenInResolution(
|
||||||
deprecationResolver.isHiddenInResolution(descriptor, isSuperOrDelegatingConstructorCall(kotlinCall))
|
descriptor: DeclarationDescriptor, kotlinCall: KotlinCall, resolutionCallbacks: KotlinResolutionCallbacks
|
||||||
|
) =
|
||||||
|
deprecationResolver.isHiddenInResolution(
|
||||||
|
descriptor,
|
||||||
|
(kotlinCall as? PSIKotlinCall)?.psiCall,
|
||||||
|
(resolutionCallbacks as? KotlinResolutionCallbacksImpl)?.trace?.bindingContext,
|
||||||
|
isSuperOrDelegatingConstructorCall(kotlinCall)
|
||||||
|
)
|
||||||
|
|
||||||
override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean =
|
override fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean =
|
||||||
receiver?.psiExpression is KtSuperExpression
|
receiver?.psiExpression is KtSuperExpression
|
||||||
|
|||||||
+12
-4
@@ -35,7 +35,10 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.*
|
import org.jetbrains.kotlin.resolve.calls.context.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
|
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSupport
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionResultsHandler
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||||
@@ -219,7 +222,10 @@ class NewResolutionOldInference(
|
|||||||
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
||||||
val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments)
|
val resolvedCall = ResolvedCallImpl.create(candidate, candidateTrace, tracing, basicCallContext.dataFlowInfoForArguments)
|
||||||
|
|
||||||
if (deprecationResolver.isHiddenInResolution(candidate.descriptor, basicCallContext.isSuperCall)) {
|
if (deprecationResolver.isHiddenInResolution(
|
||||||
|
candidate.descriptor, basicCallContext.call, basicCallContext.trace.bindingContext, basicCallContext.isSuperCall
|
||||||
|
)
|
||||||
|
) {
|
||||||
return@map MyCandidate(listOf(HiddenDescriptor), resolvedCall)
|
return@map MyCandidate(listOf(HiddenDescriptor), resolvedCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,8 +454,10 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deprecationResolver.isHiddenInResolution(
|
||||||
if (deprecationResolver.isHiddenInResolution(towerCandidate.descriptor, basicCallContext.isSuperCall)) {
|
towerCandidate.descriptor, basicCallContext.call, basicCallContext.trace.bindingContext, basicCallContext.isSuperCall
|
||||||
|
)
|
||||||
|
) {
|
||||||
return MyCandidate(listOf(HiddenDescriptor), candidateCall)
|
return MyCandidate(listOf(HiddenDescriptor), candidateCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ class PSICallResolver(
|
|||||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
|
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
|
||||||
val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver
|
val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver
|
||||||
val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name)
|
val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name)
|
||||||
return SimpleCandidateFactory(callComponents, scopeTower, variableCall, context.inferenceSession)
|
return SimpleCandidateFactory(callComponents, scopeTower, variableCall, createResolutionCallbacks(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean):
|
override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean):
|
||||||
@@ -406,7 +406,7 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return variableCallArgument.receiver to SimpleCandidateFactory(
|
return variableCallArgument.receiver to SimpleCandidateFactory(
|
||||||
callComponents, scopeTower, callForInvoke, context.inferenceSession
|
callComponents, scopeTower, callForInvoke, createResolutionCallbacks(context)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -19,13 +19,17 @@ package org.jetbrains.kotlin.resolve.checkers
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.resolve.SinceKotlinAccessibility
|
||||||
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
||||||
|
|
||||||
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
|
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
|
||||||
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
||||||
targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings) { version ->
|
val accessibility = targetDescriptor.checkSinceKotlinVersionAccessibility(context.languageVersionSettings)
|
||||||
|
if (accessibility is SinceKotlinAccessibility.NotAccessible) {
|
||||||
context.trace.report(
|
context.trace.report(
|
||||||
Errors.API_NOT_AVAILABLE.on(element, version.versionString, context.languageVersionSettings.apiVersion.versionString)
|
Errors.API_NOT_AVAILABLE.on(
|
||||||
|
element, accessibility.version.versionString, context.languageVersionSettings.apiVersion.versionString
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-6
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
import org.jetbrains.kotlin.config.AnalysisFlag
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -62,7 +63,9 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
|||||||
companion object {
|
companion object {
|
||||||
val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental")
|
val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental")
|
||||||
internal val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental")
|
internal val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental")
|
||||||
|
private val WAS_EXPERIMENTAL_FQ_NAME = FqName("kotlin.WasExperimental")
|
||||||
internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
||||||
|
private val WAS_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
||||||
|
|
||||||
private val LEVEL = Name.identifier("level")
|
private val LEVEL = Name.identifier("level")
|
||||||
private val WARNING_LEVEL = Name.identifier("WARNING")
|
private val WARNING_LEVEL = Name.identifier("WARNING")
|
||||||
@@ -119,21 +122,24 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
|||||||
return Experimentality(fqNameSafe, severity)
|
return Experimentality(fqNameSafe, severity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.isExperimentalityAccepted(annotationFqName: FqName, context: CheckerContext): Boolean =
|
||||||
|
isExperimentalityAccepted(annotationFqName, context.languageVersionSettings, context.trace.bindingContext)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether there's an element lexically above in the tree, annotated with `@UseExperimental(X::class)`, or a declaration
|
* Checks whether there's an element lexically above in the tree, annotated with `@UseExperimental(X::class)`, or a declaration
|
||||||
* annotated with `@X` where [annotationFqName] is the FQ name of X
|
* annotated with `@X` where [annotationFqName] is the FQ name of X
|
||||||
*/
|
*/
|
||||||
private fun PsiElement.isExperimentalityAccepted(annotationFqName: FqName, context: CheckerContext): Boolean {
|
fun PsiElement.isExperimentalityAccepted(
|
||||||
val languageVersionSettings = context.languageVersionSettings
|
annotationFqName: FqName,
|
||||||
val bindingContext = context.trace.bindingContext
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
|
bindingContext: BindingContext
|
||||||
return annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlag.experimental) ||
|
): Boolean =
|
||||||
|
annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlag.experimental) ||
|
||||||
annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlag.useExperimental) ||
|
annotationFqName.asString() in languageVersionSettings.getFlag(AnalysisFlag.useExperimental) ||
|
||||||
anyParentMatches { element ->
|
anyParentMatches { element ->
|
||||||
element.isDeclarationAnnotatedWith(annotationFqName, bindingContext) ||
|
element.isDeclarationAnnotatedWith(annotationFqName, bindingContext) ||
|
||||||
element.isElementAnnotatedWithUseExperimentalOf(annotationFqName, bindingContext)
|
element.isElementAnnotatedWithUseExperimentalOf(annotationFqName, bindingContext)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiElement.isDeclarationAnnotatedWith(annotationFqName: FqName, bindingContext: BindingContext): Boolean {
|
private fun PsiElement.isDeclarationAnnotatedWith(annotationFqName: FqName, bindingContext: BindingContext): Boolean {
|
||||||
if (this !is KtDeclaration) return false
|
if (this !is KtDeclaration) return false
|
||||||
@@ -163,6 +169,20 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun Annotated.loadWasExperimentalMarkerFqNames(): List<FqName> {
|
||||||
|
val wasExperimental = annotations.findAnnotation(WAS_EXPERIMENTAL_FQ_NAME)
|
||||||
|
if (wasExperimental != null) {
|
||||||
|
val annotationClasses = wasExperimental.allValueArguments[WAS_EXPERIMENTAL_ANNOTATION_CLASS]
|
||||||
|
if (annotationClasses is ArrayValue) {
|
||||||
|
return annotationClasses.value.mapNotNull { annotationClass ->
|
||||||
|
(annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor?.fqNameSafe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
fun checkCompilerArguments(
|
fun checkCompilerArguments(
|
||||||
module: ModuleDescriptor,
|
module: ModuleDescriptor,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
|
|||||||
@@ -32,10 +32,12 @@ import org.jetbrains.kotlin.diagnostics.Errors
|
|||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
|
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.psi.Call
|
||||||
import org.jetbrains.kotlin.resolve.DeprecationLevelValue.*
|
import org.jetbrains.kotlin.resolve.DeprecationLevelValue.*
|
||||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.isOperatorMod
|
import org.jetbrains.kotlin.resolve.calls.checkers.isOperatorMod
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.shouldWarnAboutDeprecatedModFromBuiltIns
|
import org.jetbrains.kotlin.resolve.calls.checkers.shouldWarnAboutDeprecatedModFromBuiltIns
|
||||||
|
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
|
||||||
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
|
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||||
@@ -210,6 +212,8 @@ class DeprecationResolver(
|
|||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun isHiddenInResolution(
|
fun isHiddenInResolution(
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
|
call: Call? = null,
|
||||||
|
bindingContext: BindingContext? = null,
|
||||||
isSuperCall: Boolean = false
|
isSuperCall: Boolean = false
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (descriptor is FunctionDescriptor) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
@@ -217,7 +221,19 @@ class DeprecationResolver(
|
|||||||
if (descriptor.isHiddenForResolutionEverywhereBesideSupercalls && !isSuperCall) return true
|
if (descriptor.isHiddenForResolutionEverywhereBesideSupercalls && !isSuperCall) return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isHiddenBecauseOfKotlinVersionAccessibility(descriptor.original)) return true
|
val sinceKotlinAccessibility = isHiddenBecauseOfKotlinVersionAccessibility(descriptor.original)
|
||||||
|
if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessible) return true
|
||||||
|
|
||||||
|
if (sinceKotlinAccessibility is SinceKotlinAccessibility.NotAccessibleButWasExperimental) {
|
||||||
|
if (call != null && bindingContext != null) {
|
||||||
|
return with(ExperimentalUsageChecker) {
|
||||||
|
sinceKotlinAccessibility.annotationFqNames.any { fqName ->
|
||||||
|
!call.callElement.isExperimentalityAccepted(fqName, languageVersionSettings, bindingContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return isDeprecatedHidden(descriptor)
|
return isDeprecatedHidden(descriptor)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.name.isChildOf
|
import org.jetbrains.kotlin.name.isChildOf
|
||||||
import org.jetbrains.kotlin.name.isSubpackageOf
|
import org.jetbrains.kotlin.name.isSubpackageOf
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
|
import org.jetbrains.kotlin.resolve.SinceKotlinAccessibility
|
||||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||||
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
@@ -69,7 +70,7 @@ class DefaultImportProvider(
|
|||||||
val excludedImports: List<FqName> by storageManager.createLazyValue {
|
val excludedImports: List<FqName> by storageManager.createLazyValue {
|
||||||
val builtinTypeAliases =
|
val builtinTypeAliases =
|
||||||
moduleDescriptor.findTypeAliasesInPackages(PACKAGES_WITH_ALIASES)
|
moduleDescriptor.findTypeAliasesInPackages(PACKAGES_WITH_ALIASES)
|
||||||
.filter { it.checkSinceKotlinVersionAccessibility(languageVersionSettings) }
|
.filter { it.checkSinceKotlinVersionAccessibility(languageVersionSettings) == SinceKotlinAccessibility.Accessible }
|
||||||
|
|
||||||
val nonKotlinDefaultImportedPackages =
|
val nonKotlinDefaultImportedPackages =
|
||||||
defaultImports
|
defaultImports
|
||||||
|
|||||||
+22
-25
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
*
|
* that can be found in the license/LICENSE.txt file.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.resolve
|
package org.jetbrains.kotlin.resolve
|
||||||
@@ -22,17 +11,22 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject
|
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject
|
||||||
|
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
|
||||||
|
|
||||||
val SINCE_KOTLIN_FQ_NAME = FqName("kotlin.SinceKotlin")
|
sealed class SinceKotlinAccessibility {
|
||||||
|
object Accessible : SinceKotlinAccessibility()
|
||||||
|
|
||||||
/**
|
data class NotAccessibleButWasExperimental(
|
||||||
* @return true if the descriptor is accessible according to [languageVersionSettings], or false otherwise. The [actionIfInaccessible]
|
val version: ApiVersion,
|
||||||
* callback is called with the version specified in the [SinceKotlin] annotation if the descriptor is inaccessible.
|
val annotationFqNames: List<FqName>
|
||||||
*/
|
) : SinceKotlinAccessibility()
|
||||||
fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility(
|
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
data class NotAccessible(
|
||||||
actionIfInaccessible: ((ApiVersion) -> Unit)? = null
|
val version: ApiVersion
|
||||||
): Boolean {
|
) : SinceKotlinAccessibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings: LanguageVersionSettings): SinceKotlinAccessibility {
|
||||||
val version =
|
val version =
|
||||||
if (this is CallableMemberDescriptor && !kind.isReal) getSinceKotlinVersionByOverridden(this)
|
if (this is CallableMemberDescriptor && !kind.isReal) getSinceKotlinVersionByOverridden(this)
|
||||||
else getOwnSinceKotlinVersion()
|
else getOwnSinceKotlinVersion()
|
||||||
@@ -41,11 +35,14 @@ fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility(
|
|||||||
// 1) There's no @SinceKotlin annotation for this descriptor
|
// 1) There's no @SinceKotlin annotation for this descriptor
|
||||||
// 2) There's a @SinceKotlin annotation but its value is some unrecognizable nonsense
|
// 2) There's a @SinceKotlin annotation but its value is some unrecognizable nonsense
|
||||||
// 3) The value as a version is not greater than our API version
|
// 3) The value as a version is not greater than our API version
|
||||||
if (version == null || version <= languageVersionSettings.apiVersion) return true
|
if (version == null || version <= languageVersionSettings.apiVersion) return SinceKotlinAccessibility.Accessible
|
||||||
|
|
||||||
actionIfInaccessible?.invoke(version)
|
val wasExperimentalFqNames = with(ExperimentalUsageChecker) { loadWasExperimentalMarkerFqNames() }
|
||||||
|
if (wasExperimentalFqNames.isNotEmpty()) {
|
||||||
|
return SinceKotlinAccessibility.NotAccessibleButWasExperimental(version, wasExperimentalFqNames)
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return SinceKotlinAccessibility.NotAccessible(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
|
val SINCE_KOTLIN_FQ_NAME = FqName("kotlin.SinceKotlin")
|
||||||
@@ -45,7 +45,7 @@ class KotlinCallResolver(
|
|||||||
): CallResolutionResult {
|
): CallResolutionResult {
|
||||||
kotlinCall.checkCallInvariants()
|
kotlinCall.checkCallInvariants()
|
||||||
|
|
||||||
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks.inferenceSession)
|
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks)
|
||||||
val processor = when (kotlinCall.callKind) {
|
val processor = when (kotlinCall.callKind) {
|
||||||
KotlinCallKind.VARIABLE -> {
|
KotlinCallKind.VARIABLE -> {
|
||||||
createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver)
|
createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver)
|
||||||
@@ -96,7 +96,7 @@ class KotlinCallResolver(
|
|||||||
collectAllCandidates: Boolean
|
collectAllCandidates: Boolean
|
||||||
): CallResolutionResult {
|
): CallResolutionResult {
|
||||||
kotlinCall.checkCallInvariants()
|
kotlinCall.checkCallInvariants()
|
||||||
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks.inferenceSession)
|
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall, resolutionCallbacks)
|
||||||
|
|
||||||
val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
|
val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -21,7 +21,10 @@ interface KotlinResolutionStatelessCallbacks {
|
|||||||
fun isInfixCall(kotlinCall: KotlinCall): Boolean
|
fun isInfixCall(kotlinCall: KotlinCall): Boolean
|
||||||
fun isOperatorCall(kotlinCall: KotlinCall): Boolean
|
fun isOperatorCall(kotlinCall: KotlinCall): Boolean
|
||||||
fun isSuperOrDelegatingConstructorCall(kotlinCall: KotlinCall): Boolean
|
fun isSuperOrDelegatingConstructorCall(kotlinCall: KotlinCall): Boolean
|
||||||
fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall): Boolean
|
fun isHiddenInResolution(
|
||||||
|
descriptor: DeclarationDescriptor, kotlinCall: KotlinCall, resolutionCallbacks: KotlinResolutionCallbacks
|
||||||
|
): Boolean
|
||||||
|
|
||||||
fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean
|
fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean
|
||||||
fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower
|
fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower
|
||||||
fun getVariableCandidateIfInvoke(functionCall: KotlinCall): KotlinResolutionCandidate?
|
fun getVariableCandidateIfInvoke(functionCall: KotlinCall): KotlinResolutionCandidate?
|
||||||
|
|||||||
+4
-2
@@ -49,8 +49,10 @@ class SimpleCandidateFactory(
|
|||||||
val callComponents: KotlinCallComponents,
|
val callComponents: KotlinCallComponents,
|
||||||
val scopeTower: ImplicitScopeTower,
|
val scopeTower: ImplicitScopeTower,
|
||||||
val kotlinCall: KotlinCall,
|
val kotlinCall: KotlinCall,
|
||||||
val inferenceSession: InferenceSession
|
val resolutionCallbacks: KotlinResolutionCallbacks
|
||||||
) : CandidateFactory<KotlinResolutionCandidate> {
|
) : CandidateFactory<KotlinResolutionCandidate> {
|
||||||
|
val inferenceSession: InferenceSession = resolutionCallbacks.inferenceSession
|
||||||
|
|
||||||
val baseSystem: ConstraintStorage
|
val baseSystem: ConstraintStorage
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -144,7 +146,7 @@ class SimpleCandidateFactory(
|
|||||||
|
|
||||||
initialDiagnostics.forEach(candidate::addDiagnostic)
|
initialDiagnostics.forEach(candidate::addDiagnostic)
|
||||||
|
|
||||||
if (callComponents.statelessCallbacks.isHiddenInResolution(descriptor, kotlinCall)) {
|
if (callComponents.statelessCallbacks.isHiddenInResolution(descriptor, kotlinCall, resolutionCallbacks)) {
|
||||||
candidate.addDiagnostic(HiddenDescriptor)
|
candidate.addDiagnostic(HiddenDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
// !API_VERSION: 1.2
|
||||||
|
// !USE_EXPERIMENTAL: kotlin.Experimental
|
||||||
|
// !DIAGNOSTICS: -INVISIBLE_MEMBER -INVISIBLE_REFERENCE -NEWER_VERSION_IN_SINCE_KOTLIN -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
fun newPublishedFun() {}
|
||||||
|
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
annotation class Marker
|
||||||
|
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@WasExperimental(Marker::class)
|
||||||
|
fun newFunExperimentalInThePast() {}
|
||||||
|
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@WasExperimental(Marker::class)
|
||||||
|
val newValExperimentalInThePast = ""
|
||||||
|
|
||||||
|
@SinceKotlin("1.3")
|
||||||
|
@WasExperimental(Marker::class)
|
||||||
|
class NewClassExperimentalInThePast
|
||||||
|
|
||||||
|
fun use1(c: <!UNRESOLVED_REFERENCE!>NewClassExperimentalInThePast<!>) {
|
||||||
|
<!UNRESOLVED_REFERENCE!>newPublishedFun<!>()
|
||||||
|
<!UNRESOLVED_REFERENCE!>newFunExperimentalInThePast<!>()
|
||||||
|
<!UNRESOLVED_REFERENCE!>newValExperimentalInThePast<!>
|
||||||
|
<!UNRESOLVED_REFERENCE!>NewClassExperimentalInThePast<!>()
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseExperimental(Marker::class)
|
||||||
|
fun use2(c: NewClassExperimentalInThePast) {
|
||||||
|
<!UNRESOLVED_REFERENCE!>newPublishedFun<!>()
|
||||||
|
newFunExperimentalInThePast()
|
||||||
|
newValExperimentalInThePast
|
||||||
|
NewClassExperimentalInThePast()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Marker
|
||||||
|
fun use3(c: NewClassExperimentalInThePast) {
|
||||||
|
<!UNRESOLVED_REFERENCE!>newPublishedFun<!>()
|
||||||
|
newFunExperimentalInThePast()
|
||||||
|
newValExperimentalInThePast
|
||||||
|
NewClassExperimentalInThePast()
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
@kotlin.SinceKotlin(version = "1.3") @kotlin.WasExperimental(markerClass = {Marker::class}) public fun newFunExperimentalInThePast(): kotlin.Unit
|
||||||
|
@kotlin.SinceKotlin(version = "1.3") public fun newPublishedFun(): kotlin.Unit
|
||||||
|
public fun use1(): kotlin.Unit
|
||||||
|
@kotlin.UseExperimental(markerClass = {Marker::class}) public fun use2(): kotlin.Unit
|
||||||
|
@Marker public fun use3(): kotlin.Unit
|
||||||
|
|
||||||
|
@kotlin.Experimental public final annotation class Marker : kotlin.Annotation {
|
||||||
|
public constructor Marker()
|
||||||
|
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
|
||||||
|
}
|
||||||
+5
@@ -2196,6 +2196,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
public void testUseExperimentalWithSeveralAnnotations() throws Exception {
|
public void testUseExperimentalWithSeveralAnnotations() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("wasExperimental.kt")
|
||||||
|
public void testWasExperimental() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+5
@@ -2196,6 +2196,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
public void testUseExperimentalWithSeveralAnnotations() throws Exception {
|
public void testUseExperimentalWithSeveralAnnotations() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/useExperimentalWithSeveralAnnotations.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("wasExperimental.kt")
|
||||||
|
public void testWasExperimental() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/experimental/wasExperimental.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
||||||
|
|||||||
@@ -50,3 +50,10 @@ annotation class Experimental(val level: Level = Level.ERROR) {
|
|||||||
annotation class UseExperimental(
|
annotation class UseExperimental(
|
||||||
vararg val markerClass: KClass<out Annotation>
|
vararg val markerClass: KClass<out Annotation>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@Target(CLASS, PROPERTY, CONSTRUCTOR, FUNCTION)
|
||||||
|
@Retention(BINARY)
|
||||||
|
internal annotation class WasExperimental(
|
||||||
|
vararg val markerClass: KClass<out Annotation>
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user