[FIR] Implement UNDERSCORE_IS_RESERVED, UNDERSCORE_USAGE_WITHOUT_BACKTICKS diagnostics (psi only)
This commit is contained in:
committed by
TeamCityServer
parent
cc4adb798f
commit
ea2d9f7c0c
+1
@@ -67,6 +67,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
FUN_MODIFIER,
|
||||
SUSPEND_MODIFIER,
|
||||
FUN_INTERFACE,
|
||||
RESERVED_UNDERSCORE,
|
||||
|
||||
;
|
||||
|
||||
|
||||
+2
@@ -696,6 +696,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<String>("expectedFunctionSignature")
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
val UNDERSCORE_IS_RESERVED by error<KtExpression>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<KtExpression>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||
}
|
||||
|
||||
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
|
||||
|
||||
@@ -409,6 +409,8 @@ object FirErrors {
|
||||
val DELEGATE_SPECIAL_FUNCTION_MISSING by error3<KtExpression, String, ConeKotlinType, String>()
|
||||
val DELEGATE_SPECIAL_FUNCTION_AMBIGUITY by error2<KtExpression, String, Collection<AbstractFirBasedSymbol<*>>>()
|
||||
val DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE by error2<KtExpression, String, Collection<AbstractFirBasedSymbol<*>>>()
|
||||
val UNDERSCORE_IS_RESERVED by error0<KtExpression>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<KtExpression>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||
|
||||
// Type alias
|
||||
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.PsiElement
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||
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.expressions.*
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||
|
||||
object FirReservedUnderscoreExpressionChecker : FirBasicExpressionChecker() {
|
||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (expression is FirFunctionCall) {
|
||||
reportIfUnderscore(
|
||||
expression.calleeReference.psi?.text, expression.source, context, reporter,
|
||||
isExpression = true
|
||||
)
|
||||
|
||||
for (argument in expression.arguments) {
|
||||
if (argument is FirNamedArgumentExpression) {
|
||||
reportIfUnderscore(argument.psi?.firstChild?.text, argument.source, context, reporter)
|
||||
}
|
||||
}
|
||||
} else if (expression is FirQualifiedAccess) {
|
||||
fun processQualifiedAccess(psi: PsiElement?) {
|
||||
if (psi is KtNameReferenceExpression) {
|
||||
reportIfUnderscore(psi.text, expression.source, context, reporter, isExpression = true)
|
||||
} else if (psi is KtDotQualifiedExpression || psi is KtCallableReferenceExpression) {
|
||||
processQualifiedAccess(psi.firstChild)
|
||||
processQualifiedAccess(psi.lastChild)
|
||||
}
|
||||
}
|
||||
|
||||
val psi = expression.psi
|
||||
if (psi != null && psi.parent !is KtDotQualifiedExpression && psi.parent !is KtCallableReferenceExpression) {
|
||||
processQualifiedAccess(psi)
|
||||
}
|
||||
} else if (expression is FirGetClassCall) {
|
||||
for (argument in expression.argumentList.arguments) {
|
||||
reportIfUnderscore(argument.psi?.text, expression.source, context, reporter, isExpression = true)
|
||||
}
|
||||
} else if (expression is FirReturnExpression) {
|
||||
reportIfUnderscore(expression.target.labelName, expression.source, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (
|
||||
declaration is FirClass<*> ||
|
||||
declaration is FirFunction<*> ||
|
||||
declaration is FirTypeParameter ||
|
||||
declaration is FirProperty ||
|
||||
declaration is FirTypeAlias
|
||||
) {
|
||||
|
||||
reportIfUnderscore(declaration, context, reporter)
|
||||
|
||||
if (declaration is FirFunction<*>) {
|
||||
for (parameter in declaration.valueParameters) {
|
||||
reportIfUnderscore(
|
||||
parameter,
|
||||
context,
|
||||
reporter,
|
||||
isSingleUnderscoreAllowed = declaration is FirAnonymousFunction || declaration is FirPropertyAccessor
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (declaration is FirFile) {
|
||||
for (import in declaration.imports) {
|
||||
reportIfUnderscore(import.aliasName?.asString(), import.source, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportIfUnderscore(
|
||||
declaration: FirDeclaration,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
isSingleUnderscoreAllowed: Boolean = false
|
||||
) {
|
||||
val rawIdentifier = (declaration.psi as? PsiNameIdentifierOwner)?.nameIdentifier?.text ?: return
|
||||
reportIfUnderscore(rawIdentifier, declaration.source, context, reporter, isSingleUnderscoreAllowed)
|
||||
|
||||
fun reportIfAnyDescendantIfUnderscore(typeRef: FirTypeRef?) {
|
||||
if (typeRef == null) return
|
||||
|
||||
if (typeRef.psi?.anyDescendantOfType<LeafPsiElement> { isUnderscore(it.text) } == true) {
|
||||
reporter.reportOn(
|
||||
typeRef.source,
|
||||
FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (declaration is FirValueParameter) {
|
||||
val psi = declaration.returnTypeRef.psi
|
||||
if (psi !is KtFunctionLiteral && psi !is KtParameter) {
|
||||
reportIfAnyDescendantIfUnderscore(declaration.returnTypeRef)
|
||||
}
|
||||
} else if (declaration is FirFunction<*>) {
|
||||
reportIfAnyDescendantIfUnderscore(declaration.receiverTypeRef)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportIfUnderscore(
|
||||
text: String?,
|
||||
source: FirSourceElement?,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
isSingleUnderscoreAllowed: Boolean = false,
|
||||
isExpression: Boolean = false
|
||||
) {
|
||||
if (text == null || isSingleUnderscoreAllowed && text == "_") {
|
||||
return
|
||||
}
|
||||
|
||||
if (isUnderscore(text)) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
if (isExpression) FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS else FirErrors.UNDERSCORE_IS_RESERVED,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isUnderscore(text: String) = text.all { it == '_' }
|
||||
+3
@@ -642,6 +642,9 @@ object LightTreePositioningStrategies {
|
||||
return markElement(tree.typeParametersList(node) ?: node, startOffset, endOffset, tree, node)
|
||||
}
|
||||
}
|
||||
|
||||
val RESERVED_UNDERSCORE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
}
|
||||
}
|
||||
|
||||
fun FirSourceElement.hasValOrVar(): Boolean =
|
||||
|
||||
+5
@@ -228,4 +228,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.TYPE_PARAMETERS_LIST,
|
||||
PositioningStrategies.TYPE_PARAMETERS_LIST
|
||||
)
|
||||
|
||||
val RESERVED_UNDERSCORE = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.RESERVED_UNDERSCORE,
|
||||
PositioningStrategies.RESERVED_UNDERSCORE
|
||||
)
|
||||
}
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer
|
||||
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.FirReservedUnderscoreDeclarationChecker
|
||||
|
||||
object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
@@ -20,6 +21,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirConflictsChecker,
|
||||
FirConflictingProjectionChecker,
|
||||
FirTypeConstraintsChecker,
|
||||
FirReservedUnderscoreDeclarationChecker
|
||||
)
|
||||
|
||||
override val memberDeclarationCheckers: Set<FirMemberDeclarationChecker>
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
|
||||
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
|
||||
get() = setOf(
|
||||
FirReservedUnderscoreExpressionChecker
|
||||
)
|
||||
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
@@ -31,7 +32,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirTypeParameterInQualifiedAccessChecker,
|
||||
FirSealedClassConstructorCallChecker,
|
||||
FirUninitializedEnumChecker,
|
||||
FirFunInterfaceConstructorReferenceChecker,
|
||||
FirFunInterfaceConstructorReferenceChecker
|
||||
)
|
||||
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.cfg.UnreachableCode
|
||||
@@ -144,10 +145,10 @@ object PositioningStrategies {
|
||||
ClassKind -> {
|
||||
val startElement =
|
||||
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||
val endElement =
|
||||
element.node.findChildByType(classKindTokens)?.psi
|
||||
?: element.nameIdentifier
|
||||
?: element.nameIdentifier
|
||||
if (startElement != null && endElement != null) {
|
||||
return markRange(startElement, endElement)
|
||||
} else {
|
||||
@@ -160,7 +161,7 @@ object PositioningStrategies {
|
||||
}
|
||||
CallableKind -> {
|
||||
(callableDeclaration as? KtNamedFunction)?.funKeyword
|
||||
?: (callableDeclaration as? KtProperty)?.valOrVarKeyword
|
||||
?: (callableDeclaration as? KtProperty)?.valOrVarKeyword
|
||||
}
|
||||
ParameterShape -> {
|
||||
callableDeclaration?.let { it.receiverTypeReference ?: it.valueParameterList }
|
||||
@@ -239,7 +240,7 @@ object PositioningStrategies {
|
||||
val startElement =
|
||||
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
|
||||
?: element
|
||||
?: element
|
||||
|
||||
return markRange(startElement, nameIdentifier)
|
||||
}
|
||||
@@ -264,13 +265,13 @@ object PositioningStrategies {
|
||||
is KtFunction -> {
|
||||
val endOfSignatureElement =
|
||||
element.typeReference
|
||||
?: element.valueParameterList
|
||||
?: element.nameIdentifier
|
||||
?: element
|
||||
?: element.valueParameterList
|
||||
?: element.nameIdentifier
|
||||
?: element
|
||||
val startElement = if (element is KtFunctionLiteral) {
|
||||
element.getReceiverTypeReference()
|
||||
?: element.getValueParameterList()
|
||||
?: element
|
||||
?: element.getValueParameterList()
|
||||
?: element
|
||||
} else element
|
||||
return markRange(startElement, endOfSignatureElement)
|
||||
}
|
||||
@@ -281,8 +282,8 @@ object PositioningStrategies {
|
||||
is KtPropertyAccessor -> {
|
||||
val endOfSignatureElement =
|
||||
element.returnTypeReference
|
||||
?: element.rightParenthesis
|
||||
?: element.namePlaceholder
|
||||
?: element.rightParenthesis
|
||||
?: element.namePlaceholder
|
||||
|
||||
return markRange(element, endOfSignatureElement)
|
||||
}
|
||||
@@ -390,6 +391,7 @@ object PositioningStrategies {
|
||||
return markElement(nameIdentifier ?: element)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val FOR_UNRESOLVED_REFERENCE: PositioningStrategy<KtReferenceExpression> = object : PositioningStrategy<KtReferenceExpression>() {
|
||||
override fun mark(element: KtReferenceExpression): List<TextRange> {
|
||||
@@ -783,6 +785,31 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
val RESERVED_UNDERSCORE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
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 KtImportDirective) {
|
||||
return super.mark(element.alias?.nameIdentifier ?: element)
|
||||
} else if (element is KtReturnExpression) {
|
||||
val prevSibling = element.getPrevSiblingIgnoringWhitespace()
|
||||
if (prevSibling is KtContainerNode) {
|
||||
return mark(prevSibling)
|
||||
}
|
||||
} else if (element !is LeafPsiElement) {
|
||||
val ranges = element.collectDescendantsOfType<LeafPsiElement> { descendant -> descendant.text.all { it == '_' } }
|
||||
.map { markSingleElement(it) }
|
||||
if (ranges.isNotEmpty()) {
|
||||
return ranges
|
||||
}
|
||||
}
|
||||
return super.mark(element)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val FUN_INTERFACE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
|
||||
override fun mark(element: KtDeclaration): List<TextRange> {
|
||||
|
||||
@@ -43,6 +43,10 @@ fun markElement(element: PsiElement): List<TextRange> {
|
||||
return listOf(TextRange(getStartOffset(element), getEndOffset(element)))
|
||||
}
|
||||
|
||||
fun markSingleElement(element: PsiElement): TextRange {
|
||||
return TextRange(getStartOffset(element), getEndOffset(element))
|
||||
}
|
||||
|
||||
fun markNode(node: ASTNode): List<TextRange> {
|
||||
return markElement(node.psi)
|
||||
}
|
||||
|
||||
+24
-20
@@ -1,46 +1,50 @@
|
||||
// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY
|
||||
|
||||
import kotlin.Deprecated as ___
|
||||
import kotlin.Deprecated as <!UNDERSCORE_IS_RESERVED!>___<!>
|
||||
|
||||
@___("") data class Pair(val x: Int, val y: Int)
|
||||
|
||||
class _<________>
|
||||
val ______ = _<Int>()
|
||||
class <!UNDERSCORE_IS_RESERVED, UNDERSCORE_IS_RESERVED!>_<!><<!UNDERSCORE_IS_RESERVED!>________<!>>
|
||||
val <!UNDERSCORE_IS_RESERVED!>______<!> = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>()
|
||||
|
||||
fun __(___: Int, y: _<Int>?): Int {
|
||||
val (_, z) = Pair(___ - 1, 42)
|
||||
val (x, __________) = Pair(___ - 1, 42)
|
||||
val ____ = x
|
||||
fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>?): Int {
|
||||
val (_, z) = Pair(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!> - 1, 42)
|
||||
val (x, <!UNDERSCORE_IS_RESERVED!>__________<!>) = Pair(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!> - 1, 42)
|
||||
val <!UNDERSCORE_IS_RESERVED!>____<!> = x
|
||||
// in backquotes: allowed
|
||||
val `_` = __________
|
||||
val `_` = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__________<!>
|
||||
|
||||
val q = fun(_: Int, __: Int) {}
|
||||
val q = fun(_: Int, <!UNDERSCORE_IS_RESERVED!>__<!>: Int) {}
|
||||
q(1, 2)
|
||||
|
||||
val _ = 56
|
||||
val <!UNDERSCORE_IS_RESERVED!>_<!> = 56
|
||||
|
||||
fun localFun(_: String) = 1
|
||||
fun localFun(<!UNDERSCORE_IS_RESERVED!>_<!>: String) = 1
|
||||
|
||||
__@ return if (y != null) __(____, y) else __(`_`, ______)
|
||||
<!UNDERSCORE_IS_RESERVED!>__<!>@ return if (y != null) <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>, y) else <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(`_`, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>______<!>)
|
||||
}
|
||||
|
||||
|
||||
class A1(val _: String)
|
||||
class A2(_: String) {
|
||||
class A1(val <!UNDERSCORE_IS_RESERVED, UNDERSCORE_IS_RESERVED!>_<!>: String)
|
||||
class A2(<!UNDERSCORE_IS_RESERVED!>_<!>: String) {
|
||||
class B {
|
||||
typealias _ = CharSequence
|
||||
typealias <!UNDERSCORE_IS_RESERVED!>_<!> = CharSequence
|
||||
}
|
||||
val _: Int = 1
|
||||
val <!UNDERSCORE_IS_RESERVED!>_<!>: Int = 1
|
||||
|
||||
fun _() {}
|
||||
fun <!UNDERSCORE_IS_RESERVED!>_<!>() {}
|
||||
|
||||
fun foo(_: Double) {}
|
||||
fun foo(<!UNDERSCORE_IS_RESERVED!>_<!>: Double) {}
|
||||
}
|
||||
|
||||
// one underscore parameters for named function are still prohibited
|
||||
fun oneUnderscore(_: Int) {}
|
||||
fun oneUnderscore(<!UNDERSCORE_IS_RESERVED!>_<!>: Int) {}
|
||||
|
||||
fun doIt(f: (Any?) -> Any?) = f(null)
|
||||
|
||||
val something = doIt { __ -> __ }
|
||||
val something = doIt { <!UNDERSCORE_IS_RESERVED!>__<!> -> <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!> }
|
||||
val something2 = doIt { _ -> 1 }
|
||||
|
||||
var p: Int?
|
||||
get() = null
|
||||
set(_) {}
|
||||
|
||||
@@ -44,3 +44,7 @@ fun doIt(f: (Any?) -> Any?) = f(null)
|
||||
|
||||
val something = doIt { <!UNDERSCORE_IS_RESERVED!>__<!> -> <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!> }
|
||||
val something2 = doIt { _ -> 1 }
|
||||
|
||||
var p: Int?
|
||||
get() = null
|
||||
set(_) {}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY
|
||||
|
||||
fun test(`_`: Int) {
|
||||
_ + 1
|
||||
`_` + 1
|
||||
}
|
||||
|
||||
fun `__`() {}
|
||||
|
||||
fun testCall() {
|
||||
__()
|
||||
`__`()
|
||||
}
|
||||
|
||||
val testCallableRef = ::__
|
||||
val testCallableRef2 = ::`__`
|
||||
|
||||
|
||||
object Host {
|
||||
val `_` = 42
|
||||
object `__` {
|
||||
val bar = 4
|
||||
}
|
||||
}
|
||||
|
||||
val testQualified = Host._
|
||||
val testQualified2 = Host.`_`
|
||||
|
||||
object `___` {
|
||||
val test = 42
|
||||
}
|
||||
|
||||
val testQualifier = ___.test
|
||||
val testQualifier2 = `___`.test
|
||||
val testQualifier3 = Host.__.bar
|
||||
val testQualifier4 = Host.`__`.bar
|
||||
|
||||
fun testCallableRefLHSValue(`_`: Any) = _::toString
|
||||
fun testCallableRefLHSValue2(`_`: Any) = `_`::toString
|
||||
|
||||
val testCallableRefLHSObject = ___::toString
|
||||
val testCallableRefLHSObject2 = `___`::toString
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY
|
||||
|
||||
fun test(`_`: Int) {
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
class `___` {
|
||||
class `____`
|
||||
}
|
||||
|
||||
val testCallableRefLHSType = ___::toString
|
||||
val testCallableRefLHSType2 = `___`::toString
|
||||
|
||||
val testClassLiteralLHSType = ___::class
|
||||
val testClassLiteralLHSType2 = `___`::class
|
||||
|
||||
val tesLHSTypeFQN = `___`.____::class
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class `___` {
|
||||
class `____`
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY
|
||||
|
||||
class `_`<`__`> {
|
||||
fun testTypeArgument(x: List<__>) = x
|
||||
fun testTypeArgument2(x: List<`__`>) = x
|
||||
}
|
||||
|
||||
fun _<Any>.testTypeConstructor() {}
|
||||
fun `_`<Any>.testTypeConstructor2() {}
|
||||
|
||||
val testConstructor = _<Any>()
|
||||
val testConstructor2 = `_`<Any>()
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -DEPRECATION -TOPLEVEL_TYPEALIASES_ONLY
|
||||
|
||||
class `_`<`__`> {
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
object Host {
|
||||
val `____` = { -> }
|
||||
fun testFunTypeVal() {
|
||||
____()
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
object Host {
|
||||
val `____` = { -> }
|
||||
fun testFunTypeVal() {
|
||||
|
||||
Vendored
+9
-9
@@ -11,39 +11,39 @@ class C {
|
||||
|
||||
fun test() {
|
||||
for ((x, _) in C()) {
|
||||
foo(x, <!UNRESOLVED_REFERENCE!>_<!>)
|
||||
foo(x, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>)
|
||||
}
|
||||
|
||||
for ((_, y) in C()) {
|
||||
foo(<!UNRESOLVED_REFERENCE!>_<!>, y)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>, y)
|
||||
}
|
||||
|
||||
for ((_, _) in C()) {
|
||||
foo(<!UNRESOLVED_REFERENCE!>_<!>, <!UNRESOLVED_REFERENCE!>_<!>)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>)
|
||||
}
|
||||
|
||||
for ((_ : Int, _ : String) in C()) {
|
||||
foo(<!UNRESOLVED_REFERENCE!>_<!>, <!UNRESOLVED_REFERENCE!>_<!>)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>)
|
||||
}
|
||||
|
||||
for ((_ : String, _ : Int) in C()) {
|
||||
foo(<!UNRESOLVED_REFERENCE!>_<!>, <!UNRESOLVED_REFERENCE!>_<!>)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>)
|
||||
}
|
||||
|
||||
val (x, _) = A()
|
||||
val (_, y) = A()
|
||||
|
||||
foo(x, y)
|
||||
foo(x, <!UNRESOLVED_REFERENCE!>_<!>)
|
||||
foo(<!UNRESOLVED_REFERENCE!>_<!>, y)
|
||||
foo(x, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>, y)
|
||||
|
||||
val (`_`, z) = A()
|
||||
|
||||
foo(_, z)
|
||||
foo(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>, z)
|
||||
|
||||
val (_, `_`) = A()
|
||||
|
||||
foo(<!ARGUMENT_TYPE_MISMATCH!>_<!>, y)
|
||||
foo(<!ARGUMENT_TYPE_MISMATCH, UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>, y)
|
||||
|
||||
val (unused, _) = A()
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ fun foo() {
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
`_`.stackTrace
|
||||
val y1 = _
|
||||
val y1 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>
|
||||
val y2 = (`_`)
|
||||
}
|
||||
try {
|
||||
|
||||
Vendored
+1
-1
@@ -29,7 +29,7 @@ fun foo() {
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
`_`.stackTrace
|
||||
val y1 = _
|
||||
val y1 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!>
|
||||
val y2 = (`_`)
|
||||
}
|
||||
try {
|
||||
|
||||
+6
-1
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1
|
||||
import org.jetbrains.kotlin.checkers.utils.TypeOfCall
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
||||
import org.jetbrains.kotlin.test.directives.AdditionalFilesDirectives
|
||||
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives
|
||||
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
|
||||
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
|
||||
@@ -70,7 +72,10 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
|
||||
|
||||
for (file in module.files) {
|
||||
val firFile = info.firFiles[file] ?: continue
|
||||
val diagnostics = diagnosticsPerFile[firFile] ?: continue
|
||||
var diagnostics = diagnosticsPerFile[firFile] ?: continue
|
||||
if (AdditionalFilesDirectives.CHECK_TYPE in module.directives) {
|
||||
diagnostics = diagnostics.filter { it.factory.name != Errors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
|
||||
}
|
||||
val diagnosticsMetadataInfos = diagnostics.mapNotNull { diagnostic ->
|
||||
if (!diagnosticsService.shouldRenderDiagnostic(module, diagnostic.factory.name)) return@mapNotNull null
|
||||
// SYNTAX errors will be reported later
|
||||
|
||||
+2
-2
@@ -21,10 +21,10 @@ val value_3 = <!UNRESOLVED_REFERENCE!>_____________0000<!>
|
||||
val value_4 = <!UNRESOLVED_REFERENCE!>_______________________________________________________________________________________________________________________________________________________0<!>
|
||||
|
||||
// TESTCASE NUMBER: 5
|
||||
val value_5 = <!UNRESOLVED_REFERENCE!>____________________________________________________<!>
|
||||
val value_5 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>____________________________________________________<!>
|
||||
|
||||
// TESTCASE NUMBER: 6
|
||||
val value_6 = <!UNRESOLVED_REFERENCE!>_<!>
|
||||
val value_6 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>
|
||||
|
||||
// TESTCASE NUMBER: 7
|
||||
val value_7 = <!UNRESOLVED_REFERENCE!>_0_<!>
|
||||
|
||||
+2
-2
@@ -21,10 +21,10 @@ val value_3 = <!UNRESOLVED_REFERENCE!>_____________0000<!>
|
||||
val value_4 = <!UNRESOLVED_REFERENCE!>_______________________________________________________________________________________________________________________________________________________0<!>
|
||||
|
||||
// TESTCASE NUMBER: 5
|
||||
val value_5 = <!UNRESOLVED_REFERENCE!>____________________________________________________<!>
|
||||
val value_5 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>____________________________________________________<!>
|
||||
|
||||
// TESTCASE NUMBER: 6
|
||||
val value_6 = <!UNRESOLVED_REFERENCE!>_<!>
|
||||
val value_6 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>
|
||||
|
||||
// TESTCASE NUMBER: 7
|
||||
val value_7 = <!UNRESOLVED_REFERENCE!>_0_<!>
|
||||
|
||||
+2
-2
@@ -21,10 +21,10 @@ val value_3 = <!UNRESOLVED_REFERENCE!>_____________0000<!>
|
||||
val value_4 = <!UNRESOLVED_REFERENCE!>_______________________________________________________________________________________________________________________________________________________0<!>
|
||||
|
||||
// TESTCASE NUMBER: 5
|
||||
val value_5 = <!UNRESOLVED_REFERENCE!>____________________________________________________<!>
|
||||
val value_5 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>____________________________________________________<!>
|
||||
|
||||
// TESTCASE NUMBER: 6
|
||||
val value_6 = <!UNRESOLVED_REFERENCE!>_<!>
|
||||
val value_6 = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>
|
||||
|
||||
// TESTCASE NUMBER: 7
|
||||
val value_7 = <!UNRESOLVED_REFERENCE!>_0_<!>
|
||||
|
||||
+12
@@ -1960,6 +1960,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.UNDERSCORE_IS_RESERVED) { firDiagnostic ->
|
||||
UnderscoreIsReservedImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS) { firDiagnostic ->
|
||||
UnderscoreUsageWithoutBackticksImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TOPLEVEL_TYPEALIASES_ONLY) { firDiagnostic ->
|
||||
ToplevelTypealiasesOnlyImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
|
||||
+8
@@ -1371,6 +1371,14 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val candidates: List<KtSymbol>
|
||||
}
|
||||
|
||||
abstract class UnderscoreIsReserved : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = UnderscoreIsReserved::class
|
||||
}
|
||||
|
||||
abstract class UnderscoreUsageWithoutBackticks : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = UnderscoreUsageWithoutBackticks::class
|
||||
}
|
||||
|
||||
abstract class ToplevelTypealiasesOnly : KtFirDiagnostic<KtTypeAlias>() {
|
||||
override val diagnosticClass get() = ToplevelTypealiasesOnly::class
|
||||
}
|
||||
|
||||
+14
@@ -2224,6 +2224,20 @@ internal class DelegateSpecialFunctionNoneApplicableImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class UnderscoreIsReservedImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.UnderscoreIsReserved(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class UnderscoreUsageWithoutBackticksImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.UnderscoreUsageWithoutBackticks(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ToplevelTypealiasesOnlyImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
|
||||
Reference in New Issue
Block a user