[Low Level FIR] fix exception when creating symbol by invalid code

This commit is contained in:
Ilya Kirillov
2022-10-02 13:07:20 +02:00
committed by teamcity
parent 24bf273b93
commit 49f2f85927
29 changed files with 553 additions and 39 deletions
@@ -202,51 +202,59 @@ open class RawFirBuilder(
// Here we accept lambda as receiver to prevent expression calculation in stub mode
private fun (() -> KtExpression?).toFirExpression(errorReason: String): FirExpression =
with(this()) {
convertSafe() ?: buildErrorExpression(
this?.toFirSourceElement(), ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected),
)
}
this().toFirExpression(errorReason)
private fun KtElement?.toFirExpression(
errorReason: String,
kind: DiagnosticKind = DiagnosticKind.ExpressionExpected
): FirExpression {
val result = this.convertSafe<FirExpression>()
if (this == null) {
return buildErrorExpression(source = null, ConeSimpleDiagnostic(errorReason, kind))
}
if (result != null) {
if (this == null) {
return result
}
val callExpressionCallee = (this as? KtCallExpression)?.calleeExpression?.unwrapParenthesesLabelsAndAnnotations()
if (this is KtNameReferenceExpression ||
this is KtConstantExpression ||
(this is KtCallExpression && callExpressionCallee !is KtLambdaExpression) ||
getQualifiedExpressionForSelector() == null
) {
return result
}
return buildErrorExpression {
source = callExpressionCallee?.toFirSourceElement() ?: toFirSourceElement()
diagnostic =
ConeSimpleDiagnostic(
"The expression cannot be a selector (occur after a dot)",
if (callExpressionCallee == null) DiagnosticKind.IllegalSelector else DiagnosticKind.NoReceiverAllowed
)
expression = result
val result = when (val fir = convertElement(this)) {
is FirExpression -> fir
else -> {
return buildErrorExpression {
nonExpressionElement = fir
diagnostic = ConeSimpleDiagnostic(errorReason, kind)
source = toFirSourceElement()
}
}
}
return buildErrorExpression(
this?.toFirSourceElement(), ConeSimpleDiagnostic(errorReason, kind),
)
val callExpressionCallee = (this as? KtCallExpression)?.calleeExpression?.unwrapParenthesesLabelsAndAnnotations()
if (this is KtNameReferenceExpression ||
this is KtConstantExpression ||
(this is KtCallExpression && callExpressionCallee !is KtLambdaExpression) ||
getQualifiedExpressionForSelector() == null
) {
return result
}
return buildErrorExpression {
source = callExpressionCallee?.toFirSourceElement() ?: toFirSourceElement()
diagnostic =
ConeSimpleDiagnostic(
"The expression cannot be a selector (occur after a dot)",
if (callExpressionCallee == null) DiagnosticKind.IllegalSelector else DiagnosticKind.NoReceiverAllowed
)
expression = result
}
}
private inline fun KtExpression.toFirStatement(errorReasonLazy: () -> String): FirStatement =
convertSafe() ?: buildErrorExpression(this.toFirSourceElement(), ConeSimpleDiagnostic(errorReasonLazy(), DiagnosticKind.Syntax))
private inline fun KtExpression.toFirStatement(errorReasonLazy: () -> String): FirStatement {
return when (val fir = convertElement(this)) {
is FirStatement -> fir
else -> buildErrorExpression {
nonExpressionElement = fir
diagnostic = ConeSimpleDiagnostic(errorReasonLazy(), DiagnosticKind.Syntax)
source = toFirSourceElement()
}
}
}
private fun KtExpression.toFirStatement(): FirStatement =
convert()
@@ -23,6 +23,7 @@ abstract class FirErrorExpression : FirExpression(), FirDiagnosticHolder {
abstract override val annotations: List<FirAnnotation>
abstract override val diagnostic: ConeDiagnostic
abstract val expression: FirExpression?
abstract val nonExpressionElement: FirElement?
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitErrorExpression(this, data)
@@ -9,6 +9,7 @@ package org.jetbrains.kotlin.fir.expressions.builder
import kotlin.contracts.*
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
@@ -33,6 +34,7 @@ class FirErrorExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBu
override val annotations: MutableList<FirAnnotation> = mutableListOf()
lateinit var diagnostic: ConeDiagnostic
var expression: FirExpression? = null
var nonExpressionElement: FirElement? = null
override fun build(): FirErrorExpression {
return FirErrorExpressionImpl(
@@ -40,6 +42,7 @@ class FirErrorExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBu
annotations,
diagnostic,
expression,
nonExpressionElement,
)
}
@@ -8,6 +8,7 @@
package org.jetbrains.kotlin.fir.expressions.impl
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
@@ -27,6 +28,7 @@ internal class FirErrorExpressionImpl(
override val annotations: MutableList<FirAnnotation>,
override val diagnostic: ConeDiagnostic,
override var expression: FirExpression?,
override var nonExpressionElement: FirElement?,
) : FirErrorExpression() {
override var typeRef: FirTypeRef = FirErrorTypeRefImpl(source, null, ConeStubDiagnostic(diagnostic), false)
@@ -34,12 +36,14 @@ internal class FirErrorExpressionImpl(
typeRef.accept(visitor, data)
annotations.forEach { it.accept(visitor, data) }
expression?.accept(visitor, data)
nonExpressionElement?.accept(visitor, data)
}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirErrorExpressionImpl {
typeRef = typeRef.transform(transformer, data)
transformAnnotations(transformer, data)
expression = expression?.transform(transformer, data)
nonExpressionElement = nonExpressionElement?.transform(transformer, data)
return this
}
@@ -30,7 +30,7 @@ internal class FirErrorLoopImpl(
override val diagnostic: ConeDiagnostic,
) : FirErrorLoop() {
override var block: FirBlock = FirEmptyExpressionBlock()
override var condition: FirExpression = FirErrorExpressionImpl(source, mutableListOf(), ConeStubDiagnostic(diagnostic), null)
override var condition: FirExpression = FirErrorExpressionImpl(source, mutableListOf(), ConeStubDiagnostic(diagnostic), null, null)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
annotations.forEach { it.accept(visitor, data) }
@@ -0,0 +1,28 @@
/*
* 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.renderer
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
abstract class FirErrorExpressionRenderer {
internal lateinit var components: FirRendererComponents
protected val printer get() = components.printer
abstract fun renderErrorExpression(errorExpression: FirErrorExpression)
}
class FirErrorExpressionOnlyErrorRenderer : FirErrorExpressionRenderer() {
override fun renderErrorExpression(errorExpression: FirErrorExpression) {
printer.print("ERROR_EXPR(${errorExpression.diagnostic.reason})")
}
}
class FirErrorExpressionExtendedRenderer : FirErrorExpressionRenderer() {
override fun renderErrorExpression(errorExpression: FirErrorExpression) {
printer.print("ERROR_EXPR(${errorExpression.diagnostic.reason})")
errorExpression.nonExpressionElement?.accept(components.visitor)
}
}
@@ -41,6 +41,7 @@ class FirRenderer(
override val resolvePhaseRenderer: FirResolvePhaseRenderer? = null,
override val typeRenderer: ConeTypeRenderer = ConeTypeRendererForDebugging(),
override val valueParameterRenderer: FirValueParameterRenderer = FirValueParameterRenderer(),
override val errorExpressionRenderer: FirErrorExpressionRenderer = FirErrorExpressionOnlyErrorRenderer(),
) : FirRendererComponents {
override val visitor = Visitor()
@@ -75,6 +76,7 @@ class FirRenderer(
typeRenderer.builder = builder
typeRenderer.idRenderer = idRenderer
valueParameterRenderer.components = this
errorExpressionRenderer.components = this
}
fun renderElementAsString(element: FirElement): String {
@@ -1000,7 +1002,7 @@ class FirRenderer(
}
override fun visitErrorExpression(errorExpression: FirErrorExpression) {
print("ERROR_EXPR(${errorExpression.diagnostic.reason})")
errorExpressionRenderer.renderErrorExpression(errorExpression)
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier) {
@@ -23,4 +23,5 @@ internal interface FirRendererComponents {
val resolvePhaseRenderer: FirResolvePhaseRenderer?
val typeRenderer: ConeTypeRenderer
val valueParameterRenderer: FirValueParameterRenderer
val errorExpressionRenderer: FirErrorExpressionRenderer
}
@@ -159,7 +159,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(errorLoop) {
default("block", "FirEmptyExpressionBlock()")
default("condition", "FirErrorExpressionImpl(source, mutableListOf(), ConeStubDiagnostic(diagnostic), null)")
default("condition", "FirErrorExpressionImpl(source, mutableListOf(), ConeStubDiagnostic(diagnostic), null, null)")
useTypes(emptyExpressionBlock, coneStubDiagnosticType)
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.tree.generator.FieldSets.valueParameters
import org.jetbrains.kotlin.fir.tree.generator.FieldSets.visibility
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFieldConfigurator
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder.Companion.baseFirElement
import org.jetbrains.kotlin.fir.tree.generator.context.type
import org.jetbrains.kotlin.fir.tree.generator.model.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
@@ -105,6 +106,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
errorExpression.configure {
+field("expression", expression, nullable = true)
+field("nonExpressionElement", baseFirElement, nullable = true)
}
errorFunction.configure {
@@ -19,6 +19,7 @@ fun detectBaseTransformerTypes(builder: AbstractFirTreeBuilder) {
is FieldList -> field.baseType as AbstractElement
else -> throw IllegalArgumentException()
}
if (fieldElement == AbstractFirTreeBuilder.baseFirElement) continue
usedAsFieldType[fieldElement] = true
}
}