diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinChainTransformerImpl.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinChainTransformerImpl.kt index 153a08126bc..4719102f67e 100644 --- a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinChainTransformerImpl.kt +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinChainTransformerImpl.kt @@ -6,18 +6,22 @@ import com.intellij.debugger.streams.kotlin.psi.KotlinPsiUtil import com.intellij.debugger.streams.kotlin.psi.callName import com.intellij.debugger.streams.kotlin.psi.resolveType import com.intellij.debugger.streams.psi.ChainTransformer +import com.intellij.debugger.streams.trace.impl.handler.type.GenericType import com.intellij.debugger.streams.wrapper.CallArgument import com.intellij.debugger.streams.wrapper.IntermediateStreamCall +import com.intellij.debugger.streams.wrapper.QualifierExpression import com.intellij.debugger.streams.wrapper.StreamChain import com.intellij.debugger.streams.wrapper.impl.* import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import org.jetbrains.kotlin.psi.KtValueArgument import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.types.KotlinType /** * @author Vitaliy.Bibaev @@ -37,15 +41,10 @@ class KotlinChainTransformerImpl(private val typeExtractor: CallTypeExtractor) : terminationsPsiCall.valueArguments.map { createCallArgument(terminationsPsiCall, it) }, typeBeforeTerminator, resultType, terminationsPsiCall.textRange) - val qualifierTypeAfter = + val typeAfterQualifier = if (intermediateCalls.isEmpty()) typeBeforeTerminator else intermediateCalls.first().typeBefore - val firstCall = callChain.first() - val parent = firstCall.parent - val qualifier = if (parent is KtDotQualifiedExpression) - QualifierExpressionImpl(parent.receiverExpression.text, parent.receiverExpression.textRange, qualifierTypeAfter) - else // This is possible only when {@code this} inherits Stream/Iterable/Sequence/etc - QualifierExpressionImpl("", TextRange.EMPTY_RANGE, qualifierTypeAfter) + val qualifier = createQualifier(callChain.first(), typeAfterQualifier) return StreamChainImpl(qualifier, intermediateCalls, terminationCall, context) } @@ -61,4 +60,29 @@ class KotlinChainTransformerImpl(private val typeExtractor: CallTypeExtractor) : val parameter = resolvedCall.getParameterForArgument(arg) ?: return arg.toCallArgument() return CallArgumentImpl(KotlinPsiUtil.getTypeName(parameter.type), arg.text) } + + private fun createQualifier(expression: PsiElement, typeAfter: GenericType): QualifierExpression { + val parent = expression.parent as? KtDotQualifiedExpression + ?: return QualifierExpressionImpl("", TextRange.EMPTY_RANGE, typeAfter) + val receiver = parent.receiverExpression + val qualifier = QualifierExpressionImpl(receiver.text, receiver.textRange, typeAfter) + if (receiver.resolveType().isArray) { + return WrappedQualifier(qualifier) + } + + return qualifier + } + + /** + * Kotlin arrays has not {@code onEach} extension. But current implementation uses onEach to increment a time counter. + * We use asIterable to avoid further issues with the transformed expression evaluation + */ + private class WrappedQualifier(private val qualifierExpression: QualifierExpression) + : QualifierExpression by qualifierExpression { + override val text: String + get() = qualifierExpression.text + ".asIterable()" + } + + private val KotlinType.isArray: Boolean + get() = KotlinBuiltIns.isArray(this) || KotlinBuiltIns.isPrimitiveArray(this) } diff --git a/idea/testData/debugger/sequence/exec/collection/outs/filterPrimitiveAsTermination.out b/idea/testData/debugger/sequence/exec/collection/outs/filterPrimitiveAsTermination.out index 99068d8823e..444a4696eb3 100644 --- a/idea/testData/debugger/sequence/exec/collection/outs/filterPrimitiveAsTermination.out +++ b/idea/testData/debugger/sequence/exec/collection/outs/filterPrimitiveAsTermination.out @@ -2,15 +2,18 @@ LineBreakpoint created at FilterPrimitiveAsTermination.kt:5 Run Java Connected to the target VM FilterPrimitiveAsTermination.kt:5 -Exception caught: junit.framework.AssertionFailedError: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: -@SinceKotlin public inline fun ???.onEach(action: (Char) -> Unit): ??? defined in kotlin.text -@SinceKotlin public inline fun > ByteArray.onEach(action: (???) -> Unit): ByteArray defined in kotlin.collections -@SinceKotlin public inline fun > ByteArray.onEach(action: (Map.Entry) -> Unit): ByteArray defined in kotlin.collections -@SinceKotlin public fun Sequence.onEach(action: (???) -> Unit): Sequence defined in kotlin.sequences, Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: -@SinceKotlin public inline fun ???.onEach(action: (Char) -> Unit): ??? defined in kotlin.text -@SinceKotlin public inline fun > ByteArray.onEach(action: (???) -> Unit): ByteArray defined in kotlin.collections -@SinceKotlin public inline fun > ByteArray.onEach(action: (Map.Entry) -> Unit): ByteArray defined in kotlin.collections -@SinceKotlin public fun Sequence.onEach(action: (???) -> Unit): Sequence defined in kotlin.sequences +byteArrayOf(1, 3, 50).asIterable() +.filter({ it == 50.toByte() }) +filter + before: 4,6,8 + after: 8 +mappings for filter + direct: + 4 -> nothing + 6 -> nothing + 8 -> 8 + reverse: + 8 <- 8 Disconnected from the target VM WRONG!