Implement chain builder for kotlin collections

This commit is contained in:
Vitaliy.Bibaev
2017-10-26 20:05:10 +03:00
committed by Yan Zhulanow
parent ad1a91a6c8
commit e15f3624cf
4 changed files with 57 additions and 19 deletions
@@ -7,6 +7,5 @@ import com.intellij.debugger.streams.lib.impl.LibrarySupportBase
*/
class KotlinCollectionLibrarySupport : LibrarySupportBase() {
init {
TODO("add supported operations")
}
}
@@ -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
}
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
@@ -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<KtCallExpression, KtCallExpression> = mutableMapOf()
private val visitedCalls: MutableSet<KtCallExpression> = 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<List<KtCallExpression>> {
return emptyList()
val notLastCalls: Set<KtCallExpression> = previousCalls.values.toSet()
return visitedCalls.filter { it !in notLastCalls }.map { buildPsiChain(it) }
}
private fun buildPsiChain(expression: KtCallExpression): List<KtCallExpression> {
val result = mutableListOf<KtCallExpression>()
var current: KtCallExpression? = expression
while (current != null) {
result.add(current)
current = previousCalls[current]
}
result.reverse()
return result
}
}
}
@@ -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)