[FIR] Implement RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER

Split underscore checkers
This commit is contained in:
Ivan Kochurkin
2021-07-23 15:49:20 +03:00
committed by Space
parent 10d9988824
commit 8bfaa39a5c
15 changed files with 297 additions and 194 deletions
@@ -1070,6 +1070,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val UNDERSCORE_IS_RESERVED by error<PsiElement>(PositioningStrategy.NAME_IDENTIFIER)
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<PsiElement>(PositioningStrategy.NAME_IDENTIFIER)
val RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER by warning<KtNameReferenceExpression>()
val INVALID_CHARACTERS by error<KtNamedDeclaration>(PositioningStrategy.NAME_IDENTIFIER) {
parameter<String>("message")
}
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtParameter
@@ -556,6 +557,7 @@ object FirErrors {
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error3<KtExpression, String, ConeKotlinType, ConeKotlinType>()
val UNDERSCORE_IS_RESERVED by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
val RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER by warning0<KtNameReferenceExpression>()
val INVALID_CHARACTERS by error1<KtNamedDeclaration, String>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
val DANGEROUS_CHARACTERS by warning1<KtNamedDeclaration, String>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnonymousFunctionParametersChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirReservedUnderscoreDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirAnonymousFunctionSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirDelegationInInterfaceSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirFunctionTypeParametersSyntaxChecker
@@ -16,7 +16,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
get() = setOf(
FirReservedUnderscoreExpressionChecker,
FirUnderscoreChecker,
FirExpressionAnnotationChecker,
FirDeprecationChecker
)
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2021 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.analysis.checkers
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
fun checkUnderscoreDiagnostics(
source: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter,
isExpression: Boolean
) {
if (source != null && source.kind !is FirFakeSourceElementKind) {
with(SourceNavigator.forSource(source)) {
if (source.getRawIdentifier()?.isUnderscore == true) {
reporter.reportOn(
source,
if (isExpression) FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS else FirErrors.UNDERSCORE_IS_RESERVED,
context
)
}
}
}
}
val CharSequence.isUnderscore: Boolean
get() = all { it == '_' }
@@ -6,15 +6,22 @@
package org.jetbrains.kotlin.fir.analysis.checkers
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.getAncestors
import org.jetbrains.kotlin.fir.analysis.diagnostics.nameIdentifier
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType
import org.jetbrains.kotlin.psi.stubs.elements.KtTypeProjectionElementType
/**
* Service to answer source-related questions in generic fashion.
@@ -26,17 +33,27 @@ interface SourceNavigator {
fun FirTypeRef.isInTypeConstraint(): Boolean
fun FirSourceElement.getRawIdentifier(): String?
fun FirDeclaration.getRawName(): String?
fun FirValueParameterSymbol.isCatchElementParameter(): Boolean
companion object {
private val lightTreeInstance = LightTreeSourceNavigator()
fun forElement(e: FirElement): SourceNavigator = when (e.source) {
fun forElement(e: FirElement): SourceNavigator = forSource(e.source)
fun forSource(e: FirSourceElement?): SourceNavigator = when (e) {
is FirLightSourceElement -> lightTreeInstance
is FirPsiSourceElement -> PsiSourceNavigator
null -> lightTreeInstance //shouldn't matter
}
inline fun <R> FirElement.withNavigator(block: SourceNavigator.() -> R): R = with(forElement(this), block)
inline fun <R> FirElement.withNavigator(block: SourceNavigator.() -> R): R = with(forSource(this.source), block)
inline fun <R> FirSourceElement.withNavigator(block: SourceNavigator.() -> R): R = with(forSource(this), block)
}
}
@@ -55,16 +72,61 @@ open class LightTreeSourceNavigator : SourceNavigator {
.find { it.tokenType == KtNodeTypes.TYPE_CONSTRAINT || it.tokenType == KtNodeTypes.TYPE_PARAMETER }
?.tokenType == KtNodeTypes.TYPE_CONSTRAINT
}
override fun FirSourceElement.getRawIdentifier(): String? {
val tokenType = elementType
return if (tokenType is KtNameReferenceExpressionElementType || tokenType == KtTokens.IDENTIFIER) {
lighterASTNode.toString()
} else if (tokenType is KtTypeProjectionElementType) {
lighterASTNode.getChildren(treeStructure).last().toString()
} else {
null
}
}
override fun FirDeclaration.getRawName(): String? {
return source?.let { it.treeStructure.nameIdentifier(it.lighterASTNode)?.toString() }
}
override fun FirValueParameterSymbol.isCatchElementParameter(): Boolean {
val localSource = source ?: return false
var parent = localSource.treeStructure.getParent(localSource.lighterASTNode)
parent?.let { parent = localSource.treeStructure.getParent(it) }
return parent?.tokenType == KtNodeTypes.CATCH
}
}
//by default psi tree can reuse light tree manipulations
object PsiSourceNavigator : LightTreeSourceNavigator() {
//Swallows incorrect casts!!!
private inline fun <reified P : PsiElement> FirElement.psi(): P? {
val psi = (source as? FirPsiSourceElement)?.psi
private inline fun <reified P : PsiElement> FirElement.psi(): P? = source?.psi()
private inline fun <reified P : PsiElement> FirSourceElement.psi(): P? {
val psi = (this as? FirPsiSourceElement)?.psi
return psi as? P
}
override fun FirTypeRef.isInConstructorCallee(): Boolean = psi<KtTypeReference>()?.parent is KtConstructorCalleeExpression
override fun FirSourceElement.getRawIdentifier(): String? {
val psi = psi<PsiElement>()
return if (psi is KtNameReferenceExpression) {
psi.getReferencedNameElement().node.text
} else if (psi is KtTypeProjection) {
psi.typeReference?.typeElement?.text
} else if (psi is LeafPsiElement && psi.elementType == KtTokens.IDENTIFIER) {
psi.text
} else {
null
}
}
override fun FirDeclaration.getRawName(): String? {
return (this.psi() as? PsiNameIdentifierOwner)?.nameIdentifier?.text
}
override fun FirValueParameterSymbol.isCatchElementParameter(): Boolean {
return source?.psi<PsiElement>()?.parent?.parent is KtCatchClause
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2021 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.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.SourceNavigator
import org.jetbrains.kotlin.fir.analysis.checkers.checkUnderscoreDiagnostics
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isUnderscore
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirUserTypeRef
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (
declaration is FirRegularClass ||
declaration is FirTypeParameter ||
declaration is FirProperty ||
declaration is FirTypeAlias
) {
reportIfUnderscore(declaration, context, reporter)
} else if (declaration is FirFunction) {
if (declaration is FirSimpleFunction) {
reportIfUnderscore(declaration, context, reporter)
}
val isSingleUnderscoreAllowed = declaration is FirAnonymousFunction || declaration is FirPropertyAccessor
for (parameter in declaration.valueParameters) {
reportIfUnderscore(
parameter,
context,
reporter,
isSingleUnderscoreAllowed = isSingleUnderscoreAllowed
)
}
} else if (declaration is FirFile) {
for (import in declaration.imports) {
checkUnderscoreDiagnostics(import.aliasSource, context, reporter, isExpression = false)
}
}
}
private fun reportIfUnderscore(
declaration: FirDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
isSingleUnderscoreAllowed: Boolean = false
) {
val declarationSource = declaration.source
if (declarationSource != null && declarationSource.kind !is FirFakeSourceElementKind) {
with(SourceNavigator.forElement(declaration)) {
val rawName = declaration.getRawName()
if (rawName?.isUnderscore == true && !(isSingleUnderscoreAllowed && rawName == "_")) {
reporter.reportOn(
declarationSource,
FirErrors.UNDERSCORE_IS_RESERVED,
context
)
}
}
}
val returnOrReceiverTypeRef = when (declaration) {
is FirValueParameter -> declaration.returnTypeRef
is FirFunction -> declaration.receiverTypeRef
else -> null
}
if (returnOrReceiverTypeRef is FirResolvedTypeRef) {
val delegatedTypeRef = returnOrReceiverTypeRef.delegatedTypeRef
if (delegatedTypeRef is FirUserTypeRef) {
for (qualifierPart in delegatedTypeRef.qualifier) {
checkUnderscoreDiagnostics(qualifierPart.source, context, reporter, isExpression = true)
for (typeArgument in qualifierPart.typeArgumentList.typeArguments) {
checkUnderscoreDiagnostics(typeArgument.source, context, reporter, isExpression = true)
}
}
}
}
}
}
@@ -1,171 +0,0 @@
/*
* Copyright 2010-2021 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.analysis.checkers.expression
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.diagnostics.ConeUnderscoreUsageWithoutBackticks
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtTypeProjection
import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType
import org.jetbrains.kotlin.psi.stubs.elements.KtTypeProjectionElementType
object FirReservedUnderscoreExpressionChecker : FirBasicExpressionChecker() {
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
when (expression) {
is FirResolvable -> {
reportIfUnderscore(expression.calleeReference.source, context, reporter, isExpression = true)
}
is FirResolvedQualifier -> {
for (reservedUnderscoreDiagnostic in expression.nonFatalDiagnostics.filterIsInstance<ConeUnderscoreUsageWithoutBackticks>()) {
reporter.reportOn(reservedUnderscoreDiagnostic.source, FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS, context)
}
}
}
}
}
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (
declaration is FirRegularClass ||
declaration is FirTypeParameter ||
declaration is FirProperty ||
declaration is FirTypeAlias
) {
reportIfUnderscore(declaration, context, reporter)
} else if (declaration is FirFunction) {
if (declaration is FirSimpleFunction) {
reportIfUnderscore(declaration, context, reporter)
}
val isSingleUnderscoreAllowed = declaration is FirAnonymousFunction || declaration is FirPropertyAccessor
for (parameter in declaration.valueParameters) {
reportIfUnderscore(
parameter,
context,
reporter,
isSingleUnderscoreAllowed = isSingleUnderscoreAllowed
)
}
} else if (declaration is FirFile) {
for (import in declaration.imports) {
reportIfUnderscore(import.aliasSource, context, reporter, isExpression = false)
}
}
}
}
private fun reportIfUnderscore(
declaration: FirDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter,
isSingleUnderscoreAllowed: Boolean = false
) {
val declarationSource = declaration.source
val rawName = when (declarationSource) {
is FirPsiSourceElement ->
(declarationSource.psi as? PsiNameIdentifierOwner)?.nameIdentifier?.text
is FirLightSourceElement ->
declarationSource.treeStructure.nameIdentifier(declarationSource.lighterASTNode)?.toString()
else ->
null
}
reportIfUnderscore(rawName, declarationSource, context, reporter, isSingleUnderscoreAllowed)
val returnOrReceiverTypeRef = when (declaration) {
is FirValueParameter -> declaration.returnTypeRef
is FirFunction -> declaration.receiverTypeRef
else -> null
}
if (returnOrReceiverTypeRef is FirResolvedTypeRef) {
val delegatedTypeRef = returnOrReceiverTypeRef.delegatedTypeRef
if (delegatedTypeRef is FirUserTypeRef) {
for (qualifierPart in delegatedTypeRef.qualifier) {
reportIfUnderscore(qualifierPart.source, context, reporter, isExpression = true)
for (typeArgument in qualifierPart.typeArgumentList.typeArguments) {
reportIfUnderscore(typeArgument.source, context, reporter, isExpression = true)
}
}
}
}
}
private fun reportIfUnderscore(
source: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter,
isExpression: Boolean
) {
if (source != null && source.kind !is FirFakeSourceElementKind) {
var rawName: String? = null
if (source is FirPsiSourceElement) {
val psi = source.psi
rawName = if (psi is KtNameReferenceExpression) {
psi.getReferencedNameElement().node.text
} else if (psi is KtTypeProjection) {
psi.typeReference?.typeElement?.text
} else if (psi is LeafPsiElement && psi.elementType == KtTokens.IDENTIFIER) {
psi.text
} else {
null
}
} else if (source is FirLightSourceElement) {
val tokenType = source.elementType
rawName = if (tokenType is KtNameReferenceExpressionElementType || tokenType == KtTokens.IDENTIFIER) {
source.lighterASTNode.toString()
} else if (tokenType is KtTypeProjectionElementType) {
source.lighterASTNode.getChildren(source.treeStructure).last().toString()
} else {
null
}
}
if (rawName?.isUnderscore == true) {
reporter.reportOn(
source,
if (isExpression) FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS else FirErrors.UNDERSCORE_IS_RESERVED,
context
)
}
}
}
private fun reportIfUnderscore(
rawName: CharSequence?,
source: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter,
isSingleUnderscoreAllowed: Boolean
) {
if (source == null || rawName == null || isSingleUnderscoreAllowed && rawName == "_") {
return
}
if (rawName.isUnderscore && source.kind !is FirFakeSourceElementKind) {
reporter.reportOn(
source,
FirErrors.UNDERSCORE_IS_RESERVED,
context
)
}
}
val CharSequence.isUnderscore: Boolean
get() = all { it == '_' }
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2021 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.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.checkUnderscoreDiagnostics
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.diagnostics.ConeUnderscoreUsageWithoutBackticks
import org.jetbrains.kotlin.fir.expressions.FirResolvable
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.fir.analysis.checkers.SourceNavigator
object FirUnderscoreChecker : FirBasicExpressionChecker() {
private val singleUnderscore: Name = Name.identifier("_")
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
when (expression) {
is FirResolvable -> {
checkUnderscoreDiagnostics(expression.calleeReference.source, context, reporter, true)
checkResolvedToUnderscoreNamedCatchParameter(expression, context, reporter)
}
is FirResolvedQualifier -> {
for (reservedUnderscoreDiagnostic in expression.nonFatalDiagnostics.filterIsInstance<ConeUnderscoreUsageWithoutBackticks>()) {
reporter.reportOn(reservedUnderscoreDiagnostic.source, FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS, context)
}
}
}
}
private fun checkResolvedToUnderscoreNamedCatchParameter(
expression: FirResolvable,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val calleeReference = expression.calleeReference
val symbol = calleeReference.toResolvedCallableSymbol()
with(SourceNavigator.forElement(expression)) {
if (symbol is FirValueParameterSymbol && symbol.isCatchElementParameter() && symbol.name == singleUnderscore) {
reporter.reportOn(
calleeReference.source,
FirErrors.RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER,
context
)
}
}
}
}
@@ -340,6 +340,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_BOUND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESOLUTION_TO_CLASSIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESULT_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_FOR_BUILT_IN_SUSPEND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY
@@ -1400,6 +1401,10 @@ class FirDefaultErrorMessages {
UNDERSCORE_USAGE_WITHOUT_BACKTICKS,
"Names _, __, ___, ... can be used only in back-ticks (`_`, `__`, `___`, ...)"
)
map.put(
RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER,
"Referencing to an underscore-named parameter is deprecated. It will be an error in a future release."
)
map.put(
INVALID_CHARACTERS,
"Name {0}",
@@ -838,12 +838,17 @@ object PositioningStrategies {
}
val NAME_IDENTIFIER: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
private fun KtTypeElement.getReferencedTypeExpression(): KtElement? {
return when (this) {
is KtUserType -> referenceExpression
is KtNullableType -> innerType?.getReferencedTypeExpression()
is KtDefinitelyNotNullType -> innerType?.getReferencedTypeExpression()
else -> null
override fun mark(element: PsiElement): List<TextRange> {
if (element is PsiNameIdentifierOwner) {
val nameIdentifier = element.nameIdentifier
if (nameIdentifier != null) {
return super.mark(nameIdentifier)
}
} else if (element is KtLabelReferenceExpression) {
return super.mark(element.getReferencedNameElement())
}
return DEFAULT.mark(element)
}
}
@@ -6,7 +6,7 @@ fun foo() {
try {
TODO()
} catch (_: Exception) {
`_`.stackTrace
<!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>.stackTrace
}
try {
TODO()
@@ -17,20 +17,20 @@ fun foo() {
val x4 = { _: Int ->
`_`
}
`_`
<!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>
}
`_`
<!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>
10
}
fun bar(x: Exception = `_`) {}
fun bar(x: Exception = <!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>) {}
class Bar(`_`: Exception = <!UNINITIALIZED_PARAMETER!>`_`<!>) {
inner class Bar2(x: Exception = `_`) { }
inner class Bar2(x: Exception = <!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>) { }
}
}
} catch (_: Exception) {
`_`.stackTrace
val y1 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>
val y2 = (`_`)
<!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>.stackTrace
val y1 = <!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER, UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>
val y2 = (<!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>)
}
try {
TODO()
@@ -38,7 +38,7 @@ fun foo() {
try {
TODO()
} catch (x: Exception) {
`_`.stackTrace
<!RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER!>`_`<!>.stackTrace
}
}
val boo1 = { `_`: Exception ->
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtParameter
@@ -2876,6 +2877,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.RESOLVED_TO_UNDERSCORE_NAMED_CATCH_PARAMETER) { firDiagnostic ->
ResolvedToUnderscoreNamedCatchParameterImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.INVALID_CHARACTERS) { firDiagnostic ->
InvalidCharactersImpl(
firDiagnostic.a,
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtParameter
@@ -2011,6 +2012,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = UnderscoreUsageWithoutBackticks::class
}
abstract class ResolvedToUnderscoreNamedCatchParameter : KtFirDiagnostic<KtNameReferenceExpression>() {
override val diagnosticClass get() = ResolvedToUnderscoreNamedCatchParameter::class
}
abstract class InvalidCharacters : KtFirDiagnostic<KtNamedDeclaration>() {
override val diagnosticClass get() = InvalidCharacters::class
abstract val message: String
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtParameter
@@ -3239,6 +3240,13 @@ internal class UnderscoreUsageWithoutBackticksImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ResolvedToUnderscoreNamedCatchParameterImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.ResolvedToUnderscoreNamedCatchParameter(), KtAbstractFirDiagnostic<KtNameReferenceExpression> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class InvalidCharactersImpl(
override val message: String,
firDiagnostic: FirPsiDiagnostic,