Introduce deprecation of companion objects nested classes

Introdude deprecation as per KT-21515. Warning is reported on type
usage, that soon will became invisible. Quickfix by adding explicit
import is added.

Idea behind implementation is to mark scopes that are deprecated (see
ClassResolutionScopesSupport).

Then, during walk along hierarchy of scopes, look at deprecation status
of the scope that has provided this classifier.
Note that we also have to check if there are *some* non-deprecated
visibility paths (because we can see classifier by two paths, e.g. if
we've added explicit import) -- then this type reference shouldn't be
treated as deprecated.
This commit is contained in:
Dmitry Savvinov
2017-12-14 18:59:32 +03:00
parent acd8edaa9c
commit d570b863ce
117 changed files with 8027 additions and 113 deletions
@@ -24,9 +24,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.model.DiagnosticReporter
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.*
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.KotlinType
@@ -110,3 +108,5 @@ object HiddenDescriptor : ResolutionDiagnostic(HIDDEN)
object InvokeConventionCallNoOperatorModifier : ResolutionDiagnostic(CONVENTION_ERROR)
object InfixCallNoInfixModifier : ResolutionDiagnostic(CONVENTION_ERROR)
object DeprecatedUnaryPlusAsPlus : ResolutionDiagnostic(CONVENTION_ERROR)
class ResolvedUsingDeprecatedVisbility(val baseSourceScope: ResolutionScope, val lookupLocation: LookupLocation) : ResolutionDiagnostic(RESOLVED)
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.getImmediateSuperclassNotAny
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
import kotlin.collections.ArrayList
internal abstract class AbstractScopeTowerLevel(
protected val scopeTower: ImplicitScopeTower
@@ -201,15 +201,14 @@ internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qual
override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope
.getContributedObjectVariables(name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
createCandidateDescriptor(it, dispatchReceiver = null)
}
override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope
.getContributedFunctionsAndConstructors(
name,
location,
scopeTower.syntheticScopes,
qualifier.staticScope
scopeTower.syntheticScopes
).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
@@ -235,20 +234,37 @@ internal open class ScopeBasedTowerLevel protected constructor(
override fun getObjects(
name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> = resolutionScope.getContributedObjectVariables(name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
): Collection<CandidateWithBoundDispatchReceiver> =
resolutionScope.getContributedObjectVariablesIncludeDeprecated(name, location).map { (classifier, isDeprecated) ->
createCandidateDescriptor(
classifier,
dispatchReceiver = null,
specialError = if (isDeprecated) ResolvedUsingDeprecatedVisbility(resolutionScope, location) else null
)
}
override fun getFunctions(
name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> = resolutionScope.getContributedFunctionsAndConstructors(
name,
location,
scopeTower.syntheticScopes,
resolutionScope
).map {
createCandidateDescriptor(it, dispatchReceiver = null)
): Collection<CandidateWithBoundDispatchReceiver> {
val result: ArrayList<CandidateWithBoundDispatchReceiver> = ArrayList()
resolutionScope.getContributedFunctionsAndConstructors(name, location, scopeTower.syntheticScopes)
.mapTo(result) { createCandidateDescriptor(it, dispatchReceiver = null) }
// Add constructors of deprecated classifier with an additional diagnostic
val descriptorWithDeprecation = resolutionScope.getContributedClassifierIncludeDeprecated(name, location)
if (descriptorWithDeprecation != null && descriptorWithDeprecation.isDeprecated) {
getConstructorsOfClassifier(descriptorWithDeprecation.descriptor).mapTo(result) {
createCandidateDescriptor(
it,
dispatchReceiver = null,
specialError = ResolvedUsingDeprecatedVisbility(resolutionScope, location)
)
}
}
return result
}
override fun recordLookup(name: Name) {
@@ -339,32 +355,41 @@ private fun KotlinType?.getInnerConstructors(name: Name, location: LookupLocatio
private fun ResolutionScope.getContributedFunctionsAndConstructors(
name: Name,
location: LookupLocation,
syntheticScopes: SyntheticScopes,
scope: ResolutionScope
syntheticScopes: SyntheticScopes
): Collection<FunctionDescriptor> {
val result = ArrayList<FunctionDescriptor>(getContributedFunctions(name, location))
val classifier = getContributedClassifier(name, location)
getContributedClassifier(name, location)?.let {
result.addAll(getConstructorsOfClassifier(it))
}
result.addAll(syntheticScopes.collectSyntheticStaticFunctions(this, name, location))
result.addAll(syntheticScopes.collectSyntheticConstructors(this, name, location))
return result.toList()
}
private fun getConstructorsOfClassifier(classifier: ClassifierDescriptor?): List<ConstructorDescriptor> {
val callableConstructors = when (classifier) {
is TypeAliasDescriptor -> if (classifier.canHaveCallableConstructors) classifier.constructors else emptyList()
is ClassDescriptor -> if (classifier.canHaveCallableConstructors) classifier.constructors else emptyList()
else -> emptyList()
}
callableConstructors.filterTo(result) { it.dispatchReceiverParameter == null }
result.addAll(syntheticScopes.collectSyntheticStaticFunctions(scope, name, location))
result.addAll(syntheticScopes.collectSyntheticConstructors(scope, name, location))
return result.toList()
return callableConstructors.filter { it.dispatchReceiverParameter == null }
}
private fun ResolutionScope.getContributedObjectVariables(name: Name, location: LookupLocation): Collection<VariableDescriptor> {
val objectDescriptor = getFakeDescriptorForObject(getContributedClassifier(name, location))
return listOfNotNull(objectDescriptor)
}
private fun ResolutionScope.getContributedObjectVariablesIncludeDeprecated(name: Name, location: LookupLocation): Collection<DescriptorWithDeprecation<VariableDescriptor>> {
val (classifier, isOwnerDeprecated) = getContributedClassifierIncludeDeprecated(name, location) ?: return emptyList()
val objectDescriptor = getFakeDescriptorForObject(classifier) ?: return emptyList()
return listOf(DescriptorWithDeprecation(objectDescriptor, isOwnerDeprecated))
}
fun getFakeDescriptorForObject(classifier: ClassifierDescriptor?): FakeCallableDescriptorForObject? =
when (classifier) {
is TypeAliasDescriptor ->
@@ -0,0 +1,33 @@
/*
* Copyright 2000-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.scopes
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorWithDeprecation
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
class DeprecatedLexicalScope(private val workerScope: LexicalScope) : LexicalScope by workerScope {
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null
override fun getContributedClassifierIncludeDeprecated(
name: Name,
location: LookupLocation
): DescriptorWithDeprecation<ClassifierDescriptor>? {
return workerScope.getContributedClassifier(name, location)?.let { DescriptorWithDeprecation.createDeprecated(it) }
}
}
class DeprecatedMemberScope(private val workerScope: MemberScope) : MemberScope by workerScope {
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null
override fun getContributedClassifierIncludeDeprecated(
name: Name,
location: LookupLocation
): DescriptorWithDeprecation<ClassifierDescriptor>? {
return workerScope.getContributedClassifier(name, location)?.let { DescriptorWithDeprecation.createDeprecated(it) }
}
}
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.resolve.scopes
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorWithDeprecation
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
@@ -24,6 +26,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.takeSnapshot
import org.jetbrains.kotlin.util.collectionUtils.getFirstClassifierDiscriminateHeaders
import org.jetbrains.kotlin.util.collectionUtils.getFromAllScopes
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class LexicalChainedScope @JvmOverloads constructor(
parent: LexicalScope,
@@ -31,6 +34,8 @@ class LexicalChainedScope @JvmOverloads constructor(
override val isOwnerDescriptorAccessibleByLabel: Boolean,
override val implicitReceiver: ReceiverParameterDescriptor?,
override val kind: LexicalScopeKind,
// NB. Here can be very special subtypes of MemberScope (e.g., DeprecatedMemberScope).
// Please, do not leak them outside of LexicalChainedScope, because other parts of compiler are not ready to work with them
private val memberScopes: List<MemberScope>,
@Deprecated("This value is temporary hack for resolve -- don't use it!")
val isStaticScope: Boolean = false
@@ -43,6 +48,22 @@ class LexicalChainedScope @JvmOverloads constructor(
override fun getContributedClassifier(name: Name, location: LookupLocation) =
getFirstClassifierDiscriminateHeaders(memberScopes) { it.getContributedClassifier(name, location) }
override fun getContributedClassifierIncludeDeprecated(name: Name, location: LookupLocation): DescriptorWithDeprecation<ClassifierDescriptor>? {
val (firstClassifier, isFirstDeprecated) = memberScopes.firstNotNullResult {
it.getContributedClassifierIncludeDeprecated(name, location)
} ?: return null
if (!isFirstDeprecated) return DescriptorWithDeprecation.createNonDeprecated(firstClassifier)
// Slow-path: try to find the same classifier, but without deprecation
for (scope in memberScopes) {
val (descriptor, isDeprecated) = scope.getContributedClassifierIncludeDeprecated(name, location) ?: continue
if (descriptor == firstClassifier && !isDeprecated) return DescriptorWithDeprecation.createNonDeprecated(descriptor)
}
return DescriptorWithDeprecation.createDeprecated(firstClassifier)
}
override fun getContributedVariables(name: Name, location: LookupLocation) =
getFromAllScopes(memberScopes) { it.getContributedVariables(name, location) }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class LexicalWritableScope(
parent: LexicalScope,
@@ -74,6 +75,18 @@ class LexicalWritableScope(
override fun getContributedClassifier(name: Name, location: LookupLocation) =
variableOrClassDescriptorByName(name, descriptorLimit) as? ClassifierDescriptor
// NB. This is important to have this explicit override, otherwise calls will be delegated to `this`-delegate,
// which will use default implementation from `ResolutionScope`, which will call `getContributedClassifier` on
// the `LexicalWritableScope` instead of calling it on this snapshot
override fun getContributedClassifierIncludeDeprecated(
name: Name,
location: LookupLocation
): DescriptorWithDeprecation<ClassifierDescriptor>? {
return variableOrClassDescriptorByName(name, descriptorLimit)
?.safeAs<ClassifierDescriptor>()
?.let { DescriptorWithDeprecation.createNonDeprecated(it) }
}
override fun getContributedVariables(name: Name, location: LookupLocation) =
listOfNotNull(variableOrClassDescriptorByName(name, descriptorLimit) as? VariableDescriptor)
@@ -81,6 +81,22 @@ fun LexicalScope.findLocalVariable(name: Name): VariableDescriptor? {
fun HierarchicalScope.findClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? =
findFirstFromMeAndParent { it.getContributedClassifier(name, location) }
fun DeclarationDescriptor.canBeResolvedWithoutDeprecation(
scopeForResolution: HierarchicalScope,
location: LookupLocation
): Boolean {
for (scope in scopeForResolution.parentsWithSelf) {
val (descriptorFromCurrentScope, isDeprecated) = scope.getContributedClassifierIncludeDeprecated(name, location) ?: continue
if (descriptorFromCurrentScope == this && !isDeprecated) return true
}
return false
}
fun HierarchicalScope.findFirstClassifierWithDeprecationStatus(name: Name, location: LookupLocation): DescriptorWithDeprecation<ClassifierDescriptor>? {
return findFirstFromMeAndParent { it.getContributedClassifierIncludeDeprecated(name, location) }
}
fun HierarchicalScope.findPackage(name: Name): PackageViewDescriptor? = findFirstFromImportingScopes { it.getContributedPackage(name) }
fun HierarchicalScope.collectVariables(name: Name, location: LookupLocation): Collection<VariableDescriptor> =