diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt
index ab8e63d8dbd..2eb31a8ca51 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt
@@ -460,6 +460,35 @@ private class ContextCollectorVisitor(
}
}
+ /**
+ * We visit fields to properly handle supertypes delegation:
+ *
+ * ```kt
+ * class Foo : Bar by baz
+ * ```
+ *
+ * In the code above, `baz` expression is saved into a separate synthetic field.
+ * It's not accessible from the delegated constructor, it's just added to the
+ * `Foo` class body.
+ */
+ override fun visitField(field: FirField) = withProcessor {
+ dumpContext(field, ContextKind.SELF)
+
+ processSignatureAnnotations(field)
+
+ onActiveBody {
+ field.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
+
+ context.withField(field) {
+ dumpContext(field, ContextKind.BODY)
+
+ onActive {
+ process(field.initializer)
+ }
+ }
+ }
+ }
+
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor) = withProcessor {
dumpContext(propertyAccessor, ContextKind.SELF)
diff --git a/analysis/low-level-api-fir/testdata/contextCollector/propertyDelegateInitializer.kt b/analysis/low-level-api-fir/testdata/contextCollector/propertyDelegateInitializer.kt
new file mode 100644
index 00000000000..1ef1124e1eb
--- /dev/null
+++ b/analysis/low-level-api-fir/testdata/contextCollector/propertyDelegateInitializer.kt
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package test
+
+interface MyInterface {
+ operator fun getValue(thisRef: Any, property: Any): MyInterface
+}
+
+class Foo(constructorParam: MyInterface) {
+ val regularProperty: MyInterface
+
+ val property: MyInterface by constructorParam
+}
\ No newline at end of file
diff --git a/analysis/low-level-api-fir/testdata/contextCollector/propertyDelegateInitializer.txt b/analysis/low-level-api-fir/testdata/contextCollector/propertyDelegateInitializer.txt
new file mode 100644
index 00000000000..0743979e4cb
--- /dev/null
+++ b/analysis/low-level-api-fir/testdata/contextCollector/propertyDelegateInitializer.txt
@@ -0,0 +1,43 @@
+Tower Data Context:
+ Element 0
+ Scope: FirDefaultStarImportingScope
+ Element 1
+ Scope: FirDefaultSimpleImportingScope
+ Element 2
+ Scope: FirExplicitStarImportingScope
+ Element 3
+ Scope: FirDefaultSimpleImportingScope
+ Element 4
+ Scope: FirDefaultSimpleImportingScope
+ Element 5
+ Scope: FirPackageMemberScope
+ Element 6
+ Scope: FirExplicitSimpleImportingScope
+ Element 7
+ Implicit receiver:
+ FirRegularClassSymbol public final class Foo : R|kotlin/Any|
+ Type: test/Foo
+ Element 8
+ Scope: FirLocalScope
+ Properties:
+ FirValueParameterSymbol constructorParam: R|test/MyInterface|
+
+FILE: [ResolvedTo(IMPORTS)] propertyDelegateInitializer.kt
+ public abstract [ResolvedTo(STATUS)] interface MyInterface : R|kotlin/Any| {
+ public abstract operator [ResolvedTo(CONTRACTS)] fun getValue([ResolvedTo(CONTRACTS)] thisRef: R|kotlin/Any|, [ResolvedTo(CONTRACTS)] property: R|kotlin/Any|): R|test/MyInterface|
+
+ }
+ public final [ResolvedTo(STATUS)] class Foo : R|kotlin/Any| {
+ public [ResolvedTo(STATUS)] constructor([ResolvedTo(STATUS)] constructorParam: R|test/MyInterface|): R|test/Foo| {
+ LAZY_super
+ }
+
+ public final [ResolvedTo(STATUS)] val regularProperty: R|test/MyInterface|
+ public [ResolvedTo(STATUS)] get(): R|test/MyInterface|
+
+ public final [ResolvedTo(BODY_RESOLVE)] val property: R|test/MyInterface|by R|/constructorParam|
+ public [ResolvedTo(BODY_RESOLVE)] get(): R|test/MyInterface| {
+ ^ this@R|test/Foo|.D|test/Foo.property|.R|test/MyInterface.getValue|(this@R|test/Foo|, ::R|test/Foo.property|)
+ }
+
+ }
diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/ContextCollectorSourceTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/ContextCollectorSourceTestGenerated.java
index 192562e60a1..484d9976d8d 100644
--- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/ContextCollectorSourceTestGenerated.java
+++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/ContextCollectorSourceTestGenerated.java
@@ -90,6 +90,12 @@ public class ContextCollectorSourceTestGenerated extends AbstractContextCollecto
runTest("analysis/low-level-api-fir/testdata/contextCollector/primaryConstructorParameter.kt");
}
+ @Test
+ @TestMetadata("propertyDelegateInitializer.kt")
+ public void testPropertyDelegateInitializer() throws Exception {
+ runTest("analysis/low-level-api-fir/testdata/contextCollector/propertyDelegateInitializer.kt");
+ }
+
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {