[stream-debugger] Support JBIterable in Java Stream Debugger plugin

This commit is contained in:
Vitaliy.Bibaev
2018-06-19 19:24:11 +03:00
parent 70dd8e1551
commit a5cfa7f8c2
4 changed files with 133 additions and 0 deletions
@@ -65,6 +65,7 @@
<extensions defaultExtensionNs="org.jetbrains.debugger.streams">
<librarySupport implementation="com.intellij.debugger.streams.lib.impl.StandardLibrarySupportProvider"/>
<librarySupport implementation="com.intellij.debugger.streams.lib.impl.StreamExLibrarySupportProvider"/>
<librarySupport implementation="com.intellij.debugger.streams.lib.impl.JBIterableSupportProvider"/>
</extensions>
<actions>
@@ -0,0 +1,35 @@
// Copyright 2000-2018 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.lib.impl
import com.intellij.debugger.streams.resolve.AppendResolver
import com.intellij.debugger.streams.trace.impl.handler.unified.DistinctByKeyHandler
import com.intellij.debugger.streams.trace.impl.handler.unified.DistinctTraceHandler
/**
* @author Vitaliy.Bibaev
*/
class JBIterableSupport : LibrarySupportBase() {
companion object {
fun filterOperations(vararg names: String): Array<FilterOperation> = names.map { FilterOperation(it) }.toTypedArray()
fun mapOperations(vararg names: String): Array<MappingOperation> = names.map { MappingOperation(it) }.toTypedArray()
}
init {
addIntermediateOperationsSupport(*filterOperations("filter", "skip", "skipWhile", "take", "takeWhile"))
addIntermediateOperationsSupport(*mapOperations("map", "transform"))
addIntermediateOperationsSupport(FlatMappingOperation("flatMap"),
FlatMappingOperation("flatten"))
addIntermediateOperationsSupport(DistinctOperation("unique") { num, call, dsl ->
val arguments = call.arguments
if (arguments.isEmpty()) {
return@DistinctOperation DistinctTraceHandler(num, call, dsl)
}
return@DistinctOperation DistinctByKeyHandler(num, call, dsl)
})
addIntermediateOperationsSupport(ConcatOperation("append", AppendResolver()))
addIntermediateOperationsSupport(SortedOperation("sorted"), SortedOperation("collect"))
}
}
@@ -0,0 +1,71 @@
// Copyright 2000-2018 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.lib.impl
import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.psi.impl.InheritanceBasedChainDetector
import com.intellij.debugger.streams.psi.impl.JavaChainTransformerImpl
import com.intellij.debugger.streams.psi.impl.JavaStreamChainBuilder
import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.Lambda
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.trace.dsl.impl.TextExpression
import com.intellij.debugger.streams.trace.dsl.impl.java.JavaStatementFactory
import com.intellij.debugger.streams.trace.impl.JavaTraceExpressionBuilder
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.StreamCallType
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.CommonClassNames
/**
* @author Vitaliy.Bibaev
*/
class JBIterableSupportProvider : LibrarySupportProvider {
private companion object {
const val CLASS_NAME = "com.intellij.util.containers.JBIterable"
}
private val librarySupport = JBIterableSupport()
private val dsl = DslImpl(JBIterableJavaStatementFactory())
override fun getLanguageId(): String = "JAVA"
override fun getChainBuilder(): StreamChainBuilder {
return JavaStreamChainBuilder(JavaChainTransformerImpl(), InheritanceBasedChainDetector(CLASS_NAME))
}
override fun getExpressionBuilder(project: Project): TraceExpressionBuilder {
return JavaTraceExpressionBuilder(project, librarySupport.createHandlerFactory(dsl), dsl)
}
override fun getLibrarySupport(): LibrarySupport = librarySupport
private class JBIterableJavaStatementFactory : JavaStatementFactory() {
override fun createPeekCall(elementsType: GenericType, lambda: Lambda): IntermediateStreamCall {
val lambdaBody = createEmptyLambdaBody(lambda.variableName).apply {
add(lambda.body)
doReturn(TextExpression("true"))
}
val newLambda = createLambda(lambda.variableName, lambdaBody)
return JBIterablePeekCall(elementsType, newLambda.toCode())
}
}
private class JBIterablePeekCall(private val elementsType: GenericType, private val argText: String) : IntermediateStreamCall {
override fun getName(): String = "filter"
override fun getArguments(): List<CallArgument> = listOf(CallArgumentImpl(CommonClassNames.JAVA_LANG_OBJECT, argText))
override fun getType(): StreamCallType = StreamCallType.INTERMEDIATE
override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE
override fun getTypeBefore(): GenericType = elementsType
override fun getTypeAfter(): GenericType = elementsType
}
}
@@ -0,0 +1,26 @@
// Copyright 2000-2018 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.psi.impl
import com.intellij.debugger.streams.psi.ChainDetector
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiType
import com.intellij.psi.util.InheritanceUtil
/**
* @author Vitaliy.Bibaev
*/
class InheritanceBasedChainDetector(private val baseClassName: String) : ChainDetector {
override fun isTerminationCall(callExpression: PsiMethodCallExpression): Boolean {
val method = callExpression.resolveMethod() ?: return false
return isStreamType(method.parent as? PsiClass) && !isStreamType(method.returnType)
}
override fun isIntermediateCall(callExpression: PsiMethodCallExpression): Boolean {
return isStreamType(callExpression.resolveMethod()?.returnType)
}
private fun isStreamType(type: PsiType?): Boolean = InheritanceUtil.isInheritor(type, baseClassName)
private fun isStreamType(type: PsiClass?): Boolean = InheritanceUtil.isInheritor(type, baseClassName)
}