Add the option to create temporary variables for all inlined arguments
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt
index 98f0807..286868b 100644
--- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt
@@ -83,7 +83,8 @@
     val context: CommonBackendContext,
     val inlineFunctionResolver: InlineFunctionResolver,
     val innerClassesSupport: InnerClassesSupport? = null,
-    val insertAdditionalImplicitCasts: Boolean = false
+    val insertAdditionalImplicitCasts: Boolean = false,
+    val alwaysCreateTemporaryVariablesForArguments: Boolean = false
 ) : IrElementTransformerVoidWithContext(), BodyLoweringPass {
 
     constructor(context: CommonBackendContext) : this(context, DefaultInlineFunctionResolver(context), null)
@@ -590,55 +591,63 @@
             val evaluationStatements = mutableListOf<IrStatement>()
             val substitutor = ParameterSubstitutor()
             arguments.forEach { argument ->
+                val parameter = argument.parameter
                 /*
                  * We need to create temporary variable for each argument except inlinable lambda arguments.
                  * For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
                  * not only for those referring to inlinable lambdas.
                  */
                 if (argument.isInlinableLambdaArgument) {
-                    substituteMap[argument.parameter] = argument.argumentExpression
+                    substituteMap[parameter] = argument.argumentExpression
                     (argument.argumentExpression as? IrFunctionReference)?.let { evaluationStatements += evaluateArguments(it) }
 
                     return@forEach
                 }
 
-                if (argument.isImmutableVariableLoad) {
-                    substituteMap[argument.parameter] =
-                        argument.argumentExpression.transform( // Arguments may reference the previous ones - substitute them.
-                            substitutor,
-                            data = null
-                        )
-                    return@forEach
-                }
-
                 // Arguments may reference the previous ones - substitute them.
                 val variableInitializer = argument.argumentExpression.transform(substitutor, data = null)
-
-                val argumentExtracted = !argument.argumentExpression.isPure(false, context = context)
-
-                if (!argumentExtracted) {
-                    substituteMap[argument.parameter] = variableInitializer
-                } else {
-                    val newVariable =
-                        currentScope.scope.createTemporaryVariable(
-                            irExpression = IrBlockImpl(
-                                variableInitializer.startOffset,
-                                variableInitializer.endOffset,
-                                variableInitializer.type,
-                                InlinerExpressionLocationHint((currentScope.irElement as IrSymbolOwner).symbol)
-                            ).apply {
-                                statements.add(variableInitializer)
-                            },
-                            nameHint = callee.symbol.owner.name.toString(),
-                            isMutable = false
-                        )
-
+                val shouldCreateTemporaryVariable =
+                    (alwaysCreateTemporaryVariablesForArguments && !parameter.isInlineParameter()) ||
+                            argument.shouldBeSubstitutedViaTemporaryVariable()
+                if (shouldCreateTemporaryVariable) {
+                    val newVariable = createTemporaryVariable(parameter, variableInitializer, callee)
                     evaluationStatements.add(newVariable)
-                    substituteMap[argument.parameter] = IrGetValueWithoutLocation(newVariable.symbol)
+                    substituteMap[parameter] = IrGetValueWithoutLocation(newVariable.symbol)
+                } else {
+                    substituteMap[parameter] = variableInitializer
                 }
             }
             return evaluationStatements
         }
+
+        private fun ParameterToArgument.shouldBeSubstitutedViaTemporaryVariable(): Boolean =
+            !isImmutableVariableLoad && !argumentExpression.isPure(false, context = context)
+
+        private fun createTemporaryVariable(parameter: IrValueParameter, variableInitializer: IrExpression, callee: IrFunction): IrVariable {
+            val variable = currentScope.scope.createTemporaryVariable(
+                irExpression = IrBlockImpl(
+                    variableInitializer.startOffset,
+                    variableInitializer.endOffset,
+                    variableInitializer.type,
+                    InlinerExpressionLocationHint((currentScope.irElement as IrSymbolOwner).symbol)
+                ).apply {
+                    statements.add(variableInitializer)
+                },
+                nameHint = callee.symbol.owner.name.toString(),
+                isMutable = false,
+                origin = if (parameter == callee.extensionReceiverParameter) {
+                    IrDeclarationOrigin.IR_TEMPORARY_VARIABLE_FOR_INLINED_EXTENSION_RECEIVER
+                } else {
+                    IrDeclarationOrigin.IR_TEMPORARY_VARIABLE_FOR_INLINED_PARAMETER
+                }
+            )
+
+            if (alwaysCreateTemporaryVariablesForArguments) {
+                variable.name = parameter.name
+            }
+
+            return variable
+        }
     }
 
     private class IrGetValueWithoutLocation(
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt
index 4b58e0c..53ad8a1 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt
@@ -52,6 +52,8 @@
     object INSTANCE_RECEIVER : IrDeclarationOriginImpl("INSTANCE_RECEIVER")
     object PRIMARY_CONSTRUCTOR_PARAMETER : IrDeclarationOriginImpl("PRIMARY_CONSTRUCTOR_PARAMETER")
     object IR_TEMPORARY_VARIABLE : IrDeclarationOriginImpl("IR_TEMPORARY_VARIABLE")
+    object IR_TEMPORARY_VARIABLE_FOR_INLINED_PARAMETER : IrDeclarationOriginImpl("IR_TEMPORARY_VARIABLE_FOR_INLINED_PARAMETER")
+    object IR_TEMPORARY_VARIABLE_FOR_INLINED_EXTENSION_RECEIVER : IrDeclarationOriginImpl("IR_TEMPORARY_VARIABLE_FOR_INLINED_EXTENSION_RECEIVER")
     object IR_EXTERNAL_DECLARATION_STUB : IrDeclarationOriginImpl("IR_EXTERNAL_DECLARATION_STUB")
     object IR_EXTERNAL_JAVA_DECLARATION_STUB : IrDeclarationOriginImpl("IR_EXTERNAL_JAVA_DECLARATION_STUB")
     object IR_BUILTINS_STUB : IrDeclarationOriginImpl("IR_BUILTINS_STUB")
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt
index 7957472..91e23d7 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Lowerings.kt
@@ -321,7 +321,11 @@
         lowering = { context: NativeGenerationState ->
             object : FileLoweringPass {
                 override fun lower(irFile: IrFile) {
-                    FunctionInlining(context.context, NativeInlineFunctionResolver(context.context, context)).lower(irFile)
+                    FunctionInlining(
+                            context.context,
+                            NativeInlineFunctionResolver(context.context, context),
+                            alwaysCreateTemporaryVariablesForArguments = context.shouldContainDebugInfo()
+                    ).lower(irFile)
                 }
             }
         },
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt
index 70253e3..5b242d7 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt
@@ -2905,12 +2905,10 @@
     }
 }
 
-private fun IrValueParameter.debugNameConversion() = descriptor.name.debugNameConversion()
-
-private fun IrVariable.debugNameConversion() = descriptor.name.debugNameConversion()
-
 private val thisName = Name.special("<this>")
 private val underscoreThisName = Name.identifier("_this")
+private val doubleUnderscoreThisName = Name.identifier("__this")
+
 /**
  * HACK: this is workaround for GH-2316, to let IDE some how operate with this.
  * We're experiencing issue with libclang which is used as compiler of expression in lldb
@@ -2918,9 +2916,15 @@
  *   1. <this> isn't accepted by libclang as valid variable name.
  *   2. this is reserved name and compiled in special way.
  */
-private fun Name.debugNameConversion(): Name = when(this) {
-    thisName -> underscoreThisName
-    else -> this
+private fun IrValueDeclaration.debugNameConversion(): Name {
+    val name = descriptor.name
+    if (name == thisName) {
+        return when (origin) {
+            IrDeclarationOrigin.IR_TEMPORARY_VARIABLE_FOR_INLINED_EXTENSION_RECEIVER -> doubleUnderscoreThisName
+            else -> underscoreThisName
+        }
+    }
+    return name
 }
 
 internal class LocationInfo(val scope: DIScopeOpaqueRef,
diff --git a/kotlin-native/backend.native/tests/debugger/src/test/kotlin/org/jetbrains/kotlin/native/test/debugger/LldbTests.kt b/kotlin-native/backend.native/tests/debugger/src/test/kotlin/org/jetbrains/kotlin/native/test/debugger/LldbTests.kt
index e1d9e76..e60c9c7 100644
--- a/kotlin-native/backend.native/tests/debugger/src/test/kotlin/org/jetbrains/kotlin/native/test/debugger/LldbTests.kt
+++ b/kotlin-native/backend.native/tests/debugger/src/test/kotlin/org/jetbrains/kotlin/native/test/debugger/LldbTests.kt
@@ -495,4 +495,261 @@
         """.trimIndent().lldb(program)
     }
 
-}
\ No newline at end of file
+    @Test
+    fun `inline function arguments as expressions are visible`() = lldbTest("""
+        inline fun foo(
+            p1: Int, p2: Int, p3: Int, p4: Int, p5: Int, p6: Int, p7: Int,
+            f: (Int, Int, Int, Int, Int, Int, Int) -> Unit
+        ) { 
+            println()
+            f(p1, p2, p3, p4, p5, p6, p7)
+        }
+
+        fun bar() = 3
+        inline fun baz() = 3
+        fun getCondition() = true
+        fun getNull(): Int? = null
+
+        const val X = 10
+
+        fun main() {
+            val tmp = bar()
+            foo(
+                1, 
+                tmp,
+                tmp + 2, 
+                bar(), 
+                X,
+                if (getCondition()) 1 else 2,
+                when {
+                    tmp >= 0 -> 1
+                    tmp < 0 -> 2
+                    else -> 0
+                }
+            ) { p1, p2, p3, p4, p5, p6, p7 ->
+               println(p1 + p2 + p3 + p4 + p5 + p6 + p7) 
+            }
+
+            foo(
+                { 2 + 2 }(),
+                baz(),
+                listOf(1, 2, 3).filter { it > 2 }.sum(), 
+                getNull()?.let { it + 1 } ?: 0,
+                try { bar() } finally { baz() },
+                "".length, 
+                object : Any() {
+                    override fun hashCode(): Int {
+                        return 1
+                    }
+                }.hashCode()
+            ) { p1, p2, p3, p4, p5, p6, p7 ->
+               println(p1 + p2 + p3 + p4 + p5 + p6 + p7) 
+            }
+        }    
+        """, """
+        > b main.kt:5
+        > b main.kt:31
+        > b main.kt:47
+        > ${lldbCommandRunOrContinue()}
+        > v
+        (int) p1 = 1
+        (int) p2 = 3
+        (int) p3 = 5
+        (int) p4 = 3
+        (int) p5 = 10
+        (int) p6 = 1
+        (int) p7 = 1
+        > c
+        > v
+        (int) p1 = 1
+        (int) p2 = 3
+        (int) p3 = 5
+        (int) p4 = 3
+        (int) p5 = 10
+        (int) p6 = 1
+        (int) p7 = 1
+        > c
+        > v
+        (int) p1 = 4
+        (int) p2 = 3
+        (int) p3 = 3
+        (int) p4 = 0
+        (int) p5 = 3
+        (int) p6 = 0
+        (int) p7 = 1
+        > c
+        > v
+        (int) p1 = 4
+        (int) p2 = 3
+        (int) p3 = 3
+        (int) p4 = 0
+        (int) p5 = 3
+        (int) p6 = 0
+        (int) p7 = 1
+        > q
+    """)
+
+    @Test
+    fun `inline lambda anonymous argument is visible`() = lldbTest("""
+        fun main() {
+            val list = listOf(1)
+            list.filter {
+                it > 2
+            }
+
+            list.map {
+                it * 2
+            }
+
+            list.find {
+                it == 1
+            }
+        }    
+        """, """
+        > b main.kt:4
+        > b main.kt:8
+        > b main.kt:12
+        > ${lldbCommandRunOrContinue()}
+        > v
+        (int) it = 1
+        > c
+        > v
+        (int) it = 1
+        > c
+        > v
+        (int) it = 1
+        > q
+    """)
+
+    @Test
+    fun `inline function arguments of various types are visible`() = lldbTest("""
+        class A
+        object B
+        data class C(val x: Int)
+        interface I
+
+        inline fun foo(a: A, b: B, c: C, i: I, f: (A, B, C, I) -> Unit) {
+            println()
+            f(a, b, c, i)
+        }
+
+        fun main() {
+            val a = A()
+            val b = B
+            val c = C(0)
+            val i = object : I {}
+            foo(a, b, c, i) { pa, pb, pc, pi ->
+                println(pa)
+                println(pb)
+                println(pc)
+                println(pi)
+            }
+
+            foo(A(), B, C(0), object : I {}) { pa, pb, pc, pi ->
+                println(pa)
+                println(pb)
+                println(pc)
+                println(pi)
+            }
+        }    
+        """, """
+        > b main.kt:7
+        > b main.kt:17
+        > b main.kt:24
+        > ${lldbCommandRunOrContinue()}
+        > v
+        (ObjHeader *) a = []
+        (ObjHeader *) b = []
+        (ObjHeader *) c = [x: ...]
+        (ObjHeader *) i = []
+        > c
+        > v
+        (ObjHeader *) pa = []
+        (ObjHeader *) pb = []
+        (ObjHeader *) pc = [x: ...]
+        (ObjHeader *) pi = []
+        > c
+        > v
+        (ObjHeader *) a = []
+        (ObjHeader *) b = []
+        (ObjHeader *) c = [x: ...]
+        (ObjHeader *) i = []
+        > c
+        > v
+        (ObjHeader *) pa = []
+        (ObjHeader *) pb = []
+        (ObjHeader *) pc = [x: ...]
+        (ObjHeader *) pi = []
+        > q
+    """)
+
+    @Test
+    fun `inline function default parameters are visible`() = lldbTest("""
+        inline fun foo(x: Int = 0, y: String = "STRING", z: Any? = null) {
+            println(x)
+            println(y)
+            println(z)
+        }
+
+        fun main() {
+            foo()
+            foo(1)
+            foo(1, "TEST_STRING")
+            foo(1, "TEST_STRING", Any())
+        }    
+        """, """
+        > b main.kt:2
+        > ${lldbCommandRunOrContinue()}
+        > v
+        (int) x = 0
+        (ObjHeader *) y = STRING
+        (ObjHeader *) z = NULL
+        > c
+        > v
+        (int) x = 1
+        (ObjHeader *) y = STRING
+        (ObjHeader *) z = NULL
+        > c
+        > v
+        (int) x = 1
+        (ObjHeader *) y = TEST_STRING
+        (ObjHeader *) z = NULL
+        > c
+        > v
+        (int) x = 1
+        (ObjHeader *) y = TEST_STRING
+        (ObjHeader *) z = []
+        > q
+    """)
+
+    @Test
+    fun `inline function extension receiver is visible`() = lldbTest("""
+        class A {
+            inline fun String.foo(f: String.() -> Unit) {
+                println()
+                f()
+            }
+            
+            fun bar() {
+                "TEST".foo {
+                    println()
+                }
+            }
+        }
+
+        fun main() {
+            A().bar()
+        }    
+        """, """
+        > b main.kt:3
+        > b main.kt:9
+        > ${lldbCommandRunOrContinue()}
+        > v
+        (ObjHeader *) _this = []
+        (ObjHeader *) __this = TEST
+        > c
+        > v
+        (ObjHeader *) ${"$"}this${"$"}foo = TEST
+        > q
+    """)
+}