Implement chain builder for kotlin collections
This commit is contained in:
committed by
Yan Zhulanow
parent
ad1a91a6c8
commit
e15f3624cf
-1
@@ -7,6 +7,5 @@ import com.intellij.debugger.streams.lib.impl.LibrarySupportBase
|
|||||||
*/
|
*/
|
||||||
class KotlinCollectionLibrarySupport : LibrarySupportBase() {
|
class KotlinCollectionLibrarySupport : LibrarySupportBase() {
|
||||||
init {
|
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.
|
// 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
|
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.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
|
||||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
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.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,13 +16,19 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
fun KtExpression.resolveType(): KotlinType =
|
fun KtExpression.resolveType(): KotlinType =
|
||||||
this.analyze().getType(this)!!
|
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.callName(): String = this.calleeExpression!!.text
|
||||||
|
|
||||||
fun KtCallExpression.receiverType(): KotlinType? {
|
fun KtCallExpression.receiver(): ReceiverValue? {
|
||||||
val resolvedCall = getResolvedCall(analyze())
|
val resolvedCall = getResolvedCall(analyze()) ?: return null
|
||||||
return resolvedCall?.dispatchReceiver?.type
|
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
|
||||||
+39
-5
@@ -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.
|
// 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
|
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
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Vitaliy.Bibaev
|
* @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 val existenceChecker: ExistenceChecker = object : ExistenceChecker() {
|
||||||
override fun visitCallExpression(expression: KtCallExpression) {
|
override fun visitCallExpression(expression: KtCallExpression) {
|
||||||
if (isFound()) return
|
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() {
|
override fun createChainsBuilder(): ChainBuilder = object : ChainBuilder() {
|
||||||
private val previousCalls: MutableMap<KtCallExpression, KtCallExpression> = mutableMapOf()
|
private val previousCalls: MutableMap<KtCallExpression, KtCallExpression> = mutableMapOf()
|
||||||
|
private val visitedCalls: MutableSet<KtCallExpression> = mutableSetOf()
|
||||||
|
|
||||||
override fun visitCallExpression(expression: KtCallExpression) {
|
override fun visitCallExpression(expression: KtCallExpression) {
|
||||||
super.visitCallExpression(expression)
|
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>> {
|
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
-2
@@ -2,6 +2,7 @@
|
|||||||
package com.intellij.debugger.streams.kotlin.psi.impl
|
package com.intellij.debugger.streams.kotlin.psi.impl
|
||||||
|
|
||||||
import com.intellij.debugger.streams.kotlin.psi.StreamCallChecker
|
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.KtCallExpression
|
||||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -40,8 +41,7 @@ class KotlinJavaStreamChainBuilder(private val callChecker: StreamCallChecker) :
|
|||||||
myTerminationCalls.add(expression)
|
myTerminationCalls.add(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
val parent = expression.parent as? KtDotQualifiedExpression ?: return
|
val parentCall = expression.previousCall()
|
||||||
val parentCall = (parent.receiverExpression as? KtDotQualifiedExpression)?.selectorExpression
|
|
||||||
if (parentCall is KtCallExpression && callChecker.isStreamCall(parentCall)) {
|
if (parentCall is KtCallExpression && callChecker.isStreamCall(parentCall)) {
|
||||||
myPreviousCalls.put(expression, parentCall)
|
myPreviousCalls.put(expression, parentCall)
|
||||||
updateCallTree(parentCall)
|
updateCallTree(parentCall)
|
||||||
|
|||||||
Reference in New Issue
Block a user