Do not use unsafe getClassDescriptor() inside resolveToDescriptor

Introduce getClassDescriptorIfAny / findClassDescriptorIfAny instead
May fix KT-18740 / EA-76201
This commit is contained in:
Mikhail Glukhikh
2017-09-25 16:56:58 +03:00
parent adf0b25c0b
commit 5c0bc266b3
2 changed files with 38 additions and 18 deletions
@@ -57,26 +57,40 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace) this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace)
} }
open fun getClassDescriptorIfAny(classOrObject: KtClassOrObject, location: LookupLocation): ClassDescriptor? =
findClassDescriptorIfAny(classOrObject, location)
open fun getClassDescriptor(classOrObject: KtClassOrObject, location: LookupLocation): ClassDescriptor = open fun getClassDescriptor(classOrObject: KtClassOrObject, location: LookupLocation): ClassDescriptor =
findClassDescriptor(classOrObject, location) findClassDescriptor(classOrObject, location)
fun getScriptDescriptor(script: KtScript, location: LookupLocation): ScriptDescriptor = fun getScriptDescriptor(script: KtScript, location: LookupLocation): ScriptDescriptor =
findClassDescriptor(script, location) as ScriptDescriptor findClassDescriptor(script, location) as ScriptDescriptor
private fun findClassDescriptor( private fun findClassDescriptorIfAny(
classObjectOrScript: KtNamedDeclaration, classObjectOrScript: KtNamedDeclaration,
location: LookupLocation location: LookupLocation
): ClassDescriptor { ): ClassDescriptor? {
val scope = getMemberScopeDeclaredIn(classObjectOrScript, location) val scope = getMemberScopeDeclaredIn(classObjectOrScript, location)
// Why not use the result here. Because it may be that there is a redeclaration: // Why not use the result here. Because it may be that there is a redeclaration:
// class A {} class A { fun foo(): A<completion here>} // class A {} class A { fun foo(): A<completion here>}
// and if we find the class by name only, we may b-not get the right one. // and if we find the class by name only, we may b-not get the right one.
// This call is only needed to make sure the classes are written to trace // This call is only needed to make sure the classes are written to trace
val scopeDescriptor = scope.getContributedClassifier(classObjectOrScript.nameAsSafeName, location) scope.getContributedClassifier(classObjectOrScript.nameAsSafeName, location)
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObjectOrScript) val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObjectOrScript)
if (descriptor !is ClassDescriptor) { return descriptor as? ClassDescriptor
}
private fun findClassDescriptor(
classObjectOrScript: KtNamedDeclaration,
location: LookupLocation
): ClassDescriptor {
val descriptor = findClassDescriptorIfAny(classObjectOrScript, location)
if (descriptor == null) {
val scope = getMemberScopeDeclaredIn(classObjectOrScript, location)
val scopeDescriptor = scope.getContributedClassifier(classObjectOrScript.nameAsSafeName, location)
var providerInfoString: String? = null var providerInfoString: String? = null
if (scope is AbstractLazyMemberScope<*, *>) { if (scope is AbstractLazyMemberScope<*, *>) {
@@ -101,23 +115,23 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
} }
fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor = fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor =
resolveToDescriptor(declaration, /*track =*/true) resolveToDescriptor(declaration, /*track =*/true) ?: absentDescriptorHandler.diagnoseDescriptorNotFound(declaration)
private fun resolveToDescriptor(declaration: KtDeclaration, track: Boolean): DeclarationDescriptor { private fun resolveToDescriptor(declaration: KtDeclaration, track: Boolean): DeclarationDescriptor? {
return declaration.accept(object : KtVisitor<DeclarationDescriptor?, Nothing?>() { return declaration.accept(object : KtVisitor<DeclarationDescriptor?, Nothing?>() {
private fun lookupLocationFor(declaration: KtDeclaration, isTopLevel: Boolean): LookupLocation = private fun lookupLocationFor(declaration: KtDeclaration, isTopLevel: Boolean): LookupLocation =
if (isTopLevel && track) KotlinLookupLocation(declaration) if (isTopLevel && track) KotlinLookupLocation(declaration)
else NoLookupLocation.WHEN_RESOLVE_DECLARATION else NoLookupLocation.WHEN_RESOLVE_DECLARATION
override fun visitClass(klass: KtClass, data: Nothing?): DeclarationDescriptor = override fun visitClass(klass: KtClass, data: Nothing?): DeclarationDescriptor? =
getClassDescriptor(klass, lookupLocationFor(klass, klass.isTopLevel())) getClassDescriptorIfAny(klass, lookupLocationFor(klass, klass.isTopLevel()))
override fun visitObjectDeclaration(declaration: KtObjectDeclaration, data: Nothing?): DeclarationDescriptor = override fun visitObjectDeclaration(declaration: KtObjectDeclaration, data: Nothing?): DeclarationDescriptor? =
getClassDescriptor(declaration, lookupLocationFor(declaration, declaration.isTopLevel())) getClassDescriptorIfAny(declaration, lookupLocationFor(declaration, declaration.isTopLevel()))
override fun visitTypeParameter(parameter: KtTypeParameter, data: Nothing?): DeclarationDescriptor { override fun visitTypeParameter(parameter: KtTypeParameter, data: Nothing?): DeclarationDescriptor? {
val ownerElement = PsiTreeUtil.getParentOfType(parameter, KtTypeParameterListOwner::class.java) ?: error("Owner not found for type parameter: " + parameter.text) val ownerElement = PsiTreeUtil.getParentOfType(parameter, KtTypeParameterListOwner::class.java) ?: error("Owner not found for type parameter: " + parameter.text)
val ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false) val ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false) ?: return null
val typeParameters: List<TypeParameterDescriptor> val typeParameters: List<TypeParameterDescriptor>
typeParameters = when (ownerDescriptor) { typeParameters = when (ownerDescriptor) {
@@ -144,8 +158,9 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
is KtPrimaryConstructor -> { is KtPrimaryConstructor -> {
val jetClass = grandFather.getContainingClassOrObject() val jetClass = grandFather.getContainingClassOrObject()
// This is a primary constructor parameter // This is a primary constructor parameter
val classDescriptor = getClassDescriptor(jetClass, lookupLocationFor(jetClass, false)) val classDescriptor = getClassDescriptorIfAny(jetClass, lookupLocationFor(jetClass, false))
return when { return when {
classDescriptor == null -> null
parameter.hasValOrVar() -> { parameter.hasValOrVar() -> {
classDescriptor.defaultType.memberScope.getContributedVariables( classDescriptor.defaultType.memberScope.getContributedVariables(
parameter.nameAsSafeName, lookupLocationFor(parameter, false)) parameter.nameAsSafeName, lookupLocationFor(parameter, false))
@@ -177,12 +192,12 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
} }
override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor, data: Nothing?): DeclarationDescriptor? { override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor, data: Nothing?): DeclarationDescriptor? {
getClassDescriptor(constructor.parent.parent as KtClassOrObject, lookupLocationFor(constructor, false)).constructors getClassDescriptorIfAny(constructor.parent.parent as KtClassOrObject, lookupLocationFor(constructor, false))?.constructors
return bindingContext.get(BindingContext.CONSTRUCTOR, constructor) return bindingContext.get(BindingContext.CONSTRUCTOR, constructor)
} }
override fun visitPrimaryConstructor(constructor: KtPrimaryConstructor, data: Nothing?): DeclarationDescriptor? { override fun visitPrimaryConstructor(constructor: KtPrimaryConstructor, data: Nothing?): DeclarationDescriptor? {
getClassDescriptor(constructor.getContainingClassOrObject(), lookupLocationFor(constructor, false)).constructors getClassDescriptorIfAny(constructor.getContainingClassOrObject(), lookupLocationFor(constructor, false))?.constructors
return bindingContext.get(BindingContext.CONSTRUCTOR, constructor) return bindingContext.get(BindingContext.CONSTRUCTOR, constructor)
} }
@@ -217,7 +232,7 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
throw IllegalArgumentException("Unsupported declaration type: " + element + " " + throw IllegalArgumentException("Unsupported declaration type: " + element + " " +
element.getElementTextWithContext()) element.getElementTextWithContext())
} }
}, null) ?: absentDescriptorHandler.diagnoseDescriptorNotFound(declaration) }, null)
} }
internal fun getMemberScopeDeclaredIn(declaration: KtDeclaration, location: LookupLocation): internal fun getMemberScopeDeclaredIn(declaration: KtDeclaration, location: LookupLocation):
@@ -18,10 +18,8 @@ package org.jetbrains.kotlin.types.expressions
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.TargetPlatformVersion import org.jetbrains.kotlin.config.TargetPlatformVersion
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.GlobalContext import org.jetbrains.kotlin.context.GlobalContext
import org.jetbrains.kotlin.context.withModule import org.jetbrains.kotlin.context.withModule
@@ -200,6 +198,13 @@ class LocalLazyDeclarationResolver(
} }
return super.getClassDescriptor(classOrObject, location) return super.getClassDescriptor(classOrObject, location)
} }
override fun getClassDescriptorIfAny(classOrObject: KtClassOrObject, location: LookupLocation): ClassDescriptor? {
if (localClassDescriptorManager.isMyClass(classOrObject)) {
return localClassDescriptorManager.getClassDescriptor(classOrObject, scopeProvider)
}
return super.getClassDescriptorIfAny(classOrObject, location)
}
} }