[FIR] Check the presence of delegated constructor call via stubs

After `4b8b7aaa` external classes' secondary
constructors should not have a delegated call, so we
don't create a call if there's no explicit call.
But we need to check if there is.

The failing tests were muted in
`8fcf91d8`, and are now unmuted
back. Those are the ones in the
`testData/rawBuilder/declarations`
folder. These tests fail because they supply
PSI stubs for the secondary constructors,
so arbitrary operations (like reading .text of
the delegated constructor call) are not allowed
for them. This commit modifies secondary
constructor stubs to include the
required information.

^KT-65268 Fixed


Merge-request: KT-MR-13982
Merged-by: Nikolay Lunyak <Nikolay.Lunyak@jetbrains.com>
This commit is contained in:
Nikolay Lunyak
2024-02-02 08:15:54 +00:00
committed by Space Team
parent 77dba281a3
commit 9688865953
103 changed files with 253 additions and 270 deletions
@@ -2006,14 +2006,12 @@ open class PsiRawFirBuilder(
}
dispatchReceiverType = owner.obtainDispatchReceiverForConstructor()
contextReceivers.addAll(convertContextReceivers(owner.contextReceivers))
val delegationCall = getDelegationCall()
val hasExplicitDelegationCall = delegationCall.textLength > 0
if (!owner.hasModifier(EXTERNAL_KEYWORD) || hasExplicitDelegationCall) {
if (!owner.hasModifier(EXTERNAL_KEYWORD) || isExplicitDelegationCall()) {
delegatedConstructor = buildOrLazyDelegatedConstructorCall(
isThis = isDelegatedCallToThis(),
constructedTypeRef = delegatedTypeRef,
) {
delegationCall.convert(delegatedTypeRef)
getDelegationCall().convert(delegatedTypeRef)
}
}
this@PsiRawFirBuilder.context.firFunctionTargets += target
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.PROPERTY,
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
open class A(init: A.() -> Unit) {
val prop: String = ""
}
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
object A {
constructor()
init {}
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
class A {
constructor(param: @Anno("parameter type $prop") List<@Anno("nested parameter type $prop") Collection<@Anno("nested nested parameter type $prop") String>> = @Anno("defaultValue $prop") fun(i: @Anno("anonymousFunction parameter type $prop") Int): @Anno("anonymousFunction return type $prop") Int {})
}
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
package util
class A {
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
class C {
constructor(x) {}
}
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
class NoPrimary {
val x: String
@@ -1,4 +1,3 @@
// IGNORE_TREE_ACCESS: KT-65268
package util
@Target(AnnotationTarget.TYPE)
@@ -64,6 +64,15 @@ abstract class KtConstructor<T : KtConstructor<T>> : KtDeclarationStub<KotlinCon
}
}
fun isExplicitDelegationCall(): Boolean {
stub?.let { return it.isExplicitDelegationCall() }
return when (this) {
is KtPrimaryConstructor -> false
is KtSecondaryConstructor -> getDelegationCallOrNull()?.isImplicit == false
else -> throw IllegalStateException("Unknown constructor type: $this")
}
}
override fun hasBody(): Boolean {
stub?.let { return it.hasBody() }
return bodyExpression != null
@@ -12,12 +12,12 @@ object KotlinStubVersions {
// Though only kotlin declarations (no code in the bodies) are stubbed, please do increase this version
// if you are not 100% sure it can be avoided.
// Increasing this version will lead to reindexing of all kotlin source files on the first IDE startup with the new version.
const val SOURCE_STUB_VERSION = 158
const val SOURCE_STUB_VERSION = 159
// Binary stub version should be increased if stub format (org.jetbrains.kotlin.psi.stubs.impl) is changed
// or changes are made to the core stub building code (org.jetbrains.kotlin.idea.decompiler.stubBuilder).
// Increasing this version will lead to reindexing of all binary files that are potentially kotlin binaries (including all class files).
private const val BINARY_STUB_VERSION = 96
private const val BINARY_STUB_VERSION = 97
// Classfile stub version should be increased if changes are made to classfile stub building subsystem (org.jetbrains.kotlin.idea.decompiler.classFile)
// Increasing this version will lead to reindexing of all classfiles.
@@ -91,6 +91,7 @@ interface KotlinConstructorStub<T : KtConstructor<T>> :
KotlinCallableStubBase<T> {
fun hasBody(): Boolean
fun isDelegatedCallToThis(): Boolean
fun isExplicitDelegationCall(): Boolean
}
interface KotlinImportAliasStub : StubElement<KtImportAlias> {
@@ -12,7 +12,6 @@ import com.intellij.util.io.StringRef
import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.stubs.KotlinConstructorStub
import org.jetbrains.kotlin.psi.stubs.elements.StubIndexService.Companion.getInstance
import java.io.IOException
abstract class KtConstructorElementType<T : KtConstructor<T>>(
@@ -25,14 +24,18 @@ abstract class KtConstructorElementType<T : KtConstructor<T>>(
nameRef: StringRef?,
hasBody: Boolean,
isDelegatedCallToThis: Boolean,
isExplicitDelegationCall: Boolean,
): KotlinConstructorStub<T>
protected abstract fun isDelegatedCallToThis(constructor: T): Boolean
protected abstract fun isExplicitDelegationCall(constructor: T): Boolean
override fun createStub(psi: T, parentStub: StubElement<*>): KotlinConstructorStub<T> {
val hasBody = psi.hasBody()
val isDelegatedCallToThis = isDelegatedCallToThis(psi)
return newStub(parentStub, StringRef.fromString(psi.name), hasBody, isDelegatedCallToThis)
val isExplicitDelegationCall = isExplicitDelegationCall(psi)
return newStub(parentStub, StringRef.fromString(psi.name), hasBody, isDelegatedCallToThis, isExplicitDelegationCall)
}
@Throws(IOException::class)
@@ -40,6 +43,7 @@ abstract class KtConstructorElementType<T : KtConstructor<T>>(
dataStream.writeName(stub.name)
dataStream.writeBoolean(stub.hasBody())
dataStream.writeBoolean(stub.isDelegatedCallToThis())
dataStream.writeBoolean(stub.isExplicitDelegationCall())
}
@Throws(IOException::class)
@@ -47,7 +51,8 @@ abstract class KtConstructorElementType<T : KtConstructor<T>>(
val name = dataStream.readName()
val hasBody = dataStream.readBoolean()
val isDelegatedCallToThis = dataStream.readBoolean()
return newStub(parentStub, name, hasBody, isDelegatedCallToThis)
val isExplicitDelegationCall = dataStream.readBoolean()
return newStub(parentStub, name, hasBody, isDelegatedCallToThis, isExplicitDelegationCall)
}
override fun indexStub(stub: KotlinConstructorStub<T>, sink: IndexSink) {
@@ -17,11 +17,14 @@ class KtPrimaryConstructorElementType(debugName: String) :
nameRef: StringRef?,
hasBody: Boolean,
isDelegatedCallToThis: Boolean,
isExplicitDelegationCall: Boolean,
): KotlinConstructorStub<KtPrimaryConstructor> {
return KotlinConstructorStubImpl(
parentStub, KtStubElementTypes.PRIMARY_CONSTRUCTOR, nameRef, hasBody, isDelegatedCallToThis
parentStub, KtStubElementTypes.PRIMARY_CONSTRUCTOR, nameRef, hasBody, isDelegatedCallToThis, isExplicitDelegationCall
)
}
override fun isDelegatedCallToThis(constructor: KtPrimaryConstructor) = false
override fun isExplicitDelegationCall(constructor: KtPrimaryConstructor) = false
}
@@ -17,11 +17,14 @@ class KtSecondaryConstructorElementType(debugName: String) :
nameRef: StringRef?,
hasBody: Boolean,
isDelegatedCallToThis: Boolean,
isExplicitDelegationCall: Boolean,
): KotlinConstructorStub<KtSecondaryConstructor> {
return KotlinConstructorStubImpl(
parentStub, KtStubElementTypes.SECONDARY_CONSTRUCTOR, nameRef, hasBody, isDelegatedCallToThis
parentStub, KtStubElementTypes.SECONDARY_CONSTRUCTOR, nameRef, hasBody, isDelegatedCallToThis, isExplicitDelegationCall
)
}
override fun isDelegatedCallToThis(constructor: KtSecondaryConstructor) = constructor.getDelegationCallOrNull()?.isCallToThis ?: true
override fun isExplicitDelegationCall(constructor: KtSecondaryConstructor) = constructor.getDelegationCallOrNull()?.isImplicit == false
}
@@ -18,6 +18,7 @@ class KotlinConstructorStubImpl<T : KtConstructor<T>>(
private val containingClassName: StringRef?,
private val hasBody: Boolean,
private val isDelegatedCallToThis: Boolean,
private val isExplicitDelegationCall: Boolean,
) : KotlinStubBaseImpl<T>(parent, elementType), KotlinConstructorStub<T> {
override fun getFqName() = null
override fun getName() = StringRef.toString(containingClassName)
@@ -25,4 +26,5 @@ class KotlinConstructorStubImpl<T : KtConstructor<T>>(
override fun isExtension() = false
override fun hasBody() = hasBody
override fun isDelegatedCallToThis() = isDelegatedCallToThis
override fun isExplicitDelegationCall() = isExplicitDelegationCall
}