diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt index 050f3ab5592..a34392f07ff 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/DebuggerFieldSyntheticScopeProvider.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.resolve.DescriptorFactory -import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt index 94cb4bba8ac..da7a0d11109 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinCodeFragmentFactory.kt @@ -168,10 +168,12 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() { else debuggerContext.frameProxy?.stackFrame - val visibleVariables = frame?.let { - val values = it.getValues(it.visibleVariables()) + val visibleVariables = if (frame != null) { + val values = frame.getValues(frame.visibleVariables()) values.filterValues { it != null } - } ?: emptyMap() + } else { + emptyMap() + } frameInfo = FrameInfo(frame?.thisObject(), visibleVariables) } catch (ignored: AbsentInformationException) { @@ -315,7 +317,7 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() { // elementAt can be PsiWhiteSpace when codeFragment is created from line start offset (in case of first opening EE window) val lineStartOffset = if (elementAt is PsiWhiteSpace || elementAt is PsiComment) { PsiTreeUtil.skipSiblingsForward(elementAt, PsiWhiteSpace::class.java, PsiComment::class.java)?.textOffset - ?: elementAt.textOffset + ?: elementAt.textOffset } else { elementAt.textOffset } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt index be423439301..47c6fea3d79 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt @@ -59,31 +59,39 @@ import java.util.concurrent.ConcurrentHashMap class KotlinDebuggerCaches(project: Project) { private val cachedCompiledData = CachedValuesManager.getManager(project).createCachedValue( - { - CachedValueProvider.Result>( - MultiMap.create(), PsiModificationTracker.MODIFICATION_COUNT) - }, false) + { + CachedValueProvider.Result>( + MultiMap.create(), PsiModificationTracker.MODIFICATION_COUNT + ) + }, false + ) private val cachedClassNames = CachedValuesManager.getManager(project).createCachedValue( - { - CachedValueProvider.Result>>( - ConcurrentHashMap>(), - PsiModificationTracker.MODIFICATION_COUNT) - }, false) + { + CachedValueProvider.Result>>( + ConcurrentHashMap(), + PsiModificationTracker.MODIFICATION_COUNT + ) + }, false + ) private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue( - { - CachedValueProvider.Result>( - ConcurrentHashMap(), - PsiModificationTracker.MODIFICATION_COUNT) - }, false) + { + CachedValueProvider.Result>( + ConcurrentHashMap(), + PsiModificationTracker.MODIFICATION_COUNT + ) + }, false + ) private val debugInfoCache = CachedValuesManager.getManager(project).createCachedValue( - { - CachedValueProvider.Result( - createWeakBytecodeDebugInfoStorage(), - PsiModificationTracker.MODIFICATION_COUNT) - }, false) + { + CachedValueProvider.Result( + createWeakBytecodeDebugInfoStorage(), + PsiModificationTracker.MODIFICATION_COUNT + ) + }, false + ) companion object { private val LOG = Logger.getLogger(KotlinDebuggerCaches::class.java)!! @@ -91,10 +99,10 @@ class KotlinDebuggerCaches(project: Project) { fun getInstance(project: Project) = ServiceManager.getService(project, KotlinDebuggerCaches::class.java)!! fun getOrCreateCompiledData( - codeFragment: KtCodeFragment, - sourcePosition: SourcePosition, - evaluationContext: EvaluationContextImpl, - create: (KtCodeFragment, SourcePosition) -> CompiledDataDescriptor + codeFragment: KtCodeFragment, + sourcePosition: SourcePosition, + evaluationContext: EvaluationContextImpl, + create: (KtCodeFragment, SourcePosition) -> CompiledDataDescriptor ): CompiledDataDescriptor { val evaluateExpressionCache = getInstance(codeFragment.project) @@ -157,8 +165,7 @@ class KotlinDebuggerCaches(project: Project) { val newValue = if (!isInLibrary) { createTypeMapperForSourceFile(file) - } - else { + } else { val element = getElementToCreateTypeMapperForLibraryFile(psiElement) createTypeMapperForLibraryFile(element, file) } @@ -168,40 +175,42 @@ class KotlinDebuggerCaches(project: Project) { } fun getOrReadDebugInfoFromBytecode( - project: Project, - jvmName: JvmClassName, - file: VirtualFile): BytecodeDebugInfo? { + project: Project, + jvmName: JvmClassName, + file: VirtualFile + ): BytecodeDebugInfo? { val cache = getInstance(project) return cache.debugInfoCache.value[BinaryCacheKey(project, jvmName, file)] } private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) = - runReadAction { element as? KtElement ?: PsiTreeUtil.getParentOfType(element, KtElement::class.java)!! } + runReadAction { element as? KtElement ?: PsiTreeUtil.getParentOfType(element, KtElement::class.java)!! } private fun createTypeMapperForLibraryFile(element: KtElement, file: KtFile): KotlinTypeMapper = - runInReadActionWithWriteActionPriorityWithPCE { - createTypeMapper(file, element.analyzeAndGetResult()) - } + runInReadActionWithWriteActionPriorityWithPCE { + createTypeMapper(file, element.analyzeAndGetResult()) + } private fun createTypeMapperForSourceFile(file: KtFile): KotlinTypeMapper = - runInReadActionWithWriteActionPriorityWithPCE { - createTypeMapper(file, file.analyzeWithAllCompilerChecks().apply(AnalysisResult::throwIfError)) - } + runInReadActionWithWriteActionPriorityWithPCE { + createTypeMapper(file, file.analyzeWithAllCompilerChecks().apply(AnalysisResult::throwIfError)) + } private fun createTypeMapper(file: KtFile, analysisResult: AnalysisResult): KotlinTypeMapper { val state = GenerationState.Builder( - file.project, - ClassBuilderFactories.THROW_EXCEPTION, - analysisResult.moduleDescriptor, - analysisResult.bindingContext, - listOf(file), - CompilerConfiguration.EMPTY + file.project, + ClassBuilderFactories.THROW_EXCEPTION, + analysisResult.moduleDescriptor, + analysisResult.bindingContext, + listOf(file), + CompilerConfiguration.EMPTY ).build() state.beforeCompile() return state.typeMapper } - @TestOnly fun addTypeMapper(file: KtFile, typeMapper: KotlinTypeMapper) { + @TestOnly + fun addTypeMapper(file: KtFile, typeMapper: KotlinTypeMapper) { getInstance(file.project).cachedTypeMappers.value[file] = typeMapper } } @@ -216,7 +225,12 @@ class KotlinDebuggerCaches(project: Project) { val thisDescriptor = value.asmType.getClassDescriptor(context.debugProcess.searchScope) val superClassDescriptor = jetType.constructor.declarationDescriptor as? ClassDescriptor - return@all thisDescriptor != null && superClassDescriptor != null && runReadAction { DescriptorUtils.isSubclass(thisDescriptor, superClassDescriptor) } + return@all thisDescriptor != null && superClassDescriptor != null && runReadAction { + DescriptorUtils.isSubclass( + thisDescriptor, + superClassDescriptor + ) + } } } @@ -230,6 +244,7 @@ class KotlinDebuggerCaches(project: Project) { data class Parameter(val callText: String, val type: KotlinType, val value: Value? = null, val error: EvaluateException? = null) class ComputedClassNames(val classNames: List, val shouldBeCached: Boolean) { + @Suppress("FunctionName") companion object { val EMPTY = ComputedClassNames.Cached(emptyList()) @@ -242,8 +257,7 @@ class KotlinDebuggerCaches(project: Project) { fun distinct() = ComputedClassNames(classNames.distinct(), shouldBeCached) operator fun plus(other: ComputedClassNames) = ComputedClassNames( - classNames + other.classNames, shouldBeCached && other.shouldBeCached) + classNames + other.classNames, shouldBeCached && other.shouldBeCached + ) } -} - -private fun String?.toList() = if (this == null) emptyList() else listOf(this) \ No newline at end of file +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt index c1b9e061b7e..396b6486d87 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -95,12 +95,11 @@ import org.jetbrains.org.objectweb.asm.tree.ClassNode import org.jetbrains.org.objectweb.asm.tree.MethodNode import java.util.* -internal val THIS_NAME = "this" internal val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluator") -internal val GENERATED_FUNCTION_NAME = "generated_for_debugger_fun" -internal val GENERATED_CLASS_NAME = "Generated_for_debugger_class" +internal const val GENERATED_FUNCTION_NAME = "generated_for_debugger_fun" +internal const val GENERATED_CLASS_NAME = "Generated_for_debugger_class" -private val DEBUG_MODE = false +private const val DEBUG_MODE = false object KotlinEvaluationBuilder : EvaluatorBuilder { override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator { @@ -117,17 +116,23 @@ object KotlinEvaluationBuilder : EvaluatorBuilder { val document = PsiDocumentManager.getInstance(file.project).getDocument(file) if (document == null || document.lineCount < position.line) { throw EvaluateExceptionUtil.createEvaluateException( - "Couldn't evaluate kotlin expression: breakpoint is placed outside the file. " + - "It may happen when you've changed source file after starting a debug process.") + "Couldn't evaluate kotlin expression: breakpoint is placed outside the file. " + + "It may happen when you've changed source file after starting a debug process." + ) } } if (codeFragment.context !is KtElement) { - val attachments = arrayOf(attachmentByPsiFile(position.file), - attachmentByPsiFile(codeFragment), - Attachment("breakpoint.info", "line: ${position.line}")) + val attachments = arrayOf( + attachmentByPsiFile(position.file), + attachmentByPsiFile(codeFragment), + Attachment("breakpoint.info", "line: ${position.line}") + ) - LOG.error("Trying to evaluate ${codeFragment::class.java} with context ${codeFragment.context?.javaClass}", mergeAttachments(*attachments)) + LOG.error( + "Trying to evaluate ${codeFragment::class.java} with context ${codeFragment.context?.javaClass}", + mergeAttachments(*attachments) + ) throw EvaluateExceptionUtil.createEvaluateException("Couldn't evaluate kotlin expression in this context") } @@ -147,8 +152,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour var isCompiledDataFromCache = true try { - val compiledData = KotlinDebuggerCaches.getOrCreateCompiledData(codeFragment, sourcePosition, context) { - fragment, position -> + val compiledData = KotlinDebuggerCaches.getOrCreateCompiledData(codeFragment, sourcePosition, context) { fragment, position -> isCompiledDataFromCache = false extractAndCompile(fragment, position, context) } @@ -157,8 +161,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val result = if (classLoaderRef != null) { evaluateWithCompilation(context, compiledData, classLoaderRef) ?: runEval4j(context, compiledData, classLoaderRef) - } - else { + } else { runEval4j(context, compiledData, classLoaderRef) } @@ -172,32 +175,33 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour } else { result } - } - catch (e: EvaluateException) { + } catch (e: EvaluateException) { throw e - } - catch (e: ProcessCanceledException) { + } catch (e: ProcessCanceledException) { exception(e) - } - catch (e: Eval4JInterpretingException) { + } catch (e: Eval4JInterpretingException) { exception(e.cause) - } - catch (e: Exception) { + } catch (e: Exception) { val isSpecialException = isSpecialException(e) if (isSpecialException) { exception(e) } val text = runReadAction { codeFragment.context?.text ?: "null" } - val attachments = arrayOf(attachmentByPsiFile(sourcePosition.file), - attachmentByPsiFile(codeFragment), - Attachment("breakpoint.info", "line: ${runReadAction { sourcePosition.line }}"), - Attachment("context.info", text)) + val attachments = arrayOf( + attachmentByPsiFile(sourcePosition.file), + attachmentByPsiFile(codeFragment), + Attachment("breakpoint.info", "line: ${runReadAction { sourcePosition.line }}"), + Attachment("context.info", text) + ) - LOG.error(LogMessageEx.createEvent( + LOG.error( + LogMessageEx.createEvent( "Couldn't evaluate expression", ExceptionUtil.getThrowableText(e), - mergeAttachments(*attachments))) + mergeAttachments(*attachments) + ) + ) val cause = if (e.message != null) ": ${e.message}" else "" exception("An exception occurs during Evaluate Expression Action $cause") @@ -223,7 +227,11 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour } companion object { - private fun extractAndCompile(codeFragment: KtCodeFragment, sourcePosition: SourcePosition, context: EvaluationContextImpl): CompiledDataDescriptor { + private fun extractAndCompile( + codeFragment: KtCodeFragment, + sourcePosition: SourcePosition, + context: EvaluationContextImpl + ): CompiledDataDescriptor { var bindingContext = codeFragment.checkForErrors().bindingContext if (codeFragment.wrapToStringIfNeeded(bindingContext)) { @@ -234,7 +242,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val variablesCrossingInlineBounds = ScopeCheckerForEvaluator.checkScopes(bindingContext, codeFragment) val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line) - ?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}") + ?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}") val (parametersDescriptor, extractedFunction) = try { extractionResult.getParametersForDebugger(codeFragment, context) to extractionResult.declaration as KtNamedFunction } finally { @@ -253,6 +261,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour if (LOG.isDebugEnabled) { LOG.debug("Output file generated: ${file.relativePath}") } + @Suppress("ConstantConditionIf") if (DEBUG_MODE) { println(file.asText()) } @@ -297,7 +306,8 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour private val CompiledDataDescriptor.mainClass get() = classes.firstOrNull { it.isMainClass() } ?: error( - "Can't find main class for " + sourcePosition.elementAt.getParentOfType(strict = false)) + "Can't find main class for " + sourcePosition.elementAt.getParentOfType(strict = false) + ) private fun evaluateWithCompilation( context: EvaluationContextImpl, @@ -331,12 +341,12 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val argumentTypes = Type.getArgumentTypes(methodToInvoke.desc) val args = context.getArgumentsForEvaluation(compiledData.parameters, argumentTypes, compiledData) - .zip(argumentTypes) - .map { (value, type) -> - // Make argument type classes prepared for sure - eval.loadClassByName(type.className, classLoader) - boxOrUnboxArgumentIfNeeded(eval, value, type).asJdiValue(vm, type) - } + .zip(argumentTypes) + .map { (value, type) -> + // Make argument type classes prepared for sure + eval.loadClassByName(type.className, classLoader) + boxOrUnboxArgumentIfNeeded(eval, value, type).asJdiValue(vm, type) + } mainClass.invokeMethod(thread, mainClass.methods().single(), args, invokePolicy) @@ -359,8 +369,15 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val mainClassBytecode = compiledData.mainClass.bytes ClassReader(mainClassBytecode).accept(object : ClassVisitor(API_VERSION) { - override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { + override fun visitMethod( + access: Int, + name: String, + desc: String, + signature: String?, + exceptions: Array? + ): MethodVisitor? { // Maybe just take the single method from the class, as it is done in 'evaluateWithCompilation' + @Suppress("ConvertToStringTemplate") if (name == GENERATED_FUNCTION_NAME || name.startsWith(GENERATED_FUNCTION_NAME + "-")) { val argumentTypes = Type.getArgumentTypes(desc) val args = context.getArgumentsForEvaluation(compiledData.parameters, argumentTypes, compiledData) @@ -368,15 +385,25 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour return object : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) { override fun visitEnd() { virtualMachine.executeWithBreakpointsDisabled { - val eval = JDIEval(virtualMachine, - classLoader ?: context.classLoader, - context.suspendContext.thread?.threadReference!!, - context.suspendContext.getInvokePolicy()) + val eval = JDIEval( + virtualMachine, + classLoader ?: context.classLoader, + context.suspendContext.thread?.threadReference!!, + context.suspendContext.getInvokePolicy() + ) resultValue = interpreterLoop( + this, + makeInitialFrame( this, - makeInitialFrame(this, args.zip(argumentTypes).map { boxOrUnboxArgumentIfNeeded(eval, it.first, it.second) }), - eval + args.zip(argumentTypes).map { + boxOrUnboxArgumentIfNeeded( + eval, + it.first, + it.second + ) + }), + eval ) } } @@ -387,7 +414,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour } }, 0) - return resultValue ?: throw IllegalStateException("resultValue is null: cannot find method " + GENERATED_FUNCTION_NAME) + return resultValue ?: throw IllegalStateException("resultValue is null: cannot find method $GENERATED_FUNCTION_NAME") } private inline fun VirtualMachine.executeWithBreakpointsDisabled(block: () -> T): T { @@ -410,8 +437,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour if (parameterType == unboxedType) { return eval.unboxType(argumentValue, parameterType) } - } - catch(ignored: UnsupportedOperationException) { + } catch (ignored: UnsupportedOperationException) { } } @@ -465,7 +491,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour override fun visitProperty(property: KtProperty) { val value = property.getUserData(KotlinCodeFragmentFactory.LABEL_VARIABLE_VALUE_KEY) if (value != null) { - valuesForLabels.put(property.name?.quoteIfNeeded()!!, value.asValue()) + valuesForLabels[property.name?.quoteIfNeeded()!!] = value.asValue() } } }) @@ -474,7 +500,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour val parameters = mutableListOf() val receiver = config.descriptor.receiverParameter if (receiver != null) { - parameters += Parameter(THIS_NAME + "@" + config.descriptor.name, receiver.getParameterType(true)) + parameters += Parameter(AsmUtil.THIS + "@" + config.descriptor.name, receiver.getParameterType(true)) } for (param in config.descriptor.parameters) { @@ -537,10 +563,10 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour } private fun createClassFileFactory( - codeFragment: KtCodeFragment, - extractedFunction: KtNamedFunction, - context: EvaluationContextImpl, - parameters: List + codeFragment: KtCodeFragment, + extractedFunction: KtNamedFunction, + context: EvaluationContextImpl, + parameters: List ): ClassFileFactory { return runReadAction { val fileForDebugger = createFileForDebugger(codeFragment, extractedFunction) @@ -548,22 +574,28 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour LOG.debug("File for eval4j:\n${runReadAction { fileForDebugger.text }}") } - val (bindingContext, moduleDescriptor, files) = fileForDebugger.checkForErrors(true, codeFragment.getContextContainingFile()) + val (bindingContext, moduleDescriptor, files) = fileForDebugger.checkForErrors( + true, + codeFragment.getContextContainingFile() + ) val generateClassFilter = object : GenerationState.GenerateClassFilter() { override fun shouldGeneratePackagePart(ktFile: KtFile) = ktFile == fileForDebugger override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject) = true - override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject) = processingClassOrObject.containingKtFile == fileForDebugger + override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject) = + processingClassOrObject.containingKtFile == fileForDebugger + override fun shouldGenerateScript(script: KtScript) = false } + @Suppress("ConstantConditionIf") val state = GenerationState.Builder( - fileForDebugger.project, - if (!DEBUG_MODE) ClassBuilderFactories.BINARIES else ClassBuilderFactories.TEST, - moduleDescriptor, - bindingContext, - files, - CompilerConfiguration.EMPTY + fileForDebugger.project, + if (!DEBUG_MODE) ClassBuilderFactories.BINARIES else ClassBuilderFactories.TEST, + moduleDescriptor, + bindingContext, + files, + CompilerConfiguration.EMPTY ).generateDeclaredClassFilter(generateClassFilter).build() val variableFinder = VariableFinder.instance(context) ?: error("No stack frame available") @@ -577,15 +609,16 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour } val valueParameters = extractedFunction.valueParameters - var paramIndex = 0 - for (param in parameters) { - val valueParameter = valueParameters[paramIndex++] + for ((paramIndex, param) in parameters.withIndex()) { + val valueParameter = valueParameters[paramIndex] val paramRef = valueParameter.typeReference if (paramRef == null) { - LOG.error("Each parameter for extracted function should have a type reference", - Attachment("codeFragment.txt", codeFragment.text), - Attachment("extractedFunction.txt", extractedFunction.text)) + LOG.error( + "Each parameter for extracted function should have a type reference", + Attachment("codeFragment.txt", codeFragment.text), + Attachment("extractedFunction.txt", extractedFunction.text) + ) exception("An exception occurs during Evaluate Expression Action") } @@ -631,8 +664,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour return runInReadActionWithWriteActionPriorityWithPCE { try { AnalyzingUtils.checkForSyntacticErrors(this) - } - catch (e: IllegalArgumentException) { + } catch (e: IllegalArgumentException) { throw EvaluateExceptionUtil.createEvaluateException(e.message) } @@ -655,18 +687,21 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour if (analyzeInlineFunctions) { val (newBindingContext, files) = DebuggerUtils.analyzeInlinedFunctions(resolutionFacade, this, false) ExtendedAnalysisResult(newBindingContext, analysisResult.moduleDescriptor, files) - } - else { + } else { ExtendedAnalysisResult(bindingContext, analysisResult.moduleDescriptor, Collections.singletonList(this)) } } } - private data class ExtendedAnalysisResult(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor, val files: List) + private data class ExtendedAnalysisResult( + val bindingContext: BindingContext, + val moduleDescriptor: ModuleDescriptor, + val files: List + ) } } -private val template = """ +private const val template = """ @file:kotlin.jvm.JvmName("$GENERATED_CLASS_NAME") !PACKAGE! @@ -675,24 +710,22 @@ private val template = """ !FUNCTION! """ -private fun createFileForDebugger(codeFragment: KtCodeFragment, - extractedFunction: KtNamedFunction +private fun createFileForDebugger( + codeFragment: KtCodeFragment, + extractedFunction: KtNamedFunction ): KtFile { val containingContextFile = codeFragment.getContextContainingFile() val importsFromContextFile = containingContextFile?.importList?.let { it.text + "\n" } ?: "" var fileText = template.replace( - "!IMPORT_LIST!", - importsFromContextFile + codeFragment.importsToString().split(KtCodeFragment.IMPORT_SEPARATOR).joinToString("\n") + "!IMPORT_LIST!", + importsFromContextFile + codeFragment.importsToString().split(KtCodeFragment.IMPORT_SEPARATOR).joinToString("\n") ) val packageFromContextFile = containingContextFile?.packageFqName?.let { if (!it.isRoot) "package ${it.quoteSegmentsIfNeeded()}" else "" } ?: "" fileText = fileText.replace("!PACKAGE!", packageFromContextFile) - - val extractedFunctionText = extractedFunction.text - assert(extractedFunctionText != null) { "Text of extracted function shouldn't be null" } fileText = fileText.replace("!FUNCTION!", extractedFunction.text!!) val jetFile = codeFragment.createKtFile("debugFile.kt", fileText) @@ -717,7 +750,7 @@ private fun PsiElement.createKtFile(fileName: String, fileText: String): KtFile val virtualFile = LightVirtualFile(fileName, KotlinLanguage.INSTANCE, fileText) virtualFile.charset = CharsetToolkit.UTF8_CHARSET val jetFile = (PsiFileFactory.getInstance(project) as PsiFileFactoryImpl) - .trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile + .trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile jetFile.analysisContext = this return jetFile } @@ -733,7 +766,7 @@ fun Type.getClassDescriptor(scope: GlobalSearchScope): ClassDescriptor? { // TODO: use the correct built-ins from the module instead of DefaultBuiltIns here JavaToKotlinClassMap.mapJavaToKotlin(jvmName)?.let( - DefaultBuiltIns.Instance.builtInsModule::findClassAcrossModuleDependencies + DefaultBuiltIns.Instance.builtInsModule::findClassAcrossModuleDependencies )?.let { return it } return runReadAction { diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinRuntimeTypeEvaluator.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinRuntimeTypeEvaluator.kt index e334c7e273e..21832b46291 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinRuntimeTypeEvaluator.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinRuntimeTypeEvaluator.kt @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.debugger.evaluate import com.intellij.debugger.DebuggerBundle import com.intellij.debugger.DebuggerInvocationUtil -import com.intellij.debugger.EvaluatingComputable import com.intellij.debugger.engine.ContextUtil import com.intellij.debugger.engine.evaluation.EvaluateException import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil @@ -41,22 +40,19 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Type as AsmType abstract class KotlinRuntimeTypeEvaluator( - editor: Editor?, - expression: KtExpression, - context: DebuggerContextImpl, - indicator: ProgressIndicator + editor: Editor?, + expression: KtExpression, + context: DebuggerContextImpl, + indicator: ProgressIndicator ) : EditorEvaluationCommand(editor, expression, context, indicator) { override fun threadAction() { var type: KotlinType? = null try { type = evaluate() - } - catch (ignored: ProcessCanceledException) { - } - catch (ignored: EvaluateException) { - } - finally { + } catch (ignored: ProcessCanceledException) { + } catch (ignored: EvaluateException) { + } finally { typeCalculationFinished(type) } } @@ -66,11 +62,12 @@ abstract class KotlinRuntimeTypeEvaluator( override fun evaluate(evaluationContext: EvaluationContextImpl): KotlinType? { val project = evaluationContext.project - val evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, EvaluatingComputable { - val codeFragment = KtPsiFactory(myElement.project).createExpressionCodeFragment( - myElement.text, myElement.containingFile.context) - KotlinEvaluationBuilder.build(codeFragment, ContextUtil.getSourcePosition(evaluationContext)) - }) + val evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project) { + val codeFragment = KtPsiFactory(myElement.project).createExpressionCodeFragment( + myElement.text, myElement.containingFile.context + ) + KotlinEvaluationBuilder.build(codeFragment, ContextUtil.getSourcePosition(evaluationContext)) + } val value = evaluator.evaluate(evaluationContext) if (value != null) { diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ScopeCheckerForEvaluator.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ScopeCheckerForEvaluator.kt index cf777fbf1ae..20826ec4c37 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ScopeCheckerForEvaluator.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/ScopeCheckerForEvaluator.kt @@ -51,7 +51,7 @@ object ScopeCheckerForEvaluator { return true } } - + currentParent = when (currentParent) { is KtCodeFragment -> currentParent.context else -> currentParent.parent diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt index 221ba650594..9c68f9683de 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt @@ -29,15 +29,15 @@ abstract class AbstractAndroidClassLoadingAdapter : ClassLoadingAdapter { protected fun wrapToByteBuffer(bytes: ArrayReference, context: EvaluationContext, process: DebugProcessImpl): ObjectReference { val byteBufferClass = process.findClass(context, "java.nio.ByteBuffer", context.classLoader) as ClassType val wrapMethod = byteBufferClass.concreteMethodByName("wrap", "([B)Ljava/nio/ByteBuffer;") - ?: error("'wrap' method not found") + ?: error("'wrap' method not found") return process.invokeMethod(context, byteBufferClass, wrapMethod, listOf(bytes)) as ObjectReference } protected fun DebugProcessImpl.tryLoadClass( - context: EvaluationContextImpl, - fqName: String, - classLoader: ClassLoaderReference? + context: EvaluationContextImpl, + fqName: String, + classLoader: ClassLoaderReference? ): ReferenceType? { return try { loadClass(context, fqName, classLoader) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidDexer.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidDexer.kt index 032726ac12a..eb2e3a74a58 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidDexer.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidDexer.kt @@ -20,7 +20,8 @@ import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor interface AndroidDexer { companion object : ProjectExtensionDescriptor( - "org.jetbrains.kotlin.androidDexer", AndroidDexer::class.java) + "org.jetbrains.kotlin.androidDexer", AndroidDexer::class.java + ) fun dex(classes: Collection): ByteArray? } \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt index ded7fbfcbc9..2014fc8907e 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AndroidOClassLoadingAdapter.kt @@ -29,11 +29,12 @@ class AndroidOClassLoadingAdapter : AbstractAndroidClassLoadingAdapter() { } private fun resolveClassLoaderClass(context: EvaluationContextImpl): ClassType? { - try { - return context.debugProcess.tryLoadClass( - context, "dalvik.system.InMemoryDexClassLoader", context.classLoader) as? ClassType + return try { + context.debugProcess.tryLoadClass( + context, "dalvik.system.InMemoryDexClassLoader", context.classLoader + ) as? ClassType } catch (e: EvaluateException) { - return null + null } } @@ -41,14 +42,17 @@ class AndroidOClassLoadingAdapter : AbstractAndroidClassLoadingAdapter() { val process = context.debugProcess val inMemoryClassLoaderClass = resolveClassLoaderClass(context) ?: error("InMemoryDexClassLoader class not found") val constructorMethod = inMemoryClassLoaderClass.concreteMethodByName( - JVMNameUtil.CONSTRUCTOR_NAME, "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V") ?: error("Constructor method not found") + JVMNameUtil.CONSTRUCTOR_NAME, "(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V" + ) ?: error("Constructor method not found") val dexBytes = dex(context, classes) ?: error("Can't dex classes") val dexBytesMirror = mirrorOfByteArray(dexBytes, context, process) val dexByteBuffer = wrapToByteBuffer(dexBytesMirror, context, process) - val newClassLoader = process.newInstance(context, inMemoryClassLoaderClass, constructorMethod, - listOf(dexByteBuffer, context.classLoader)) + val newClassLoader = process.newInstance( + context, inMemoryClassLoaderClass, constructorMethod, + listOf(dexByteBuffer, context.classLoader) + ) DebuggerUtilsEx.keep(newClassLoader, context) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt index 4e6dd606cc1..a60a02895b4 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt @@ -73,46 +73,44 @@ class OrdinaryClassLoadingAdapter : ClassLoadingAdapter { val classLoader = try { ClassLoadingUtils.getClassLoader(context, process) - } - catch (e: Exception) { - throw EvaluateException("Error creating evaluation class loader: " + e, e) + } catch (e: Exception) { + throw EvaluateException("Error creating evaluation class loader: $e", e) } val debugProcessVersionString = process.virtualMachineProxy.version() val debugProcessVersion = JavaSdkVersion.fromVersionString(debugProcessVersionString) - ?: throw EvaluateException("Unable to parse java version from $debugProcessVersionString.") + ?: throw EvaluateException("Unable to parse java version from $debugProcessVersionString.") val ideaJavaVersion = JavaSdkVersion.fromVersionString(SystemInfo.JAVA_RUNTIME_VERSION) - ?: throw EvaluateException("Unable to parse java version from ${SystemInfo.JAVA_RUNTIME_VERSION}.") + ?: throw EvaluateException("Unable to parse java version from ${SystemInfo.JAVA_RUNTIME_VERSION}.") if (!ideaJavaVersion.isAtLeast(debugProcessVersion)) { throw EvaluateException( - "Unable to compile for target level ${debugProcessVersion.description}. " + - "Need to run IDEA on java version at least $debugProcessVersion, " + - "currently running on $ideaJavaVersion") + "Unable to compile for target level ${debugProcessVersion.description}. " + + "Need to run IDEA on java version at least $debugProcessVersion, " + + "currently running on $ideaJavaVersion" + ) } try { defineClasses(classes, context, process, classLoader) - } - catch (e: Exception) { - throw EvaluateException("Error during classes definition " + e, e) + } catch (e: Exception) { + throw EvaluateException("Error during classes definition $e", e) } return classLoader } private fun defineClasses( - classes: Collection, - context: EvaluationContextImpl, - process: DebugProcessImpl, - classLoader: ClassLoaderReference + classes: Collection, + context: EvaluationContextImpl, + process: DebugProcessImpl, + classLoader: ClassLoaderReference ) { val classesToLoad = if (classes.size == 1) { // No need in loading lambda superclass if there're no lambdas classes - } - else { + } else { val lambdaSuperclasses = LAMBDA_SUPERCLASSES.map { ClassToLoad(it.name, it.name.replace('.', '/') + ".class", it.bytes) } @@ -125,12 +123,12 @@ class OrdinaryClassLoadingAdapter : ClassLoadingAdapter { } } - fun defineClass( - name: String, - bytes: ByteArray, - context: EvaluationContextImpl, - process: DebugProcessImpl, - classLoader: ClassLoaderReference + private fun defineClass( + name: String, + bytes: ByteArray, + context: EvaluationContextImpl, + process: DebugProcessImpl, + classLoader: ClassLoaderReference ) { try { val vm = process.virtualMachineProxy @@ -138,13 +136,15 @@ class OrdinaryClassLoadingAdapter : ClassLoadingAdapter { val defineMethod = classLoaderType.concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;") val nameObj = vm.mirrorOf(name) + // Still actual for older platform versions + @Suppress("DEPRECATION") DebuggerUtilsEx.keep(nameObj, context) process.invokeMethod( - context, classLoader, defineMethod, - listOf(nameObj, mirrorOfByteArray(bytes, context, process), vm.mirrorOf(0), vm.mirrorOf(bytes.size))) - } - catch (e: Exception) { + context, classLoader, defineMethod, + listOf(nameObj, mirrorOfByteArray(bytes, context, process), vm.mirrorOf(0), vm.mirrorOf(bytes.size)) + ) + } catch (e: Exception) { throw EvaluateException("Error during class $name definition: $e", e) } @@ -153,7 +153,7 @@ class OrdinaryClassLoadingAdapter : ClassLoadingAdapter { private class ClassBytes(val name: String) { val bytes: ByteArray by lazy { val inputStream = this::class.java.classLoader.getResourceAsStream(name.replace('.', '/') + ".class") - ?: throw EvaluateException("Couldn't find $name class in current class loader") + ?: throw EvaluateException("Couldn't find $name class in current class loader") inputStream.use { it.readBytes() diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt index 239eea583b1..a5bc373f18c 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -44,26 +44,31 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST fun getFunctionForExtractedFragment( - codeFragment: KtCodeFragment, - breakpointFile: PsiFile, - breakpointLine: Int + codeFragment: KtCodeFragment, + breakpointFile: PsiFile, + breakpointLine: Int ): ExtractionResult? { fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult, tmpFile: KtFile): String { if (ApplicationManager.getApplication().isInternal) { - val attachments = arrayOf(attachmentByPsiFile(tmpFile), - attachmentByPsiFile(breakpointFile), - attachmentByPsiFile(codeFragment), - Attachment("breakpoint.info", "line: $breakpointLine"), - Attachment("context.info", codeFragment.context?.text ?: "null"), - Attachment("errors.info", analysisResult.messages.joinToString("\n") { "$it: ${it.renderMessage()}" })) - LOG.error(LogMessageEx.createEvent( + val attachments = arrayOf( + attachmentByPsiFile(tmpFile), + attachmentByPsiFile(breakpointFile), + attachmentByPsiFile(codeFragment), + Attachment("breakpoint.info", "line: $breakpointLine"), + Attachment("context.info", codeFragment.context?.text ?: "null"), + Attachment("errors.info", analysisResult.messages.joinToString("\n") { "$it: ${it.renderMessage()}" }) + ) + LOG.error( + LogMessageEx.createEvent( "Internal error during evaluate expression", ExceptionUtil.getThrowableText(Throwable("Extract function fails with ${analysisResult.messages.joinToString { it.name }}")), - mergeAttachments(*attachments))) + mergeAttachments(*attachments) + ) + ) } return analysisResult.messages.joinToString(", ") { errorMessage -> - val message = when(errorMessage) { + val message = when (errorMessage) { ErrorMessage.NO_EXPRESSION -> "Cannot perform an action without an expression" ErrorMessage.NO_CONTAINER -> "Cannot perform an action at this breakpoint ${breakpointFile.name}:$breakpointLine" ErrorMessage.SYNTAX_ERRORS -> "Cannot perform an action due to erroneous code" @@ -93,11 +98,13 @@ fun getFunctionForExtractedFragment( val targetSibling = tmpFile.declarations.firstOrNull() ?: return null - val options = ExtractionOptions(inferUnitTypeForUnusedValues = false, - enableListBoxing = true, - allowSpecialClassNames = true, - captureLocalFunctions = true, - canWrapInWith = true) + val options = ExtractionOptions( + inferUnitTypeForUnusedValues = false, + enableListBoxing = true, + allowSpecialClassNames = true, + captureLocalFunctions = true, + canWrapInWith = true + ) val extractionData = ExtractionData(tmpFile, newDebugExpressions.toRange(), targetSibling, null, options) try { val analysisResult = extractionData.performAnalysis() @@ -107,12 +114,18 @@ fun getFunctionForExtractedFragment( val validationResult = analysisResult.descriptor!!.validate() if (!validationResult.conflicts.isEmpty) { - throw EvaluateExceptionUtil.createEvaluateException("Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet().joinToString(",") { it.text }}") + throw EvaluateExceptionUtil.createEvaluateException( + "Following declarations are unavailable in debug scope: ${validationResult.conflicts.keySet().joinToString( + "," + ) { it.text }}" + ) } - val generatorOptions = ExtractionGeneratorOptions(inTempFile = true, - dummyName = GENERATED_FUNCTION_NAME, - allowExpressionBody = false) + val generatorOptions = ExtractionGeneratorOptions( + inTempFile = true, + dummyName = GENERATED_FUNCTION_NAME, + allowExpressionBody = false + ) return ExtractionGeneratorConfiguration(validationResult.descriptor, generatorOptions).generateDeclaration() } finally { Disposer.dispose(extractionData) @@ -154,7 +167,7 @@ private fun KtCodeFragment.clearContextElement() { } private fun KtFile.findContextElement(): KtElement? { - return this.findDescendantOfType { it.IS_CONTEXT_ELEMENT == true } + return this.findDescendantOfType { it.IS_CONTEXT_ELEMENT } } private var PsiElement.DEBUG_SMART_CAST: PsiElement? by CopyablePsiUserDataProperty(Key.create("DEBUG_SMART_CAST")) @@ -167,8 +180,9 @@ private fun KtCodeFragment.markSmartCasts() { val smartCast = bindingContext.get(SMARTCAST, expression)?.defaultType if (smartCast != null) { val smartCastedExpression = factory.createExpressionByPattern( - "($0 as ${DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(smartCast)})", - expression) as KtParenthesizedExpression + "($0 as ${DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(smartCast)})", + expression + ) as KtParenthesizedExpression expression.DEBUG_SMART_CAST = smartCastedExpression } @@ -194,8 +208,7 @@ private fun addImportsToFile(newImportList: KtImportList?, tmpFile: KtFile) { val packageDirective = tmpFile.packageDirective tmpFile.addAfter(psiFactory.createNewLine(), packageDirective) tmpFile.addAfter(newImportList, tmpFile.packageDirective) - } - else { + } else { newImportList.imports.forEach { tmpFileImportList.add(psiFactory.createNewLine()) tmpFileImportList.add(it) @@ -293,20 +306,17 @@ private fun findElementBefore(contextElement: PsiElement): PsiElement? { val delegateExpressionOrInitializer = contextElement.delegateExpressionOrInitializer if (delegateExpressionOrInitializer != null) { wrapInLambdaCall(delegateExpressionOrInitializer) - } - else { + } else { val getter = contextElement.getter val bodyExpression = getter?.bodyExpression if (getter != null && bodyExpression != null) { if (!getter.hasBlockBody()) { wrapInLambdaCall(bodyExpression) - } - else { + } else { (bodyExpression as KtBlockExpression).statements.first() } - } - else { + } else { contextElement } } @@ -343,8 +353,7 @@ private fun findElementBefore(contextElement: PsiElement): PsiElement? { val entryExpression = contextElement.expression if (entryExpression is KtBlockExpression) { entryExpression.statements.firstOrNull() ?: entryExpression.lastChild - } - else { + } else { wrapInLambdaCall(entryExpression!!) } }