Skip to content

Commit d09d620

Browse files
sellmairgoodwinnk
authored andcommitted
[FIR2IR] Find defaultValue from expect functions when 'allowNonCachedDeclarations'
... To support code fragments (such as in the debuggers 'evaluate expression'. See: IDEA-358599
1 parent 4803b99 commit d09d620

File tree

9 files changed

+103
-9
lines changed

9 files changed

+103
-9
lines changed

analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisLibrarySourceModuleCompilerFacilityTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/compilerFacility/FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
MODULE_FRAGMENT
2+
FILE fqName:<root> fileName:fragment.kt
3+
CLASS CLASS name:CodeFragment modality:FINAL visibility:public superTypes:[kotlin.Any]
4+
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.CodeFragment
5+
CONSTRUCTOR visibility:public <> () returnType:<root>.CodeFragment [primary]
6+
BLOCK_BODY
7+
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
8+
FUN name:run visibility:public modality:FINAL <> () returnType:kotlin.Int
9+
EXPRESSION_BODY
10+
BLOCK type=kotlin.Int origin=null
11+
CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUS
12+
$this: CALL 'public final fun foo (default: kotlin.Int): kotlin.Int declared in <root>.JvmKt' type=kotlin.Int origin=null
13+
other: CALL 'public final fun bar (): kotlin.Int declared in <root>.JvmKt' type=kotlin.Int origin=null
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// LANGUAGE: +MultiPlatformProjects
2+
3+
// MODULE: common
4+
// TARGET_PLATFORM: Common
5+
// FILE: common.kt
6+
7+
8+
expect fun foo(default: Int = 42): Int
9+
10+
expect fun bar(): Int
11+
12+
fun test() {
13+
<caret_context>val x = 0
14+
}
15+
16+
// MODULE: jvm()()(common)
17+
// TARGET_PLATFORM: JVM
18+
// FILE: jvm.kt
19+
actual fun foo(default: Int) = default
20+
21+
actual fun bar() = 0
22+
23+
// MODULE: main
24+
// MODULE_KIND: CodeFragment
25+
// CONTEXT_MODULE: common
26+
// ANALYSIS_CONTEXT_MODULE: jvm
27+
28+
// FILE: fragment.kt
29+
// CODE_FRAGMENT_KIND: EXPRESSION
30+
foo() + bar()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public final class CodeFragment {
2+
// source: 'fragment.kt'
3+
public method <init>(): void
4+
public final static method run(): int
5+
}

analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/AnalysisApiTestDirectives.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,17 @@ object AnalysisApiTestDirectives : SimpleDirectivesContainer() {
3636
)
3737

3838
val CONTEXT_MODULE by stringDirective(
39-
description = "Specifies the module name which should be treated as a context module for the current one",
39+
description = "Specifies the module name used to find the 'context psi element' for this module",
40+
applicability = DirectiveApplicability.Module
41+
)
42+
43+
/*
44+
Note: the 'contextElement' can be different from the 'contextModule'.
45+
E.g., consider a multiplatform project where the contextElement is in 'commonMain', but the contextModule can be
46+
configured as 'jvmMain'
47+
*/
48+
val ANALYSIS_CONTEXT_MODULE by stringDirective(
49+
description = "Specifies the module name which should be treated as a context module for the current one (can overwrite 'CONTEXT_MODULE')",
4050
applicability = DirectiveApplicability.Module
4151
)
4252
}

analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/projectStructure/KtCodeFragmentTestModuleFactory.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
package org.jetbrains.kotlin.analysis.test.framework.projectStructure
77

88
import com.intellij.openapi.project.Project
9+
import org.jetbrains.kotlin.analysis.api.KaImplementationDetail
910
import org.jetbrains.kotlin.analysis.api.projectStructure.KaDanglingFileResolutionMode
1011
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KaDanglingFileModuleImpl
1112
import org.jetbrains.kotlin.analysis.api.platform.projectStructure.forcedSpecialModule
13+
import org.jetbrains.kotlin.analysis.api.projectStructure.analysisContextModule
1214
import org.jetbrains.kotlin.analysis.test.framework.services.TestForeignValue
1315
import org.jetbrains.kotlin.analysis.test.framework.services.TestForeignValueProviderService
1416
import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider
@@ -20,6 +22,7 @@ import org.jetbrains.kotlin.psi.KtElement
2022
import org.jetbrains.kotlin.psi.KtExpressionCodeFragment
2123
import org.jetbrains.kotlin.psi.KtFile
2224
import org.jetbrains.kotlin.psi.KtTypeCodeFragment
25+
import org.jetbrains.kotlin.psi.analysisContext
2326
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
2427
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
2528
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
@@ -28,6 +31,7 @@ import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
2831
import org.jetbrains.kotlin.test.model.TestFile
2932
import org.jetbrains.kotlin.test.model.TestModule
3033
import org.jetbrains.kotlin.test.services.TestServices
34+
import org.jetbrains.kotlin.test.services.moduleStructure
3135
import org.jetbrains.kotlin.test.services.sourceFileProvider
3236
import org.jetbrains.org.objectweb.asm.Type
3337
import java.nio.file.Path

analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/projectStructure/TestModuleStructureFactory.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ import com.intellij.psi.PsiManager
1111
import com.intellij.psi.search.GlobalSearchScope
1212
import org.jetbrains.kotlin.analysis.api.projectStructure.*
1313
import org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure.StandaloneProjectFactory
14-
import org.jetbrains.kotlin.analysis.api.projectStructure.KaDanglingFileModule
15-
import org.jetbrains.kotlin.analysis.api.projectStructure.KaLibraryModule
16-
import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule
17-
import org.jetbrains.kotlin.analysis.api.projectStructure.KaNotUnderContentRootModule
1814
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
1915
import org.jetbrains.kotlin.analysis.test.framework.services.environmentManager
2016
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
@@ -46,7 +42,7 @@ object TestModuleStructureFactory {
4642
fun createProjectStructureByTestStructure(
4743
moduleStructure: TestModuleStructure,
4844
testServices: TestServices,
49-
project: Project
45+
project: Project,
5046
): KtTestModuleStructure {
5147
val modules = createModules(moduleStructure, testServices, project)
5248

@@ -81,14 +77,17 @@ object TestModuleStructureFactory {
8177
val contextModuleName = testModule.directives.singleOrZeroValue(AnalysisApiTestDirectives.CONTEXT_MODULE)
8278
val contextModule = contextModuleName?.let(existingModules::getValue)
8379

80+
val analysisContextModuleName = testModule.directives.singleOrZeroValue(AnalysisApiTestDirectives.ANALYSIS_CONTEXT_MODULE)
81+
val analysisContextModule = analysisContextModuleName?.let(existingModules::getValue)
82+
8483
val dependencyBinaryRoots = testModule.regularDependencies.flatMap { dependency ->
8584
val libraryModule = existingModules.getValue(dependency.moduleName).ktModule as? KaLibraryModule
8685
libraryModule?.binaryRoots.orEmpty()
8786
}
8887

8988
val ktTestModule = testServices
9089
.getKtModuleFactoryForTestModule(testModule)
91-
.createModule(testModule, contextModule, dependencyBinaryRoots, testServices, project)
90+
.createModule(testModule, analysisContextModule ?: contextModule, dependencyBinaryRoots, testServices, project)
9291

9392
existingModules[testModule.name] = ktTestModule
9493
result.add(ktTestModule)
@@ -146,7 +145,7 @@ object TestModuleStructureFactory {
146145
testModule: TestModule,
147146
testServices: TestServices,
148147
ktModule: KtModuleWithModifiableDependencies,
149-
libraryCache: (paths: Set<Path>, factory: () -> KaLibraryModule) -> KaLibraryModule
148+
libraryCache: (paths: Set<Path>, factory: () -> KaLibraryModule) -> KaLibraryModule,
150149
) {
151150
val project = ktModule.project
152151

compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,28 @@ class Fir2IrCallableDeclarationsGenerator(private val c: Fir2IrComponents) : Fir
751751
isNoinline = valueParameter.isNoinline,
752752
isHidden = false,
753753
).apply {
754-
val defaultValue = valueParameter.defaultValue
754+
val defaultValue = valueParameter.defaultValue ?: run tryFindInExpect@{
755+
/*
756+
Scenarios, such as evaluating expressions in the debugger, will 'allow non-cached declarations'.
757+
In this case some symbols, which can be considered 'dependencies' will not produce IR.
758+
Therefore, the 'FunctionDefaultParametersActualizer' will not run.
759+
760+
In such cases, we're trying to look up default values from such 'dependency' classes manually
761+
*/
762+
if (!c.configuration.allowNonCachedDeclarations) return@tryFindInExpect null
763+
764+
val actualFunction = valueParameter.containingFunctionSymbol
765+
if (!actualFunction.isActual) return@tryFindInExpect null
766+
767+
val expectFunction = actualFunction.getSingleMatchedExpectForActualOrNull()
768+
?: return@tryFindInExpect null
769+
770+
val expectValueParam = expectFunction.valueParameterSymbols.find { it.name == name }
771+
?: return@tryFindInExpect null
772+
773+
expectValueParam.fir.defaultValue
774+
}
775+
755776
if (!skipDefaultParameter && defaultValue != null) {
756777
this.defaultValue = when {
757778
forcedDefaultValueConversion && defaultValue !is FirExpressionStub ->

0 commit comments

Comments
 (0)