[Analysis API FIR] fix KtSymbol creation for _ destructuring parameter

We need to have a corresponding declaration in the FIR tree,
so we can create a symbol for it

^KT-60904 fixed
^KT-60904 fixed
This commit is contained in:
Ilya Kirillov
2023-08-15 18:52:46 +02:00
committed by Space Team
parent 04b9faf9e6
commit c963eadb44
36 changed files with 431 additions and 11 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased
import com.intellij.extapi.psi.StubBasedPsiElementBase
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtVariableDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
@@ -36,8 +38,12 @@ internal class KtFe10PsiLocalVariableSymbol(
}
override val name: Name
get() = withValidityAssertion { psi.nameAsSafeName }
get() = withValidityAssertion {
when {
psi.nameIdentifier?.text == "_" -> SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
else -> psi.nameAsSafeName
}
}
override val returnType: KtType
get() = withValidityAssertion { descriptor?.type?.toKtType(analysisContext) ?: createErrorType() }
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext
@@ -68,7 +69,10 @@ internal class KtFe10PsiValueParameterSymbol(
}
override val name: Name
get() = withValidityAssertion { psi.nameAsSafeName }
get() = withValidityAssertion {
if (psi.destructuringDeclaration != null) SpecialNames.DESTRUCT
else psi.nameAsSafeName
}
context(KtAnalysisSession)
override fun createPointer(): KtSymbolPointer<KtValueParameterSymbol> = withValidityAssertion {
@@ -314,6 +314,46 @@ public class Fe10IdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated extends
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring")
@TestDataPath("$PROJECT_ROOT")
public class Destructuring {
@Test
public void testAllFilesPresentInDestructuring() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("destructuringDeclarationParameterInLambda.kt")
public void testDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/destructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryInDestructuringDeclaration.kt")
public void testEntryInDestructuringDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryInDestructuringDeclarationParameterInLambda.kt")
public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryInDestructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclaration.kt")
public void testEntryUnderscoreInDestructuringDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryUnderscoreInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclarationParameterInLambda.kt")
public void testEntryUnderscoreInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.kt");
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors")
@TestDataPath("$PROJECT_ROOT")
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi
@@ -130,6 +131,11 @@ internal class KtFirImportOptimizer(
super.visitImplicitInvokeCall(implicitInvokeCall)
}
override fun visitProperty(property: FirProperty) {
if (property.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return
super.visitProperty(property)
}
override fun visitComponentCall(componentCall: FirComponentCall) {
processFunctionCall(componentCall)
super.visitComponentCall(componentCall)
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.fir.components.KtFirAnalysisSessionComp
import org.jetbrains.kotlin.analysis.api.getModule
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbolOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore
internal class KtFirSymbolProvider(
override val analysisSession: KtFirAnalysisSession,
@@ -186,11 +188,14 @@ internal class KtFirSymbolProvider(
override val ROOT_PACKAGE_SYMBOL: KtPackageSymbol = KtFirPackageSymbol(FqName.ROOT, firResolveSession.project, token)
override fun getDestructuringDeclarationEntrySymbol(psi: KtDestructuringDeclarationEntry): KtFirLocalOrErrorVariableSymbol<*, *> {
return when (val firSymbol = psi.resolveToFirSymbolOfType<FirVariableSymbol<*>>(firResolveSession)) {
override fun getDestructuringDeclarationEntrySymbol(psi: KtDestructuringDeclarationEntry): KtLocalVariableSymbol {
return when (val firSymbol = psi.resolveToFirSymbol(firResolveSession)) {
is FirPropertySymbol -> firSymbolBuilder.variableLikeBuilder.buildLocalVariableSymbol(firSymbol)
is FirErrorPropertySymbol -> firSymbolBuilder.variableLikeBuilder.buildErrorVariableSymbol(firSymbol)
else -> throwUnexpectedFirElementError(firSymbol, psi, FirPropertySymbol::class, FirErrorPropertySymbol::class)
else -> throwUnexpectedFirElementError(
firSymbol, psi,
FirPropertySymbol::class, FirErrorPropertySymbol::class, FirValueParameterSymbol::class
)
}
}
}
@@ -314,6 +314,46 @@ public class FirIdeNormalAnalysisSourceModuleSingleSymbolByPsiGenerated extends
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring")
@TestDataPath("$PROJECT_ROOT")
public class Destructuring {
@Test
public void testAllFilesPresentInDestructuring() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("destructuringDeclarationParameterInLambda.kt")
public void testDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/destructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryInDestructuringDeclaration.kt")
public void testEntryInDestructuringDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryInDestructuringDeclarationParameterInLambda.kt")
public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryInDestructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclaration.kt")
public void testEntryUnderscoreInDestructuringDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryUnderscoreInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclarationParameterInLambda.kt")
public void testEntryUnderscoreInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.kt");
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors")
@TestDataPath("$PROJECT_ROOT")
@@ -314,6 +314,46 @@ public class FirStandaloneNormalAnalysisSourceModuleSingleSymbolByPsiGenerated e
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring")
@TestDataPath("$PROJECT_ROOT")
public class Destructuring {
@Test
public void testAllFilesPresentInDestructuring() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("destructuringDeclarationParameterInLambda.kt")
public void testDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/destructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryInDestructuringDeclaration.kt")
public void testEntryInDestructuringDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryInDestructuringDeclarationParameterInLambda.kt")
public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryInDestructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclaration.kt")
public void testEntryUnderscoreInDestructuringDeclaration() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryUnderscoreInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclarationParameterInLambda.kt")
public void testEntryUnderscoreInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/analysis-api/testData/symbols/singleSymbolByPsi/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.kt");
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors")
@TestDataPath("$PROJECT_ROOT")
@@ -0,0 +1,12 @@
// LOOK_UP_FOR_ELEMENT_OF_TYPE: KtParameter
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE
data class X(val a: Int, val b: Int)
fun x(action: (X, Int) -> Unit) {}
fun main() {
x { <expr>(a, b)</expr>, i ->
}
}
@@ -0,0 +1,22 @@
KtValueParameterSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
generatedPrimaryConstructorProperty: null
hasDefaultValue: false
isCrossinline: false
isExtension: false
isImplicitLambdaParameter: false
isNoinline: false
isVararg: false
name: <destruct>
origin: SOURCE
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: X
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,8 @@
// LOOK_UP_FOR_ELEMENT_OF_TYPE: KtDestructuringDeclarationEntry
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE
data class X(val a: Int, val b: Int)
fun main(x: X) {
val (<expr>a</expr>, b) = x
}
@@ -0,0 +1,17 @@
KtLocalVariableSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
isExtension: false
isVal: true
name: a
origin: SOURCE
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,12 @@
// LOOK_UP_FOR_ELEMENT_OF_TYPE: KtDestructuringDeclarationEntry
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE
data class X(val a: Int, val b: Int)
fun x(action: (X) -> Unit) {}
fun main() {
x { (<expr>a</expr>, b) ->
}
}
@@ -0,0 +1,17 @@
KtLocalVariableSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
isExtension: false
isVal: true
name: a
origin: SOURCE
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,8 @@
// LOOK_UP_FOR_ELEMENT_OF_TYPE: KtDestructuringDeclarationEntry
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE
data class X(val a: Int, val b: Int)
fun main(x: X) {
val (<expr>_</expr>, b) = x
}
@@ -0,0 +1,17 @@
KtLocalVariableSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
isExtension: false
isVal: true
name: <unused var>
origin: SOURCE
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,12 @@
// LOOK_UP_FOR_ELEMENT_OF_TYPE: KtDestructuringDeclarationEntry
// DO_NOT_CHECK_NON_PSI_SYMBOL_RESTORE
data class X(val a: Int, val b: Int)
fun x(action: (X) -> Unit) {}
fun main() {
x { (<expr>_</expr>, b) ->
}
}
@@ -0,0 +1,17 @@
KtLocalVariableSymbol:
annotationsList: []
callableIdIfNonLocal: null
contextReceivers: []
isExtension: false
isVal: true
name: <unused var>
origin: SOURCE
receiverParameter: null
returnType: KtUsualClassType:
annotationsList: []
ownTypeArguments: []
type: kotlin/Int
symbolKind: LOCAL
typeParameters: []
getContainingModule: KtSourceModule "Sources of main"
deprecationStatus: null
@@ -0,0 +1,7 @@
// LOOK_UP_FOR_ELEMENT_OF_TYPE: org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
data class X(val a: Int, val b: Int)
fun main(x: X) {
val (<expr>_</expr>, b) = x
}
@@ -0,0 +1,32 @@
KT element: KtDestructuringDeclarationEntry
FIR element: FirPropertyImpl
FIR source kind: KtRealSourceElementKind
FIR element rendered:
[ResolvedTo(BODY_RESOLVE)] lval <unused var>: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
FIR FILE:
FILE: [ResolvedTo(IMPORTS)] entryUnderscoreInDestructuringDeclaration.kt
public final data [ResolvedTo(STATUS)] class X : R|kotlin/Any| {
public [ResolvedTo(STATUS)] [ContainingClassKey=X] constructor([ResolvedTo(STATUS)] [CorrespondingProperty=/X.a] a: R|kotlin/Int|, [ResolvedTo(STATUS)] [CorrespondingProperty=/X.b] b: R|kotlin/Int|): R|X| {
LAZY_super<R|kotlin/Any|>
}
public final [ResolvedTo(STATUS)] [ComponentFunctionSymbolKey=/X.component1, IsFromPrimaryConstructor=true] val a: R|kotlin/Int| = R|<local>/a|
public [ResolvedTo(STATUS)] [ContainingClassKey=X] get(): R|kotlin/Int|
public final [ResolvedTo(STATUS)] [ComponentFunctionSymbolKey=/X.component2, IsFromPrimaryConstructor=true] val b: R|kotlin/Int| = R|<local>/b|
public [ResolvedTo(STATUS)] [ContainingClassKey=X] get(): R|kotlin/Int|
public final operator [ResolvedTo(CONTRACTS)] fun component1(): R|kotlin/Int|
public final operator [ResolvedTo(CONTRACTS)] fun component2(): R|kotlin/Int|
public final [ResolvedTo(STATUS)] fun copy([ResolvedTo(STATUS)] a: R|kotlin/Int| = this@R|/X|.R|/X.a|, [ResolvedTo(STATUS)] b: R|kotlin/Int| = this@R|/X|.R|/X.b|): R|X|
}
public final [ResolvedTo(BODY_RESOLVE)] fun main([ResolvedTo(BODY_RESOLVE)] x: R|X|): R|kotlin/Unit| {
[ResolvedTo(BODY_RESOLVE)] lval <destruct>: R|X| = R|<local>/x|
[ResolvedTo(BODY_RESOLVE)] lval <unused var>: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
[ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component2|()
}
@@ -0,0 +1,11 @@
// LOOK_UP_FOR_ELEMENT_OF_TYPE: org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
data class X(val a: Int, val b: Int)
fun x(action: (X) -> Unit) {}
fun main() {
x { (<expr>_</expr>, b) ->
}
}
@@ -0,0 +1,37 @@
KT element: KtDestructuringDeclarationEntry
FIR element: FirPropertyImpl
FIR source kind: KtRealSourceElementKind
FIR element rendered:
[ResolvedTo(BODY_RESOLVE)] lval <unused var>: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
FIR FILE:
FILE: [ResolvedTo(IMPORTS)] entryUnderscoreInDestructuringDeclarationParameterInLambda.kt
public final data [ResolvedTo(STATUS)] class X : R|kotlin/Any| {
public [ResolvedTo(STATUS)] [ContainingClassKey=X] constructor([ResolvedTo(STATUS)] [CorrespondingProperty=/X.a] a: R|kotlin/Int|, [ResolvedTo(STATUS)] [CorrespondingProperty=/X.b] b: R|kotlin/Int|): R|X| {
LAZY_super<R|kotlin/Any|>
}
public final [ResolvedTo(STATUS)] [ComponentFunctionSymbolKey=/X.component1, IsFromPrimaryConstructor=true] val a: R|kotlin/Int| = R|<local>/a|
public [ResolvedTo(STATUS)] [ContainingClassKey=X] get(): R|kotlin/Int|
public final [ResolvedTo(STATUS)] [ComponentFunctionSymbolKey=/X.component2, IsFromPrimaryConstructor=true] val b: R|kotlin/Int| = R|<local>/b|
public [ResolvedTo(STATUS)] [ContainingClassKey=X] get(): R|kotlin/Int|
public final operator [ResolvedTo(CONTRACTS)] fun component1(): R|kotlin/Int|
public final operator [ResolvedTo(CONTRACTS)] fun component2(): R|kotlin/Int|
public final [ResolvedTo(STATUS)] fun copy([ResolvedTo(STATUS)] a: R|kotlin/Int| = this@R|/X|.R|/X.a|, [ResolvedTo(STATUS)] b: R|kotlin/Int| = this@R|/X|.R|/X.b|): R|X|
}
public final [ResolvedTo(CONTRACTS)] fun x([ResolvedTo(CONTRACTS)] action: R|(X) -> kotlin/Unit|): R|kotlin/Unit| {
}
public final [ResolvedTo(BODY_RESOLVE)] fun main(): R|kotlin/Unit| {
R|/x|(<L> = [ResolvedTo(BODY_RESOLVE)] [MatchingParameterFunctionTypeKey=kotlin/Function1<X, kotlin/Unit>] x@fun <anonymous>([ResolvedTo(BODY_RESOLVE)] <destruct>: R|X|): R|kotlin/Unit| <inline=NoInline> {
[ResolvedTo(BODY_RESOLVE)] lval <unused var>: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component1|()
[ResolvedTo(BODY_RESOLVE)] lval b: R|kotlin/Int| = R|<local>/<destruct>|.R|/X.component2|()
^@x Unit
}
)
}
@@ -606,6 +606,18 @@ public class OutOfContentRootGetOrBuildFirTestGenerated extends AbstractOutOfCon
public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclaration.kt")
public void testEntryUnderscoreInDestructuringDeclaration() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclarationParameterInLambda.kt")
public void testEntryUnderscoreInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.kt");
}
}
@Nested
@@ -606,6 +606,18 @@ public class SourceGetOrBuildFirTestGenerated extends AbstractSourceGetOrBuildFi
public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclaration.kt")
public void testEntryUnderscoreInDestructuringDeclaration() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclaration.kt");
}
@Test
@TestMetadata("entryUnderscoreInDestructuringDeclarationParameterInLambda.kt")
public void testEntryUnderscoreInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryUnderscoreInDestructuringDeclarationParameterInLambda.kt");
}
}
@Nested
@@ -26,11 +26,13 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.AbstractTypeChecker
object FirDestructuringDeclarationChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
val source = declaration.source ?: return
if (declaration.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return
// val (...) = `destructuring_declaration`
if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION) {
checkInitializer(source, declaration.initializer, reporter, context)
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.isCatchParameter
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirUserTypeRef
import org.jetbrains.kotlin.name.SpecialNames
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -55,7 +56,10 @@ object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
isSingleUnderscoreAllowed: Boolean = false
) {
val declarationSource = declaration.source
if (declarationSource != null && declarationSource.kind !is KtFakeSourceElementKind) {
if (declarationSource != null &&
declarationSource.kind !is KtFakeSourceElementKind &&
(declaration as? FirProperty)?.name != SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
) {
with(SourceNavigator.forElement(declaration)) {
val rawName = declaration.getRawName()
if (rawName?.isUnderscore == true && !(isSingleUnderscoreAllowed && rawName == "_")) {
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isBasicFunctionType
import org.jetbrains.kotlin.name.SpecialNames
object UnusedChecker : AbstractFirPropertyInitializationChecker() {
override fun analyze(data: PropertyInitializationInfoData, reporter: DiagnosticReporter, context: CheckerContext) {
@@ -62,6 +63,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
val variableSymbol = node.fir.symbol
if (node.fir.source == null) return
if (variableSymbol.isLoopIterator) return
if (variableSymbol.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return
val dataPerNode = data[node] ?: return
val data = dataPerNode.values.mapNotNull { it[variableSymbol] }.reduceOrNull { acc, it -> acc.merge(it) }
@@ -251,6 +251,9 @@ class Fir2IrVisitor(
for (statement in script.statements) {
val irStatement = if (statement is FirDeclaration) {
when {
statement is FirProperty && statement.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR -> {
continue
}
statement is FirProperty && statement.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -> {
// Generating the result property only for expressions with a meaningful result type
// otherwise skip the property and convert the expression into the statement
@@ -820,6 +823,7 @@ class Fir2IrVisitor(
}
if (this is FirContractCallBlock) return null
if (this is FirBlock) return convertToIrExpression(this)
if (this is FirProperty && name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return null
return accept(this@Fir2IrVisitor, null) as IrStatement
}
@@ -1390,8 +1390,11 @@ class LightTreeRawFirDeclarationBuilder(
}
}
if (identifier == "_") return null
val name = identifier.nameAsSafeName()
val name = if (identifier == "_") {
SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
} else {
identifier.nameAsSafeName()
}
return buildProperty {
source = entry.toFirSourceElement()
moduleData = baseModuleData
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.*
internal fun KtWhenCondition.toFirWhenCondition(
@@ -135,9 +136,12 @@ internal fun generateDestructuringBlock(
}
val isVar = multiDeclaration.isVar
for ((index, entry) in multiDeclaration.entries.withIndex()) {
if (entry.nameIdentifier?.text == "_") continue
val name = if (entry.nameIdentifier?.text == "_") {
SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
} else {
entry.nameAsSafeName
}
val entrySource = entry.toKtPsiSourceElement()
val name = entry.nameAsSafeName
statements += buildProperty {
source = entrySource
this.moduleData = moduleData
@@ -34,5 +34,6 @@ FILE: destructuring.kt
public? final? fun bar(some: Some): R|kotlin/Unit| {
lval <destruct>: <implicit> = some#
lval a: <implicit> = R|<local>/<destruct>|.component1#()
lval <unused var>: <implicit> = R|<local>/<destruct>|.component2#()
lval _: <implicit> = R|<local>/<destruct>|.component3#()
}
@@ -48,4 +48,5 @@ FILE: RedeclaredValsAndVars.fir.kt
lval <destruct>: R|A| = R|/A.A|()
lval _: R|kotlin/Int| = R|<local>/<destruct>|.R|/A.component1|()
lval <unused var>: R|kotlin/String| = R|<local>/<destruct>|.R|/A.component2|()
}