[LL API] Fix analysis of functions inside code fragments
FirDeclarationsResolveTransformer.transformSimpleFunction() performs proper local function analysis only if the parent is properly set. ^KTIJ-26608 Fixed
This commit is contained in:
+6
@@ -91,6 +91,12 @@ public class FirIdeNormalAnalysisLibrarySourceModuleCompilerFacilityTestGenerate
|
|||||||
runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/duplicateLibrary.kt");
|
runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/duplicateLibrary.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fragmentFunction.kt")
|
||||||
|
public void testFragmentFunction() throws Exception {
|
||||||
|
runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/fragmentFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("imports.kt")
|
@TestMetadata("imports.kt")
|
||||||
public void testImports() throws Exception {
|
public void testImports() throws Exception {
|
||||||
|
|||||||
+6
@@ -91,6 +91,12 @@ public class FirIdeNormalAnalysisSourceModuleCompilerFacilityTestGenerated exten
|
|||||||
runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/duplicateLibrary.kt");
|
runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/duplicateLibrary.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("fragmentFunction.kt")
|
||||||
|
public void testFragmentFunction() throws Exception {
|
||||||
|
runTest("analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/fragmentFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("imports.kt")
|
@TestMetadata("imports.kt")
|
||||||
public void testImports() throws Exception {
|
public void testImports() throws Exception {
|
||||||
|
|||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
fun String.ext() = this + "EXT"
|
||||||
|
"base".ext()
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
MODULE_FRAGMENT
|
||||||
|
FILE fqName:<root> fileName:fragment.kt
|
||||||
|
CLASS CLASS name:CodeFragment modality:FINAL visibility:public superTypes:[kotlin.Any]
|
||||||
|
$this: VALUE_PARAMETER INSTANCE_RECEIVER name:<this> type:<root>.CodeFragment
|
||||||
|
CONSTRUCTOR visibility:public <> () returnType:<root>.CodeFragment [primary]
|
||||||
|
BLOCK_BODY
|
||||||
|
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
|
||||||
|
FUN name:run visibility:public modality:FINAL <> () returnType:kotlin.String
|
||||||
|
EXPRESSION_BODY
|
||||||
|
BLOCK type=kotlin.String origin=null
|
||||||
|
FUN LOCAL_FUNCTION name:ext visibility:local modality:FINAL <> ($receiver:kotlin.String) returnType:kotlin.String
|
||||||
|
$receiver: VALUE_PARAMETER name:<this> type:kotlin.String
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='local final fun ext (): kotlin.String declared in <root>.CodeFragment.run'
|
||||||
|
CALL 'public final fun plus (other: kotlin.Any?): kotlin.String [operator] declared in kotlin.String' type=kotlin.String origin=PLUS
|
||||||
|
$this: GET_VAR '<this>: kotlin.String declared in <root>.CodeFragment.run.ext' type=kotlin.String origin=null
|
||||||
|
other: CONST String type=kotlin.String value="EXT"
|
||||||
|
CALL 'local final fun ext (): kotlin.String declared in <root>.CodeFragment.run' type=kotlin.String origin=null
|
||||||
|
$receiver: CONST String type=kotlin.String value="base"
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun test() {
|
||||||
|
<caret>val x = 0
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
public final class CodeFragment {
|
||||||
|
// source: 'fragment.kt'
|
||||||
|
public method <init>(): void
|
||||||
|
private final static method run$ext(p0: java.lang.String): java.lang.String
|
||||||
|
public final static method run(): java.lang.String
|
||||||
|
}
|
||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
fun foo() {}
|
fun foo(a: Int, b: String) {}
|
||||||
|
|
||||||
fun bar() {
|
fun bar() {
|
||||||
<expr>foo()</expr>
|
<expr>foo(1, "foo")</expr>
|
||||||
}
|
}
|
||||||
|
|
||||||
bar()
|
bar()
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
BEFORE MODIFICATION:
|
BEFORE MODIFICATION:
|
||||||
CODE FRAGMENT: {
|
CODE FRAGMENT: {
|
||||||
local final? [ResolvedTo(RAW_FIR)] fun foo(): R|kotlin/Unit| {
|
local final [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] a: R|kotlin/Int|, [ResolvedTo(RAW_FIR)] b: R|kotlin/String|): R|kotlin/Unit| {
|
||||||
}
|
}
|
||||||
|
|
||||||
local final? [ResolvedTo(RAW_FIR)] fun bar(): R|kotlin/Unit| {
|
local final [ResolvedTo(RAW_FIR)] fun bar(): R|kotlin/Unit| {
|
||||||
R|/foo|()
|
R|/foo|(Int(1), String(foo))
|
||||||
}
|
}
|
||||||
|
|
||||||
R|/bar|()
|
R|/bar|()
|
||||||
|
|||||||
+3
-2
@@ -541,7 +541,8 @@ class BodyResolveContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> withScopesForCodeFragment(codeFragment: FirCodeFragment, holder: SessionHolder, f: () -> T): T {
|
@OptIn(PrivateForInline::class)
|
||||||
|
fun <T> withCodeFragment(codeFragment: FirCodeFragment, holder: SessionHolder, f: () -> T): T {
|
||||||
val codeFragmentContext = codeFragment.codeFragmentContext ?: error("Context is not set for a code fragment")
|
val codeFragmentContext = codeFragment.codeFragmentContext ?: error("Context is not set for a code fragment")
|
||||||
val towerDataContext = codeFragmentContext.towerDataContext
|
val towerDataContext = codeFragmentContext.towerDataContext
|
||||||
|
|
||||||
@@ -566,7 +567,7 @@ class BodyResolveContext(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return withTowerDataContexts(newContext) {
|
return withTowerDataContexts(newContext) {
|
||||||
f()
|
withContainer(codeFragment, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -631,7 +631,7 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
|
|
||||||
override fun transformCodeFragment(codeFragment: FirCodeFragment, data: ResolutionMode): FirCodeFragment {
|
override fun transformCodeFragment(codeFragment: FirCodeFragment, data: ResolutionMode): FirCodeFragment {
|
||||||
dataFlowAnalyzer.enterCodeFragment(codeFragment)
|
dataFlowAnalyzer.enterCodeFragment(codeFragment)
|
||||||
context.withScopesForCodeFragment(codeFragment, components) {
|
context.withCodeFragment(codeFragment, components) {
|
||||||
transformBlock(codeFragment.block, data)
|
transformBlock(codeFragment.block, data)
|
||||||
}
|
}
|
||||||
dataFlowAnalyzer.exitCodeFragment()
|
dataFlowAnalyzer.exitCodeFragment()
|
||||||
|
|||||||
Reference in New Issue
Block a user