[FIR] Optimize performance and fix UNDERSCORE_IS_RESERVED, simplify code

This commit is contained in:
Ivan Kochurkin
2021-07-22 01:47:22 +03:00
committed by Space
parent 2fbb700ec6
commit 63fc3645ab
16 changed files with 190 additions and 182 deletions
@@ -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")
@@ -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>()
@@ -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 == '_' }
@@ -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}''",
@@ -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)
} }
} }
@@ -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 =
@@ -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
View File
@@ -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()
}
+10
View File
@@ -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()
}
+16
View File
@@ -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)
@@ -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
} }
@@ -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)
} }