[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 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.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisFacade.AnalysisMode 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.analysis.api.types.KtType
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtVariableDeclaration import org.jetbrains.kotlin.psi.KtVariableDeclaration
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -36,8 +38,12 @@ internal class KtFe10PsiLocalVariableSymbol(
} }
override val name: Name 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 override val returnType: KtType
get() = withValidityAssertion { descriptor?.type?.toKtType(analysisContext) ?: createErrorType() } 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.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -68,7 +69,10 @@ internal class KtFe10PsiValueParameterSymbol(
} }
override val name: Name override val name: Name
get() = withValidityAssertion { psi.nameAsSafeName } get() = withValidityAssertion {
if (psi.destructuringDeclaration != null) SpecialNames.DESTRUCT
else psi.nameAsSafeName
}
context(KtAnalysisSession) context(KtAnalysisSession)
override fun createPointer(): KtSymbolPointer<KtValueParameterSymbol> = withValidityAssertion { 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 @Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors") @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors")
@TestDataPath("$PROJECT_ROOT") @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.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile 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.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
@@ -130,6 +131,11 @@ internal class KtFirImportOptimizer(
super.visitImplicitInvokeCall(implicitInvokeCall) 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) { override fun visitComponentCall(componentCall: FirComponentCall) {
processFunctionCall(componentCall) processFunctionCall(componentCall)
super.visitComponentCall(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.getModule
import org.jetbrains.kotlin.analysis.api.symbols.* 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.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.resolveToFirSymbolOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries 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.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore
internal class KtFirSymbolProvider( internal class KtFirSymbolProvider(
override val analysisSession: KtFirAnalysisSession, override val analysisSession: KtFirAnalysisSession,
@@ -186,11 +188,14 @@ internal class KtFirSymbolProvider(
override val ROOT_PACKAGE_SYMBOL: KtPackageSymbol = KtFirPackageSymbol(FqName.ROOT, firResolveSession.project, token) override val ROOT_PACKAGE_SYMBOL: KtPackageSymbol = KtFirPackageSymbol(FqName.ROOT, firResolveSession.project, token)
override fun getDestructuringDeclarationEntrySymbol(psi: KtDestructuringDeclarationEntry): KtFirLocalOrErrorVariableSymbol<*, *> { override fun getDestructuringDeclarationEntrySymbol(psi: KtDestructuringDeclarationEntry): KtLocalVariableSymbol {
return when (val firSymbol = psi.resolveToFirSymbolOfType<FirVariableSymbol<*>>(firResolveSession)) { return when (val firSymbol = psi.resolveToFirSymbol(firResolveSession)) {
is FirPropertySymbol -> firSymbolBuilder.variableLikeBuilder.buildLocalVariableSymbol(firSymbol) is FirPropertySymbol -> firSymbolBuilder.variableLikeBuilder.buildLocalVariableSymbol(firSymbol)
is FirErrorPropertySymbol -> firSymbolBuilder.variableLikeBuilder.buildErrorVariableSymbol(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 @Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors") @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors")
@TestDataPath("$PROJECT_ROOT") @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 @Nested
@TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors") @TestMetadata("analysis/analysis-api/testData/symbols/singleSymbolByPsi/errors")
@TestDataPath("$PROJECT_ROOT") @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 { public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.kt"); 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 @Nested
@@ -606,6 +606,18 @@ public class SourceGetOrBuildFirTestGenerated extends AbstractSourceGetOrBuildFi
public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception { public void testEntryInDestructuringDeclarationParameterInLambda() throws Exception {
runTest("analysis/low-level-api-fir/testdata/getOrBuildFir/destructuring/entryInDestructuringDeclarationParameterInLambda.kt"); 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 @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.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeChecker
object FirDestructuringDeclarationChecker : FirPropertyChecker() { object FirDestructuringDeclarationChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
val source = declaration.source ?: return val source = declaration.source ?: return
if (declaration.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return
// val (...) = `destructuring_declaration` // val (...) = `destructuring_declaration`
if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION) { if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION) {
checkInitializer(source, declaration.initializer, reporter, context) 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.isCatchParameter
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirUserTypeRef import org.jetbrains.kotlin.fir.types.FirUserTypeRef
import org.jetbrains.kotlin.name.SpecialNames
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() { object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -55,7 +56,10 @@ object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
isSingleUnderscoreAllowed: Boolean = false isSingleUnderscoreAllowed: Boolean = false
) { ) {
val declarationSource = declaration.source 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)) { with(SourceNavigator.forElement(declaration)) {
val rawName = declaration.getRawName() val rawName = declaration.getRawName()
if (rawName?.isUnderscore == true && !(isSingleUnderscoreAllowed && rawName == "_")) { 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.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isBasicFunctionType import org.jetbrains.kotlin.fir.types.isBasicFunctionType
import org.jetbrains.kotlin.name.SpecialNames
object UnusedChecker : AbstractFirPropertyInitializationChecker() { object UnusedChecker : AbstractFirPropertyInitializationChecker() {
override fun analyze(data: PropertyInitializationInfoData, reporter: DiagnosticReporter, context: CheckerContext) { override fun analyze(data: PropertyInitializationInfoData, reporter: DiagnosticReporter, context: CheckerContext) {
@@ -62,6 +63,7 @@ object UnusedChecker : AbstractFirPropertyInitializationChecker() {
val variableSymbol = node.fir.symbol val variableSymbol = node.fir.symbol
if (node.fir.source == null) return if (node.fir.source == null) return
if (variableSymbol.isLoopIterator) return if (variableSymbol.isLoopIterator) return
if (variableSymbol.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR) return
val dataPerNode = data[node] ?: return val dataPerNode = data[node] ?: return
val data = dataPerNode.values.mapNotNull { it[variableSymbol] }.reduceOrNull { acc, it -> acc.merge(it) } val data = dataPerNode.values.mapNotNull { it[variableSymbol] }.reduceOrNull { acc, it -> acc.merge(it) }
@@ -251,6 +251,9 @@ class Fir2IrVisitor(
for (statement in script.statements) { for (statement in script.statements) {
val irStatement = if (statement is FirDeclaration) { val irStatement = if (statement is FirDeclaration) {
when { when {
statement is FirProperty && statement.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR -> {
continue
}
statement is FirProperty && statement.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -> { statement is FirProperty && statement.origin == FirDeclarationOrigin.ScriptCustomization.ResultProperty -> {
// Generating the result property only for expressions with a meaningful result type // Generating the result property only for expressions with a meaningful result type
// otherwise skip the property and convert the expression into the statement // 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 FirContractCallBlock) return null
if (this is FirBlock) return convertToIrExpression(this) 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 return accept(this@Fir2IrVisitor, null) as IrStatement
} }
@@ -1390,8 +1390,11 @@ class LightTreeRawFirDeclarationBuilder(
} }
} }
if (identifier == "_") return null val name = if (identifier == "_") {
val name = identifier.nameAsSafeName() SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
} else {
identifier.nameAsSafeName()
}
return buildProperty { return buildProperty {
source = entry.toFirSourceElement() source = entry.toFirSourceElement()
moduleData = baseModuleData 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.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
internal fun KtWhenCondition.toFirWhenCondition( internal fun KtWhenCondition.toFirWhenCondition(
@@ -135,9 +136,12 @@ internal fun generateDestructuringBlock(
} }
val isVar = multiDeclaration.isVar val isVar = multiDeclaration.isVar
for ((index, entry) in multiDeclaration.entries.withIndex()) { 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 entrySource = entry.toKtPsiSourceElement()
val name = entry.nameAsSafeName
statements += buildProperty { statements += buildProperty {
source = entrySource source = entrySource
this.moduleData = moduleData this.moduleData = moduleData
@@ -34,5 +34,6 @@ FILE: destructuring.kt
public? final? fun bar(some: Some): R|kotlin/Unit| { public? final? fun bar(some: Some): R|kotlin/Unit| {
lval <destruct>: <implicit> = some# lval <destruct>: <implicit> = some#
lval a: <implicit> = R|<local>/<destruct>|.component1#() lval a: <implicit> = R|<local>/<destruct>|.component1#()
lval <unused var>: <implicit> = R|<local>/<destruct>|.component2#()
lval _: <implicit> = R|<local>/<destruct>|.component3#() lval _: <implicit> = R|<local>/<destruct>|.component3#()
} }
@@ -48,4 +48,5 @@ FILE: RedeclaredValsAndVars.fir.kt
lval <destruct>: R|A| = R|/A.A|() lval <destruct>: R|A| = R|/A.A|()
lval _: R|kotlin/Int| = R|<local>/<destruct>|.R|/A.component1|() lval _: R|kotlin/Int| = R|<local>/<destruct>|.R|/A.component1|()
lval <unused var>: R|kotlin/String| = R|<local>/<destruct>|.R|/A.component2|()
} }