[compiler] preserve fir receiver in tree

when selector is invalid expression,
ensure that fir tree still contains receiver as well as selector

KTIJ-23578
This commit is contained in:
Anna Kozlova
2022-11-21 15:34:41 +01:00
committed by Space Team
parent 1aae9d6456
commit 3fdd0aacd3
17 changed files with 243 additions and 2 deletions
@@ -0,0 +1,6 @@
fun main(args: Array<String>) {
val anyClass = Any()
funOne(<expr>anyClass</expr>.class)
}
fun funOne(x: Any): Unit {}
@@ -0,0 +1,6 @@
KT element: KtNameReferenceExpression
FIR element: FirPropertyAccessExpressionImpl
FIR source kind: KtRealSourceElementKind
FIR element rendered:
R|<local>/anyClass|
@@ -540,6 +540,22 @@ public class GetOrBuildFirTestGenerated extends AbstractGetOrBuildFirTest {
}
}
@Nested
@TestMetadata("analysis/low-level-api-fir/testdata/getOrBuildFir/invalidCode")
@TestDataPath("$PROJECT_ROOT")
public class InvalidCode {
@Test
public void testAllFilesPresentInInvalidCode() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/low-level-api-fir/testdata/getOrBuildFir/invalidCode"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("javaClassLiteral.kt")
public void testJavaClassLiteral() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/invalidCode/javaClassLiteral.kt");
}
}
@Nested
@TestMetadata("analysis/low-level-api-fir/testdata/getOrBuildFir/qualifiedExpressions")
@TestDataPath("$PROJECT_ROOT")
@@ -557,6 +557,18 @@ class ExpressionsConverter(
result = convertFirSelector(it, dotQualifiedExpression.toFirSourceElement(), firReceiver!!) as? FirExpression
}
val receiver = firReceiver
if (receiver != null) {
(firSelector as? FirErrorExpression)?.let { errorExpression ->
return buildQualifiedErrorAccessExpression {
this.receiver = receiver
this.selector = errorExpression
source = dotQualifiedExpression.toFirSourceElement()
diagnostic = ConeSimpleDiagnostic("Qualified expression with unexpected selector", DiagnosticKind.Syntax)
}
}
}
return result ?: buildErrorExpression {
source = null
diagnostic = ConeSimpleDiagnostic("Qualified expression without selector", DiagnosticKind.Syntax)
@@ -2462,6 +2462,14 @@ open class RawFirBuilder(
return convertFirSelector(firSelector, expression.toFirSourceElement(), receiver)
}
if (firSelector is FirErrorExpression) {
return buildQualifiedErrorAccessExpression {
this.receiver = receiver
this.selector = firSelector
source = expression.toFirSourceElement()
diagnostic = ConeSimpleDiagnostic("Qualified expression with unexpected selector", DiagnosticKind.Syntax)
}
}
return firSelector
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.fir.expressions
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.*
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
abstract class FirQualifiedErrorAccessExpression : FirExpression(), FirDiagnosticHolder {
abstract override val source: KtSourceElement?
abstract override val typeRef: FirTypeRef
abstract override val annotations: List<FirAnnotation>
abstract override val diagnostic: ConeDiagnostic
abstract val selector: FirErrorExpression
abstract val receiver: FirExpression
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitQualifiedErrorAccessExpression(this, data)
@Suppress("UNCHECKED_CAST")
override fun <E: FirElement, D> transform(transformer: FirTransformer<D>, data: D): E =
transformer.transformQualifiedErrorAccessExpression(this, data) as E
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirQualifiedErrorAccessExpression
}
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("DuplicatedCode")
package org.jetbrains.kotlin.fir.expressions.builder
import kotlin.contracts.*
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedErrorAccessExpression
import org.jetbrains.kotlin.fir.expressions.builder.FirExpressionBuilder
import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedErrorAccessExpressionImpl
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.*
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
@FirBuilderDsl
class FirQualifiedErrorAccessExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBuilder {
override var source: KtSourceElement? = null
override val annotations: MutableList<FirAnnotation> = mutableListOf()
lateinit var diagnostic: ConeDiagnostic
lateinit var selector: FirErrorExpression
lateinit var receiver: FirExpression
override fun build(): FirQualifiedErrorAccessExpression {
return FirQualifiedErrorAccessExpressionImpl(
source,
annotations,
diagnostic,
selector,
receiver,
)
}
@Deprecated("Modification of 'typeRef' has no impact for FirQualifiedErrorAccessExpressionBuilder", level = DeprecationLevel.HIDDEN)
override var typeRef: FirTypeRef
get() = throw IllegalStateException()
set(_) {
throw IllegalStateException()
}
}
@OptIn(ExperimentalContracts::class)
inline fun buildQualifiedErrorAccessExpression(init: FirQualifiedErrorAccessExpressionBuilder.() -> Unit): FirQualifiedErrorAccessExpression {
contract {
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
}
return FirQualifiedErrorAccessExpressionBuilder().apply(init).build()
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("DuplicatedCode")
package org.jetbrains.kotlin.fir.expressions.impl
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedErrorAccessExpression
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.*
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
internal class FirQualifiedErrorAccessExpressionImpl(
override val source: KtSourceElement?,
override val annotations: MutableList<FirAnnotation>,
override val diagnostic: ConeDiagnostic,
override var selector: FirErrorExpression,
override var receiver: FirExpression,
) : FirQualifiedErrorAccessExpression() {
override var typeRef: FirTypeRef = FirErrorTypeRefImpl(source, null, ConeStubDiagnostic(diagnostic), false)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
typeRef.accept(visitor, data)
annotations.forEach { it.accept(visitor, data) }
selector.accept(visitor, data)
receiver.accept(visitor, data)
}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirQualifiedErrorAccessExpressionImpl {
typeRef = typeRef.transform(transformer, data)
transformAnnotations(transformer, data)
selector = selector.transform(transformer, data)
receiver = receiver.transform(transformer, data)
return this
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirQualifiedErrorAccessExpressionImpl {
annotations.transformInplace(transformer, data)
return this
}
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
typeRef = newTypeRef
}
}
@@ -93,6 +93,7 @@ import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorProperty
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedErrorAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall
@@ -93,6 +93,7 @@ import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorProperty
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedErrorAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall
@@ -93,6 +93,7 @@ import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorProperty
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedErrorAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall
@@ -500,6 +501,10 @@ abstract class FirTransformer<in D> : FirVisitor<FirElement, D>() {
return transformElement(qualifiedAccessExpression, data)
}
open fun transformQualifiedErrorAccessExpression(qualifiedErrorAccessExpression: FirQualifiedErrorAccessExpression, data: D): FirStatement {
return transformElement(qualifiedErrorAccessExpression, data)
}
open fun transformPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: D): FirStatement {
return transformElement(propertyAccessExpression, data)
}
@@ -1048,6 +1053,10 @@ abstract class FirTransformer<in D> : FirVisitor<FirElement, D>() {
return transformQualifiedAccessExpression(qualifiedAccessExpression, data)
}
final override fun visitQualifiedErrorAccessExpression(qualifiedErrorAccessExpression: FirQualifiedErrorAccessExpression, data: D): FirStatement {
return transformQualifiedErrorAccessExpression(qualifiedErrorAccessExpression, data)
}
final override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: D): FirStatement {
return transformPropertyAccessExpression(propertyAccessExpression, data)
}
@@ -93,6 +93,7 @@ import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorProperty
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedErrorAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall
@@ -325,6 +326,8 @@ abstract class FirVisitor<out R, in D> {
open fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: D): R = visitElement(qualifiedAccessExpression, data)
open fun visitQualifiedErrorAccessExpression(qualifiedErrorAccessExpression: FirQualifiedErrorAccessExpression, data: D): R = visitElement(qualifiedErrorAccessExpression, data)
open fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: D): R = visitElement(propertyAccessExpression, data)
open fun visitFunctionCall(functionCall: FirFunctionCall, data: D): R = visitElement(functionCall, data)
@@ -93,6 +93,7 @@ import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.declarations.FirErrorProperty
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedErrorAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirIntegerLiteralOperatorCall
@@ -499,6 +500,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitElement(qualifiedAccessExpression)
}
open fun visitQualifiedErrorAccessExpression(qualifiedErrorAccessExpression: FirQualifiedErrorAccessExpression) {
visitElement(qualifiedErrorAccessExpression)
}
open fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
visitElement(propertyAccessExpression)
}
@@ -1047,6 +1052,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitQualifiedAccessExpression(qualifiedAccessExpression)
}
final override fun visitQualifiedErrorAccessExpression(qualifiedErrorAccessExpression: FirQualifiedErrorAccessExpression, data: Nothing?) {
visitQualifiedErrorAccessExpression(qualifiedErrorAccessExpression)
}
final override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: Nothing?) {
visitPropertyAccessExpression(propertyAccessExpression)
}
@@ -116,6 +116,7 @@ object FirTreeBuilder : AbstractFirTreeBuilder() {
val errorFunction by element(Declaration, function, diagnosticHolder)
val errorProperty by element(Declaration, variable, diagnosticHolder)
val qualifiedAccessExpression by element(Expression, expression, qualifiedAccess)
val qualifiedErrorAccessExpression by element(Expression, expression, diagnosticHolder)
val propertyAccessExpression by element(Expression, qualifiedAccessExpression)
val functionCall by element(Expression, qualifiedAccessExpression, call)
val integerLiteralOperatorCall by element(Expression, functionCall)
@@ -433,6 +433,11 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
useTypes(errorTypeRefImplType, coneStubDiagnosticType)
}
impl(qualifiedErrorAccessExpression) {
default("typeRef", "FirErrorTypeRefImpl(source, null, ConeStubDiagnostic(diagnostic), false)")
useTypes(errorTypeRefImplType, coneStubDiagnosticType)
}
impl(errorFunction) {
defaultNull("receiverParameter", "body", withGetter = true)
default("returnTypeRef", "FirErrorTypeRefImpl(null, null, diagnostic, false)")
@@ -207,6 +207,11 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+fieldList("nonFatalDiagnostics", coneDiagnosticType)
}
qualifiedErrorAccessExpression.configure {
+field("selector", errorExpression)
+field("receiver", expression)
}
constExpression.configure {
withArg("T")
+field("kind", constKindType.withArgs("T"), withReplace = true)
@@ -3,6 +3,6 @@
fun test() {
"a".<!ILLEGAL_SELECTOR!>"b"<!>::<!UNRESOLVED_REFERENCE!>foo<!>
"a".<!ILLEGAL_SELECTOR!>"b"<!>::class
"a"."b".<!ILLEGAL_SELECTOR!>"c"<!>::<!UNRESOLVED_REFERENCE!>foo<!>
"a"."b".<!ILLEGAL_SELECTOR!>"c"<!>::class
"a".<!ILLEGAL_SELECTOR!>"b"<!>.<!ILLEGAL_SELECTOR!>"c"<!>::<!UNRESOLVED_REFERENCE!>foo<!>
"a".<!ILLEGAL_SELECTOR!>"b"<!>.<!ILLEGAL_SELECTOR!>"c"<!>::class
}