[FIR] buildErrorExpression for labels with underscored name
Add ConeDiagnosticWithSource, ConeUnderscoreIsReserved, ConeUnderscoreUsageWithoutBackticks diagnostics
This commit is contained in:
+3
-1
@@ -72,7 +72,7 @@ private fun ConeDiagnostic.toFirDiagnostic(
|
||||
is ConeUnexpectedTypeArgumentsError -> FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.createOn(this.source ?: source)
|
||||
is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.createOn(source, this.name.asString())
|
||||
is ConeWrongNumberOfTypeArgumentsError ->
|
||||
FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.createOn(this.source ?: qualifiedAccessSource ?: source, this.desiredCount, this.symbol)
|
||||
FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.createOn(this.source, this.desiredCount, this.symbol)
|
||||
is ConeOuterClassArgumentsRequired ->
|
||||
FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED.createOn(qualifiedAccessSource ?: source, this.symbol)
|
||||
is ConeNoTypeArgumentsOnRhsError ->
|
||||
@@ -92,6 +92,8 @@ private fun ConeDiagnostic.toFirDiagnostic(
|
||||
is ConeUnsupportedDynamicType -> FirErrors.UNSUPPORTED.createOn(source, this.reason)
|
||||
is ConeLocalVariableNoTypeOrInitializer ->
|
||||
runIf(variable.isLocalMember) { FirErrors.VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.createOn(source) }
|
||||
is ConeUnderscoreIsReserved -> FirErrors.UNDERSCORE_IS_RESERVED.createOn(this.source)
|
||||
is ConeUnderscoreUsageWithoutBackticks -> FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.createOn(this.source)
|
||||
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.parsing.KotlinExpressionParsing
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStringTemplateExpressionElementType
|
||||
|
||||
@@ -41,7 +42,7 @@ private val expressionSet = listOf(
|
||||
|
||||
fun String?.nameAsSafeName(defaultName: String = ""): Name {
|
||||
return when {
|
||||
this != null -> Name.identifier(this.replace("`", ""))
|
||||
this != null -> Name.identifier(KtPsiUtil.unquoteIdentifier(this))
|
||||
defaultName.isNotEmpty() -> Name.identifier(defaultName)
|
||||
else -> SpecialNames.NO_NAME_PROVIDED
|
||||
}
|
||||
|
||||
+12
-7
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeNotAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeUnderscoreIsReserved
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
@@ -331,13 +332,17 @@ class ExpressionsConverter(
|
||||
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitLabeledExpression
|
||||
*/
|
||||
private fun convertLabeledExpression(labeledExpression: LighterASTNode): FirElement {
|
||||
val size = context.firLabels.size
|
||||
var firExpression: FirElement? = null
|
||||
val previousLabelsSize = context.firLabels.size
|
||||
var errorLabelSource: FirSourceElement? = null
|
||||
|
||||
labeledExpression.forEachChildren {
|
||||
when (it.tokenType) {
|
||||
LABEL_QUALIFIER -> context.firLabels += buildLabel {
|
||||
source = labeledExpression.toFirLightSourceElement(tree)
|
||||
name = it.toString().replace("@", "")
|
||||
LABEL_QUALIFIER -> {
|
||||
val rawName = it.toString()
|
||||
val pair = buildLabelAndErrorSource(rawName.substring(0, rawName.length - 1), it.toFirSourceElement())
|
||||
context.firLabels += pair.first
|
||||
errorLabelSource = pair.second
|
||||
}
|
||||
BLOCK -> firExpression = declarationsConverter.convertBlock(it)
|
||||
PROPERTY -> firExpression = declarationsConverter.convertPropertyDeclaration(it)
|
||||
@@ -345,11 +350,11 @@ class ExpressionsConverter(
|
||||
}
|
||||
}
|
||||
|
||||
if (size != context.firLabels.size) {
|
||||
if (context.firLabels.size != previousLabelsSize) {
|
||||
context.firLabels.removeLast()
|
||||
//println("Unused label: ${labeledExpression.getAsString()}")
|
||||
}
|
||||
return firExpression ?: buildErrorExpression(null, ConeSimpleDiagnostic("Empty label", DiagnosticKind.Syntax))
|
||||
|
||||
return buildExpressionWithErrorLabel(firExpression, errorLabelSource, labeledExpression.toFirSourceElement())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-12
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeNotAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
||||
@@ -2219,21 +2217,24 @@ open class RawFirBuilder(
|
||||
}
|
||||
|
||||
override fun visitLabeledExpression(expression: KtLabeledExpression, data: Unit): FirElement {
|
||||
val sourceElement = expression.toFirSourceElement()
|
||||
val label = expression.getTargetLabel()
|
||||
val size = context.firLabels.size
|
||||
val previousLabelsSize = context.firLabels.size
|
||||
var errorLabelSource: FirSourceElement? = null
|
||||
|
||||
if (label != null) {
|
||||
context.firLabels += buildLabel {
|
||||
source = label.toFirPsiSourceElement()
|
||||
name = label.getReferencedName()
|
||||
}
|
||||
val rawName = label.getReferencedNameElement().node!!.text
|
||||
val labelAndErrorSource = buildLabelAndErrorSource(rawName, label.toFirPsiSourceElement())
|
||||
context.firLabels += labelAndErrorSource.first
|
||||
errorLabelSource = labelAndErrorSource.second
|
||||
}
|
||||
|
||||
val result = expression.baseExpression?.accept(this, data)
|
||||
?: buildErrorExpression(sourceElement, ConeSimpleDiagnostic("Empty label", DiagnosticKind.Syntax))
|
||||
if (size != context.firLabels.size) {
|
||||
|
||||
if (context.firLabels.size != previousLabelsSize) {
|
||||
context.firLabels.removeLast()
|
||||
}
|
||||
return result
|
||||
|
||||
return buildExpressionWithErrorLabel(result, errorLabelSource, expression.toFirSourceElement())
|
||||
}
|
||||
|
||||
override fun visitAnnotatedExpression(expression: KtAnnotatedExpression, data: Unit): FirElement {
|
||||
|
||||
+49
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.addDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeUnderscoreIsReserved
|
||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.parsing.*
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
@@ -1195,6 +1197,53 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
}
|
||||
}
|
||||
|
||||
protected fun buildLabelAndErrorSource(rawName: String, source: FirSourceElement): Pair<FirLabel, FirSourceElement?> {
|
||||
val firLabel = buildLabel {
|
||||
name = KtPsiUtil.unquoteIdentifier(rawName)
|
||||
this.source = source
|
||||
}
|
||||
|
||||
return Pair(firLabel, if (rawName.isUnderscore) firLabel.source else null)
|
||||
}
|
||||
|
||||
protected fun buildExpressionWithErrorLabel(
|
||||
element: FirElement?,
|
||||
errorLabelSource: FirSourceElement?,
|
||||
elementSource: FirSourceElement
|
||||
): FirElement {
|
||||
return if (element != null) {
|
||||
if (errorLabelSource != null) {
|
||||
buildErrorExpression {
|
||||
this.source = element.source
|
||||
this.expression = element as? FirExpression
|
||||
diagnostic = ConeUnderscoreIsReserved(errorLabelSource)
|
||||
}
|
||||
} else {
|
||||
element
|
||||
}
|
||||
} else {
|
||||
buildErrorExpression(elementSource, ConeSimpleDiagnostic("Empty label", DiagnosticKind.Syntax))
|
||||
}
|
||||
}
|
||||
|
||||
protected fun convertValueParameterName(
|
||||
safeName: Name,
|
||||
rawName: String?,
|
||||
valueParameterDeclaration: ValueParameterDeclaration
|
||||
): Name {
|
||||
return if (valueParameterDeclaration == ValueParameterDeclaration.LAMBDA && rawName == "_"
|
||||
||
|
||||
valueParameterDeclaration == ValueParameterDeclaration.CATCH &&
|
||||
baseSession.sessionProvider != null &&
|
||||
baseSession.languageVersionSettings.supportsFeature(LanguageFeature.ForbidReferencingToUnderscoreNamedParameterOfCatchBlock) &&
|
||||
safeName.asString() == "_"
|
||||
) {
|
||||
SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
|
||||
} else {
|
||||
safeName
|
||||
}
|
||||
}
|
||||
|
||||
/**** Common utils ****/
|
||||
companion object {
|
||||
val ANONYMOUS_OBJECT_NAME = Name.special("<anonymous>")
|
||||
|
||||
+3
@@ -542,6 +542,9 @@ fun FirQualifiedAccess.wrapWithSafeCall(receiver: FirExpression, source: FirSour
|
||||
}
|
||||
}
|
||||
|
||||
val CharSequence.isUnderscore: Boolean
|
||||
get() = all { it == '_' }
|
||||
|
||||
data class CalleeAndReceiver(
|
||||
val reference: FirNamedReference,
|
||||
val receiverExpression: FirExpression? = null,
|
||||
|
||||
+3
-2
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnosticWithSource
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -112,8 +113,8 @@ abstract class ConeUnmatchedTypeArgumentsError(val desiredCount: Int, val type:
|
||||
class ConeWrongNumberOfTypeArgumentsError(
|
||||
val desiredCount: Int,
|
||||
val symbol: FirRegularClassSymbol,
|
||||
val source: FirSourceElement?
|
||||
) : ConeDiagnostic() {
|
||||
source: FirSourceElement
|
||||
) : ConeDiagnosticWithSource(source) {
|
||||
override val reason: String get() = "Wrong number of type arguments"
|
||||
}
|
||||
|
||||
|
||||
+9
-6
@@ -301,13 +301,16 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
||||
(parameterClass != null && parameterClass.classId.relativeClassName.parent().isRoot)
|
||||
|| outerClass != null
|
||||
) {
|
||||
return ConeClassErrorType(
|
||||
ConeWrongNumberOfTypeArgumentsError(
|
||||
actualTypeParametersCount,
|
||||
parameterClass?.symbol ?: symbol,
|
||||
getTypeArgumentsOrNameSource(userTypeRef, qualifierPartIndex)
|
||||
val source = getTypeArgumentsOrNameSource(userTypeRef, qualifierPartIndex)
|
||||
if (source != null) {
|
||||
return ConeClassErrorType(
|
||||
ConeWrongNumberOfTypeArgumentsError(
|
||||
actualTypeParametersCount,
|
||||
parameterClass?.symbol ?: symbol,
|
||||
source
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
|
||||
class ConeSimpleDiagnostic(override val reason: String, val kind: DiagnosticKind = DiagnosticKind.Other) : ConeDiagnostic()
|
||||
|
||||
class ConeNotAnnotationContainer(val text: String) : ConeDiagnostic() {
|
||||
override val reason: String get() = "Strange annotated expression: $text"
|
||||
}
|
||||
|
||||
abstract class ConeDiagnosticWithSource(val source: FirSourceElement) : ConeDiagnostic()
|
||||
|
||||
class ConeUnderscoreIsReserved(source: FirSourceElement) : ConeDiagnosticWithSource(source) {
|
||||
override val reason: String get() = "Names _, __, ___, ..., are reserved in Kotlin"
|
||||
}
|
||||
|
||||
class ConeUnderscoreUsageWithoutBackticks(source: FirSourceElement) : ConeDiagnosticWithSource(source) {
|
||||
override val reason: String get() = "Names _, __, ___, ... can be used only in back-ticks (`_`, `__`, `___`, ...)"
|
||||
}
|
||||
|
||||
enum class DiagnosticKind {
|
||||
Syntax,
|
||||
ExpressionExpected,
|
||||
|
||||
Reference in New Issue
Block a user