diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/KotlinCollectionLibrarySupport.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/KotlinCollectionLibrarySupport.kt index fd7d16ebdfd..0b461b7f036 100644 --- a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/KotlinCollectionLibrarySupport.kt +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/lib/KotlinCollectionLibrarySupport.kt @@ -7,6 +7,5 @@ import com.intellij.debugger.streams.lib.impl.LibrarySupportBase */ class KotlinCollectionLibrarySupport : LibrarySupportBase() { init { - TODO("add supported operations") } } \ No newline at end of file diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/KotlinPsiUtil.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/KotlinPsiUtil.kt index ce8610d13e0..557185b1504 100644 --- a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/KotlinPsiUtil.kt +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/KotlinPsiUtil.kt @@ -1,13 +1,12 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.streams.kotlin.psi -import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.idea.caches.resolve.analyze -import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtValueArgument import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.KotlinType /** @@ -17,13 +16,19 @@ import org.jetbrains.kotlin.types.KotlinType fun KtExpression.resolveType(): KotlinType = this.analyze().getType(this)!! -fun KtValueArgument.resolveType(): KotlinType = getArgumentExpression()!!.resolveType() - -fun KotlinType.getPackage(withGenerics: Boolean): String = StringUtil.getPackageName(getJetTypeFqName(withGenerics)) - fun KtCallExpression.callName(): String = this.calleeExpression!!.text -fun KtCallExpression.receiverType(): KotlinType? { - val resolvedCall = getResolvedCall(analyze()) - return resolvedCall?.dispatchReceiver?.type -} \ No newline at end of file +fun KtCallExpression.receiver(): ReceiverValue? { + val resolvedCall = getResolvedCall(analyze()) ?: return null + return resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver +} + +fun KtCallExpression.previousCall(): KtCallExpression? { + val parent = this.parent as? KtDotQualifiedExpression ?: return null + val receiverExpression = parent.receiverExpression + if (receiverExpression is KtCallExpression) return receiverExpression + if (receiverExpression is KtDotQualifiedExpression) return receiverExpression.selectorExpression as? KtCallExpression + return null +} + +fun KtCallExpression.receiverType(): KotlinType? = receiver()?.type \ No newline at end of file diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinCollectionChainBuilder.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinCollectionChainBuilder.kt index ffb33f67cdc..b3a8445315d 100644 --- a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinCollectionChainBuilder.kt +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinCollectionChainBuilder.kt @@ -1,12 +1,26 @@ // Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.streams.kotlin.psi.impl +import com.intellij.debugger.streams.kotlin.psi.previousCall +import com.intellij.debugger.streams.kotlin.psi.receiverType +import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.psi.KtCallExpression /** * @author Vitaliy.Bibaev */ -class KotlinCollectionChainBuilder : KotlinChainBuilderBase(TODO("transmit here a correct transformer")) { +class KotlinCollectionChainBuilder : KotlinChainBuilderBase(KotlinChainTransformerImpl()) { + private companion object { + // TODO: Avoid enumeration of all available types + val SUPPORTED_RECEIVERS = setOf("kotlin.collections.List", "kotlin.collections.Set") + } + + private fun isCollectionTransformationCall(expression: KtCallExpression): Boolean { + val receiverType = expression.receiverType() ?: return false + val receiverTypeName = receiverType.getJetTypeFqName(false) + return SUPPORTED_RECEIVERS.contains(receiverTypeName) + } + override val existenceChecker: ExistenceChecker = object : ExistenceChecker() { override fun visitCallExpression(expression: KtCallExpression) { if (isFound()) return @@ -17,20 +31,40 @@ class KotlinCollectionChainBuilder : KotlinChainBuilderBase(TODO("transmit here } } - private fun isCollectionTransformationCall(expression: KtCallExpression): Boolean { - TODO("determine that expression is a collection transformation") - } + } override fun createChainsBuilder(): ChainBuilder = object : ChainBuilder() { private val previousCalls: MutableMap = mutableMapOf() + private val visitedCalls: MutableSet = mutableSetOf() override fun visitCallExpression(expression: KtCallExpression) { super.visitCallExpression(expression) + if (isCollectionTransformationCall(expression)) { + visitedCalls.add(expression) + val previous = expression.previousCall() + if (previous != null && isCollectionTransformationCall(previous)) { + previousCalls[expression] = previous + } + } } override fun chains(): List> { - return emptyList() + val notLastCalls: Set = previousCalls.values.toSet() + return visitedCalls.filter { it !in notLastCalls }.map { buildPsiChain(it) } + } + + private fun buildPsiChain(expression: KtCallExpression): List { + val result = mutableListOf() + var current: KtCallExpression? = expression + while (current != null) { + result.add(current) + current = previousCalls[current] + } + + result.reverse() + + return result } } } \ No newline at end of file diff --git a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinJavaStreamChainBuilder.kt b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinJavaStreamChainBuilder.kt index 4e438e715e1..916d542448e 100644 --- a/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinJavaStreamChainBuilder.kt +++ b/idea/idea-jvm/src/com/intellij/debugger/streams/kotlin/psi/impl/KotlinJavaStreamChainBuilder.kt @@ -2,6 +2,7 @@ package com.intellij.debugger.streams.kotlin.psi.impl import com.intellij.debugger.streams.kotlin.psi.StreamCallChecker +import com.intellij.debugger.streams.kotlin.psi.previousCall import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import java.util.* @@ -40,8 +41,7 @@ class KotlinJavaStreamChainBuilder(private val callChecker: StreamCallChecker) : myTerminationCalls.add(expression) } - val parent = expression.parent as? KtDotQualifiedExpression ?: return - val parentCall = (parent.receiverExpression as? KtDotQualifiedExpression)?.selectorExpression + val parentCall = expression.previousCall() if (parentCall is KtCallExpression && callChecker.isStreamCall(parentCall)) { myPreviousCalls.put(expression, parentCall) updateCallTree(parentCall)