FIR: track KtSuperTypeCallEntry in FirDelegatedConstructorCall

In PSI world, a call to super type constructor is represented by a
KtSuperTypeCallEntry. Currently FIR tracks the callee reference to this
constructor call.

This is undesirable because

1. We may want to report issues on the call arguments, so FIR must track
   the entire call rather than just the callee reference

2. Light tree actually reports the KtSuperTypeCallEntry.

3. Both the FirDelegatedConstructorCall and its `calleeReference` are
   currently referencing the same KtConstructorCalleeExpression PSI
   element as the source.

This change makes FirDelegatedConstructorCall track the entire
KtSuperTypeCallEntry as the source, if possible.
This commit is contained in:
Tianyu Geng
2021-03-10 16:03:02 -08:00
committed by Dmitriy Novozhilov
parent 5243720043
commit 6134c00698
4 changed files with 50 additions and 48 deletions
@@ -386,7 +386,7 @@ object LightTreePositioningStrategies {
when (selector.tokenType) {
KtNodeTypes.REFERENCE_EXPRESSION ->
return markElement(selector, startOffset, endOffset, tree, node)
KtNodeTypes.CALL_EXPRESSION, KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL ->
KtNodeTypes.CALL_EXPRESSION, KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL, KtNodeTypes.SUPER_TYPE_CALL_ENTRY ->
return markElement(tree.referenceExpression(selector) ?: selector, startOffset, endOffset, tree, node)
}
}
@@ -625,11 +625,11 @@ open class RawFirBuilder(
ownerTypeParameters: List<FirTypeParameterRef>,
body: FirBlock? = null
): FirConstructor {
val constructorCallee = superTypeCallEntry?.calleeExpression?.toFirSourceElement()
val constructorCall = superTypeCallEntry?.toFirSourceElement()
val constructorSource = this?.toFirSourceElement()
?: owner.toFirPsiSourceElement(FirFakeSourceElementKind.ImplicitConstructor)
val firDelegatedCall = buildDelegatedConstructorCall {
source = constructorCallee ?: constructorSource.fakeElement(FirFakeSourceElementKind.DelegatingConstructorCall)
source = constructorCall ?: constructorSource.fakeElement(FirFakeSourceElementKind.DelegatingConstructorCall)
constructedTypeRef = delegatedSuperTypeRef.copyWithNewSourceKind(FirFakeSourceElementKind.ImplicitTypeRef)
isThis = false
if (!stubMode) {
@@ -237,51 +237,7 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
}
})
psiSetDirect -= psiSetViaFir
psiSetDirect.removeIf {
it is KtPackageDirective || it is KtImportList || it is KtClassBody ||
it is KtModifierList ||
it is KtUserType || it is KtNullableType || it is KtFunctionType || it is KtFunctionTypeReceiver ||
it is KtQualifiedExpression ||
it is KtPropertyDelegate ||
it is KtConstructorCalleeExpression && it.parent is KtAnnotationEntry ||
it is KtValueArgumentList || it is KtParameterList || it is KtTypeParameterList || it is KtTypeArgumentList ||
it is KtTypeReference && it.parent.parent.parent is KtCallExpression ||
it is KtSuperTypeList || it is KtSuperTypeListEntry ||
it is KtValueArgument || it is KtLambdaArgument || it is KtValueArgumentName ||
it is KtContainerNodeForControlStructureBody || it is KtContainerNode ||
it is KtStringTemplateEntry ||
it is KtOperationReferenceExpression ||
it is KtLabelReferenceExpression ||
it is KtConstructorDelegationReferenceExpression ||
it is KtParenthesizedExpression ||
it is KtLabeledExpression ||
it is KtAnnotatedExpression ||
it is KtWhenConditionWithExpression ||
it is KtFinallySection ||
it is KtObjectLiteralExpression ||
// TODO: KT-24089 (support of dynamic)
it is KtDynamicType ||
// NB: KtAnnotation is processed via its KtAnnotationEntries
it is KtFileAnnotationList || it is KtAnnotationUseSiteTarget || it is KtAnnotation ||
it is KtInitializerList || it is KtEnumEntrySuperclassReferenceExpression ||
it is KtLambdaExpression ||
it is KtTypeConstraintList ||
it is KtTypeConstraint ||
it is KtStringTemplateExpression && it.entries.size <= 1 ||
it is KtDestructuringDeclaration && it.parent is KtParameter ||
it is KtArrayAccessExpression && it.parent is KtBinaryExpression ||
it is KtCallExpression && it.parent is KtQualifiedExpression ||
it is KtNameReferenceExpression &&
(it.parent is KtUserType || it.parent is KtInstanceExpressionWithLabel ||
it.parent is KtValueArgumentName || it.parent is KtTypeConstraint) ||
it.getStrictParentOfType<KtPackageDirective>() != null ||
it.getStrictParentOfType<KtImportDirective>() != null ||
(it is KtPropertyAccessor && !it.hasBody()) ||
it is KtDestructuringDeclarationEntry && it.text == "_" ||
it is KtConstantExpression && it.parent.let { parent ->
parent is KtPrefixExpression && (parent.operationToken == KtTokens.MINUS || parent.operationToken == KtTokens.PLUS)
}
}
psiSetDirect.removeIf(::isKnownToBeNotTraversedByFirTree)
if (psiSetDirect.isNotEmpty()) {
println("Total of $counter files processed successfully")
println("FILE ${file.toRelativeString(root)} has not traversed PSI elements (total of ${psiSetDirect.size})!")
@@ -298,4 +254,49 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
counter++
}
}
private fun isKnownToBeNotTraversedByFirTree(it: KtElement): Boolean {
return it is KtPackageDirective || it is KtImportList || it is KtClassBody ||
it is KtModifierList ||
it is KtUserType || it is KtNullableType || it is KtFunctionType || it is KtFunctionTypeReceiver ||
it is KtQualifiedExpression ||
it is KtPropertyDelegate ||
it is KtConstructorCalleeExpression && (it.parent is KtAnnotationEntry || it.parent is KtSuperTypeCallEntry) ||
it is KtValueArgumentList || it is KtParameterList || it is KtTypeParameterList || it is KtTypeArgumentList ||
it is KtTypeReference && it.parent.parent.parent is KtCallExpression ||
it is KtSuperTypeList || (it is KtSuperTypeListEntry && it !is KtSuperTypeCallEntry) ||
it is KtValueArgument || it is KtLambdaArgument || it is KtValueArgumentName ||
it is KtContainerNodeForControlStructureBody || it is KtContainerNode ||
it is KtStringTemplateEntry ||
it is KtOperationReferenceExpression ||
it is KtLabelReferenceExpression ||
it is KtConstructorDelegationReferenceExpression ||
it is KtParenthesizedExpression ||
it is KtLabeledExpression ||
it is KtAnnotatedExpression ||
it is KtWhenConditionWithExpression ||
it is KtFinallySection ||
it is KtObjectLiteralExpression ||// TODO: KT-24089 (support of dynamic)
it is KtDynamicType ||
// NB: KtAnnotation is processed via its KtAnnotationEntries
it is KtFileAnnotationList || it is KtAnnotationUseSiteTarget || it is KtAnnotation ||
it is KtInitializerList || it is KtEnumEntrySuperclassReferenceExpression ||
it is KtLambdaExpression ||
it is KtTypeConstraintList ||
it is KtTypeConstraint ||
it is KtStringTemplateExpression && it.entries.size <= 1 ||
it is KtDestructuringDeclaration && it.parent is KtParameter ||
it is KtArrayAccessExpression && it.parent is KtBinaryExpression ||
it is KtCallExpression && it.parent is KtQualifiedExpression ||
it is KtNameReferenceExpression &&
(it.parent is KtUserType || it.parent is KtInstanceExpressionWithLabel ||
it.parent is KtValueArgumentName || it.parent is KtTypeConstraint) ||
it.getStrictParentOfType<KtPackageDirective>() != null ||
it.getStrictParentOfType<KtImportDirective>() != null ||
(it is KtPropertyAccessor && !it.hasBody()) ||
it is KtDestructuringDeclarationEntry && it.text == "_" ||
it is KtConstantExpression && it.parent.let { parent ->
parent is KtPrefixExpression && (parent.operationToken == KtTokens.MINUS || parent.operationToken == KtTokens.PLUS)
}
}
}
@@ -755,6 +755,7 @@ object PositioningStrategies {
}
is KtCallExpression -> return mark(element.calleeExpression ?: element)
is KtConstructorDelegationCall -> return mark(element.calleeExpression ?: element)
is KtSuperTypeCallEntry -> return mark(element.calleeExpression)
}
return super.mark(element)
}