[FIR] Optimize performance and fix UNDERSCORE_IS_RESERVED, simplify code
This commit is contained in:
+2
-2
@@ -1068,8 +1068,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
parameter<ConeKotlinType>("actualType")
|
parameter<ConeKotlinType>("actualType")
|
||||||
}
|
}
|
||||||
|
|
||||||
val UNDERSCORE_IS_RESERVED by error<KtElement>(PositioningStrategy.RESERVED_UNDERSCORE)
|
val UNDERSCORE_IS_RESERVED by error<PsiElement>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<KtElement>(PositioningStrategy.RESERVED_UNDERSCORE)
|
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<PsiElement>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||||
|
|
||||||
val EQUALITY_NOT_APPLICABLE by error<KtBinaryExpression> {
|
val EQUALITY_NOT_APPLICABLE by error<KtBinaryExpression> {
|
||||||
parameter<String>("operator")
|
parameter<String>("operator")
|
||||||
|
|||||||
+2
-2
@@ -554,8 +554,8 @@ object FirErrors {
|
|||||||
val DELEGATE_SPECIAL_FUNCTION_AMBIGUITY by error2<KtExpression, String, Collection<FirBasedSymbol<*>>>()
|
val DELEGATE_SPECIAL_FUNCTION_AMBIGUITY by error2<KtExpression, String, Collection<FirBasedSymbol<*>>>()
|
||||||
val DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE by error2<KtExpression, String, Collection<FirBasedSymbol<*>>>()
|
val DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE by error2<KtExpression, String, Collection<FirBasedSymbol<*>>>()
|
||||||
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error3<KtExpression, String, ConeKotlinType, ConeKotlinType>()
|
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error3<KtExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||||
val UNDERSCORE_IS_RESERVED by error0<KtElement>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
val UNDERSCORE_IS_RESERVED by error0<PsiElement>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<KtElement>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<PsiElement>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||||
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||||
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||||
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||||
|
|||||||
+92
-130
@@ -5,108 +5,34 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
import com.intellij.lang.LighterASTNode
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiNameIdentifierOwner
|
import com.intellij.psi.PsiNameIdentifierOwner
|
||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.FirLightSourceElement
|
|
||||||
import org.jetbrains.kotlin.fir.FirPsiSourceElement
|
|
||||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
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.declaration.FirBasicDeclarationChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
|
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeUnderscoreUsageWithoutBackticks
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.text
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtDotQualifiedExpressionElementType
|
import org.jetbrains.kotlin.psi.KtTypeProjection
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType
|
import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.elements.KtTypeProjectionElementType
|
||||||
|
|
||||||
object FirReservedUnderscoreExpressionChecker : FirBasicExpressionChecker() {
|
object FirReservedUnderscoreExpressionChecker : FirBasicExpressionChecker() {
|
||||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val source = expression.source
|
when (expression) {
|
||||||
|
is FirResolvable -> {
|
||||||
if (expression is FirFunctionCall) {
|
reportIfUnderscore(expression.calleeReference.source, context, reporter, isExpression = true)
|
||||||
val calleeReferenceSource = expression.calleeReference.source
|
|
||||||
if (calleeReferenceSource is FirLightSourceElement && calleeReferenceSource.lighterASTNode.tokenType == KtNodeTypes.OPERATION_REFERENCE) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
is FirResolvedQualifier -> {
|
||||||
reportIfUnderscore(
|
for (reservedUnderscoreDiagnostic in expression.nonFatalDiagnostics.filterIsInstance<ConeUnderscoreUsageWithoutBackticks>()) {
|
||||||
expression.calleeReference.source.text, expression.calleeReference.source, context, reporter,
|
reporter.reportOn(reservedUnderscoreDiagnostic.source, FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS, context)
|
||||||
isExpression = true
|
|
||||||
)
|
|
||||||
} else if (expression is FirQualifiedAccess) {
|
|
||||||
if (source is FirPsiSourceElement) {
|
|
||||||
reportIfUnderscoreInQualifiedAccess(source, expression, context, reporter)
|
|
||||||
} else if (source is FirLightSourceElement) {
|
|
||||||
reportIfUnderscoreInQualifiedAccess(source, expression, context, reporter)
|
|
||||||
}
|
|
||||||
} else if (expression is FirGetClassCall) {
|
|
||||||
for (argument in expression.argumentList.arguments) {
|
|
||||||
reportIfUnderscore(argument.source.text, expression.source, context, reporter, isExpression = true)
|
|
||||||
}
|
|
||||||
} else if (expression is FirReturnExpression) {
|
|
||||||
var labelName: String? = null
|
|
||||||
if (source is FirPsiSourceElement) {
|
|
||||||
labelName = (source.psi.parent as? KtLabeledExpression)?.getLabelName()
|
|
||||||
} else if (source is FirLightSourceElement) {
|
|
||||||
val parent = source.treeStructure.getParent(source.lighterASTNode)
|
|
||||||
if (parent != null && parent.tokenType == KtNodeTypes.LABELED_EXPRESSION) {
|
|
||||||
labelName = source.treeStructure.findDescendantByType(parent, KtNodeTypes.LABEL).toString()
|
|
||||||
labelName = labelName.substring(0, labelName.length - 1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reportIfUnderscore(labelName, expression.source, context, reporter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reportIfUnderscoreInQualifiedAccess(
|
|
||||||
source: FirPsiSourceElement,
|
|
||||||
expression: FirStatement,
|
|
||||||
context: CheckerContext,
|
|
||||||
reporter: DiagnosticReporter
|
|
||||||
) {
|
|
||||||
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 = source.psi
|
|
||||||
if (psi.parent !is KtDotQualifiedExpression && psi.parent !is KtCallableReferenceExpression) {
|
|
||||||
processQualifiedAccess(psi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reportIfUnderscoreInQualifiedAccess(
|
|
||||||
source: FirLightSourceElement,
|
|
||||||
expression: FirStatement,
|
|
||||||
context: CheckerContext,
|
|
||||||
reporter: DiagnosticReporter
|
|
||||||
) {
|
|
||||||
fun processQualifiedAccess(lightSourceElement: LighterASTNode?) {
|
|
||||||
val tokenType = lightSourceElement?.tokenType
|
|
||||||
if (tokenType is KtNameReferenceExpressionElementType) {
|
|
||||||
reportIfUnderscore(lightSourceElement.toString(), expression.source, context, reporter, isExpression = true)
|
|
||||||
} else if (lightSourceElement != null && (tokenType is KtDotQualifiedExpressionElementType || tokenType == KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION)) {
|
|
||||||
val children = lightSourceElement.getChildren(source.treeStructure)
|
|
||||||
processQualifiedAccess(children.first())
|
|
||||||
processQualifiedAccess(children.last())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val astNode = source.lighterASTNode
|
|
||||||
val parent = source.treeStructure.getParent(astNode)
|
|
||||||
if (parent?.tokenType !is KtDotQualifiedExpressionElementType && parent?.tokenType != KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION) {
|
|
||||||
processQualifiedAccess(astNode)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,27 +40,29 @@ object FirReservedUnderscoreExpressionChecker : FirBasicExpressionChecker() {
|
|||||||
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
|
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
|
||||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (
|
if (
|
||||||
declaration is FirClass ||
|
declaration is FirRegularClass ||
|
||||||
declaration is FirFunction ||
|
|
||||||
declaration is FirTypeParameter ||
|
declaration is FirTypeParameter ||
|
||||||
declaration is FirProperty ||
|
declaration is FirProperty ||
|
||||||
declaration is FirTypeAlias
|
declaration is FirTypeAlias
|
||||||
) {
|
) {
|
||||||
reportIfUnderscore(declaration, context, reporter)
|
reportIfUnderscore(declaration, context, reporter)
|
||||||
|
} else if (declaration is FirFunction) {
|
||||||
|
if (declaration is FirSimpleFunction) {
|
||||||
|
reportIfUnderscore(declaration, context, reporter)
|
||||||
|
}
|
||||||
|
|
||||||
if (declaration is FirFunction) {
|
val isSingleUnderscoreAllowed = declaration is FirAnonymousFunction || declaration is FirPropertyAccessor
|
||||||
for (parameter in declaration.valueParameters) {
|
for (parameter in declaration.valueParameters) {
|
||||||
reportIfUnderscore(
|
reportIfUnderscore(
|
||||||
parameter,
|
parameter,
|
||||||
context,
|
context,
|
||||||
reporter,
|
reporter,
|
||||||
isSingleUnderscoreAllowed = declaration is FirAnonymousFunction || declaration is FirPropertyAccessor
|
isSingleUnderscoreAllowed = isSingleUnderscoreAllowed
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (declaration is FirFile) {
|
} else if (declaration is FirFile) {
|
||||||
for (import in declaration.imports) {
|
for (import in declaration.imports) {
|
||||||
reportIfUnderscore(import.aliasName?.asString(), import.source, context, reporter)
|
reportIfUnderscore(import.aliasSource, context, reporter, isExpression = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,64 +74,98 @@ private fun reportIfUnderscore(
|
|||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
isSingleUnderscoreAllowed: Boolean = false
|
isSingleUnderscoreAllowed: Boolean = false
|
||||||
) {
|
) {
|
||||||
val source = declaration.source
|
val declarationSource = declaration.source
|
||||||
val rawIdentifier = when (source) {
|
val rawName = when (declarationSource) {
|
||||||
is FirPsiSourceElement ->
|
is FirPsiSourceElement ->
|
||||||
(source.psi as? PsiNameIdentifierOwner)?.nameIdentifier?.text
|
(declarationSource.psi as? PsiNameIdentifierOwner)?.nameIdentifier?.text
|
||||||
is FirLightSourceElement ->
|
is FirLightSourceElement ->
|
||||||
source.treeStructure.nameIdentifier(source.lighterASTNode)?.toString()
|
declarationSource.treeStructure.nameIdentifier(declarationSource.lighterASTNode)?.toString()
|
||||||
else ->
|
else ->
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
reportIfUnderscore(rawIdentifier, source, context, reporter, isSingleUnderscoreAllowed)
|
reportIfUnderscore(rawName, declarationSource, context, reporter, isSingleUnderscoreAllowed)
|
||||||
|
|
||||||
val returnOrReceiverTypeRef = when (declaration) {
|
val returnOrReceiverTypeRef = when (declaration) {
|
||||||
is FirValueParameter -> declaration.returnTypeRef.source
|
is FirValueParameter -> declaration.returnTypeRef
|
||||||
is FirFunction -> declaration.receiverTypeRef?.source
|
is FirFunction -> declaration.receiverTypeRef
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
val isReportUnderscoreInReturnOrReceiverTypeRef = when (returnOrReceiverTypeRef) {
|
if (returnOrReceiverTypeRef is FirResolvedTypeRef) {
|
||||||
is FirPsiSourceElement -> {
|
val delegatedTypeRef = returnOrReceiverTypeRef.delegatedTypeRef
|
||||||
val psi = returnOrReceiverTypeRef.psi
|
if (delegatedTypeRef is FirUserTypeRef) {
|
||||||
psi is KtTypeReference && psi.anyDescendantOfType<LeafPsiElement> { isUnderscore(it.text) }
|
for (qualifierPart in delegatedTypeRef.qualifier) {
|
||||||
}
|
reportIfUnderscore(qualifierPart.source, context, reporter, isExpression = true)
|
||||||
is FirLightSourceElement -> {
|
|
||||||
val lighterASTNode = returnOrReceiverTypeRef.lighterASTNode
|
|
||||||
lighterASTNode.tokenType == KtNodeTypes.TYPE_REFERENCE &&
|
|
||||||
source?.treeStructure?.findFirstDescendant(lighterASTNode)
|
|
||||||
{ it.tokenType == KtNodeTypes.REFERENCE_EXPRESSION && isUnderscore(it.toString()) } != null
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isReportUnderscoreInReturnOrReceiverTypeRef) {
|
for (typeArgument in qualifierPart.typeArgumentList.typeArguments) {
|
||||||
reporter.reportOn(returnOrReceiverTypeRef, FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS, context)
|
reportIfUnderscore(typeArgument.source, context, reporter, isExpression = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reportIfUnderscore(
|
private fun reportIfUnderscore(
|
||||||
text: CharSequence?,
|
|
||||||
source: FirSourceElement?,
|
source: FirSourceElement?,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
isSingleUnderscoreAllowed: Boolean = false,
|
isExpression: Boolean
|
||||||
isExpression: Boolean = false
|
|
||||||
) {
|
) {
|
||||||
if (text == null || isSingleUnderscoreAllowed && text == "_") {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUnderscore(text)) {
|
if (rawName.isUnderscore && source.kind !is FirFakeSourceElementKind) {
|
||||||
reporter.reportOn(
|
reporter.reportOn(
|
||||||
source,
|
source,
|
||||||
if (isExpression) FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS else FirErrors.UNDERSCORE_IS_RESERVED,
|
FirErrors.UNDERSCORE_IS_RESERVED,
|
||||||
context
|
context
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isUnderscore(text: CharSequence) = text.all { it == '_' }
|
val CharSequence.isUnderscore: Boolean
|
||||||
|
get() = all { it == '_' }
|
||||||
|
|
||||||
|
|||||||
+10
@@ -387,6 +387,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_OF
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_ON_LHS_OF_DOT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_ON_LHS_OF_DOT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_VARIANCE_CONFLICT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_VARIANCE_CONFLICT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNDERSCORE_IS_RESERVED
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNEXPECTED_SAFE_CALL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNEXPECTED_SAFE_CALL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_COMPANION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_COMPANION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_ENTRY
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_ENUM_ENTRY
|
||||||
@@ -1388,6 +1390,14 @@ class FirDefaultErrorMessages {
|
|||||||
RENDER_TYPE,
|
RENDER_TYPE,
|
||||||
RENDER_TYPE,
|
RENDER_TYPE,
|
||||||
)
|
)
|
||||||
|
map.put(
|
||||||
|
UNDERSCORE_IS_RESERVED,
|
||||||
|
"Names _, __, ___, ..., are reserved in Kotlin"
|
||||||
|
)
|
||||||
|
map.put(
|
||||||
|
UNDERSCORE_USAGE_WITHOUT_BACKTICKS,
|
||||||
|
"Names _, __, ___, ... can be used only in back-ticks (`_`, `__`, `___`, ...)"
|
||||||
|
)
|
||||||
map.put(
|
map.put(
|
||||||
EQUALITY_NOT_APPLICABLE,
|
EQUALITY_NOT_APPLICABLE,
|
||||||
"Operator ''{0}'' cannot be applied to ''{1}'' and ''{2}''",
|
"Operator ''{0}'' cannot be applied to ''{1}'' and ''{2}''",
|
||||||
|
|||||||
+6
-13
@@ -715,20 +715,13 @@ object LightTreePositioningStrategies {
|
|||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||||
): List<TextRange> {
|
): List<TextRange> {
|
||||||
if (node.tokenType == KtNodeTypes.RETURN) {
|
val nameIdentifier = tree.nameIdentifier(node)
|
||||||
val parent = tree.getParent(node)
|
if (nameIdentifier != null) {
|
||||||
if (parent != null) {
|
return markElement(nameIdentifier, startOffset, endOffset, tree, node)
|
||||||
val label = tree.findDescendantByType(parent, KtNodeTypes.LABEL)
|
}
|
||||||
if (label != null) {
|
if (node.tokenType == KtNodeTypes.LABEL_QUALIFIER) {
|
||||||
return markElement(label, startOffset, endOffset - 1, tree, node)
|
return super.mark(node, startOffset, endOffset - 1, tree)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val descendants =
|
|
||||||
tree.collectDescendantsOfType(node, KtTokens.IDENTIFIER) { descendant -> descendant.toString().all { it == '_' } }
|
|
||||||
if (descendants.isNotEmpty())
|
|
||||||
return descendants.map { markSingleElement(it, it, startOffset, endOffset, tree, node) }
|
|
||||||
return super.mark(node, startOffset, endOffset, tree)
|
return super.mark(node, startOffset, endOffset, tree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-6
@@ -19,10 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction
|
|||||||
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
|
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeNotAnnotationContainer
|
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||||
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.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
||||||
@@ -969,9 +966,16 @@ class ExpressionsConverter(
|
|||||||
private fun convertSimpleNameExpression(referenceExpression: LighterASTNode): FirQualifiedAccessExpression {
|
private fun convertSimpleNameExpression(referenceExpression: LighterASTNode): FirQualifiedAccessExpression {
|
||||||
return buildQualifiedAccessExpression {
|
return buildQualifiedAccessExpression {
|
||||||
source = referenceExpression.toFirSourceElement()
|
source = referenceExpression.toFirSourceElement()
|
||||||
|
|
||||||
|
val nameSource = this@buildQualifiedAccessExpression.source
|
||||||
|
val rawText = referenceExpression.asText
|
||||||
|
if (nameSource != null && rawText.isUnderscore) {
|
||||||
|
nonFatalDiagnostics.add(ConeUnderscoreUsageWithoutBackticks(nameSource))
|
||||||
|
}
|
||||||
|
|
||||||
calleeReference = buildSimpleNamedReference {
|
calleeReference = buildSimpleNamedReference {
|
||||||
source = this@buildQualifiedAccessExpression.source
|
source = nameSource
|
||||||
name = referenceExpression.asText.nameAsSafeName()
|
name = rawText.nameAsSafeName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1054,7 +1054,7 @@ open class RawFirBuilder(
|
|||||||
null,
|
null,
|
||||||
ClassKind.CLASS,
|
ClassKind.CLASS,
|
||||||
containerTypeParameters = emptyList(),
|
containerTypeParameters = emptyList(),
|
||||||
containingClassIsExpectClass = false
|
containingClassIsExpectClass = false
|
||||||
)
|
)
|
||||||
|
|
||||||
for (declaration in objectDeclaration.declarations) {
|
for (declaration in objectDeclaration.declarations) {
|
||||||
@@ -1667,7 +1667,20 @@ open class RawFirBuilder(
|
|||||||
expression.getQualifiedExpressionForSelector() != null -> expression.parent
|
expression.getQualifiedExpressionForSelector() != null -> expression.parent
|
||||||
else -> expression
|
else -> expression
|
||||||
}.toFirSourceElement()
|
}.toFirSourceElement()
|
||||||
return generateAccessExpression(qualifiedSource, expression.toFirSourceElement(), expression.getReferencedNameAsName())
|
|
||||||
|
val expressionSource = expression.toFirSourceElement()
|
||||||
|
var diagnostic: ConeDiagnostic? = null
|
||||||
|
val rawText = expression.getReferencedNameElement().node.text
|
||||||
|
if (rawText.isUnderscore) {
|
||||||
|
diagnostic = ConeUnderscoreUsageWithoutBackticks(expressionSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateAccessExpression(
|
||||||
|
qualifiedSource,
|
||||||
|
expressionSource,
|
||||||
|
expression.getReferencedNameAsName(),
|
||||||
|
diagnostic
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit): FirElement =
|
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit): FirElement =
|
||||||
|
|||||||
+6
-1
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirVariable
|
|||||||
import org.jetbrains.kotlin.fir.declarations.builder.*
|
import org.jetbrains.kotlin.fir.declarations.builder.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||||
@@ -250,7 +251,8 @@ private fun FirExpression.createConventionCall(
|
|||||||
fun generateAccessExpression(
|
fun generateAccessExpression(
|
||||||
qualifiedSource: FirSourceElement?,
|
qualifiedSource: FirSourceElement?,
|
||||||
calleeReferenceSource: FirSourceElement?,
|
calleeReferenceSource: FirSourceElement?,
|
||||||
name: Name
|
name: Name,
|
||||||
|
diagnostic: ConeDiagnostic? = null
|
||||||
): FirQualifiedAccessExpression =
|
): FirQualifiedAccessExpression =
|
||||||
buildQualifiedAccessExpression {
|
buildQualifiedAccessExpression {
|
||||||
this.source = qualifiedSource
|
this.source = qualifiedSource
|
||||||
@@ -258,6 +260,9 @@ fun generateAccessExpression(
|
|||||||
this.source = calleeReferenceSource
|
this.source = calleeReferenceSource
|
||||||
this.name = name
|
this.name = name
|
||||||
}
|
}
|
||||||
|
if (diagnostic != null) {
|
||||||
|
this.nonFatalDiagnostics.add(diagnostic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateResolvedAccessExpression(source: FirSourceElement?, variable: FirVariable): FirQualifiedAccessExpression =
|
fun generateResolvedAccessExpression(source: FirSourceElement?, variable: FirVariable): FirQualifiedAccessExpression =
|
||||||
|
|||||||
@@ -844,20 +844,10 @@ object PositioningStrategies {
|
|||||||
if (nameIdentifier != null) {
|
if (nameIdentifier != null) {
|
||||||
return super.mark(nameIdentifier)
|
return super.mark(nameIdentifier)
|
||||||
}
|
}
|
||||||
} else if (element is KtImportDirective) {
|
} else if (element is KtLabelReferenceExpression) {
|
||||||
return super.mark(element.alias?.nameIdentifier ?: element)
|
return super.mark(element.getReferencedNameElement())
|
||||||
} 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)
|
return super.mark(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-3
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
import kotlin.Deprecated as <!UNDERSCORE_IS_RESERVED!>___<!>
|
import kotlin.Deprecated as <!UNDERSCORE_IS_RESERVED!>___<!>
|
||||||
|
|
||||||
@___("") data class Pair(val x: Int, val y: Int)
|
@<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>___<!>("") data class Pair(val x: Int, val y: Int)
|
||||||
|
|
||||||
class <!UNDERSCORE_IS_RESERVED, UNDERSCORE_IS_RESERVED!>_<!><<!UNDERSCORE_IS_RESERVED!>________<!>>
|
class <!UNDERSCORE_IS_RESERVED!>_<!><<!UNDERSCORE_IS_RESERVED!>________<!>>
|
||||||
val <!UNDERSCORE_IS_RESERVED!>______<!> = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>()
|
val <!UNDERSCORE_IS_RESERVED!>______<!> = <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>()
|
||||||
|
|
||||||
fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>?): Int {
|
fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>_<!><Int>?): Int {
|
||||||
@@ -25,7 +25,7 @@ fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: <!
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class A1(val <!UNDERSCORE_IS_RESERVED, UNDERSCORE_IS_RESERVED!>_<!>: String)
|
class A1(val <!UNDERSCORE_IS_RESERVED!>_<!>: String)
|
||||||
class A2(<!UNDERSCORE_IS_RESERVED!>_<!>: String) {
|
class A2(<!UNDERSCORE_IS_RESERVED!>_<!>: String) {
|
||||||
class B {
|
class B {
|
||||||
typealias <!UNDERSCORE_IS_RESERVED!>_<!> = CharSequence
|
typealias <!UNDERSCORE_IS_RESERVED!>_<!> = CharSequence
|
||||||
@@ -48,3 +48,13 @@ val something2 = doIt { _ -> 1 }
|
|||||||
var p: Int?
|
var p: Int?
|
||||||
get() = null
|
get() = null
|
||||||
set(_) {}
|
set(_) {}
|
||||||
|
|
||||||
|
object `____` {
|
||||||
|
object Nested {
|
||||||
|
fun method() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>.Nested.method()
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,3 +48,13 @@ val something2 = doIt { _ -> 1 }
|
|||||||
var p: Int?
|
var p: Int?
|
||||||
get() = null
|
get() = null
|
||||||
set(_) {}
|
set(_) {}
|
||||||
|
|
||||||
|
object `____` {
|
||||||
|
object Nested {
|
||||||
|
fun method() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>.Nested.method()
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public val something2: kotlin.Any?
|
|||||||
public fun __(/*0*/ ___: kotlin.Int, /*1*/ y: _<kotlin.Int>?): kotlin.Int
|
public fun __(/*0*/ ___: kotlin.Int, /*1*/ y: _<kotlin.Int>?): kotlin.Int
|
||||||
public fun doIt(/*0*/ f: (kotlin.Any?) -> kotlin.Any?): kotlin.Any?
|
public fun doIt(/*0*/ f: (kotlin.Any?) -> kotlin.Any?): kotlin.Any?
|
||||||
public fun oneUnderscore(/*0*/ <anonymous parameter 0>: kotlin.Int): kotlin.Unit
|
public fun oneUnderscore(/*0*/ <anonymous parameter 0>: kotlin.Int): kotlin.Unit
|
||||||
|
public fun test(): kotlin.Unit
|
||||||
|
|
||||||
public final class A1 {
|
public final class A1 {
|
||||||
public constructor A1(/*0*/ _: kotlin.String)
|
public constructor A1(/*0*/ _: kotlin.String)
|
||||||
@@ -53,3 +54,18 @@ public final class _</*0*/ ________> {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object ____ {
|
||||||
|
private constructor ____()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
public object Nested {
|
||||||
|
private constructor Nested()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final fun method(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
package test
|
|
||||||
|
|
||||||
annotation class `__`(val value: String)
|
|
||||||
|
|
||||||
@__("") class TestAnn
|
|
||||||
@`__`("") class TestAnn2
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
package test
|
package test
|
||||||
|
|
||||||
annotation class `__`(val value: String)
|
annotation class `__`(val value: String)
|
||||||
|
|||||||
+2
-2
@@ -2003,11 +2003,11 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract val actualType: KtType
|
abstract val actualType: KtType
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class UnderscoreIsReserved : KtFirDiagnostic<KtElement>() {
|
abstract class UnderscoreIsReserved : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = UnderscoreIsReserved::class
|
override val diagnosticClass get() = UnderscoreIsReserved::class
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class UnderscoreUsageWithoutBackticks : KtFirDiagnostic<KtElement>() {
|
abstract class UnderscoreUsageWithoutBackticks : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = UnderscoreUsageWithoutBackticks::class
|
override val diagnosticClass get() = UnderscoreUsageWithoutBackticks::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -3228,14 +3228,14 @@ internal class DelegateSpecialFunctionReturnTypeMismatchImpl(
|
|||||||
internal class UnderscoreIsReservedImpl(
|
internal class UnderscoreIsReservedImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.UnderscoreIsReserved(), KtAbstractFirDiagnostic<KtElement> {
|
) : KtFirDiagnostic.UnderscoreIsReserved(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class UnderscoreUsageWithoutBackticksImpl(
|
internal class UnderscoreUsageWithoutBackticksImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtFirDiagnostic.UnderscoreUsageWithoutBackticks(), KtAbstractFirDiagnostic<KtElement> {
|
) : KtFirDiagnostic.UnderscoreUsageWithoutBackticks(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user