Apply project code style settings to sequence debugger code

This commit is contained in:
Vitaliy.Bibaev
2018-06-09 11:12:48 +03:00
committed by Yan Zhulanow
parent 245a358ea8
commit 2d22267cf1
67 changed files with 1480 additions and 1413 deletions
@@ -5,5 +5,5 @@ package org.jetbrains.kotlin.idea.debugger.sequence.lib
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
object LibraryUtil { object LibraryUtil {
val KOTLIN_LANGUAGE_ID = "kotlin" val KOTLIN_LANGUAGE_ID = "kotlin"
} }
@@ -1,7 +1,6 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.lib.collections package org.jetbrains.kotlin.idea.debugger.sequence.lib.collections
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.interpret.FilterTraceInterpreter
import com.intellij.debugger.streams.lib.IntermediateOperation import com.intellij.debugger.streams.lib.IntermediateOperation
import com.intellij.debugger.streams.lib.TerminalOperation import com.intellij.debugger.streams.lib.TerminalOperation
import com.intellij.debugger.streams.lib.impl.LibrarySupportBase import com.intellij.debugger.streams.lib.impl.LibrarySupportBase
@@ -16,38 +15,39 @@ import com.intellij.debugger.streams.wrapper.TerminatorStreamCall
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.BothSemanticHandlerWrapper import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.BothSemanticHandlerWrapper
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.BothSemanticsHandler import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.BothSemanticsHandler
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.FilterCallHandler import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.FilterCallHandler
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.interpret.FilterTraceInterpreter
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinCollectionLibrarySupport : LibrarySupportBase() { class KotlinCollectionLibrarySupport : LibrarySupportBase() {
init { init {
addOperation(FilterOperation("filter", FilterCallHandler(), true)) addOperation(FilterOperation("filter", FilterCallHandler(), true))
addOperation(FilterOperation("filterNot", FilterCallHandler(), false)) addOperation(FilterOperation("filterNot", FilterCallHandler(), false))
} }
private fun addOperation(operation: CollectionOperation) { private fun addOperation(operation: CollectionOperation) {
addIntermediateOperationsSupport(operation) addIntermediateOperationsSupport(operation)
addTerminationOperationsSupport(operation) addTerminationOperationsSupport(operation)
} }
private abstract class CollectionOperation(override val name: String, private abstract class CollectionOperation(
handler: BothSemanticsHandler override val name: String,
) handler: BothSemanticsHandler
: IntermediateOperation, TerminalOperation { ) : IntermediateOperation, TerminalOperation {
private val wrapper = BothSemanticHandlerWrapper(handler) private val wrapper = BothSemanticHandlerWrapper(handler)
override fun getTraceHandler(callOrder: Int, call: IntermediateStreamCall, dsl: Dsl): IntermediateCallHandler = override fun getTraceHandler(callOrder: Int, call: IntermediateStreamCall, dsl: Dsl): IntermediateCallHandler =
wrapper.createIntermediateHandler(callOrder, call, dsl) wrapper.createIntermediateHandler(callOrder, call, dsl)
override fun getTraceHandler(call: TerminatorStreamCall, resultExpression: String, dsl: Dsl): TerminatorCallHandler = override fun getTraceHandler(call: TerminatorStreamCall, resultExpression: String, dsl: Dsl): TerminatorCallHandler =
wrapper.createTerminatorHandler(call, resultExpression, dsl) wrapper.createTerminatorHandler(call, resultExpression, dsl)
} }
private class FilterOperation(name: String, handler: BothSemanticsHandler, valueToAccept: Boolean) private class FilterOperation(name: String, handler: BothSemanticsHandler, valueToAccept: Boolean) :
: CollectionOperation(name, handler) { CollectionOperation(name, handler) {
override val traceInterpreter: CallTraceInterpreter = FilterTraceInterpreter(valueToAccept) override val traceInterpreter: CallTraceInterpreter = FilterTraceInterpreter(valueToAccept)
override val valuesOrderResolver: ValuesOrderResolver = FilterResolver() override val valuesOrderResolver: ValuesOrderResolver = FilterResolver()
} }
} }
@@ -1,34 +1,34 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.lib.collections package org.jetbrains.kotlin.idea.debugger.sequence.lib.collections
import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil
import org.jetbrains.kotlin.idea.debugger.sequence.psi.collections.KotlinCollectionChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinCollectionsPeekCallFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder
import com.intellij.debugger.streams.lib.LibrarySupport import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.trace.TraceExpressionBuilder import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.wrapper.StreamChainBuilder import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil
import org.jetbrains.kotlin.idea.debugger.sequence.psi.collections.KotlinCollectionChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinCollectionsPeekCallFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinCollectionSupportProvider : LibrarySupportProvider { class KotlinCollectionSupportProvider : LibrarySupportProvider {
private companion object { private companion object {
val builder: StreamChainBuilder = KotlinCollectionChainBuilder() val builder: StreamChainBuilder = KotlinCollectionChainBuilder()
val support: LibrarySupport = KotlinCollectionLibrarySupport() val support: LibrarySupport = KotlinCollectionLibrarySupport()
val dsl = DslImpl(KotlinStatementFactory(KotlinCollectionsPeekCallFactory())) val dsl = DslImpl(KotlinStatementFactory(KotlinCollectionsPeekCallFactory()))
} }
override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID
override fun getChainBuilder(): StreamChainBuilder = builder override fun getChainBuilder(): StreamChainBuilder = builder
override fun getLibrarySupport(): LibrarySupport = support override fun getLibrarySupport(): LibrarySupport = support
override fun getExpressionBuilder(project: Project): TraceExpressionBuilder override fun getExpressionBuilder(project: Project): TraceExpressionBuilder =
= KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl)) KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl))
} }
@@ -1,6 +1,13 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.lib.java package org.jetbrains.kotlin.idea.debugger.sequence.lib.java
import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.lib.impl.StandardLibrarySupport
import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.PackageBasedCallChecker import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.PackageBasedCallChecker
@@ -9,33 +16,26 @@ import org.jetbrains.kotlin.idea.debugger.sequence.psi.java.JavaStreamChainTypeE
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.JavaPeekCallFactory import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.JavaPeekCallFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder
import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.lib.impl.StandardLibrarySupport
import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.project.Project
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class JavaStandardLibrarySupportProvider : LibrarySupportProvider { class JavaStandardLibrarySupportProvider : LibrarySupportProvider {
private companion object { private companion object {
val builder = TerminatedChainBuilder( val builder = TerminatedChainBuilder(
KotlinChainTransformerImpl(JavaStreamChainTypeExtractor()), KotlinChainTransformerImpl(JavaStreamChainTypeExtractor()),
PackageBasedCallChecker("java.util.stream") PackageBasedCallChecker("java.util.stream")
) )
val support = StandardLibrarySupport() val support = StandardLibrarySupport()
val dsl = DslImpl(KotlinStatementFactory(JavaPeekCallFactory())) val dsl = DslImpl(KotlinStatementFactory(JavaPeekCallFactory()))
} }
override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID
override fun getChainBuilder(): StreamChainBuilder = builder override fun getChainBuilder(): StreamChainBuilder = builder
override fun getLibrarySupport(): LibrarySupport = support override fun getLibrarySupport(): LibrarySupport = support
override fun getExpressionBuilder(project: Project): TraceExpressionBuilder = override fun getExpressionBuilder(project: Project): TraceExpressionBuilder =
KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl)) KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl))
} }
@@ -1,6 +1,13 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.lib.java package org.jetbrains.kotlin.idea.debugger.sequence.lib.java
import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.lib.impl.StreamExLibrarySupport
import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.PackageBasedCallChecker import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.PackageBasedCallChecker
@@ -9,33 +16,26 @@ import org.jetbrains.kotlin.idea.debugger.sequence.psi.java.JavaStreamChainTypeE
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.JavaPeekCallFactory import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.JavaPeekCallFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder
import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.lib.impl.StreamExLibrarySupport
import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.project.Project
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class StreamExLibrarySupportProvider : LibrarySupportProvider { class StreamExLibrarySupportProvider : LibrarySupportProvider {
private companion object { private companion object {
val streamChainBuilder = TerminatedChainBuilder( val streamChainBuilder = TerminatedChainBuilder(
KotlinChainTransformerImpl(JavaStreamChainTypeExtractor()), KotlinChainTransformerImpl(JavaStreamChainTypeExtractor()),
PackageBasedCallChecker("one.util.streamex") PackageBasedCallChecker("one.util.streamex")
) )
val support = StreamExLibrarySupport() val support = StreamExLibrarySupport()
val dsl = DslImpl(KotlinStatementFactory(JavaPeekCallFactory())) val dsl = DslImpl(KotlinStatementFactory(JavaPeekCallFactory()))
val expressionBuilder = KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl)) val expressionBuilder = KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl))
} }
override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID
override fun getChainBuilder(): StreamChainBuilder = streamChainBuilder override fun getChainBuilder(): StreamChainBuilder = streamChainBuilder
override fun getLibrarySupport(): LibrarySupport = support override fun getLibrarySupport(): LibrarySupport = support
override fun getExpressionBuilder(project: Project): TraceExpressionBuilder = expressionBuilder override fun getExpressionBuilder(project: Project): TraceExpressionBuilder = expressionBuilder
} }
@@ -1,6 +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 org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence package org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence
import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil import org.jetbrains.kotlin.idea.debugger.sequence.lib.LibraryUtil
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.TerminatedChainBuilder import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.TerminatedChainBuilder
@@ -9,33 +15,27 @@ import org.jetbrains.kotlin.idea.debugger.sequence.psi.sequence.SequenceTypeExtr
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinCollectionsPeekCallFactory import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinCollectionsPeekCallFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinStatementFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.KotlinTraceExpressionBuilder
import com.intellij.debugger.streams.lib.LibrarySupport
import com.intellij.debugger.streams.lib.LibrarySupportProvider
import com.intellij.debugger.streams.trace.TraceExpressionBuilder
import com.intellij.debugger.streams.trace.dsl.impl.DslImpl
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import com.intellij.openapi.project.Project
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinSequenceSupportProvider : LibrarySupportProvider { class KotlinSequenceSupportProvider : LibrarySupportProvider {
override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID override fun getLanguageId(): String = LibraryUtil.KOTLIN_LANGUAGE_ID
private companion object { private companion object {
val builder: StreamChainBuilder = TerminatedChainBuilder( val builder: StreamChainBuilder = TerminatedChainBuilder(
KotlinChainTransformerImpl(SequenceTypeExtractor()), KotlinChainTransformerImpl(SequenceTypeExtractor()),
SequenceCallChecker() SequenceCallChecker()
) )
val support = KotlinSequencesSupport() val support = KotlinSequencesSupport()
val dsl = DslImpl(KotlinStatementFactory(KotlinCollectionsPeekCallFactory())) val dsl = DslImpl(KotlinStatementFactory(KotlinCollectionsPeekCallFactory()))
val expressionBuilder = KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl)) val expressionBuilder = KotlinTraceExpressionBuilder(dsl, support.createHandlerFactory(dsl))
} }
override fun getChainBuilder(): StreamChainBuilder = builder override fun getChainBuilder(): StreamChainBuilder = builder
override fun getLibrarySupport(): LibrarySupport = support override fun getLibrarySupport(): LibrarySupport = support
override fun getExpressionBuilder(project: Project): TraceExpressionBuilder = expressionBuilder override fun getExpressionBuilder(project: Project): TraceExpressionBuilder = expressionBuilder
} }
@@ -1,62 +1,70 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence package org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence
import org.jetbrains.kotlin.idea.debugger.sequence.resolve.ChunkedResolver
import org.jetbrains.kotlin.idea.debugger.sequence.resolve.FilteredMapResolver
import org.jetbrains.kotlin.idea.debugger.sequence.resolve.WindowedResolver
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence.FilterIsInstanceHandler
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence.KotlinDistinctByHandler
import com.intellij.debugger.streams.lib.IntermediateOperation import com.intellij.debugger.streams.lib.IntermediateOperation
import com.intellij.debugger.streams.lib.impl.* import com.intellij.debugger.streams.lib.impl.*
import com.intellij.debugger.streams.resolve.AppendResolver import com.intellij.debugger.streams.resolve.AppendResolver
import com.intellij.debugger.streams.resolve.PairMapResolver import com.intellij.debugger.streams.resolve.PairMapResolver
import com.intellij.debugger.streams.trace.impl.handler.unified.DistinctTraceHandler import com.intellij.debugger.streams.trace.impl.handler.unified.DistinctTraceHandler
import com.intellij.debugger.streams.trace.impl.interpret.SimplePeekCallTraceInterpreter import com.intellij.debugger.streams.trace.impl.interpret.SimplePeekCallTraceInterpreter
import org.jetbrains.kotlin.idea.debugger.sequence.resolve.ChunkedResolver
import org.jetbrains.kotlin.idea.debugger.sequence.resolve.FilteredMapResolver
import org.jetbrains.kotlin.idea.debugger.sequence.resolve.WindowedResolver
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence.FilterIsInstanceHandler
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence.KotlinDistinctByHandler
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinSequencesSupport : LibrarySupportBase() { class KotlinSequencesSupport : LibrarySupportBase() {
init { init {
addIntermediateOperationsSupport(*filterOperations("filter", "filterNot", "filterIndexed", addIntermediateOperationsSupport(
"drop", "dropWhile", "minus", "minusElement", "take", "takeWhile", "onEach", "asSequence")) *filterOperations(
"filter", "filterNot", "filterIndexed",
"drop", "dropWhile", "minus", "minusElement", "take", "takeWhile", "onEach", "asSequence"
)
)
addIntermediateOperationsSupport(FilterIsInstanceOperationHandler()) addIntermediateOperationsSupport(FilterIsInstanceOperationHandler())
addIntermediateOperationsSupport(*mapOperations("map", "mapIndexed", "requireNoNulls", "withIndex", addIntermediateOperationsSupport(
"zip", "constrainOnce")) *mapOperations(
"map", "mapIndexed", "requireNoNulls", "withIndex",
"zip", "constrainOnce"
)
)
addIntermediateOperationsSupport(*flatMapOperations("flatMap", "flatten")) addIntermediateOperationsSupport(*flatMapOperations("flatMap", "flatten"))
addIntermediateOperationsSupport(*sortedOperations("sorted", "sortedBy", "sortedDescending", "sortedWith")) addIntermediateOperationsSupport(*sortedOperations("sorted", "sortedBy", "sortedDescending", "sortedWith"))
addIntermediateOperationsSupport(DistinctOperation("distinct", ::DistinctTraceHandler)) addIntermediateOperationsSupport(DistinctOperation("distinct", ::DistinctTraceHandler))
addIntermediateOperationsSupport(DistinctOperation("distinctBy", ::KotlinDistinctByHandler)) addIntermediateOperationsSupport(DistinctOperation("distinctBy", ::KotlinDistinctByHandler))
addIntermediateOperationsSupport(ConcatOperation("plus", AppendResolver())) addIntermediateOperationsSupport(ConcatOperation("plus", AppendResolver()))
addIntermediateOperationsSupport(ConcatOperation("plusElement", AppendResolver())) addIntermediateOperationsSupport(ConcatOperation("plusElement", AppendResolver()))
addIntermediateOperationsSupport(OrderBasedOperation("zipWithNext", PairMapResolver())) addIntermediateOperationsSupport(OrderBasedOperation("zipWithNext", PairMapResolver()))
addIntermediateOperationsSupport(OrderBasedOperation("mapNotNull", FilteredMapResolver())) addIntermediateOperationsSupport(OrderBasedOperation("mapNotNull", FilteredMapResolver()))
addIntermediateOperationsSupport(OrderBasedOperation("chunked", ChunkedResolver())) addIntermediateOperationsSupport(OrderBasedOperation("chunked", ChunkedResolver()))
addIntermediateOperationsSupport(OrderBasedOperation("windowed", WindowedResolver())) addIntermediateOperationsSupport(OrderBasedOperation("windowed", WindowedResolver()))
} }
private fun filterOperations(vararg names: String): Array<IntermediateOperation> = private fun filterOperations(vararg names: String): Array<IntermediateOperation> =
names.map { FilterOperation(it) }.toTypedArray() names.map { FilterOperation(it) }.toTypedArray()
private fun mapOperations(vararg names: String): Array<IntermediateOperation> = private fun mapOperations(vararg names: String): Array<IntermediateOperation> =
names.map { MappingOperation(it) }.toTypedArray() names.map { MappingOperation(it) }.toTypedArray()
private fun flatMapOperations(vararg names: String): Array<IntermediateOperation> = private fun flatMapOperations(vararg names: String): Array<IntermediateOperation> =
names.map { FlatMappingOperation(it) }.toTypedArray() names.map { FlatMappingOperation(it) }.toTypedArray()
private fun sortedOperations(vararg names: String): Array<IntermediateOperation> = private fun sortedOperations(vararg names: String): Array<IntermediateOperation> =
names.map { SortedOperation(it) }.toTypedArray() names.map { SortedOperation(it) }.toTypedArray()
private class FilterIsInstanceOperationHandler() private class FilterIsInstanceOperationHandler() : IntermediateOperationBase(
: IntermediateOperationBase("filterIsInstance", ::FilterIsInstanceHandler, "filterIsInstance", ::FilterIsInstanceHandler,
SimplePeekCallTraceInterpreter(), FilteredMapResolver() SimplePeekCallTraceInterpreter(), FilteredMapResolver()
) )
} }
@@ -9,23 +9,23 @@ import org.jetbrains.kotlin.types.KotlinType
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
interface CallTypeExtractor { interface CallTypeExtractor {
fun extractIntermediateCallTypes(call: KtCallExpression): IntermediateCallTypes fun extractIntermediateCallTypes(call: KtCallExpression): IntermediateCallTypes
fun extractTerminalCallTypes(call: KtCallExpression): TerminatorCallTypes fun extractTerminalCallTypes(call: KtCallExpression): TerminatorCallTypes
data class IntermediateCallTypes(val typeBefore: GenericType, val typeAfter: GenericType) data class IntermediateCallTypes(val typeBefore: GenericType, val typeAfter: GenericType)
data class TerminatorCallTypes(val typeBefore: GenericType, val resultType: GenericType) data class TerminatorCallTypes(val typeBefore: GenericType, val resultType: GenericType)
abstract class Base : CallTypeExtractor { abstract class Base : CallTypeExtractor {
override fun extractIntermediateCallTypes(call: KtCallExpression): IntermediateCallTypes = override fun extractIntermediateCallTypes(call: KtCallExpression): IntermediateCallTypes =
IntermediateCallTypes(extractItemsType(call.receiverType()), extractItemsType(call.resolveType())) IntermediateCallTypes(extractItemsType(call.receiverType()), extractItemsType(call.resolveType()))
override fun extractTerminalCallTypes(call: KtCallExpression): TerminatorCallTypes = override fun extractTerminalCallTypes(call: KtCallExpression): TerminatorCallTypes =
TerminatorCallTypes(extractItemsType(call.receiverType()), getResultType(call.resolveType())) TerminatorCallTypes(extractItemsType(call.receiverType()), getResultType(call.resolveType()))
protected abstract fun extractItemsType(type: KotlinType?): GenericType protected abstract fun extractItemsType(type: KotlinType?): GenericType
protected abstract fun getResultType(type: KotlinType): GenericType protected abstract fun getResultType(type: KotlinType): GenericType
} }
} }
@@ -18,20 +18,20 @@ import org.jetbrains.kotlin.types.KotlinType
*/ */
object KotlinPsiUtil { object KotlinPsiUtil {
private val WITH_TYPES_RENDERER = DescriptorRenderer.FQ_NAMES_IN_TYPES private val WITH_TYPES_RENDERER = DescriptorRenderer.FQ_NAMES_IN_TYPES
fun getTypeName(type: KotlinType): String { fun getTypeName(type: KotlinType): String {
if (type is FlexibleType) { if (type is FlexibleType) {
return WITH_TYPES_RENDERER.renderType(type.approximateFlexibleTypes()) return WITH_TYPES_RENDERER.renderType(type.approximateFlexibleTypes())
}
return WITH_TYPES_RENDERER.renderType(type)
} }
return WITH_TYPES_RENDERER.renderType(type) fun getTypeWithoutTypeParameters(type: KotlinType): String {
} val descriptor = type.constructor.declarationDescriptor ?: return getTypeName(type)
return descriptor.fqNameSafe.asString()
fun getTypeWithoutTypeParameters(type: KotlinType): String { }
val descriptor = type.constructor.declarationDescriptor ?: return getTypeName(type)
return descriptor.fqNameSafe.asString()
}
} }
fun KtExpression.resolveType(): KotlinType = fun KtExpression.resolveType(): KotlinType =
@@ -40,16 +40,16 @@ fun KtExpression.resolveType(): KotlinType =
fun KtCallExpression.callName(): String = this.calleeExpression!!.text fun KtCallExpression.callName(): String = this.calleeExpression!!.text
fun KtCallExpression.receiver(): ReceiverValue? { fun KtCallExpression.receiver(): ReceiverValue? {
val resolvedCall = getResolvedCall(analyze()) ?: return null val resolvedCall = getResolvedCall(analyze()) ?: return null
return resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver return resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver
} }
fun KtCallExpression.previousCall(): KtCallExpression? { fun KtCallExpression.previousCall(): KtCallExpression? {
val parent = this.parent as? KtDotQualifiedExpression ?: return null val parent = this.parent as? KtDotQualifiedExpression ?: return null
val receiverExpression = parent.receiverExpression val receiverExpression = parent.receiverExpression
if (receiverExpression is KtCallExpression) return receiverExpression if (receiverExpression is KtCallExpression) return receiverExpression
if (receiverExpression is KtDotQualifiedExpression) return receiverExpression.selectorExpression as? KtCallExpression if (receiverExpression is KtDotQualifiedExpression) return receiverExpression.selectorExpression as? KtCallExpression
return null return null
} }
fun KtCallExpression.receiverType(): KotlinType? = receiver()?.type fun KtCallExpression.receiverType(): KotlinType? = receiver()?.type
@@ -7,8 +7,8 @@ import org.jetbrains.kotlin.psi.KtCallExpression
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
interface StreamCallChecker { interface StreamCallChecker {
fun isIntermediateCall(expression: KtCallExpression): Boolean fun isIntermediateCall(expression: KtCallExpression): Boolean
fun isTerminationCall(expression: KtCallExpression): Boolean fun isTerminationCall(expression: KtCallExpression): Boolean
fun isStreamCall(expression: KtCallExpression): Boolean = isIntermediateCall(expression) || isTerminationCall(expression) fun isStreamCall(expression: KtCallExpression): Boolean = isIntermediateCall(expression) || isTerminationCall(expression)
} }
@@ -1,14 +1,14 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.collections package org.jetbrains.kotlin.idea.debugger.sequence.psi.collections
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl
import org.jetbrains.kotlin.idea.debugger.sequence.psi.resolveType
import com.intellij.debugger.streams.psi.ChainTransformer import com.intellij.debugger.streams.psi.ChainTransformer
import com.intellij.debugger.streams.wrapper.QualifierExpression import com.intellij.debugger.streams.wrapper.QualifierExpression
import com.intellij.debugger.streams.wrapper.StreamChain import com.intellij.debugger.streams.wrapper.StreamChain
import com.intellij.debugger.streams.wrapper.impl.StreamChainImpl import com.intellij.debugger.streams.wrapper.impl.StreamChainImpl
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.debugger.sequence.psi.impl.KotlinChainTransformerImpl
import org.jetbrains.kotlin.idea.debugger.sequence.psi.resolveType
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -16,30 +16,29 @@ import org.jetbrains.kotlin.types.KotlinType
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class CollectionChainTransformer : ChainTransformer<KtCallExpression> { class CollectionChainTransformer : ChainTransformer<KtCallExpression> {
private val transformer = KotlinChainTransformerImpl(KotlinCollectionsTypeExtractor()) private val transformer = KotlinChainTransformerImpl(KotlinCollectionsTypeExtractor())
override fun transform(chainCalls: List<KtCallExpression>, context: PsiElement): StreamChain { override fun transform(chainCalls: List<KtCallExpression>, context: PsiElement): StreamChain {
val chain = transformer.transform(chainCalls, context) val chain = transformer.transform(chainCalls, context)
if (chainCalls.first().resolveType().isArray) { if (chainCalls.first().resolveType().isArray) {
val qualifier = WrappedQualifier(chain.qualifierExpression) val qualifier = WrappedQualifier(chain.qualifierExpression)
return StreamChainImpl(qualifier, chain.intermediateCalls, chain.terminationCall, chain.context) return StreamChainImpl(qualifier, chain.intermediateCalls, chain.terminationCall, chain.context)
}
return chain
} }
return chain /**
} * Kotlin arrays have 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
* TODO: Avoid showing "asIterable()" in the tab name in trace window
*/
private class WrappedQualifier(private val qualifierExpression: QualifierExpression) : QualifierExpression by qualifierExpression {
override val text: String
get() = qualifierExpression.text + ".asIterable()"
}
/** private val KotlinType.isArray: Boolean
* Kotlin arrays have not {@code onEach} extension. But current implementation uses onEach to increment a time counter. get() = KotlinBuiltIns.isArray(this) || KotlinBuiltIns.isPrimitiveArray(this)
* We use asIterable to avoid further issues with the transformed expression evaluation
* TODO: Avoid showing "asIterable()" in the tab name in trace window
*/
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)
} }
@@ -13,64 +13,66 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinCollectionChainBuilder class KotlinCollectionChainBuilder
: KotlinChainBuilderBase(CollectionChainTransformer()) { : KotlinChainBuilderBase(CollectionChainTransformer()) {
private companion object { private companion object {
// TODO: Avoid enumeration of all available types // TODO: Avoid enumeration of all available types
val SUPPORTED_RECEIVERS = setOf("kotlin.collections.Iterable", "kotlin.CharSequence", "kotlin.Array", val SUPPORTED_RECEIVERS = setOf(
"kotlin.BooleanArray", "kotlin.ByteArray", "kotlin.ShortArray", "kotlin.CharArray", "kotlin.IntArray", "kotlin.collections.Iterable", "kotlin.CharSequence", "kotlin.Array",
"kotlin.LongArray", "kotlin.DoubleArray", "kotlin.FloatArray") "kotlin.BooleanArray", "kotlin.ByteArray", "kotlin.ShortArray", "kotlin.CharArray", "kotlin.IntArray",
} "kotlin.LongArray", "kotlin.DoubleArray", "kotlin.FloatArray"
)
private fun isCollectionTransformationCall(expression: KtCallExpression): Boolean {
val receiverType = expression.receiverType() ?: return false
if (isTypeSuitable(receiverType)) return true
return receiverType.supertypes().any { isTypeSuitable(it) }
}
override val existenceChecker: ExistenceChecker = object : ExistenceChecker() {
override fun visitCallExpression(expression: KtCallExpression) {
if (isFound()) return
if (isCollectionTransformationCall(expression)) {
fireElementFound()
} else {
super.visitCallExpression(expression)
}
} }
}
override fun createChainsBuilder(): ChainBuilder = object : ChainBuilder() { private fun isCollectionTransformationCall(expression: KtCallExpression): Boolean {
private val previousCalls: MutableMap<KtCallExpression, KtCallExpression> = mutableMapOf() val receiverType = expression.receiverType() ?: return false
private val visitedCalls: MutableSet<KtCallExpression> = mutableSetOf() if (isTypeSuitable(receiverType)) return true
return receiverType.supertypes().any { isTypeSuitable(it) }
}
override fun visitCallExpression(expression: KtCallExpression) { override val existenceChecker: ExistenceChecker = object : ExistenceChecker() {
super.visitCallExpression(expression) override fun visitCallExpression(expression: KtCallExpression) {
if (isCollectionTransformationCall(expression)) { if (isFound()) return
visitedCalls.add(expression) if (isCollectionTransformationCall(expression)) {
val previous = expression.previousCall() fireElementFound()
if (previous != null && isCollectionTransformationCall(previous)) { } else {
previousCalls[expression] = previous super.visitCallExpression(expression)
}
} }
}
} }
override fun chains(): List<List<KtCallExpression>> { override fun createChainsBuilder(): ChainBuilder = object : ChainBuilder() {
val notLastCalls: Set<KtCallExpression> = previousCalls.values.toSet() private val previousCalls: MutableMap<KtCallExpression, KtCallExpression> = mutableMapOf()
return visitedCalls.filter { it !in notLastCalls }.map { buildPsiChain(it) } 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>> {
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
}
} }
private fun buildPsiChain(expression: KtCallExpression): List<KtCallExpression> { private fun isTypeSuitable(type: KotlinType): Boolean =
val result = mutableListOf<KtCallExpression>() SUPPORTED_RECEIVERS.contains(KotlinPsiUtil.getTypeWithoutTypeParameters(type))
var current: KtCallExpression? = expression
while (current != null) {
result.add(current)
current = previousCalls[current]
}
result.reverse()
return result
}
}
private fun isTypeSuitable(type: KotlinType): Boolean =
SUPPORTED_RECEIVERS.contains(KotlinPsiUtil.getTypeWithoutTypeParameters(type))
} }
@@ -1,13 +1,13 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.collections package org.jetbrains.kotlin.idea.debugger.sequence.psi.collections
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.idea.debugger.sequence.psi.CallTypeExtractor import org.jetbrains.kotlin.idea.debugger.sequence.psi.CallTypeExtractor
import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.ANY import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.ANY
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.NULLABLE_ANY import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.NULLABLE_ANY
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.typeUtil.supertypes
@@ -15,45 +15,45 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinCollectionsTypeExtractor : CallTypeExtractor.Base() { class KotlinCollectionsTypeExtractor : CallTypeExtractor.Base() {
private companion object { private companion object {
val LOG = Logger.getInstance(KotlinCollectionsTypeExtractor::class.java) val LOG = Logger.getInstance(KotlinCollectionsTypeExtractor::class.java)
}
override fun extractItemsType(type: KotlinType?): GenericType {
if (type == null) return NULLABLE_ANY
return tryToFindElementType(type) ?: defaultType(type)
}
override fun getResultType(type: KotlinType): GenericType {
val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
return KotlinTypes.primitiveTypeByName(typeName) ?: KotlinTypes.primitiveArrayByName(typeName) ?: getAny(type)
}
private fun tryToFindElementType(type: KotlinType): GenericType? {
val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
if (typeName == "kotlin.collections.Iterable" || typeName == "kotlin.Array") {
if (type.arguments.isEmpty()) return NULLABLE_ANY
val itemsType = type.arguments.first().type
if (itemsType.isMarkedNullable) return NULLABLE_ANY
val primitiveType = KotlinTypes.primitiveTypeByName(KotlinPsiUtil.getTypeWithoutTypeParameters(itemsType))
return primitiveType ?: ANY
} }
if (typeName == "kotlin.String" || typeName == "kotlin.CharSequence") return KotlinTypes.CHAR override fun extractItemsType(type: KotlinType?): GenericType {
if (type == null) return NULLABLE_ANY
val primitiveArray = KotlinTypes.primitiveArrayByName(typeName) return tryToFindElementType(type) ?: defaultType(type)
if (primitiveArray != null) return primitiveArray.elementType }
return type.supertypes().asSequence() override fun getResultType(type: KotlinType): GenericType {
.map(this::tryToFindElementType) val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
.firstOrNull() return KotlinTypes.primitiveTypeByName(typeName) ?: KotlinTypes.primitiveArrayByName(typeName) ?: getAny(type)
} }
private fun defaultType(type: KotlinType): GenericType { private fun tryToFindElementType(type: KotlinType): GenericType? {
LOG.warn("Could not find type of items for type ${KotlinPsiUtil.getTypeName(type)}") val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
return getAny(type) if (typeName == "kotlin.collections.Iterable" || typeName == "kotlin.Array") {
} if (type.arguments.isEmpty()) return NULLABLE_ANY
val itemsType = type.arguments.first().type
private fun getAny(type: KotlinType): GenericType = if (type.isMarkedNullable) NULLABLE_ANY else ANY if (itemsType.isMarkedNullable) return NULLABLE_ANY
val primitiveType = KotlinTypes.primitiveTypeByName(KotlinPsiUtil.getTypeWithoutTypeParameters(itemsType))
return primitiveType ?: ANY
}
if (typeName == "kotlin.String" || typeName == "kotlin.CharSequence") return KotlinTypes.CHAR
val primitiveArray = KotlinTypes.primitiveArrayByName(typeName)
if (primitiveArray != null) return primitiveArray.elementType
return type.supertypes().asSequence()
.map(this::tryToFindElementType)
.firstOrNull()
}
private fun defaultType(type: KotlinType): GenericType {
LOG.warn("Could not find type of items for type ${KotlinPsiUtil.getTypeName(type)}")
return getAny(type)
}
private fun getAny(type: KotlinType): GenericType = if (type.isMarkedNullable) NULLABLE_ANY else ANY
} }
@@ -13,81 +13,81 @@ import org.jetbrains.kotlin.psi.*
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
abstract class KotlinChainBuilderBase(private val transformer: ChainTransformer<KtCallExpression>) : StreamChainBuilder { abstract class KotlinChainBuilderBase(private val transformer: ChainTransformer<KtCallExpression>) : StreamChainBuilder {
protected abstract val existenceChecker: ExistenceChecker protected abstract val existenceChecker: ExistenceChecker
override fun isChainExists(startElement: PsiElement): Boolean { override fun isChainExists(startElement: PsiElement): Boolean {
val start = if (startElement is PsiWhiteSpace) PsiUtil.ignoreWhiteSpaces(startElement) else startElement val start = if (startElement is PsiWhiteSpace) PsiUtil.ignoreWhiteSpaces(startElement) else startElement
var element = getLatestElementInScope(start) var element = getLatestElementInScope(start)
existenceChecker.reset() existenceChecker.reset()
while (element != null && !existenceChecker.isFound()) { while (element != null && !existenceChecker.isFound()) {
existenceChecker.reset() existenceChecker.reset()
element.accept(existenceChecker) element.accept(existenceChecker)
element = toUpperLevel(element) element = toUpperLevel(element)
}
return existenceChecker.isFound()
} }
return existenceChecker.isFound() override fun build(startElement: PsiElement): List<StreamChain> {
} val visitor = createChainsBuilder()
val start = if (startElement is PsiWhiteSpace) PsiUtil.ignoreWhiteSpaces(startElement) else startElement
var element = getLatestElementInScope(start)
while (element != null) {
element.accept(visitor)
element = toUpperLevel(element)
}
override fun build(startElement: PsiElement): List<StreamChain> { return visitor.chains().map { transformer.transform(it, startElement) }
val visitor = createChainsBuilder()
val start = if (startElement is PsiWhiteSpace) PsiUtil.ignoreWhiteSpaces(startElement) else startElement
var element = getLatestElementInScope(start)
while (element != null) {
element.accept(visitor)
element = toUpperLevel(element)
} }
return visitor.chains().map { transformer.transform(it, startElement) } private fun toUpperLevel(element: PsiElement): PsiElement? {
} var current = element.parent
private fun toUpperLevel(element: PsiElement): PsiElement? { while (current != null && !(current is KtLambdaExpression || current is KtAnonymousInitializer || current is KtObjectDeclaration)) {
var current = element.parent current = current.parent
}
while (current != null && !(current is KtLambdaExpression || current is KtAnonymousInitializer || current is KtObjectDeclaration)) { return getLatestElementInScope(current)
current = current.parent
} }
return getLatestElementInScope(current) protected abstract fun createChainsBuilder(): ChainBuilder
}
protected abstract fun createChainsBuilder(): ChainBuilder private fun getLatestElementInScope(element: PsiElement?): PsiElement? {
var current = element
while (current != null) {
if (current is KtNamedFunction && current.hasInitializer()) {
break
}
private fun getLatestElementInScope(element: PsiElement?): PsiElement? { val parent = current.parent
var current = element if (parent is KtBlockExpression || parent is KtLambdaExpression) {
while (current != null) { break
if (current is KtNamedFunction && current.hasInitializer()) { }
break
}
val parent = current.parent
if (parent is KtBlockExpression || parent is KtLambdaExpression) {
break
}
current = parent current = parent
}
return current
} }
return current protected abstract class ExistenceChecker : MyTreeVisitor() {
} private var myIsFound: Boolean = false
fun isFound(): Boolean = myIsFound
fun reset() = setFound(false)
protected fun fireElementFound() = setFound(true)
protected abstract class ExistenceChecker : MyTreeVisitor() { private fun setFound(value: Boolean) {
private var myIsFound: Boolean = false myIsFound = value
fun isFound(): Boolean = myIsFound }
fun reset() = setFound(false)
protected fun fireElementFound() = setFound(true)
private fun setFound(value: Boolean) {
myIsFound = value
} }
}
protected abstract class ChainBuilder : MyTreeVisitor() { protected abstract class ChainBuilder : MyTreeVisitor() {
abstract fun chains(): List<List<KtCallExpression>> abstract fun chains(): List<List<KtCallExpression>>
} }
protected abstract class MyTreeVisitor : KtTreeVisitorVoid() { protected abstract class MyTreeVisitor : KtTreeVisitorVoid() {
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {} override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {}
override fun visitBlockExpression(expression: KtBlockExpression) {} override fun visitBlockExpression(expression: KtBlockExpression) {}
} }
} }
@@ -25,45 +25,51 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinChainTransformerImpl(private val typeExtractor: CallTypeExtractor) : ChainTransformer<KtCallExpression> { class KotlinChainTransformerImpl(private val typeExtractor: CallTypeExtractor) : ChainTransformer<KtCallExpression> {
override fun transform(callChain: List<KtCallExpression>, context: PsiElement): StreamChain { override fun transform(callChain: List<KtCallExpression>, context: PsiElement): StreamChain {
val intermediateCalls = mutableListOf<IntermediateStreamCall>() val intermediateCalls = mutableListOf<IntermediateStreamCall>()
for (call in callChain.subList(0, callChain.size - 1)) { for (call in callChain.subList(0, callChain.size - 1)) {
val (typeBefore, typeAfter) = typeExtractor.extractIntermediateCallTypes(call) val (typeBefore, typeAfter) = typeExtractor.extractIntermediateCallTypes(call)
intermediateCalls += IntermediateStreamCallImpl(call.callName(), intermediateCalls += IntermediateStreamCallImpl(call.callName(),
call.valueArguments.map { createCallArgument(call, it) }, typeBefore, typeAfter, call.textRange) call.valueArguments.map { createCallArgument(call, it) },
typeBefore,
typeAfter,
call.textRange
)
}
val terminationsPsiCall = callChain.last()
val (typeBeforeTerminator, resultType) = typeExtractor.extractTerminalCallTypes(terminationsPsiCall)
val terminationCall = TerminatorStreamCallImpl(
terminationsPsiCall.callName(),
terminationsPsiCall.valueArguments.map { createCallArgument(terminationsPsiCall, it) },
typeBeforeTerminator, resultType, terminationsPsiCall.textRange
)
val typeAfterQualifier =
if (intermediateCalls.isEmpty()) typeBeforeTerminator else intermediateCalls.first().typeBefore
val qualifier = createQualifier(callChain.first(), typeAfterQualifier)
return StreamChainImpl(qualifier, intermediateCalls, terminationCall, context)
} }
val terminationsPsiCall = callChain.last() private fun createCallArgument(callExpression: KtCallExpression, arg: KtValueArgument): CallArgument {
val (typeBeforeTerminator, resultType) = typeExtractor.extractTerminalCallTypes(terminationsPsiCall) fun KtValueArgument.toCallArgument(): CallArgument {
val terminationCall = TerminatorStreamCallImpl(terminationsPsiCall.callName(), val argExpression = getArgumentExpression()!!
terminationsPsiCall.valueArguments.map { createCallArgument(terminationsPsiCall, it) }, return CallArgumentImpl(KotlinPsiUtil.getTypeName(argExpression.resolveType()), this.text)
typeBeforeTerminator, resultType, terminationsPsiCall.textRange) }
val typeAfterQualifier = val bindingContext = callExpression.getResolutionFacade().analyzeWithAllCompilerChecks(listOf(callExpression)).bindingContext
if (intermediateCalls.isEmpty()) typeBeforeTerminator else intermediateCalls.first().typeBefore val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return arg.toCallArgument()
val parameter = resolvedCall.getParameterForArgument(arg) ?: return arg.toCallArgument()
val qualifier = createQualifier(callChain.first(), typeAfterQualifier) return CallArgumentImpl(KotlinPsiUtil.getTypeName(parameter.type), arg.text)
return StreamChainImpl(qualifier, intermediateCalls, terminationCall, context)
}
private fun createCallArgument(callExpression: KtCallExpression, arg: KtValueArgument): CallArgument {
fun KtValueArgument.toCallArgument(): CallArgument {
val argExpression = getArgumentExpression()!!
return CallArgumentImpl(KotlinPsiUtil.getTypeName(argExpression.resolveType()), this.text)
} }
val bindingContext = callExpression.getResolutionFacade().analyzeWithAllCompilerChecks(listOf(callExpression)).bindingContext private fun createQualifier(expression: PsiElement, typeAfter: GenericType): QualifierExpression {
val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return arg.toCallArgument() val parent = expression.parent as? KtDotQualifiedExpression
val parameter = resolvedCall.getParameterForArgument(arg) ?: return arg.toCallArgument() ?: return QualifierExpressionImpl("", TextRange.EMPTY_RANGE, typeAfter)
return CallArgumentImpl(KotlinPsiUtil.getTypeName(parameter.type), arg.text) val receiver = parent.receiverExpression
}
private fun createQualifier(expression: PsiElement, typeAfter: GenericType): QualifierExpression { return QualifierExpressionImpl(receiver.text, receiver.textRange, typeAfter)
val parent = expression.parent as? KtDotQualifiedExpression }
?: return QualifierExpressionImpl("", TextRange.EMPTY_RANGE, typeAfter)
val receiver = parent.receiverExpression
return QualifierExpressionImpl(receiver.text, receiver.textRange, typeAfter)
}
} }
@@ -1,11 +1,11 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.impl package org.jetbrains.kotlin.idea.debugger.sequence.psi.impl
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil
import org.jetbrains.kotlin.idea.debugger.sequence.psi.StreamCallChecker import org.jetbrains.kotlin.idea.debugger.sequence.psi.StreamCallChecker
import org.jetbrains.kotlin.idea.debugger.sequence.psi.receiverType import org.jetbrains.kotlin.idea.debugger.sequence.psi.receiverType
import org.jetbrains.kotlin.idea.debugger.sequence.psi.resolveType import org.jetbrains.kotlin.idea.debugger.sequence.psi.resolveType
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -13,27 +13,29 @@ import org.jetbrains.kotlin.types.KotlinType
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class PackageBasedCallChecker(private val supportedPackage: String) : StreamCallChecker { class PackageBasedCallChecker(private val supportedPackage: String) : StreamCallChecker {
override fun isIntermediateCall(expression: KtCallExpression): Boolean { override fun isIntermediateCall(expression: KtCallExpression): Boolean {
return checkReceiverSupported(expression) && checkResultSupported(expression, true) return checkReceiverSupported(expression) && checkResultSupported(expression, true)
} }
override fun isTerminationCall(expression: KtCallExpression): Boolean { override fun isTerminationCall(expression: KtCallExpression): Boolean {
return checkReceiverSupported(expression) && checkResultSupported(expression, false) return checkReceiverSupported(expression) && checkResultSupported(expression, false)
} }
private fun checkResultSupported(expression: KtCallExpression, private fun checkResultSupported(
shouldSupportResult: Boolean): Boolean { expression: KtCallExpression,
val resultType = expression.resolveType() shouldSupportResult: Boolean
return shouldSupportResult == isSupportedType(resultType) ): Boolean {
} val resultType = expression.resolveType()
return shouldSupportResult == isSupportedType(resultType)
}
private fun checkReceiverSupported(expression: KtCallExpression): Boolean { private fun checkReceiverSupported(expression: KtCallExpression): Boolean {
val receiverType = expression.receiverType() val receiverType = expression.receiverType()
return receiverType != null && isSupportedType(receiverType) return receiverType != null && isSupportedType(receiverType)
} }
private fun isSupportedType(type: KotlinType): Boolean { private fun isSupportedType(type: KotlinType): Boolean {
val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type) val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
return StringUtil.getPackageName(typeName).startsWith(supportedPackage) return StringUtil.getPackageName(typeName).startsWith(supportedPackage)
} }
} }
@@ -1,74 +1,74 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.impl package org.jetbrains.kotlin.idea.debugger.sequence.psi.impl
import com.intellij.debugger.streams.psi.ChainTransformer
import org.jetbrains.kotlin.idea.debugger.sequence.psi.StreamCallChecker import org.jetbrains.kotlin.idea.debugger.sequence.psi.StreamCallChecker
import org.jetbrains.kotlin.idea.debugger.sequence.psi.previousCall import org.jetbrains.kotlin.idea.debugger.sequence.psi.previousCall
import com.intellij.debugger.streams.psi.ChainTransformer
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
import java.util.* import java.util.*
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
open class TerminatedChainBuilder(transformer: ChainTransformer<KtCallExpression>, open class TerminatedChainBuilder(
private val callChecker: StreamCallChecker transformer: ChainTransformer<KtCallExpression>,
) private val callChecker: StreamCallChecker
: KotlinChainBuilderBase(transformer) { ) : KotlinChainBuilderBase(transformer) {
override val existenceChecker: ExistenceChecker = MyExistenceChecker() override val existenceChecker: ExistenceChecker = MyExistenceChecker()
override fun createChainsBuilder(): ChainBuilder = MyBuilderVisitor() override fun createChainsBuilder(): ChainBuilder = MyBuilderVisitor()
private inner class MyExistenceChecker : ExistenceChecker() { private inner class MyExistenceChecker : ExistenceChecker() {
override fun visitCallExpression(expression: KtCallExpression) { override fun visitCallExpression(expression: KtCallExpression) {
if (callChecker.isTerminationCall(expression)) { if (callChecker.isTerminationCall(expression)) {
fireElementFound() fireElementFound()
} else { } else {
super.visitCallExpression(expression) super.visitCallExpression(expression)
} }
} }
}
private inner class MyBuilderVisitor : ChainBuilder() {
private val myTerminationCalls = mutableSetOf<KtCallExpression>()
private val myPreviousCalls = mutableMapOf<KtCallExpression, KtCallExpression>()
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
if (!myPreviousCalls.containsKey(expression) && callChecker.isStreamCall(expression)) {
updateCallTree(expression)
}
} }
private fun updateCallTree(expression: KtCallExpression) { private inner class MyBuilderVisitor : ChainBuilder() {
if (callChecker.isTerminationCall(expression)) { private val myTerminationCalls = mutableSetOf<KtCallExpression>()
myTerminationCalls.add(expression) private val myPreviousCalls = mutableMapOf<KtCallExpression, KtCallExpression>()
}
val parentCall = expression.previousCall() override fun visitCallExpression(expression: KtCallExpression) {
if (parentCall is KtCallExpression && callChecker.isStreamCall(parentCall)) { super.visitCallExpression(expression)
myPreviousCalls.put(expression, parentCall) if (!myPreviousCalls.containsKey(expression) && callChecker.isStreamCall(expression)) {
updateCallTree(parentCall) updateCallTree(expression)
} }
}
override fun chains(): List<List<KtCallExpression>> {
val chains = ArrayList<List<KtCallExpression>>()
for (terminationCall in myTerminationCalls) {
val chain = ArrayList<KtCallExpression>()
var current: KtCallExpression? = terminationCall
while (current != null) {
if (!callChecker.isStreamCall(current)) {
break
}
chain.add(current)
current = myPreviousCalls[current]
} }
Collections.reverse(chain) private fun updateCallTree(expression: KtCallExpression) {
chains.add(chain) if (callChecker.isTerminationCall(expression)) {
} myTerminationCalls.add(expression)
}
return chains val parentCall = expression.previousCall()
if (parentCall is KtCallExpression && callChecker.isStreamCall(parentCall)) {
myPreviousCalls.put(expression, parentCall)
updateCallTree(parentCall)
}
}
override fun chains(): List<List<KtCallExpression>> {
val chains = ArrayList<List<KtCallExpression>>()
for (terminationCall in myTerminationCalls) {
val chain = ArrayList<KtCallExpression>()
var current: KtCallExpression? = terminationCall
while (current != null) {
if (!callChecker.isStreamCall(current)) {
break
}
chain.add(current)
current = myPreviousCalls[current]
}
Collections.reverse(chain)
chains.add(chain)
}
return chains
}
} }
}
} }
@@ -1,12 +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 org.jetbrains.kotlin.idea.debugger.sequence.psi.java package org.jetbrains.kotlin.idea.debugger.sequence.psi.java
import org.jetbrains.kotlin.idea.debugger.sequence.psi.CallTypeExtractor
import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import com.intellij.debugger.streams.trace.impl.handler.type.ClassTypeImpl import com.intellij.debugger.streams.trace.impl.handler.type.ClassTypeImpl
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import com.intellij.psi.CommonClassNames import com.intellij.psi.CommonClassNames
import org.jetbrains.kotlin.idea.debugger.sequence.psi.CallTypeExtractor
import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.getImmediateSuperclassNotAny import org.jetbrains.kotlin.types.typeUtil.getImmediateSuperclassNotAny
@@ -14,19 +14,19 @@ import org.jetbrains.kotlin.types.typeUtil.getImmediateSuperclassNotAny
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class JavaStreamChainTypeExtractor : CallTypeExtractor.Base() { class JavaStreamChainTypeExtractor : CallTypeExtractor.Base() {
override fun extractItemsType(type: KotlinType?): GenericType { override fun extractItemsType(type: KotlinType?): GenericType {
if (type == null) { if (type == null) {
return KotlinTypes.NULLABLE_ANY return KotlinTypes.NULLABLE_ANY
}
return when (KotlinPsiUtil.getTypeWithoutTypeParameters(type)) {
CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM -> KotlinTypes.INT
CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM -> KotlinTypes.DOUBLE
CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM -> KotlinTypes.LONG
CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM -> KotlinTypes.NULLABLE_ANY
else -> extractItemsType(type.getImmediateSuperclassNotAny())
}
} }
return when (KotlinPsiUtil.getTypeWithoutTypeParameters(type)) { override fun getResultType(type: KotlinType): GenericType = ClassTypeImpl(KotlinPsiUtil.getTypeName(type))
CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM -> KotlinTypes.INT
CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM -> KotlinTypes.DOUBLE
CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM -> KotlinTypes.LONG
CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM -> KotlinTypes.NULLABLE_ANY
else -> extractItemsType(type.getImmediateSuperclassNotAny())
}
}
override fun getResultType(type: KotlinType): GenericType = ClassTypeImpl(KotlinPsiUtil.getTypeName(type))
} }
@@ -13,19 +13,19 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class SequenceCallChecker : StreamCallChecker { class SequenceCallChecker : StreamCallChecker {
override fun isIntermediateCall(expression: KtCallExpression): Boolean { override fun isIntermediateCall(expression: KtCallExpression): Boolean {
val receiverType = expression.receiverType() ?: return false val receiverType = expression.receiverType() ?: return false
return isSequenceInheritor(receiverType) && isSequenceInheritor(expression.resolveType()) return isSequenceInheritor(receiverType) && isSequenceInheritor(expression.resolveType())
} }
override fun isTerminationCall(expression: KtCallExpression): Boolean { override fun isTerminationCall(expression: KtCallExpression): Boolean {
val receiverType = expression.receiverType() ?: return false val receiverType = expression.receiverType() ?: return false
return isSequenceInheritor(receiverType) && !isSequenceInheritor(expression.resolveType()) return isSequenceInheritor(receiverType) && !isSequenceInheritor(expression.resolveType())
} }
private fun isSequenceInheritor(type: KotlinType): Boolean = private fun isSequenceInheritor(type: KotlinType): Boolean =
isSequenceType(type) || type.supertypes().any(this::isSequenceType) isSequenceType(type) || type.supertypes().any(this::isSequenceType)
private fun isSequenceType(type: KotlinType): Boolean = private fun isSequenceType(type: KotlinType): Boolean =
"kotlin.sequences.Sequence" == KotlinPsiUtil.getTypeWithoutTypeParameters(type) "kotlin.sequences.Sequence" == KotlinPsiUtil.getTypeWithoutTypeParameters(type)
} }
@@ -1,12 +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 org.jetbrains.kotlin.idea.debugger.sequence.psi.sequence package org.jetbrains.kotlin.idea.debugger.sequence.psi.sequence
import org.jetbrains.kotlin.idea.debugger.sequence.psi.CallTypeExtractor
import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import com.intellij.debugger.streams.trace.impl.handler.type.ClassTypeImpl import com.intellij.debugger.streams.trace.impl.handler.type.ClassTypeImpl
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.idea.debugger.sequence.psi.CallTypeExtractor
import org.jetbrains.kotlin.idea.debugger.sequence.psi.KotlinPsiUtil
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.typeUtil.supertypes
@@ -14,40 +14,40 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class SequenceTypeExtractor : CallTypeExtractor.Base() { class SequenceTypeExtractor : CallTypeExtractor.Base() {
private companion object { private companion object {
val LOG = Logger.getInstance(SequenceTypeExtractor::class.java) val LOG = Logger.getInstance(SequenceTypeExtractor::class.java)
}
override fun extractItemsType(type: KotlinType?): GenericType {
if (type == null) return KotlinTypes.NULLABLE_ANY
return tryToFindElementType(type) ?: defaultType(type)
}
override fun getResultType(type: KotlinType): GenericType {
val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
return KotlinTypes.primitiveTypeByName(typeName)
?: KotlinTypes.primitiveArrayByName(typeName)
?: ClassTypeImpl(KotlinPsiUtil.getTypeName(type))
}
private fun tryToFindElementType(type: KotlinType): GenericType? {
val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
if (typeName == "kotlin.sequences.Sequence") {
if (type.arguments.isEmpty()) return KotlinTypes.NULLABLE_ANY
val itemsType = type.arguments.single().type
if (itemsType.isMarkedNullable) return KotlinTypes.NULLABLE_ANY
val primitiveType = KotlinTypes.primitiveTypeByName(KotlinPsiUtil.getTypeWithoutTypeParameters(itemsType))
return primitiveType ?: KotlinTypes.ANY
} }
return type.supertypes().asSequence() override fun extractItemsType(type: KotlinType?): GenericType {
.map(this::tryToFindElementType) if (type == null) return KotlinTypes.NULLABLE_ANY
.firstOrNull()
}
private fun defaultType(type: KotlinType): GenericType { return tryToFindElementType(type) ?: defaultType(type)
LOG.warn("Could not find type of items for type ${KotlinPsiUtil.getTypeName(type)}") }
return if (type.isMarkedNullable) KotlinTypes.NULLABLE_ANY else KotlinTypes.ANY
} override fun getResultType(type: KotlinType): GenericType {
val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
return KotlinTypes.primitiveTypeByName(typeName)
?: KotlinTypes.primitiveArrayByName(typeName)
?: ClassTypeImpl(KotlinPsiUtil.getTypeName(type))
}
private fun tryToFindElementType(type: KotlinType): GenericType? {
val typeName = KotlinPsiUtil.getTypeWithoutTypeParameters(type)
if (typeName == "kotlin.sequences.Sequence") {
if (type.arguments.isEmpty()) return KotlinTypes.NULLABLE_ANY
val itemsType = type.arguments.single().type
if (itemsType.isMarkedNullable) return KotlinTypes.NULLABLE_ANY
val primitiveType = KotlinTypes.primitiveTypeByName(KotlinPsiUtil.getTypeWithoutTypeParameters(itemsType))
return primitiveType ?: KotlinTypes.ANY
}
return type.supertypes().asSequence()
.map(this::tryToFindElementType)
.firstOrNull()
}
private fun defaultType(type: KotlinType): GenericType {
LOG.warn("Could not find type of items for type ${KotlinPsiUtil.getTypeName(type)}")
return if (type.isMarkedNullable) KotlinTypes.NULLABLE_ANY else KotlinTypes.ANY
}
} }
@@ -9,31 +9,31 @@ import com.intellij.debugger.streams.trace.TraceInfo
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class ChunkedResolver : ValuesOrderResolver { class ChunkedResolver : ValuesOrderResolver {
override fun resolve(info: TraceInfo): ValuesOrderResolver.Result { override fun resolve(info: TraceInfo): ValuesOrderResolver.Result {
val beforeIndex = info.valuesOrderBefore val beforeIndex = info.valuesOrderBefore
val afterIndex = info.valuesOrderAfter val afterIndex = info.valuesOrderAfter
val invertedOrder = mutableMapOf<Int, MutableList<Int>>() val invertedOrder = mutableMapOf<Int, MutableList<Int>>()
val beforeTimes = beforeIndex.keys.sorted().toTypedArray() val beforeTimes = beforeIndex.keys.sorted().toTypedArray()
val afterTimes = afterIndex.keys.sorted().toTypedArray() val afterTimes = afterIndex.keys.sorted().toTypedArray()
var beforeIx = 0 var beforeIx = 0
for (afterTime in afterTimes) { for (afterTime in afterTimes) {
while (beforeIx < beforeTimes.size && beforeTimes[beforeIx] < afterTime) { while (beforeIx < beforeTimes.size && beforeTimes[beforeIx] < afterTime) {
invertedOrder.computeIfAbsent(afterTime, { _ -> mutableListOf() }).add(beforeTimes[beforeIx]) invertedOrder.computeIfAbsent(afterTime, { _ -> mutableListOf() }).add(beforeTimes[beforeIx])
beforeIx += 1 beforeIx += 1
} }
}
val direct = mutableMapOf<TraceElement, List<TraceElement>>()
val reverse = mutableMapOf<TraceElement, List<TraceElement>>()
for ((timeAfter, elementAfter) in afterIndex) {
val before: List<Int> = invertedOrder[timeAfter] ?: emptyList()
val beforeElements = before.map { beforeIndex[it]!! }
beforeElements.forEach { direct[it] = listOf(elementAfter) }
reverse[elementAfter] = beforeElements
}
return ValuesOrderResolver.Result.of(direct, reverse)
} }
val direct = mutableMapOf<TraceElement, List<TraceElement>>()
val reverse = mutableMapOf<TraceElement, List<TraceElement>>()
for ((timeAfter, elementAfter) in afterIndex) {
val before: List<Int> = invertedOrder[timeAfter] ?: emptyList()
val beforeElements = before.map { beforeIndex[it]!! }
beforeElements.forEach { direct[it] = listOf(elementAfter) }
reverse[elementAfter] = beforeElements
}
return ValuesOrderResolver.Result.of(direct, reverse)
}
} }
@@ -9,32 +9,32 @@ import com.intellij.debugger.streams.trace.TraceInfo
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class FilteredMapResolver : ValuesOrderResolver { class FilteredMapResolver : ValuesOrderResolver {
override fun resolve(info: TraceInfo): ValuesOrderResolver.Result { override fun resolve(info: TraceInfo): ValuesOrderResolver.Result {
val before = info.valuesOrderBefore val before = info.valuesOrderBefore
val after = info.valuesOrderAfter val after = info.valuesOrderAfter
val invertedOrder = mutableMapOf<Int, Int>() val invertedOrder = mutableMapOf<Int, Int>()
val beforeTimes = before.keys.sorted().toIntArray() val beforeTimes = before.keys.sorted().toIntArray()
val afterTimes = after.keys.sorted().toIntArray() val afterTimes = after.keys.sorted().toIntArray()
var beforeIndex = 0 var beforeIndex = 0
for (afterTime in afterTimes) { for (afterTime in afterTimes) {
while (beforeIndex < beforeTimes.size && afterTime > beforeTimes[beforeIndex]) beforeIndex += 1 while (beforeIndex < beforeTimes.size && afterTime > beforeTimes[beforeIndex]) beforeIndex += 1
val beforeTime = beforeTimes[beforeIndex - 1] val beforeTime = beforeTimes[beforeIndex - 1]
if (beforeTime < afterTime) { if (beforeTime < afterTime) {
invertedOrder[afterTime] = beforeTime invertedOrder[afterTime] = beforeTime
} }
}
val direct = mutableMapOf<TraceElement, List<TraceElement>>()
val reverse = mutableMapOf<TraceElement, List<TraceElement>>()
for ((afterTime, beforeTime) in invertedOrder) {
val beforeElement = before.getValue(beforeTime)
val afterElement = after.getValue(afterTime)
direct[beforeElement] = listOf(afterElement)
reverse[afterElement] = listOf(beforeElement)
}
return ValuesOrderResolver.Result.of(direct, reverse)
} }
val direct = mutableMapOf<TraceElement, List<TraceElement>>()
val reverse = mutableMapOf<TraceElement, List<TraceElement>>()
for ((afterTime, beforeTime) in invertedOrder) {
val beforeElement = before.getValue(beforeTime)
val afterElement = after.getValue(afterTime)
direct[beforeElement] = listOf(afterElement)
reverse[afterElement] = listOf(beforeElement)
}
return ValuesOrderResolver.Result.of(direct, reverse)
}
} }
@@ -9,49 +9,49 @@ import com.intellij.debugger.streams.trace.TraceInfo
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class WindowedResolver : ValuesOrderResolver { class WindowedResolver : ValuesOrderResolver {
override fun resolve(info: TraceInfo): ValuesOrderResolver.Result { override fun resolve(info: TraceInfo): ValuesOrderResolver.Result {
val indexBefore = info.valuesOrderBefore val indexBefore = info.valuesOrderBefore
val indexAfter = info.valuesOrderAfter val indexAfter = info.valuesOrderAfter
val timesBefore = indexBefore.keys.sorted().toIntArray() val timesBefore = indexBefore.keys.sorted().toIntArray()
val timesAfter = indexAfter.keys.sorted().toIntArray() val timesAfter = indexAfter.keys.sorted().toIntArray()
if (timesAfter.isEmpty()) return emptyTransitions(indexBefore) if (timesAfter.isEmpty()) return emptyTransitions(indexBefore)
val direct = mutableMapOf<TraceElement, MutableList<TraceElement>>() val direct = mutableMapOf<TraceElement, MutableList<TraceElement>>()
val reverse = mutableMapOf<TraceElement, List<TraceElement>>() val reverse = mutableMapOf<TraceElement, List<TraceElement>>()
var windowStartIndex = 0 var windowStartIndex = 0
var windowEndIndex = calcWindowSize(timesBefore, timesAfter) var windowEndIndex = calcWindowSize(timesBefore, timesAfter)
for (timeAfter in timesAfter) { for (timeAfter in timesAfter) {
if (windowEndIndex == timesAfter.size) { if (windowEndIndex == timesAfter.size) {
windowStartIndex += 1 windowStartIndex += 1
} else { } else {
while (windowEndIndex < timesBefore.size && timesBefore[windowEndIndex] < timeAfter) { while (windowEndIndex < timesBefore.size && timesBefore[windowEndIndex] < timeAfter) {
windowStartIndex += 1 windowStartIndex += 1
windowEndIndex += 1 windowEndIndex += 1
}
}
val window = (windowStartIndex until windowEndIndex).asSequence()
.map { indexBefore[timesBefore[it]]!! }
.toList()
val mappedElement = indexAfter[timeAfter]!!
window.forEach { direct.computeIfAbsent(it, { mutableListOf() }).add(mappedElement) }
reverse[mappedElement] = window
} }
}
val window = (windowStartIndex until windowEndIndex).asSequence() return ValuesOrderResolver.Result.of(direct, reverse)
.map { indexBefore[timesBefore[it]]!! }
.toList()
val mappedElement = indexAfter[timeAfter]!!
window.forEach { direct.computeIfAbsent(it, { mutableListOf() }).add(mappedElement) }
reverse[mappedElement] = window
} }
return ValuesOrderResolver.Result.of(direct, reverse) private fun calcWindowSize(before: IntArray, after: IntArray): Int {
} var size = 0
while (size < before.size && before[size] < after[0]) size += 1
return size
}
private fun calcWindowSize(before: IntArray, after: IntArray): Int { private fun emptyTransitions(indexBefore: MutableMap<Int, TraceElement>): ValuesOrderResolver.Result {
var size = 0 val direct = indexBefore.asSequence().sortedBy { it.key }.associate { it.value to emptyList<TraceElement>() }
while (size < before.size && before[size] < after[0]) size += 1 return ValuesOrderResolver.Result.of(direct, emptyMap())
return size }
}
private fun emptyTransitions(indexBefore: MutableMap<Int, TraceElement>): ValuesOrderResolver.Result {
val direct = indexBefore.asSequence().sortedBy { it.key }.associate { it.value to emptyList<TraceElement>() }
return ValuesOrderResolver.Result.of(direct, emptyMap())
}
} }
@@ -9,6 +9,6 @@ import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class JavaPeekCallFactory : PeekCallFactory { class JavaPeekCallFactory : PeekCallFactory {
override fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall = override fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall =
PeekCall(lambda, elementsType) PeekCall(lambda, elementsType)
} }
@@ -11,12 +11,11 @@ import com.intellij.debugger.streams.trace.impl.handler.type.ArrayType
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinArrayVariable(override val type: ArrayType, override val name: String) class KotlinArrayVariable(override val type: ArrayType, override val name: String) : VariableImpl(type, name), ArrayVariable {
: VariableImpl(type, name), ArrayVariable { override fun get(index: Expression): Expression = TextExpression("$name[${index.toCode()}]!!")
override fun get(index: Expression): Expression = TextExpression("$name[${index.toCode()}]!!")
override fun set(index: Expression, value: Expression): Expression = TextExpression("$name[${index.toCode()}] = ${value.toCode()}") override fun set(index: Expression, value: Expression): Expression = TextExpression("$name[${index.toCode()}] = ${value.toCode()}")
override fun defaultDeclaration(size: Expression): VariableDeclaration = override fun defaultDeclaration(size: Expression): VariableDeclaration =
KotlinVariableDeclaration(this, false, type.sizedDeclaration(size.toCode())) KotlinVariableDeclaration(this, false, type.sizedDeclaration(size.toCode()))
} }
@@ -9,5 +9,5 @@ import com.intellij.debugger.streams.trace.dsl.impl.AssignmentStatement
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinAssignmentStatement(override val variable: Variable, override val expression: Expression) : AssignmentStatement { class KotlinAssignmentStatement(override val variable: Variable, override val expression: Expression) : AssignmentStatement {
override fun toCode(indent: Int): String = "${variable.toCode()} = ${expression.toCode()}".withIndent(indent) override fun toCode(indent: Int): String = "${variable.toCode()} = ${expression.toCode()}".withIndent(indent)
} }
@@ -9,5 +9,5 @@ import com.intellij.debugger.streams.trace.dsl.impl.LineSeparatedCodeBlock
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
open class KotlinCodeBlock(statementFactory: StatementFactory) : LineSeparatedCodeBlock(statementFactory) { open class KotlinCodeBlock(statementFactory: StatementFactory) : LineSeparatedCodeBlock(statementFactory) {
override fun doReturn(expression: Expression) = addStatement(expression) override fun doReturn(expression: Expression) = addStatement(expression)
} }
@@ -1,14 +1,14 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl package org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.OnEachCall
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import com.intellij.debugger.streams.wrapper.IntermediateStreamCall import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.OnEachCall
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinCollectionsPeekCallFactory : PeekCallFactory { class KotlinCollectionsPeekCallFactory : PeekCallFactory {
override fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall = override fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall =
OnEachCall(elementsType, lambda) OnEachCall(elementsType, lambda)
} }
@@ -9,11 +9,13 @@ import com.intellij.debugger.streams.trace.dsl.Variable
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinForEachLoop(private val iterateVariable: Variable, class KotlinForEachLoop(
private val collection: Expression, private val iterateVariable: Variable,
private val loopBody: ForLoopBody) : Convertable { private val collection: Expression,
override fun toCode(indent: Int): String = private val loopBody: ForLoopBody
"for (${iterateVariable.name} in ${collection.toCode()}) {\n".withIndent(indent) + ) : Convertable {
loopBody.toCode(indent + 1) + override fun toCode(indent: Int): String =
"}".withIndent(indent) "for (${iterateVariable.name} in ${collection.toCode()}) {\n".withIndent(indent) +
loopBody.toCode(indent + 1) +
"}".withIndent(indent)
} }
@@ -9,14 +9,16 @@ import com.intellij.debugger.streams.trace.dsl.VariableDeclaration
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinForLoop(private val initialization: VariableDeclaration, class KotlinForLoop(
private val condition: Expression, private val initialization: VariableDeclaration,
private val afterThought: Expression, private val condition: Expression,
private val loopBody: ForLoopBody) : Convertable { private val afterThought: Expression,
override fun toCode(indent: Int): String = private val loopBody: ForLoopBody
initialization.toCode(indent) + "\n" + ) : Convertable {
"while (${condition.toCode()}) {\n".withIndent(indent) + override fun toCode(indent: Int): String =
loopBody.toCode(indent + 1) + initialization.toCode(indent) + "\n" +
afterThought.toCode(indent + 1) + "\n" + "while (${condition.toCode()}) {\n".withIndent(indent) +
"}".withIndent(indent) loopBody.toCode(indent + 1) +
afterThought.toCode(indent + 1) + "\n" +
"}".withIndent(indent)
} }
@@ -1,21 +1,22 @@
// 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.trace.dsl package org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl
import com.intellij.debugger.streams.trace.dsl.Expression import com.intellij.debugger.streams.trace.dsl.Expression
import com.intellij.debugger.streams.trace.dsl.ForLoopBody import com.intellij.debugger.streams.trace.dsl.ForLoopBody
import com.intellij.debugger.streams.trace.dsl.StatementFactory import com.intellij.debugger.streams.trace.dsl.StatementFactory
import com.intellij.debugger.streams.trace.dsl.Variable import com.intellij.debugger.streams.trace.dsl.Variable
import com.intellij.debugger.streams.trace.dsl.impl.TextExpression import com.intellij.debugger.streams.trace.dsl.impl.TextExpression
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinCodeBlock
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinForLoopBody(override val loopVariable: Variable, class KotlinForLoopBody(
statementFactory: StatementFactory) : KotlinCodeBlock(statementFactory), ForLoopBody { override val loopVariable: Variable,
private companion object { statementFactory: StatementFactory
val BREAK = TextExpression("break") ) : KotlinCodeBlock(statementFactory), ForLoopBody {
} private companion object {
val BREAK = TextExpression("break")
}
override fun breakIteration(): Expression = BREAK override fun breakIteration(): Expression = BREAK
} }
@@ -9,19 +9,19 @@ import com.intellij.debugger.streams.trace.dsl.impl.common.IfBranchBase
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinIfBranch(condition: Expression, thenBlock: CodeBlock, statementFactory: StatementFactory) class KotlinIfBranch(condition: Expression, thenBlock: CodeBlock, statementFactory: StatementFactory) :
: IfBranchBase(condition, thenBlock, statementFactory) { IfBranchBase(condition, thenBlock, statementFactory) {
override fun toCode(indent: Int): String { override fun toCode(indent: Int): String {
val elseBlockVar = elseBlock val elseBlockVar = elseBlock
val ifThen = "if (${condition.toCode(0)}) {\n".withIndent(indent) + val ifThen = "if (${condition.toCode(0)}) {\n".withIndent(indent) +
thenBlock.toCode(indent + 1) + thenBlock.toCode(indent + 1) +
"}".withIndent(indent) "}".withIndent(indent)
if (elseBlockVar != null) { if (elseBlockVar != null) {
return ifThen + " else { \n" + return ifThen + " else { \n" +
elseBlockVar.toCode(indent + 1) + elseBlockVar.toCode(indent + 1) +
"}".withIndent(indent) "}".withIndent(indent)
} }
return ifThen return ifThen
} }
} }
@@ -10,10 +10,10 @@ import com.intellij.debugger.streams.trace.dsl.impl.TextExpression
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinLambda(override val variableName: String, override val body: CodeBlock) : Lambda { class KotlinLambda(override val variableName: String, override val body: CodeBlock) : Lambda {
override fun call(callName: String, vararg args: Expression): Expression = TextExpression("(${toCode()})").call(callName, *args) override fun call(callName: String, vararg args: Expression): Expression = TextExpression("(${toCode()})").call(callName, *args)
override fun toCode(indent: Int): String = override fun toCode(indent: Int): String =
"{ $variableName ->\n".withIndent(indent) + "{ $variableName ->\n".withIndent(indent) +
body.toCode(indent + 1) + body.toCode(indent + 1) +
"}" "}"
} }
@@ -4,10 +4,9 @@ package org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl
import com.intellij.debugger.streams.trace.dsl.Expression import com.intellij.debugger.streams.trace.dsl.Expression
import com.intellij.debugger.streams.trace.dsl.LambdaBody import com.intellij.debugger.streams.trace.dsl.LambdaBody
import com.intellij.debugger.streams.trace.dsl.StatementFactory import com.intellij.debugger.streams.trace.dsl.StatementFactory
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinCodeBlock
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinLambdaBody(override val lambdaArg: Expression, statementFactory: StatementFactory) class KotlinLambdaBody(override val lambdaArg: Expression, statementFactory: StatementFactory) : KotlinCodeBlock(statementFactory),
: KotlinCodeBlock(statementFactory), LambdaBody LambdaBody
@@ -10,16 +10,15 @@ import com.intellij.debugger.streams.trace.impl.handler.type.ListType
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinListVariable(override val type: ListType, name: String) class KotlinListVariable(override val type: ListType, name: String) : VariableImpl(type, name), ListVariable {
: VariableImpl(type, name), ListVariable { override fun get(index: Expression): Expression = call("get", index)
override fun get(index: Expression): Expression = call("get", index) override fun set(index: Expression, newValue: Expression): Expression = call("set", index, newValue)
override fun set(index: Expression, newValue: Expression): Expression = call("set", index, newValue) override fun add(element: Expression): Expression = call("add", element)
override fun add(element: Expression): Expression = call("add", element)
override fun contains(element: Expression): Expression = call("contains", element) override fun contains(element: Expression): Expression = call("contains", element)
override fun size(): Expression = property("size") override fun size(): Expression = property("size")
override fun defaultDeclaration(): VariableDeclaration = override fun defaultDeclaration(): VariableDeclaration =
KotlinVariableDeclaration(this, false, type.defaultValue) KotlinVariableDeclaration(this, false, type.defaultValue)
} }
@@ -1,7 +1,9 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl package org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl
import com.intellij.debugger.streams.trace.dsl.* import com.intellij.debugger.streams.trace.dsl.Expression
import com.intellij.debugger.streams.trace.dsl.Lambda
import com.intellij.debugger.streams.trace.dsl.VariableDeclaration
import com.intellij.debugger.streams.trace.dsl.impl.TextExpression import com.intellij.debugger.streams.trace.dsl.impl.TextExpression
import com.intellij.debugger.streams.trace.dsl.impl.common.MapVariableBase import com.intellij.debugger.streams.trace.dsl.impl.common.MapVariableBase
import com.intellij.debugger.streams.trace.impl.handler.type.MapType import com.intellij.debugger.streams.trace.impl.handler.type.MapType
@@ -10,20 +12,20 @@ import com.intellij.debugger.streams.trace.impl.handler.type.MapType
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinMapVariable(type: MapType, name: String) : MapVariableBase(type, name) { class KotlinMapVariable(type: MapType, name: String) : MapVariableBase(type, name) {
override fun get(key: Expression): Expression = this.call("getValue", key) override fun get(key: Expression): Expression = this.call("getValue", key)
override fun set(key: Expression, newValue: Expression): Expression = override fun set(key: Expression, newValue: Expression): Expression =
TextExpression("${toCode()}[${key.toCode()}] = ${newValue.toCode()}") TextExpression("${toCode()}[${key.toCode()}] = ${newValue.toCode()}")
override fun contains(key: Expression): Expression = TextExpression("(${key.toCode()} in ${toCode()})") override fun contains(key: Expression): Expression = TextExpression("(${key.toCode()} in ${toCode()})")
override fun size(): Expression = TextExpression("${toCode()}.size") override fun size(): Expression = TextExpression("${toCode()}.size")
override fun keys(): Expression = TextExpression("${toCode()}.keys") override fun keys(): Expression = TextExpression("${toCode()}.keys")
override fun computeIfAbsent(key: Expression, supplier: Lambda): Expression = override fun computeIfAbsent(key: Expression, supplier: Lambda): Expression =
TextExpression("${toCode()}.computeIfAbsent(${key.toCode()}, ${supplier.toCode()})") TextExpression("${toCode()}.computeIfAbsent(${key.toCode()}, ${supplier.toCode()})")
override fun defaultDeclaration(isMutable: Boolean): VariableDeclaration = override fun defaultDeclaration(isMutable: Boolean): VariableDeclaration =
KotlinVariableDeclaration(this, false, type.defaultValue) KotlinVariableDeclaration(this, false, type.defaultValue)
} }
@@ -1,7 +1,6 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl package org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl
import com.intellij.debugger.streams.kotlin.trace.dsl.*
import com.intellij.debugger.streams.trace.dsl.* import com.intellij.debugger.streams.trace.dsl.*
import com.intellij.debugger.streams.trace.dsl.impl.AssignmentStatement import com.intellij.debugger.streams.trace.dsl.impl.AssignmentStatement
import com.intellij.debugger.streams.trace.dsl.impl.TextExpression import com.intellij.debugger.streams.trace.dsl.impl.TextExpression
@@ -13,96 +12,99 @@ import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinStatementFactory(private val peekCallFactory: PeekCallFactory) : StatementFactory { class KotlinStatementFactory(private val peekCallFactory: PeekCallFactory) : StatementFactory {
override fun createNewListExpression(elementType: GenericType, vararg args: Expression): Expression = override fun createNewListExpression(elementType: GenericType, vararg args: Expression): Expression =
TextExpression("kotlin.collections.mutableListOf<${elementType.genericTypeName}>(${StatementFactory.commaSeparate(*args)})") TextExpression("kotlin.collections.mutableListOf<${elementType.genericTypeName}>(${StatementFactory.commaSeparate(*args)})")
override fun createListVariable(elementType: GenericType, name: String): ListVariable = KotlinListVariable(types.list(elementType), name) override fun createListVariable(elementType: GenericType, name: String): ListVariable =
KotlinListVariable(types.list(elementType), name)
override fun not(expression: Expression): Expression = TextExpression("!${expression.toCode()}") override fun not(expression: Expression): Expression = TextExpression("!${expression.toCode()}")
override val types: Types = KotlinTypes override val types: Types = KotlinTypes
override fun createEmptyCompositeCodeBlock(): CompositeCodeBlock = KotlinCodeBlock(this) override fun createEmptyCompositeCodeBlock(): CompositeCodeBlock = KotlinCodeBlock(this)
override fun createEmptyCodeBlock(): CodeBlock = KotlinCodeBlock(this) override fun createEmptyCodeBlock(): CodeBlock = KotlinCodeBlock(this)
override fun createVariableDeclaration(variable: Variable, isMutable: Boolean): VariableDeclaration = override fun createVariableDeclaration(variable: Variable, isMutable: Boolean): VariableDeclaration =
KotlinVariableDeclaration(variable, isMutable) KotlinVariableDeclaration(variable, isMutable)
override fun createVariableDeclaration(variable: Variable, init: Expression, isMutable: Boolean): VariableDeclaration = override fun createVariableDeclaration(variable: Variable, init: Expression, isMutable: Boolean): VariableDeclaration =
KotlinVariableDeclaration(variable, isMutable, init.toCode()) KotlinVariableDeclaration(variable, isMutable, init.toCode())
override fun createEmptyForLoopBody(iterateVariable: Variable): ForLoopBody = KotlinForLoopBody(iterateVariable, this) override fun createEmptyForLoopBody(iterateVariable: Variable): ForLoopBody = KotlinForLoopBody(iterateVariable, this)
override fun createForEachLoop(iterateVariable: Variable, collection: Expression, loopBody: ForLoopBody): Convertable = override fun createForEachLoop(iterateVariable: Variable, collection: Expression, loopBody: ForLoopBody): Convertable =
KotlinForEachLoop(iterateVariable, collection, loopBody) KotlinForEachLoop(iterateVariable, collection, loopBody)
override fun createForLoop(initialization: VariableDeclaration, condition: Expression, override fun createForLoop(
afterThought: Expression, loopBody: ForLoopBody): Convertable = initialization: VariableDeclaration, condition: Expression,
KotlinForLoop(initialization, condition, afterThought, loopBody) afterThought: Expression, loopBody: ForLoopBody
): Convertable =
KotlinForLoop(initialization, condition, afterThought, loopBody)
override fun createEmptyLambdaBody(argName: String): LambdaBody = KotlinLambdaBody(TextExpression(argName), this) override fun createEmptyLambdaBody(argName: String): LambdaBody = KotlinLambdaBody(TextExpression(argName), this)
override fun createLambda(argName: String, lambdaBody: LambdaBody): Lambda = KotlinLambda(argName, lambdaBody) override fun createLambda(argName: String, lambdaBody: LambdaBody): Lambda = KotlinLambda(argName, lambdaBody)
override fun createVariable(type: GenericType, name: String): Variable = VariableImpl(type, name) override fun createVariable(type: GenericType, name: String): Variable = VariableImpl(type, name)
override fun and(left: Expression, right: Expression): Expression = TextExpression("${left.toCode()} && ${right.toCode()}") override fun and(left: Expression, right: Expression): Expression = TextExpression("${left.toCode()} && ${right.toCode()}")
override fun equals(left: Expression, right: Expression): Expression = TextExpression("${left.toCode()} == ${right.toCode()}") override fun equals(left: Expression, right: Expression): Expression = TextExpression("${left.toCode()} == ${right.toCode()}")
override fun same(left: Expression, right: Expression): Expression = TextExpression("${left.toCode()} === ${right.toCode()}") override fun same(left: Expression, right: Expression): Expression = TextExpression("${left.toCode()} === ${right.toCode()}")
override fun createIfBranch(condition: Expression, thenBlock: CodeBlock): IfBranch = override fun createIfBranch(condition: Expression, thenBlock: CodeBlock): IfBranch =
KotlinIfBranch(condition, thenBlock, this) KotlinIfBranch(condition, thenBlock, this)
override fun createAssignmentStatement(variable: Variable, expression: Expression): AssignmentStatement = override fun createAssignmentStatement(variable: Variable, expression: Expression): AssignmentStatement =
KotlinAssignmentStatement(variable, expression) KotlinAssignmentStatement(variable, expression)
override fun createMapVariable(keyType: GenericType, valueType: GenericType, name: String, linked: Boolean): MapVariable = override fun createMapVariable(keyType: GenericType, valueType: GenericType, name: String, linked: Boolean): MapVariable =
KotlinMapVariable(if (linked) types.linkedMap(keyType, valueType) else types.map(keyType, valueType), name) KotlinMapVariable(if (linked) types.linkedMap(keyType, valueType) else types.map(keyType, valueType), name)
override fun createArrayVariable(elementType: GenericType, name: String): ArrayVariable = override fun createArrayVariable(elementType: GenericType, name: String): ArrayVariable =
KotlinArrayVariable(types.array(elementType), name) KotlinArrayVariable(types.array(elementType), name)
override fun createScope(codeBlock: CodeBlock): Convertable = override fun createScope(codeBlock: CodeBlock): Convertable =
object : Convertable { object : Convertable {
override fun toCode(indent: Int): String = override fun toCode(indent: Int): String =
"run {\n".withIndent(indent) + "run {\n".withIndent(indent) +
codeBlock.toCode(indent + 1) + codeBlock.toCode(indent + 1) +
"}".withIndent(indent) "}".withIndent(indent)
}
override fun createTryBlock(block: CodeBlock): TryBlock = KotlinTryBlock(block, this)
override fun createTimeVariableDeclaration(): VariableDeclaration =
KotlinVariableDeclaration(createVariable(types.TIME, "time"), false, types.TIME.defaultValue)
override fun currentTimeExpression(): Expression = TextExpression("time.get()")
override fun updateCurrentTimeExpression(): Expression = TextExpression("time.incrementAndGet()")
override fun createNewArrayExpression(elementType: GenericType, vararg args: Expression): Expression {
val arguments = args.joinToString { it.toCode() }
val text = when (elementType) {
types.BOOLEAN -> "kotlin.booleanArrayOf($arguments)"
KotlinTypes.BYTE -> "kotlin.byteArrayOf($arguments)"
KotlinTypes.SHORT -> "kotlin.shortArrayOf($arguments)"
KotlinTypes.CHAR -> "kotlin.charArrayOf($arguments)"
types.INT -> "kotlin.intArrayOf($arguments)"
types.LONG -> "kotlin.longArrayOf($arguments)"
KotlinTypes.FLOAT -> "kotlin.floatArrayOf($arguments)"
types.DOUBLE -> "kotlin.doubleArrayOf($arguments)"
else -> "kotlin.arrayOf<${types.nullable { elementType }.genericTypeName}>($arguments)"
}
return TextExpression(text)
} }
override fun createTryBlock(block: CodeBlock): TryBlock = KotlinTryBlock(block, this) override fun createNewSizedArray(elementType: GenericType, size: Expression): Expression =
TextExpression(types.array(elementType).sizedDeclaration(size.toCode()))
override fun createTimeVariableDeclaration(): VariableDeclaration =
KotlinVariableDeclaration(createVariable(types.TIME, "time"), false, types.TIME.defaultValue)
override fun currentTimeExpression(): Expression = TextExpression("time.get()")
override fun updateCurrentTimeExpression(): Expression = TextExpression("time.incrementAndGet()")
override fun createNewArrayExpression(elementType: GenericType, vararg args: Expression): Expression {
val arguments = args.joinToString { it.toCode() }
val text = when (elementType) {
types.BOOLEAN -> "kotlin.booleanArrayOf($arguments)"
KotlinTypes.BYTE -> "kotlin.byteArrayOf($arguments)"
KotlinTypes.SHORT -> "kotlin.shortArrayOf($arguments)"
KotlinTypes.CHAR -> "kotlin.charArrayOf($arguments)"
types.INT -> "kotlin.intArrayOf($arguments)"
types.LONG -> "kotlin.longArrayOf($arguments)"
KotlinTypes.FLOAT -> "kotlin.floatArrayOf($arguments)"
types.DOUBLE -> "kotlin.doubleArrayOf($arguments)"
else -> "kotlin.arrayOf<${types.nullable { elementType }.genericTypeName}>($arguments)"
}
return TextExpression(text)
}
override fun createNewSizedArray(elementType: GenericType, size: Expression): Expression =
TextExpression(types.array(elementType).sizedDeclaration(size.toCode()))
override fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall = override fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall =
peekCallFactory.createPeekCall(elementsType, lambda) peekCallFactory.createPeekCall(elementsType, lambda)
} }
@@ -9,12 +9,12 @@ import com.intellij.debugger.streams.trace.dsl.impl.common.TryBlockBase
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinTryBlock(private val block: CodeBlock, statementFactory: StatementFactory) : TryBlockBase(statementFactory) { class KotlinTryBlock(private val block: CodeBlock, statementFactory: StatementFactory) : TryBlockBase(statementFactory) {
override fun toCode(indent: Int): String { override fun toCode(indent: Int): String {
val descriptor = myCatchDescriptor ?: error("catch block must be specified") val descriptor = myCatchDescriptor ?: error("catch block must be specified")
return "try {\n".withIndent(indent) + return "try {\n".withIndent(indent) +
block.toCode(indent + 1) + block.toCode(indent + 1) +
"} catch(${descriptor.variable.name} : ${descriptor.variable.type.variableTypeName}) {\n" + "} catch(${descriptor.variable.name} : ${descriptor.variable.type.variableTypeName}) {\n" +
descriptor.block.toCode(indent + 1) + descriptor.block.toCode(indent + 1) +
"}".withIndent(indent) "}".withIndent(indent)
} }
} }
@@ -8,76 +8,84 @@ import com.intellij.debugger.streams.trace.impl.handler.type.*
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
object KotlinTypes : Types { object KotlinTypes : Types {
override val ANY: GenericType = ClassTypeImpl("kotlin.Any", "kotlin.Any()") override val ANY: GenericType = ClassTypeImpl("kotlin.Any", "kotlin.Any()")
override val BOOLEAN: GenericType = ClassTypeImpl("kotlin.Boolean", "false") override val BOOLEAN: GenericType = ClassTypeImpl("kotlin.Boolean", "false")
val BYTE: GenericType = ClassTypeImpl("kotlin.Byte", "0") val BYTE: GenericType = ClassTypeImpl("kotlin.Byte", "0")
val SHORT: GenericType = ClassTypeImpl("kotlin.Short", "0") val SHORT: GenericType = ClassTypeImpl("kotlin.Short", "0")
val CHAR: GenericType = ClassTypeImpl("kotlin.Char", "0.toChar()") val CHAR: GenericType = ClassTypeImpl("kotlin.Char", "0.toChar()")
override val INT: GenericType = ClassTypeImpl("kotlin.Int", "0") override val INT: GenericType = ClassTypeImpl("kotlin.Int", "0")
override val LONG: GenericType = ClassTypeImpl("kotlin.Long", "0L") override val LONG: GenericType = ClassTypeImpl("kotlin.Long", "0L")
val FLOAT: GenericType = ClassTypeImpl("kotlin.Float", "0.0f") val FLOAT: GenericType = ClassTypeImpl("kotlin.Float", "0.0f")
override val DOUBLE: GenericType = ClassTypeImpl("kotlin.Double", "0.0") override val DOUBLE: GenericType = ClassTypeImpl("kotlin.Double", "0.0")
override val STRING: GenericType = ClassTypeImpl("kotlin.String", "\"\"") override val STRING: GenericType = ClassTypeImpl("kotlin.String", "\"\"")
override val EXCEPTION: GenericType = ClassTypeImpl("kotlin.Throwable", "kotlin.Throwable()") override val EXCEPTION: GenericType = ClassTypeImpl("kotlin.Throwable", "kotlin.Throwable()")
override val VOID: GenericType = ClassTypeImpl("kotlin.Unit", "Unit") override val VOID: GenericType = ClassTypeImpl("kotlin.Unit", "Unit")
val NULLABLE_ANY: GenericType = nullable { ANY } val NULLABLE_ANY: GenericType = nullable { ANY }
override val TIME: GenericType = ClassTypeImpl("java.util.concurrent.atomic.AtomicInteger", override val TIME: GenericType = ClassTypeImpl(
"java.util.concurrent.atomic.AtomicInteger()") "java.util.concurrent.atomic.AtomicInteger",
"java.util.concurrent.atomic.AtomicInteger()"
)
override fun list(elementsType: GenericType): ListType = override fun list(elementsType: GenericType): ListType =
ListTypeImpl(elementsType, { "kotlin.collections.MutableList<$it>" }, "kotlin.collections.mutableListOf()") ListTypeImpl(elementsType, { "kotlin.collections.MutableList<$it>" }, "kotlin.collections.mutableListOf()")
override fun array(elementType: GenericType): ArrayType = when (elementType) { override fun array(elementType: GenericType): ArrayType = when (elementType) {
BOOLEAN -> ArrayTypeImpl(BOOLEAN, { "kotlin.BooleanArray" }, { "kotlin.BooleanArray($it)" }) BOOLEAN -> ArrayTypeImpl(BOOLEAN, { "kotlin.BooleanArray" }, { "kotlin.BooleanArray($it)" })
BYTE -> ArrayTypeImpl(BYTE, { "kotlin.ByteArray" }, { "kotlin.ByteArray($it)" }) BYTE -> ArrayTypeImpl(BYTE, { "kotlin.ByteArray" }, { "kotlin.ByteArray($it)" })
SHORT -> ArrayTypeImpl(SHORT, { "kotlin.ShortArray" }, { "kotlin.ShortArray($it)" }) SHORT -> ArrayTypeImpl(SHORT, { "kotlin.ShortArray" }, { "kotlin.ShortArray($it)" })
CHAR -> ArrayTypeImpl(CHAR, { "kotlin.CharArray" }, { "kotlin.CharArray($it)" }) CHAR -> ArrayTypeImpl(CHAR, { "kotlin.CharArray" }, { "kotlin.CharArray($it)" })
INT -> ArrayTypeImpl(INT, { "kotlin.IntArray" }, { "kotlin.IntArray($it)" }) INT -> ArrayTypeImpl(INT, { "kotlin.IntArray" }, { "kotlin.IntArray($it)" })
LONG -> ArrayTypeImpl(LONG, { "kotlin.LongArray" }, { "kotlin.LongArray($it)" }) LONG -> ArrayTypeImpl(LONG, { "kotlin.LongArray" }, { "kotlin.LongArray($it)" })
FLOAT -> ArrayTypeImpl(FLOAT, { "kotlin.FloatArray" }, { "kotlin.FloatArray($it)" }) FLOAT -> ArrayTypeImpl(FLOAT, { "kotlin.FloatArray" }, { "kotlin.FloatArray($it)" })
DOUBLE -> ArrayTypeImpl(DOUBLE, { "kotlin.DoubleArray" }, { "kotlin.DoubleArray($it)" }) DOUBLE -> ArrayTypeImpl(DOUBLE, { "kotlin.DoubleArray" }, { "kotlin.DoubleArray($it)" })
else -> ArrayTypeImpl(nullable { elementType }, { "kotlin.Array<$it>" }, else -> ArrayTypeImpl(nullable { elementType }, { "kotlin.Array<$it>" },
{ "kotlin.arrayOfNulls<${elementType.genericTypeName}>($it)" }) { "kotlin.arrayOfNulls<${elementType.genericTypeName}>($it)" })
}
override fun map(keyType: GenericType, valueType: GenericType): MapType =
MapTypeImpl(keyType, valueType,
{ keys, values -> "kotlin.collections.MutableMap<$keys, $values>" },
"kotlin.collections.mutableMapOf()")
override fun linkedMap(keyType: GenericType, valueType: GenericType): MapType =
MapTypeImpl(keyType, valueType,
{ keys, values -> "kotlin.collections.MutableMap<$keys, $values>" },
"kotlin.collections.linkedMapOf()")
override fun nullable(typeSelector: Types.() -> GenericType): GenericType {
val type = this.typeSelector()
if (type.genericTypeName.last() == '?') return type
return when (type) {
is ArrayType -> ArrayTypeImpl(type.elementType, { "kotlin.Array<$it>?" }, { type.sizedDeclaration(it) })
is ListType -> ListTypeImpl(type.elementType, { "kotlin.collections.MutableList<$it>?" }, type.defaultValue)
is MapType -> MapTypeImpl(type.keyType, type.valueType, { keys, values -> "kotlin.collections.MutableMap<$keys, $values>?" },
type.defaultValue)
else -> ClassTypeImpl(type.genericTypeName + '?', type.defaultValue)
} }
}
private val primitiveTypesIndex: Map<String, GenericType> = override fun map(keyType: GenericType, valueType: GenericType): MapType =
listOf( MapTypeImpl(
BOOLEAN, BYTE, INT, SHORT, keyType, valueType,
CHAR, LONG, FLOAT, DOUBLE { keys, values -> "kotlin.collections.MutableMap<$keys, $values>" },
) "kotlin.collections.mutableMapOf()"
.associate { it.genericTypeName to it } )
private val primitiveArraysIndex: Map<String, ArrayType> = primitiveTypesIndex.asSequence() override fun linkedMap(keyType: GenericType, valueType: GenericType): MapType =
.map { array(it.value) } MapTypeImpl(
.associate { it.genericTypeName to it } keyType, valueType,
{ keys, values -> "kotlin.collections.MutableMap<$keys, $values>" },
"kotlin.collections.linkedMapOf()"
)
fun primitiveTypeByName(typeName: String): GenericType? = primitiveTypesIndex[typeName] override fun nullable(typeSelector: Types.() -> GenericType): GenericType {
val type = this.typeSelector()
if (type.genericTypeName.last() == '?') return type
return when (type) {
is ArrayType -> ArrayTypeImpl(type.elementType, { "kotlin.Array<$it>?" }, { type.sizedDeclaration(it) })
is ListType -> ListTypeImpl(type.elementType, { "kotlin.collections.MutableList<$it>?" }, type.defaultValue)
is MapType -> MapTypeImpl(
type.keyType, type.valueType, { keys, values -> "kotlin.collections.MutableMap<$keys, $values>?" },
type.defaultValue
)
else -> ClassTypeImpl(type.genericTypeName + '?', type.defaultValue)
}
}
fun primitiveArrayByName(typeName: String): ArrayType? = primitiveArraysIndex[typeName] private val primitiveTypesIndex: Map<String, GenericType> =
listOf(
BOOLEAN, BYTE, INT, SHORT,
CHAR, LONG, FLOAT, DOUBLE
)
.associate { it.genericTypeName to it }
private val primitiveArraysIndex: Map<String, ArrayType> = primitiveTypesIndex.asSequence()
.map { array(it.value) }
.associate { it.genericTypeName to it }
fun primitiveTypeByName(typeName: String): GenericType? = primitiveTypesIndex[typeName]
fun primitiveArrayByName(typeName: String): ArrayType? = primitiveArraysIndex[typeName]
} }
@@ -7,12 +7,14 @@ import com.intellij.debugger.streams.trace.dsl.VariableDeclaration
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinVariableDeclaration(override val variable: Variable, class KotlinVariableDeclaration(
override val isMutable: Boolean, override val variable: Variable,
private val init: String = "") : VariableDeclaration { override val isMutable: Boolean,
override fun toCode(indent: Int): String { private val init: String = ""
val prefix = if (isMutable) "var" else "val" ) : VariableDeclaration {
val suffix = if (init.trim().isEmpty()) "" else " = $init" override fun toCode(indent: Int): String {
return "$prefix ${variable.name}: ${variable.type.variableTypeName}$suffix".withIndent(indent) val prefix = if (isMutable) "var" else "val"
} val suffix = if (init.trim().isEmpty()) "" else " = $init"
return "$prefix ${variable.name}: ${variable.type.variableTypeName}$suffix".withIndent(indent)
}
} }
@@ -8,5 +8,5 @@ import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
interface PeekCallFactory { interface PeekCallFactory {
fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall fun createPeekCall(elementsType: GenericType, lambda: String): IntermediateStreamCall
} }
@@ -11,19 +11,19 @@ import com.intellij.openapi.diagnostic.Logger
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinTraceExpressionBuilder(dsl: Dsl, handlerFactory: HandlerFactory) : TraceExpressionBuilderBase(dsl, handlerFactory) { class KotlinTraceExpressionBuilder(dsl: Dsl, handlerFactory: HandlerFactory) : TraceExpressionBuilderBase(dsl, handlerFactory) {
private companion object { private companion object {
private val LOG = Logger.getInstance(KotlinTraceExpressionBuilder::class.java) private val LOG = Logger.getInstance(KotlinTraceExpressionBuilder::class.java)
} }
override fun createTraceExpression(chain: StreamChain): String { override fun createTraceExpression(chain: StreamChain): String {
val expression = super.createTraceExpression(chain) val expression = super.createTraceExpression(chain)
val resultDeclaration = dsl.declaration(dsl.variable(dsl.types.nullable { ANY }, resultVariableName), dsl.nullExpression, true) val resultDeclaration = dsl.declaration(dsl.variable(dsl.types.nullable { ANY }, resultVariableName), dsl.nullExpression, true)
val result = "${resultDeclaration.toCode()}\n " + val result = "${resultDeclaration.toCode()}\n " +
"$expression\n" + "$expression\n" +
resultVariableName resultVariableName
LOG.info("trace expression: \n$result") LOG.info("trace expression: \n$result")
return result return result
} }
} }
@@ -1,33 +1,33 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler package org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import com.intellij.debugger.streams.wrapper.CallArgument import com.intellij.debugger.streams.wrapper.CallArgument
import com.intellij.debugger.streams.wrapper.IntermediateStreamCall import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
import com.intellij.debugger.streams.wrapper.StreamCallType import com.intellij.debugger.streams.wrapper.StreamCallType
import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class OnEachCall(private val elementsType: GenericType, lambda: String) : IntermediateStreamCall { class OnEachCall(private val elementsType: GenericType, lambda: String) : IntermediateStreamCall {
private val args: List<CallArgument> private val args: List<CallArgument>
init { init {
args = listOf(CallArgumentImpl(KotlinTypes.ANY.genericTypeName, lambda)) args = listOf(CallArgumentImpl(KotlinTypes.ANY.genericTypeName, lambda))
} }
override fun getArguments(): List<CallArgument> = args override fun getArguments(): List<CallArgument> = args
override fun getName(): String = "onEach" override fun getName(): String = "onEach"
override fun getType(): StreamCallType = StreamCallType.INTERMEDIATE override fun getType(): StreamCallType = StreamCallType.INTERMEDIATE
override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE
override fun getTypeBefore(): GenericType = elementsType override fun getTypeBefore(): GenericType = elementsType
override fun getTypeAfter(): GenericType = elementsType override fun getTypeAfter(): GenericType = elementsType
} }
@@ -14,9 +14,9 @@ import com.intellij.debugger.streams.wrapper.TerminatorStreamCall
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class BothSemanticHandlerWrapper(private val handler: BothSemanticsHandler) { class BothSemanticHandlerWrapper(private val handler: BothSemanticsHandler) {
fun createIntermediateHandler(order: Int, call: IntermediateStreamCall, dsl: Dsl): IntermediateCallHandler = fun createIntermediateHandler(order: Int, call: IntermediateStreamCall, dsl: Dsl): IntermediateCallHandler =
CollectionIntermediateHandler(order, call, dsl, handler) CollectionIntermediateHandler(order, call, dsl, handler)
fun createTerminatorHandler(call: TerminatorStreamCall, resultExpression: String, dsl: Dsl): TerminatorCallHandler = fun createTerminatorHandler(call: TerminatorStreamCall, resultExpression: String, dsl: Dsl): TerminatorCallHandler =
CollectionTerminatorHandler(call, resultExpression, dsl, handler) CollectionTerminatorHandler(call, resultExpression, dsl, handler)
} }
@@ -10,17 +10,17 @@ import com.intellij.debugger.streams.wrapper.TerminatorStreamCall
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
interface BothSemanticsHandler { interface BothSemanticsHandler {
fun variablesDeclaration(call: StreamCall, order: Int, dsl: Dsl): List<VariableDeclaration> fun variablesDeclaration(call: StreamCall, order: Int, dsl: Dsl): List<VariableDeclaration>
fun prepareResult(dsl: Dsl, variables: List<Variable>): CodeBlock fun prepareResult(dsl: Dsl, variables: List<Variable>): CodeBlock
fun additionalCallsBefore(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall> fun additionalCallsBefore(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall>
fun additionalCallsAfter(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall> fun additionalCallsAfter(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall>
fun transformAsIntermediateCall(call: IntermediateStreamCall, variables: List<Variable>, dsl: Dsl): IntermediateStreamCall fun transformAsIntermediateCall(call: IntermediateStreamCall, variables: List<Variable>, dsl: Dsl): IntermediateStreamCall
fun transformAsTerminalCall(call: TerminatorStreamCall, variables: List<Variable>, dsl: Dsl): TerminatorStreamCall fun transformAsTerminalCall(call: TerminatorStreamCall, variables: List<Variable>, dsl: Dsl): TerminatorStreamCall
fun getResultExpression(call: StreamCall, dsl: Dsl, variables: List<Variable>): Expression fun getResultExpression(call: StreamCall, dsl: Dsl, variables: List<Variable>): Expression
} }
@@ -11,14 +11,14 @@ import com.intellij.debugger.streams.wrapper.StreamCall
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
abstract class CollectionHandlerBase(order: Int, private val dsl: Dsl, abstract class CollectionHandlerBase(
private val call: StreamCall, private val internalHandler: BothSemanticsHandler order: Int, private val dsl: Dsl,
) private val call: StreamCall, private val internalHandler: BothSemanticsHandler
: TraceHandler { ) : TraceHandler {
private val declarations: List<VariableDeclaration> = internalHandler.variablesDeclaration(call, order, dsl) private val declarations: List<VariableDeclaration> = internalHandler.variablesDeclaration(call, order, dsl)
protected val variables: List<Variable> = declarations.map(VariableDeclaration::variable) protected val variables: List<Variable> = declarations.map(VariableDeclaration::variable)
override fun additionalVariablesDeclaration(): List<VariableDeclaration> = declarations override fun additionalVariablesDeclaration(): List<VariableDeclaration> = declarations
override fun getResultExpression(): Expression = internalHandler.getResultExpression(call, dsl, variables) override fun getResultExpression(): Expression = internalHandler.getResultExpression(call, dsl, variables)
} }
@@ -2,7 +2,9 @@
package org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections package org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections
import com.intellij.debugger.streams.trace.IntermediateCallHandler import com.intellij.debugger.streams.trace.IntermediateCallHandler
import com.intellij.debugger.streams.trace.dsl.* import com.intellij.debugger.streams.trace.dsl.CodeBlock
import com.intellij.debugger.streams.trace.dsl.Dsl
import com.intellij.debugger.streams.trace.dsl.Expression
import com.intellij.debugger.streams.wrapper.IntermediateStreamCall import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
/** /**
@@ -13,26 +15,25 @@ class CollectionIntermediateHandler(
private val call: IntermediateStreamCall, private val call: IntermediateStreamCall,
private val dsl: Dsl, private val dsl: Dsl,
private val internalHandler: BothSemanticsHandler private val internalHandler: BothSemanticsHandler
) ) : IntermediateCallHandler, CollectionHandlerBase(order, dsl, call, internalHandler) {
: IntermediateCallHandler, CollectionHandlerBase(order, dsl, call, internalHandler) {
override fun prepareResult(): CodeBlock { override fun prepareResult(): CodeBlock {
return internalHandler.prepareResult(dsl, variables) return internalHandler.prepareResult(dsl, variables)
} }
override fun additionalCallsBefore(): List<IntermediateStreamCall> { override fun additionalCallsBefore(): List<IntermediateStreamCall> {
return internalHandler.additionalCallsBefore(call, dsl) return internalHandler.additionalCallsBefore(call, dsl)
} }
override fun additionalCallsAfter(): List<IntermediateStreamCall> { override fun additionalCallsAfter(): List<IntermediateStreamCall> {
return internalHandler.additionalCallsAfter(call, dsl) return internalHandler.additionalCallsAfter(call, dsl)
} }
override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall { override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall {
return internalHandler.transformAsIntermediateCall(call, variables, dsl) return internalHandler.transformAsIntermediateCall(call, variables, dsl)
} }
override fun getResultExpression(): Expression { override fun getResultExpression(): Expression {
return internalHandler.getResultExpression(call, dsl, variables) return internalHandler.getResultExpression(call, dsl, variables)
} }
} }
@@ -8,46 +8,44 @@ import com.intellij.debugger.streams.trace.dsl.Expression
import com.intellij.debugger.streams.trace.dsl.impl.TextExpression import com.intellij.debugger.streams.trace.dsl.impl.TextExpression
import com.intellij.debugger.streams.wrapper.IntermediateStreamCall import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
import com.intellij.debugger.streams.wrapper.TerminatorStreamCall import com.intellij.debugger.streams.wrapper.TerminatorStreamCall
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.BothSemanticsHandler
import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.collections.CollectionHandlerBase
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class CollectionTerminatorHandler(private val call: TerminatorStreamCall, class CollectionTerminatorHandler(
private val resultExpression: String, private val call: TerminatorStreamCall,
private val dsl: Dsl, private val resultExpression: String,
private val internalHandler: BothSemanticsHandler private val dsl: Dsl,
) private val internalHandler: BothSemanticsHandler
: TerminatorCallHandler, CollectionHandlerBase(Int.MAX_VALUE, dsl, call, internalHandler) { ) : TerminatorCallHandler, CollectionHandlerBase(Int.MAX_VALUE, dsl, call, internalHandler) {
override fun prepareResult(): CodeBlock { override fun prepareResult(): CodeBlock {
val prepareResult = internalHandler.prepareResult(dsl, variables) val prepareResult = internalHandler.prepareResult(dsl, variables)
val additionalCallsAfter = internalHandler.additionalCallsAfter(call, dsl) val additionalCallsAfter = internalHandler.additionalCallsAfter(call, dsl)
if (additionalCallsAfter.isEmpty()) { if (additionalCallsAfter.isEmpty()) {
return prepareResult return prepareResult
}
return dsl.block {
+createCallAfterExpression(additionalCallsAfter)
add(prepareResult)
}
} }
return dsl.block { override fun additionalCallsBefore(): List<IntermediateStreamCall> =
+createCallAfterExpression(additionalCallsAfter) internalHandler.additionalCallsBefore(call, dsl)
add(prepareResult)
}
}
override fun additionalCallsBefore(): List<IntermediateStreamCall> = override fun transformCall(call: TerminatorStreamCall): TerminatorStreamCall {
internalHandler.additionalCallsBefore(call, dsl) return internalHandler.transformAsTerminalCall(call, variables, dsl)
override fun transformCall(call: TerminatorStreamCall): TerminatorStreamCall {
return internalHandler.transformAsTerminalCall(call, variables, dsl)
}
private fun createCallAfterExpression(additionalCallsAfter: List<IntermediateStreamCall>): Expression {
var result: Expression = TextExpression(resultExpression)
for (call in additionalCallsAfter) {
val args = call.arguments.map { TextExpression(it.text) }.toTypedArray()
result = result.call(call.name, *args)
} }
return result private fun createCallAfterExpression(additionalCallsAfter: List<IntermediateStreamCall>): Expression {
} var result: Expression = TextExpression(resultExpression)
for (call in additionalCallsAfter) {
val args = call.arguments.map { TextExpression(it.text) }.toTypedArray()
result = result.call(call.name, *args)
}
return result
}
} }
@@ -16,65 +16,67 @@ import org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.withArgs
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class FilterCallHandler : BothSemanticsHandler { class FilterCallHandler : BothSemanticsHandler {
private companion object { private companion object {
val VALUES_ARRAY_NAME = "objectsInPredicate" val VALUES_ARRAY_NAME = "objectsInPredicate"
val PREDICATE_RESULT_ARRAY_NAME = "filteringResults" val PREDICATE_RESULT_ARRAY_NAME = "filteringResults"
fun oldPredicateVariableName(order: Int): String = "filterPredicate" + order fun oldPredicateVariableName(order: Int): String = "filterPredicate" + order
}
override fun variablesDeclaration(call: StreamCall, order: Int, dsl: Dsl): List<VariableDeclaration> {
val types = dsl.types
val timeToObjectMap = dsl.linkedMap(types.INT, call.typeBefore(), call.name + "Values" + order)
val predicateResultMap = dsl.linkedMap(types.INT, types.BOOLEAN, call.name + "PredicateValue" + order)
val predicate = call.arguments[0]
// TODO: use generic types in CallArgument
val oldFilterPredicate = dsl.variable(ClassTypeImpl(predicate.type), oldPredicateVariableName(order))
return listOf(timeToObjectMap.defaultDeclaration(), predicateResultMap.defaultDeclaration(),
dsl.declaration(oldFilterPredicate, TextExpression(predicate.text), false))
}
override fun prepareResult(dsl: Dsl, variables: List<Variable>): CodeBlock {
val values = variables[0] as MapVariable
val filterResult = variables[1] as MapVariable
return dsl.block {
add(values.convertToArray(dsl, VALUES_ARRAY_NAME))
add(filterResult.convertToArray(dsl, PREDICATE_RESULT_ARRAY_NAME))
} }
}
override fun additionalCallsBefore(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall> = emptyList() override fun variablesDeclaration(call: StreamCall, order: Int, dsl: Dsl): List<VariableDeclaration> {
val types = dsl.types
override fun additionalCallsAfter(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall> = emptyList() val timeToObjectMap = dsl.linkedMap(types.INT, call.typeBefore(), call.name + "Values" + order)
val predicateResultMap = dsl.linkedMap(types.INT, types.BOOLEAN, call.name + "PredicateValue" + order)
val predicate = call.arguments[0]
// TODO: use generic types in CallArgument
val oldFilterPredicate = dsl.variable(ClassTypeImpl(predicate.type), oldPredicateVariableName(order))
override fun getResultExpression(call: StreamCall, dsl: Dsl, variables: List<Variable>): Expression { return listOf(
return dsl.newArray(dsl.types.ANY, TextExpression(VALUES_ARRAY_NAME), TextExpression(PREDICATE_RESULT_ARRAY_NAME)) timeToObjectMap.defaultDeclaration(), predicateResultMap.defaultDeclaration(),
} dsl.declaration(oldFilterPredicate, TextExpression(predicate.text), false)
)
}
override fun transformAsIntermediateCall(call: IntermediateStreamCall, variables: List<Variable>, dsl: Dsl): IntermediateStreamCall { override fun prepareResult(dsl: Dsl, variables: List<Variable>): CodeBlock {
return call.withArgs(listOf(createNewPredicate(variables, dsl))) val values = variables[0] as MapVariable
} val filterResult = variables[1] as MapVariable
return dsl.block {
add(values.convertToArray(dsl, VALUES_ARRAY_NAME))
add(filterResult.convertToArray(dsl, PREDICATE_RESULT_ARRAY_NAME))
}
}
override fun transformAsTerminalCall(call: TerminatorStreamCall, variables: List<Variable>, dsl: Dsl): TerminatorStreamCall { override fun additionalCallsBefore(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall> = emptyList()
return call.withArgs(listOf(createNewPredicate(variables, dsl)))
}
private fun createNewPredicate(variables: List<Variable>, dsl: Dsl): CallArgument { override fun additionalCallsAfter(call: StreamCall, dsl: Dsl): List<IntermediateStreamCall> = emptyList()
val valuesMap = variables[0] as MapVariable
val filteringMap = variables[1] as MapVariable
val oldPredicate = variables[2]
val newPredicate = dsl.lambda("value") {
+dsl.updateTime()
+valuesMap.set(dsl.currentTime(), lambdaArg)
val filterResult = dsl.variable(dsl.types.BOOLEAN, "result")
declare(filterResult, oldPredicate.call("invoke", lambdaArg), false)
+filteringMap.set(dsl.currentTime(), filterResult)
+dsl.updateTime() // reserve unique time for mapped value
doReturn(filterResult)
}.toCode()
return CallArgumentImpl(oldPredicate.type.genericTypeName, newPredicate) override fun getResultExpression(call: StreamCall, dsl: Dsl, variables: List<Variable>): Expression {
} return dsl.newArray(dsl.types.ANY, TextExpression(VALUES_ARRAY_NAME), TextExpression(PREDICATE_RESULT_ARRAY_NAME))
}
override fun transformAsIntermediateCall(call: IntermediateStreamCall, variables: List<Variable>, dsl: Dsl): IntermediateStreamCall {
return call.withArgs(listOf(createNewPredicate(variables, dsl)))
}
override fun transformAsTerminalCall(call: TerminatorStreamCall, variables: List<Variable>, dsl: Dsl): TerminatorStreamCall {
return call.withArgs(listOf(createNewPredicate(variables, dsl)))
}
private fun createNewPredicate(variables: List<Variable>, dsl: Dsl): CallArgument {
val valuesMap = variables[0] as MapVariable
val filteringMap = variables[1] as MapVariable
val oldPredicate = variables[2]
val newPredicate = dsl.lambda("value") {
+dsl.updateTime()
+valuesMap.set(dsl.currentTime(), lambdaArg)
val filterResult = dsl.variable(dsl.types.BOOLEAN, "result")
declare(filterResult, oldPredicate.call("invoke", lambdaArg), false)
+filteringMap.set(dsl.currentTime(), filterResult)
+dsl.updateTime() // reserve unique time for mapped value
doReturn(filterResult)
}.toCode()
return CallArgumentImpl(oldPredicate.type.genericTypeName, newPredicate)
}
} }
@@ -1,7 +1,6 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence package org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import com.intellij.debugger.streams.trace.dsl.CodeBlock import com.intellij.debugger.streams.trace.dsl.CodeBlock
import com.intellij.debugger.streams.trace.dsl.Dsl import com.intellij.debugger.streams.trace.dsl.Dsl
import com.intellij.debugger.streams.trace.dsl.Expression import com.intellij.debugger.streams.trace.dsl.Expression
@@ -13,65 +12,66 @@ import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl
import com.intellij.debugger.streams.wrapper.impl.IntermediateStreamCallImpl import com.intellij.debugger.streams.wrapper.impl.IntermediateStreamCallImpl
import com.intellij.openapi.util.TextRange.EMPTY_RANGE import com.intellij.openapi.util.TextRange.EMPTY_RANGE
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class FilterIsInstanceHandler(num: Int, call: IntermediateStreamCall, dsl: Dsl) : HandlerBase.Intermediate(dsl) { class FilterIsInstanceHandler(num: Int, call: IntermediateStreamCall, dsl: Dsl) : HandlerBase.Intermediate(dsl) {
private companion object { private companion object {
fun createHandler(num: Int, call: IntermediateStreamCall, dsl: Dsl): HandlerBase.Intermediate = fun createHandler(num: Int, call: IntermediateStreamCall, dsl: Dsl): HandlerBase.Intermediate =
if (call.arguments.isEmpty()) MyWithGenericsHandler(num, call, dsl) if (call.arguments.isEmpty()) MyWithGenericsHandler(num, call, dsl)
else PeekTraceHandler(num, call.name, call.typeBefore, call.typeAfter, dsl) else PeekTraceHandler(num, call.name, call.typeBefore, call.typeAfter, dsl)
}
private val filterHandler = createHandler(num, call, dsl)
// use explicit delegation to avoid issues with navigation
override fun additionalCallsAfter(): MutableList<IntermediateStreamCall> = filterHandler.additionalCallsAfter()
override fun additionalCallsBefore(): List<IntermediateStreamCall> = filterHandler.additionalCallsBefore()
override fun additionalVariablesDeclaration(): List<VariableDeclaration> = filterHandler.additionalVariablesDeclaration()
override fun getResultExpression(): Expression = filterHandler.resultExpression
override fun prepareResult(): CodeBlock = filterHandler.prepareResult()
override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall = filterHandler.transformCall(call)
/*
* Transforms filterIsInstance<ClassName> -> filter { it is ClassName }.map { it as ClassName }
*/
private class MyWithGenericsHandler(num: Int, private val call: IntermediateStreamCall, dsl: Dsl) : HandlerBase.Intermediate(dsl) {
private val peekHandler = PeekTraceHandler(num, "filterIsInstance", call.typeBefore, call.typeAfter, dsl)
override fun additionalCallsAfter(): List<IntermediateStreamCall> {
val mapperType = functionalType(call.typeBefore.genericTypeName, call.typeAfter.genericTypeName)
val mapper = CallArgumentImpl(mapperType, "{ x -> x as ${call.typeAfter.genericTypeName} }")
val result: MutableList<IntermediateStreamCall> = mutableListOf(syntheticMapCall(mapper))
result.addAll(peekHandler.additionalCallsAfter())
return result
} }
override fun additionalCallsBefore(): List<IntermediateStreamCall> = peekHandler.additionalCallsBefore() private val filterHandler = createHandler(num, call, dsl)
override fun additionalVariablesDeclaration(): List<VariableDeclaration> = // use explicit delegation to avoid issues with navigation
peekHandler.additionalVariablesDeclaration()
override fun getResultExpression(): Expression = peekHandler.resultExpression override fun additionalCallsAfter(): MutableList<IntermediateStreamCall> = filterHandler.additionalCallsAfter()
override fun additionalCallsBefore(): List<IntermediateStreamCall> = filterHandler.additionalCallsBefore()
override fun additionalVariablesDeclaration(): List<VariableDeclaration> = filterHandler.additionalVariablesDeclaration()
override fun getResultExpression(): Expression = filterHandler.resultExpression
override fun prepareResult(): CodeBlock = filterHandler.prepareResult()
override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall = filterHandler.transformCall(call)
override fun prepareResult(): CodeBlock = peekHandler.prepareResult() /*
* Transforms filterIsInstance<ClassName> -> filter { it is ClassName }.map { it as ClassName }
*/
private class MyWithGenericsHandler(num: Int, private val call: IntermediateStreamCall, dsl: Dsl) : HandlerBase.Intermediate(dsl) {
private val peekHandler = PeekTraceHandler(num, "filterIsInstance", call.typeBefore, call.typeAfter, dsl)
override fun additionalCallsAfter(): List<IntermediateStreamCall> {
val mapperType = functionalType(call.typeBefore.genericTypeName, call.typeAfter.genericTypeName)
val mapper = CallArgumentImpl(mapperType, "{ x -> x as ${call.typeAfter.genericTypeName} }")
val result: MutableList<IntermediateStreamCall> = mutableListOf(syntheticMapCall(mapper))
result.addAll(peekHandler.additionalCallsAfter())
return result
}
override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall { override fun additionalCallsBefore(): List<IntermediateStreamCall> = peekHandler.additionalCallsBefore()
val typeAfter = call.typeAfter.genericTypeName
val predicateType = functionalType(typeAfter, KotlinTypes.BOOLEAN.genericTypeName) override fun additionalVariablesDeclaration(): List<VariableDeclaration> =
val predicate = CallArgumentImpl(predicateType, " { x -> x is $typeAfter} ") peekHandler.additionalVariablesDeclaration()
return syntheticFilterCall(predicate)
override fun getResultExpression(): Expression = peekHandler.resultExpression
override fun prepareResult(): CodeBlock = peekHandler.prepareResult()
override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall {
val typeAfter = call.typeAfter.genericTypeName
val predicateType = functionalType(typeAfter, KotlinTypes.BOOLEAN.genericTypeName)
val predicate = CallArgumentImpl(predicateType, " { x -> x is $typeAfter} ")
return syntheticFilterCall(predicate)
}
private fun syntheticMapCall(mapper: CallArgument): IntermediateStreamCall =
IntermediateStreamCallImpl("map", listOf(mapper), call.typeBefore, call.typeAfter, EMPTY_RANGE)
private fun syntheticFilterCall(predicate: CallArgument): IntermediateStreamCall =
IntermediateStreamCallImpl("filter", listOf(predicate), call.typeBefore, call.typeBefore, EMPTY_RANGE)
private fun functionalType(argType: String, resultType: String): String {
return "($argType) -> $resultType"
}
} }
private fun syntheticMapCall(mapper: CallArgument): IntermediateStreamCall =
IntermediateStreamCallImpl("map", listOf(mapper), call.typeBefore, call.typeAfter, EMPTY_RANGE)
private fun syntheticFilterCall(predicate: CallArgument): IntermediateStreamCall =
IntermediateStreamCallImpl("filter", listOf(predicate), call.typeBefore, call.typeBefore, EMPTY_RANGE)
private fun functionalType(argType: String, resultType: String): String {
return "($argType) -> $resultType"
}
}
} }
@@ -1,7 +1,6 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence package org.jetbrains.kotlin.idea.debugger.sequence.trace.impl.handler.sequence
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import com.intellij.debugger.streams.trace.dsl.* import com.intellij.debugger.streams.trace.dsl.*
import com.intellij.debugger.streams.trace.dsl.impl.TextExpression import com.intellij.debugger.streams.trace.dsl.impl.TextExpression
import com.intellij.debugger.streams.trace.impl.handler.type.ClassTypeImpl import com.intellij.debugger.streams.trace.impl.handler.type.ClassTypeImpl
@@ -11,113 +10,117 @@ import com.intellij.debugger.streams.wrapper.CallArgument
import com.intellij.debugger.streams.wrapper.IntermediateStreamCall import com.intellij.debugger.streams.wrapper.IntermediateStreamCall
import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl import com.intellij.debugger.streams.wrapper.impl.CallArgumentImpl
import com.intellij.debugger.streams.wrapper.impl.IntermediateStreamCallImpl import com.intellij.debugger.streams.wrapper.impl.IntermediateStreamCallImpl
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
/** /**
* Based on com.intellij.debugger.streams.trace.impl.handler.unified.DistinctByKeyHandler * Based on com.intellij.debugger.streams.trace.impl.handler.unified.DistinctByKeyHandler
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class KotlinDistinctByHandler(callNumber: Int, private val call: IntermediateStreamCall, dsl: Dsl) class KotlinDistinctByHandler(callNumber: Int, private val call: IntermediateStreamCall, dsl: Dsl) : HandlerBase.Intermediate(dsl) {
: HandlerBase.Intermediate(dsl) { private companion object {
private companion object { val KEY_EXTRACTOR_VARIABLE_PREFIX = "keyExtractor"
val KEY_EXTRACTOR_VARIABLE_PREFIX = "keyExtractor" val TRANSITIONS_ARRAY_NAME = "transitionsArray"
val TRANSITIONS_ARRAY_NAME = "transitionsArray"
}
private val peekHandler = PeekTraceHandler(callNumber, "distinctBy", call.typeBefore, call.typeAfter, dsl)
private val keyExtractor: CallArgument
private val extractorVariable: Variable
private val beforeTimes = dsl.list(dsl.types.INT, call.name + callNumber + "BeforeTimes")
private val beforeValues = dsl.list(call.typeBefore, call.name + callNumber + "BeforeValues")
private val keys = dsl.list(KotlinTypes.NULLABLE_ANY, call.name + callNumber + "Keys")
private val time2ValueAfter = dsl.linkedMap(dsl.types.INT, call.typeAfter, call.name + callNumber + "after")
init {
val arguments = call.arguments
assert(arguments.isNotEmpty(), { "Key extractor is not specified" })
keyExtractor = arguments.first()
extractorVariable = dsl.variable(ClassTypeImpl(keyExtractor.type), KEY_EXTRACTOR_VARIABLE_PREFIX + callNumber)
}
override fun additionalVariablesDeclaration(): List<VariableDeclaration> {
val extractor = dsl.declaration(extractorVariable, TextExpression(keyExtractor.text), false)
val variables =
mutableListOf(extractor, beforeTimes.defaultDeclaration(), beforeValues.defaultDeclaration(),
time2ValueAfter.defaultDeclaration(), keys.defaultDeclaration())
variables.addAll(peekHandler.additionalVariablesDeclaration())
return variables
}
override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall {
val newKeyExtractor = dsl.lambda("x") {
val key = dsl.variable(KotlinTypes.NULLABLE_ANY, "key")
declare(key, extractorVariable.call("invoke", lambdaArg), false)
statement { beforeTimes.add(dsl.currentTime()) }
statement { beforeValues.add(lambdaArg) }
statement { keys.add(key) }
doReturn(key)
}.toCode()
return call.updateArguments(listOf(CallArgumentImpl(keyExtractor.type, newKeyExtractor)))
}
override fun prepareResult(): CodeBlock {
val keys2TimesBefore = dsl.map(KotlinTypes.NULLABLE_ANY, dsl.types.list(dsl.types.INT), "keys2Times")
val transitions = dsl.map(dsl.types.INT, dsl.types.INT, "transitionsMap")
return dsl.block {
add(peekHandler.prepareResult())
declare(keys2TimesBefore.defaultDeclaration())
declare(transitions.defaultDeclaration())
integerIteration(keys.size(), block@ this) {
val key = declare(variable(KotlinTypes.NULLABLE_ANY, "key"), keys.get(loopVariable), false)
val lst = list(dsl.types.INT, "lst")
declare(lst, keys2TimesBefore.computeIfAbsent(key, lambda("k") {
doReturn(newList(types.INT))
}), false)
statement { lst.add(beforeTimes.get(loopVariable)) }
}
forEachLoop(variable(types.INT, "afterTime"), time2ValueAfter.keys()) {
val afterTime = loopVariable
val valueAfter = declare(variable(call.typeAfter, "valueAfter"), time2ValueAfter.get(loopVariable), false)
val key = declare(variable(KotlinTypes.NULLABLE_ANY, "key"), nullExpression, true)
integerIteration(beforeTimes.size(), forEachLoop@ this) {
ifBranch((valueAfter same beforeValues.get(loopVariable)) and !transitions.contains(beforeTimes.get(loopVariable))) {
key assign keys.get(loopVariable)
statement { breakIteration() }
}
}
forEachLoop(variable(types.INT, "beforeTime"), keys2TimesBefore.get(key)) {
statement { transitions.set(loopVariable, afterTime) }
}
}
add(transitions.convertToArray(this, "transitionsArray"))
}
}
override fun getResultExpression(): Expression =
dsl.newArray(dsl.types.ANY, peekHandler.resultExpression, TextExpression(TRANSITIONS_ARRAY_NAME))
override fun additionalCallsBefore(): List<IntermediateStreamCall> = peekHandler.additionalCallsBefore()
override fun additionalCallsAfter(): List<IntermediateStreamCall> {
val callsAfter = ArrayList(peekHandler.additionalCallsAfter())
val lambda = dsl.lambda("x") {
doReturn(time2ValueAfter.set(dsl.currentTime(), lambdaArg))
} }
callsAfter.add(dsl.createPeekCall(call.typeAfter, lambda.toCode())) private val peekHandler = PeekTraceHandler(callNumber, "distinctBy", call.typeBefore, call.typeAfter, dsl)
return callsAfter private val keyExtractor: CallArgument
} private val extractorVariable: Variable
private val beforeTimes = dsl.list(dsl.types.INT, call.name + callNumber + "BeforeTimes")
private val beforeValues = dsl.list(call.typeBefore, call.name + callNumber + "BeforeValues")
private val keys = dsl.list(KotlinTypes.NULLABLE_ANY, call.name + callNumber + "Keys")
private val time2ValueAfter = dsl.linkedMap(dsl.types.INT, call.typeAfter, call.name + callNumber + "after")
private fun CodeContext.integerIteration(border: Expression, block: CodeBlock, init: ForLoopBody.() -> Unit) { init {
block.forLoop(declaration(variable(types.INT, "i"), TextExpression("0"), true), val arguments = call.arguments
TextExpression("i < ${border.toCode()}"), assert(arguments.isNotEmpty(), { "Key extractor is not specified" })
TextExpression("i = i + 1"), init) keyExtractor = arguments.first()
} extractorVariable = dsl.variable(ClassTypeImpl(keyExtractor.type), KEY_EXTRACTOR_VARIABLE_PREFIX + callNumber)
}
private fun IntermediateStreamCall.updateArguments(args: List<CallArgument>): IntermediateStreamCall = override fun additionalVariablesDeclaration(): List<VariableDeclaration> {
IntermediateStreamCallImpl("distinctBy", args, typeBefore, typeAfter, textRange) val extractor = dsl.declaration(extractorVariable, TextExpression(keyExtractor.text), false)
val variables =
mutableListOf(
extractor, beforeTimes.defaultDeclaration(), beforeValues.defaultDeclaration(),
time2ValueAfter.defaultDeclaration(), keys.defaultDeclaration()
)
variables.addAll(peekHandler.additionalVariablesDeclaration())
return variables
}
override fun transformCall(call: IntermediateStreamCall): IntermediateStreamCall {
val newKeyExtractor = dsl.lambda("x") {
val key = dsl.variable(KotlinTypes.NULLABLE_ANY, "key")
declare(key, extractorVariable.call("invoke", lambdaArg), false)
statement { beforeTimes.add(dsl.currentTime()) }
statement { beforeValues.add(lambdaArg) }
statement { keys.add(key) }
doReturn(key)
}.toCode()
return call.updateArguments(listOf(CallArgumentImpl(keyExtractor.type, newKeyExtractor)))
}
override fun prepareResult(): CodeBlock {
val keys2TimesBefore = dsl.map(KotlinTypes.NULLABLE_ANY, dsl.types.list(dsl.types.INT), "keys2Times")
val transitions = dsl.map(dsl.types.INT, dsl.types.INT, "transitionsMap")
return dsl.block {
add(peekHandler.prepareResult())
declare(keys2TimesBefore.defaultDeclaration())
declare(transitions.defaultDeclaration())
integerIteration(keys.size(), block@ this) {
val key = declare(variable(KotlinTypes.NULLABLE_ANY, "key"), keys.get(loopVariable), false)
val lst = list(dsl.types.INT, "lst")
declare(lst, keys2TimesBefore.computeIfAbsent(key, lambda("k") {
doReturn(newList(types.INT))
}), false)
statement { lst.add(beforeTimes.get(loopVariable)) }
}
forEachLoop(variable(types.INT, "afterTime"), time2ValueAfter.keys()) {
val afterTime = loopVariable
val valueAfter = declare(variable(call.typeAfter, "valueAfter"), time2ValueAfter.get(loopVariable), false)
val key = declare(variable(KotlinTypes.NULLABLE_ANY, "key"), nullExpression, true)
integerIteration(beforeTimes.size(), forEachLoop@ this) {
ifBranch((valueAfter same beforeValues.get(loopVariable)) and !transitions.contains(beforeTimes.get(loopVariable))) {
key assign keys.get(loopVariable)
statement { breakIteration() }
}
}
forEachLoop(variable(types.INT, "beforeTime"), keys2TimesBefore.get(key)) {
statement { transitions.set(loopVariable, afterTime) }
}
}
add(transitions.convertToArray(this, "transitionsArray"))
}
}
override fun getResultExpression(): Expression =
dsl.newArray(dsl.types.ANY, peekHandler.resultExpression, TextExpression(TRANSITIONS_ARRAY_NAME))
override fun additionalCallsBefore(): List<IntermediateStreamCall> = peekHandler.additionalCallsBefore()
override fun additionalCallsAfter(): List<IntermediateStreamCall> {
val callsAfter = ArrayList(peekHandler.additionalCallsAfter())
val lambda = dsl.lambda("x") {
doReturn(time2ValueAfter.set(dsl.currentTime(), lambdaArg))
}
callsAfter.add(dsl.createPeekCall(call.typeAfter, lambda.toCode()))
return callsAfter
}
private fun CodeContext.integerIteration(border: Expression, block: CodeBlock, init: ForLoopBody.() -> Unit) {
block.forLoop(
declaration(variable(types.INT, "i"), TextExpression("0"), true),
TextExpression("i < ${border.toCode()}"),
TextExpression("i = i + 1"), init
)
}
private fun IntermediateStreamCall.updateArguments(args: List<CallArgument>): IntermediateStreamCall =
IntermediateStreamCallImpl("distinctBy", args, typeBefore, typeAfter, textRange)
} }
@@ -16,52 +16,52 @@ import com.sun.jdi.Value
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class FilterTraceInterpreter(private val predicateValueToAccept: Boolean) : CallTraceInterpreter { class FilterTraceInterpreter(private val predicateValueToAccept: Boolean) : CallTraceInterpreter {
override fun resolve(call: StreamCall, value: Value): TraceInfo { override fun resolve(call: StreamCall, value: Value): TraceInfo {
if (value !is ArrayReference) throw UnexpectedValueTypeException("array reference excepted, but actual: ${value.type().name()}") if (value !is ArrayReference) throw UnexpectedValueTypeException("array reference excepted, but actual: ${value.type().name()}")
val before = resolveValuesBefore(value.getValue(0)) val before = resolveValuesBefore(value.getValue(0))
val filteringMap = value.getValue(1) val filteringMap = value.getValue(1)
val after = resolveValuesAfter(before, filteringMap) val after = resolveValuesAfter(before, filteringMap)
return ValuesOrder(call, before, after) return ValuesOrder(call, before, after)
}
private fun resolveValuesBefore(map: Value): Map<Int, TraceElement> {
val (keys, objects) = InterpreterUtil.extractMap(map)
val result: MutableList<TraceElement> = mutableListOf()
for (i in 0.until(keys.length())) {
val time = keys.getValue(i)
val value = objects.getValue(i)
if (time !is IntegerValue) throw UnexpectedValueTypeException("time should be represented by integer value")
result.add(TraceElementImpl(time.value(), value))
} }
return InterpreterUtil.createIndexByTime(result) private fun resolveValuesBefore(map: Value): Map<Int, TraceElement> {
} val (keys, objects) = InterpreterUtil.extractMap(map)
val result: MutableList<TraceElement> = mutableListOf()
for (i in 0.until(keys.length())) {
val time = keys.getValue(i)
val value = objects.getValue(i)
if (time !is IntegerValue) throw UnexpectedValueTypeException("time should be represented by integer value")
result.add(TraceElementImpl(time.value(), value))
}
private fun resolveValuesAfter(before: Map<Int, TraceElement>, filteringMap: Value): Map<Int, TraceElement> { return InterpreterUtil.createIndexByTime(result)
val predicateValues = extractPredicateValues(filteringMap)
val result = linkedMapOf<Int, TraceElement>()
for ((beforeTime, element) in before) {
val predicateValue = predicateValues[beforeTime]
if (predicateValue == predicateValueToAccept) {
result[beforeTime + 1] = TraceElementImpl(beforeTime + 1, element.value)
}
} }
return result private fun resolveValuesAfter(before: Map<Int, TraceElement>, filteringMap: Value): Map<Int, TraceElement> {
} val predicateValues = extractPredicateValues(filteringMap)
val result = linkedMapOf<Int, TraceElement>()
for ((beforeTime, element) in before) {
val predicateValue = predicateValues[beforeTime]
if (predicateValue == predicateValueToAccept) {
result[beforeTime + 1] = TraceElementImpl(beforeTime + 1, element.value)
}
}
private fun extractPredicateValues(filteringMap: Value): Map<Int, Boolean> { return result
val (keys, values) = InterpreterUtil.extractMap(filteringMap)
val result = mutableMapOf<Int, Boolean>()
for (i in 0.until(keys.length())) {
val time = keys.getValue(i)
val value = values.getValue(i)
if (time !is IntegerValue) throw UnexpectedValueTypeException("time should be represented by integer value")
if (value !is BooleanValue) throw UnexpectedValueTypeException("predicate value should be represented by boolean value")
result[time.value()] = value.value()
} }
return result private fun extractPredicateValues(filteringMap: Value): Map<Int, Boolean> {
} val (keys, values) = InterpreterUtil.extractMap(filteringMap)
val result = mutableMapOf<Int, Boolean>()
for (i in 0.until(keys.length())) {
val time = keys.getValue(i)
val value = values.getValue(i)
if (time !is IntegerValue) throw UnexpectedValueTypeException("time should be represented by integer value")
if (value !is BooleanValue) throw UnexpectedValueTypeException("predicate value should be represented by boolean value")
result[time.value()] = value.value()
}
return result
}
} }
@@ -11,23 +11,23 @@ import com.sun.jdi.Value
*/ */
object InterpreterUtil { object InterpreterUtil {
fun extractMap(value: Value): MapRepresentation { fun extractMap(value: Value): MapRepresentation {
if (value !is ArrayReference || value.length() != 2) { if (value !is ArrayReference || value.length() != 2) {
throw UnexpectedValueException("Map should be represented by array with two nested arrays: keys and values") throw UnexpectedValueException("Map should be represented by array with two nested arrays: keys and values")
}
val keys = value.getValue(0)
val values = value.getValue(1)
if (keys !is ArrayReference || values !is ArrayReference || keys.length() != values.length()) {
throw UnexpectedValueException("Keys and values should be arrays with equal counts of elements")
}
return MapRepresentation(keys, values)
} }
val keys = value.getValue(0) fun createIndexByTime(elements: List<TraceElement>): Map<Int, TraceElement> =
val values = value.getValue(1) elements.associate { elem -> elem.time to elem }
if (keys !is ArrayReference || values !is ArrayReference || keys.length() != values.length()) { data class MapRepresentation(val keys: ArrayReference, val values: ArrayReference)
throw UnexpectedValueException("Keys and values should be arrays with equal counts of elements")
}
return MapRepresentation(keys, values)
}
fun createIndexByTime(elements: List<TraceElement>): Map<Int, TraceElement> =
elements.associate { elem -> elem.time to elem }
data class MapRepresentation(val keys: ArrayReference, val values: ArrayReference)
} }
@@ -8,17 +8,18 @@ import com.intellij.debugger.streams.wrapper.StreamCall
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class ValuesOrder(private val call: StreamCall, class ValuesOrder(
private val before: Map<Int, TraceElement>, private val call: StreamCall,
private val after: Map<Int, TraceElement>) private val before: Map<Int, TraceElement>,
: TraceInfo { private val after: Map<Int, TraceElement>
override fun getValuesOrderBefore(): Map<Int, TraceElement> = before ) : TraceInfo {
override fun getValuesOrderBefore(): Map<Int, TraceElement> = before
override fun getCall(): StreamCall = call override fun getCall(): StreamCall = call
override fun getValuesOrderAfter(): Map<Int, TraceElement> = after override fun getValuesOrderAfter(): Map<Int, TraceElement> = after
override fun getDirectTrace(): MutableMap<TraceElement, MutableList<TraceElement>>? = null override fun getDirectTrace(): MutableMap<TraceElement, MutableList<TraceElement>>? = null
override fun getReverseTrace(): MutableMap<TraceElement, MutableList<TraceElement>>? = null override fun getReverseTrace(): MutableMap<TraceElement, MutableList<TraceElement>>? = null
} }
@@ -29,85 +29,93 @@ import java.util.*
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
abstract class KotlinPsiChainBuilderTestCase(private val relativePath: String) : StreamChainBuilderTestCase() { abstract class KotlinPsiChainBuilderTestCase(private val relativePath: String) : StreamChainBuilderTestCase() {
override fun getTestDataPath(): String = override fun getTestDataPath(): String =
Paths.get(File("").absolutePath, "idea/testData/debugger/sequence/psi/$relativeTestPath/").toString() Paths.get(File("").absolutePath, "idea/testData/debugger/sequence/psi/$relativeTestPath/").toString()
override fun getFileExtension(): String = ".kt"
abstract val kotlinChainBuilder: StreamChainBuilder
override fun getChainBuilder(): StreamChainBuilder = kotlinChainBuilder
private val stdLibName = "kotlin-stdlib"
protected abstract fun doTest() override fun getFileExtension(): String = ".kt"
abstract val kotlinChainBuilder: StreamChainBuilder
override fun getChainBuilder(): StreamChainBuilder = kotlinChainBuilder
private val stdLibName = "kotlin-stdlib"
override fun tearDown() { protected abstract fun doTest()
doKotlinTearDown(LightPlatformTestCase.getProject(), { super.tearDown() })
}
override final fun getRelativeTestPath(): String = relativePath override fun tearDown() {
doKotlinTearDown(LightPlatformTestCase.getProject(), { super.tearDown() })
override fun setUp() {
super.setUp()
ApplicationManager.getApplication().runWriteAction {
if (ProjectLibraryTable.getInstance(LightPlatformTestCase.getProject()).getLibraryByName(stdLibName) == null) {
val stdLibPath = ForTestCompileRuntime.runtimeJarForTests()
PsiTestUtil.addLibrary(testRootDisposable, LightPlatformTestCase.getModule(), stdLibName, stdLibPath.parent, stdLibPath.name)
}
}
LibraryModificationTracker.getInstance(LightPlatformTestCase.getProject()).incModificationCount()
}
override fun getProjectJDK(): Sdk {
return PluginTestCaseBase.mockJdk9()
}
private fun doKotlinTearDown(project: Project, runnable: () -> Unit) {
unInvalidateBuiltinsAndStdLib(project) {
runnable()
}
}
private fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: () -> Unit) {
val stdLibViewProviders = HashSet<KotlinDecompiledFileViewProvider>()
val vFileToViewProviderMap = ((PsiManager.getInstance(project) as PsiManagerEx).fileManager as FileManagerImpl).vFileToViewProviderMap
for ((file, viewProvider) in vFileToViewProviderMap) {
if (file.isStdLibFile && viewProvider is KotlinDecompiledFileViewProvider) {
stdLibViewProviders.add(viewProvider)
}
} }
runnable() override final fun getRelativeTestPath(): String = relativePath
// Base tearDown() invalidates builtins and std-lib files. Restore them with brute force. override fun setUp() {
fun unInvalidateFile(file: PsiFileImpl) { super.setUp()
val field = PsiFileImpl::class.java.getDeclaredField("myInvalidated")!! ApplicationManager.getApplication().runWriteAction {
field.isAccessible = true if (ProjectLibraryTable.getInstance(LightPlatformTestCase.getProject()).getLibraryByName(stdLibName) == null) {
field.set(file, false) val stdLibPath = ForTestCompileRuntime.runtimeJarForTests()
PsiTestUtil.addLibrary(
testRootDisposable,
LightPlatformTestCase.getModule(),
stdLibName,
stdLibPath.parent,
stdLibPath.name
)
}
}
LibraryModificationTracker.getInstance(LightPlatformTestCase.getProject()).incModificationCount()
} }
stdLibViewProviders.forEach {
it.allFiles.forEach { unInvalidateFile(it as KtDecompiledFile) }
vFileToViewProviderMap[it.virtualFile] = it
}
}
private val VirtualFile.isStdLibFile: Boolean get() = presentableUrl.contains("kotlin-runtime.jar") override fun getProjectJDK(): Sdk {
return PluginTestCaseBase.mockJdk9()
abstract class Positive(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
override fun doTest() {
val chains = buildChains()
checkChains(chains)
} }
protected fun checkChains(chains: MutableList<StreamChain>) { private fun doKotlinTearDown(project: Project, runnable: () -> Unit) {
TestCase.assertFalse(chains.isEmpty()) unInvalidateBuiltinsAndStdLib(project) {
runnable()
}
} }
}
abstract class Negative(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) { private fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: () -> Unit) {
override fun doTest() { val stdLibViewProviders = HashSet<KotlinDecompiledFileViewProvider>()
val elementAtCaret = configureAndGetElementAtCaret() val vFileToViewProviderMap =
TestCase.assertFalse(chainBuilder.isChainExists(elementAtCaret)) ((PsiManager.getInstance(project) as PsiManagerEx).fileManager as FileManagerImpl).vFileToViewProviderMap
TestCase.assertTrue(chainBuilder.build(elementAtCaret).isEmpty()) for ((file, viewProvider) in vFileToViewProviderMap) {
if (file.isStdLibFile && viewProvider is KotlinDecompiledFileViewProvider) {
stdLibViewProviders.add(viewProvider)
}
}
runnable()
// Base tearDown() invalidates builtins and std-lib files. Restore them with brute force.
fun unInvalidateFile(file: PsiFileImpl) {
val field = PsiFileImpl::class.java.getDeclaredField("myInvalidated")!!
field.isAccessible = true
field.set(file, false)
}
stdLibViewProviders.forEach {
it.allFiles.forEach { unInvalidateFile(it as KtDecompiledFile) }
vFileToViewProviderMap[it.virtualFile] = it
}
}
private val VirtualFile.isStdLibFile: Boolean get() = presentableUrl.contains("kotlin-runtime.jar")
abstract class Positive(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
override fun doTest() {
val chains = buildChains()
checkChains(chains)
}
protected fun checkChains(chains: MutableList<StreamChain>) {
TestCase.assertFalse(chains.isEmpty())
}
}
abstract class Negative(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
override fun doTest() {
val elementAtCaret = configureAndGetElementAtCaret()
TestCase.assertFalse(chainBuilder.isChainExists(elementAtCaret))
TestCase.assertTrue(chainBuilder.build(elementAtCaret).isEmpty())
}
} }
}
} }
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollect
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
@Suppress("unused")
abstract class AbstractCollectionTraceTestCase : KotlinTraceTestCase() { abstract class AbstractCollectionTraceTestCase : KotlinTraceTestCase() {
override val librarySupportProvider: LibrarySupportProvider = KotlinCollectionSupportProvider() override val librarySupportProvider: LibrarySupportProvider = KotlinCollectionSupportProvider()
} }
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibraryS
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
abstract class AbstractJavaStreamTraceTestCase: KotlinTraceTestCase() { @Suppress("unused")
abstract class AbstractJavaStreamTraceTestCase : KotlinTraceTestCase() {
override val librarySupportProvider: LibrarySupportProvider = JavaStandardLibrarySupportProvider() override val librarySupportProvider: LibrarySupportProvider = JavaStandardLibrarySupportProvider()
} }
@@ -15,7 +15,9 @@ import org.junit.runner.RunWith;
import java.io.File; import java.io.File;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ /**
* This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY
*/
@SuppressWarnings("all") @SuppressWarnings("all")
@TestMetadata("idea/testData/debugger/tinyApp/src/streams/sequence") @TestMetadata("idea/testData/debugger/tinyApp/src/streams/sequence")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -26,7 +28,8 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInSequence() throws Exception { public void testAllFilesPresentInSequence() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true, "terminal"); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true, "terminal");
} }
@TestMetadata("idea/testData/debugger/tinyApp/src/streams/sequence/append") @TestMetadata("idea/testData/debugger/tinyApp/src/streams/sequence/append")
@@ -38,7 +41,9 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInAppend() throws Exception { public void testAllFilesPresentInAppend() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/append"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(),
new File("idea/testData/debugger/tinyApp/src/streams/sequence/append"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("PlusArray.kt") @TestMetadata("PlusArray.kt")
@@ -71,7 +76,9 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInDistinct() throws Exception { public void testAllFilesPresentInDistinct() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/distinct"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(),
new File("idea/testData/debugger/tinyApp/src/streams/sequence/distinct"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("Distinct.kt") @TestMetadata("Distinct.kt")
@@ -119,7 +126,9 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInFilter() throws Exception { public void testAllFilesPresentInFilter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/filter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(),
new File("idea/testData/debugger/tinyApp/src/streams/sequence/filter"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("Drop.kt") @TestMetadata("Drop.kt")
@@ -182,7 +191,9 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInFlatMap() throws Exception { public void testAllFilesPresentInFlatMap() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/flatMap"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(),
new File("idea/testData/debugger/tinyApp/src/streams/sequence/flatMap"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("FlatMap.kt") @TestMetadata("FlatMap.kt")
@@ -205,7 +216,9 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInMap() throws Exception { public void testAllFilesPresentInMap() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/map"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils
.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/map"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("Map.kt") @TestMetadata("Map.kt")
@@ -238,7 +251,9 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInMisc() throws Exception { public void testAllFilesPresentInMisc() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/misc"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils
.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/misc"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("AsSequence.kt") @TestMetadata("AsSequence.kt")
@@ -326,7 +341,9 @@ public class SequenceTraceTestCaseGenerated extends AbstractSequenceTraceTestCas
} }
public void testAllFilesPresentInSort() throws Exception { public void testAllFilesPresentInSort() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/sort"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils
.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/streams/sequence/sort"),
Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("Sorted.kt") @TestMetadata("Sorted.kt")
@@ -1,42 +1,44 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi package org.jetbrains.kotlin.idea.debugger.sequence.psi
import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase
import com.intellij.debugger.streams.trace.impl.handler.type.GenericType import com.intellij.debugger.streams.trace.impl.handler.type.GenericType
import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
abstract class TypedChainTestCase(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) { abstract class TypedChainTestCase(relativePath: String) : KotlinPsiChainBuilderTestCase(relativePath) {
protected fun doTest(producerAfterType: GenericType, protected fun doTest(
vararg intermediateAfterTypes: GenericType) { producerAfterType: GenericType,
val elementAtCaret = configureAndGetElementAtCaret() vararg intermediateAfterTypes: GenericType
assertNotNull(elementAtCaret) ) {
val chains = chainBuilder.build(elementAtCaret) val elementAtCaret = configureAndGetElementAtCaret()
assertFalse(chains.isEmpty()) assertNotNull(elementAtCaret)
val chain = chains[0] val chains = chainBuilder.build(elementAtCaret)
val intermediateCalls = chain.intermediateCalls assertFalse(chains.isEmpty())
assertEquals(intermediateAfterTypes.size, intermediateCalls.size) val chain = chains[0]
assertEquals(producerAfterType, chain.qualifierExpression.typeAfter) val intermediateCalls = chain.intermediateCalls
assertEquals(intermediateAfterTypes.size, intermediateCalls.size)
assertEquals(producerAfterType, chain.qualifierExpression.typeAfter)
if (intermediateAfterTypes.isNotEmpty()) { if (intermediateAfterTypes.isNotEmpty()) {
assertEquals(producerAfterType, intermediateCalls[0].typeBefore) assertEquals(producerAfterType, intermediateCalls[0].typeBefore)
for (i in 0 until intermediateAfterTypes.size - 1) { for (i in 0 until intermediateAfterTypes.size - 1) {
assertEquals(intermediateAfterTypes[i], intermediateCalls[i].typeAfter) assertEquals(intermediateAfterTypes[i], intermediateCalls[i].typeAfter)
assertEquals(intermediateAfterTypes[i], intermediateCalls[i + 1].typeBefore) assertEquals(intermediateAfterTypes[i], intermediateCalls[i + 1].typeBefore)
} }
val lastAfterType = intermediateAfterTypes[intermediateAfterTypes.size - 1] val lastAfterType = intermediateAfterTypes[intermediateAfterTypes.size - 1]
assertEquals(lastAfterType, chain.terminationCall.typeBefore) assertEquals(lastAfterType, chain.terminationCall.typeBefore)
val lastCall = intermediateCalls[intermediateCalls.size - 1] val lastCall = intermediateCalls[intermediateCalls.size - 1]
assertEquals(lastAfterType, lastCall.typeAfter) assertEquals(lastAfterType, lastCall.typeAfter)
} else { } else {
assertEquals(producerAfterType, chain.terminationCall.typeBefore) assertEquals(producerAfterType, chain.terminationCall.typeBefore)
}
} }
}
override fun doTest() { override fun doTest() {
fail("Use doTest(producerAfterType, vararg intermediateAfterTypes)") fail("Use doTest(producerAfterType, vararg intermediateAfterTypes)")
} }
} }
@@ -1,18 +1,18 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.collection package org.jetbrains.kotlin.idea.debugger.sequence.psi.collection
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollectionSupportProvider import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollectionSupportProvider
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class PositiveCollectionBuildTest : KotlinPsiChainBuilderTestCase.Positive("collection/positive") { class PositiveCollectionBuildTest : KotlinPsiChainBuilderTestCase.Positive("collection/positive") {
override val kotlinChainBuilder: StreamChainBuilder = KotlinCollectionSupportProvider().chainBuilder override val kotlinChainBuilder: StreamChainBuilder = KotlinCollectionSupportProvider().chainBuilder
fun testIntermediateIsLastCall() = doTest() fun testIntermediateIsLastCall() = doTest()
fun testOnlyFilterCall() = doTest() fun testOnlyFilterCall() = doTest()
fun testTerminationCallUsed() = doTest() fun testTerminationCallUsed() = doTest()
fun testOnlyTerminationCallUsed() = doTest() fun testOnlyTerminationCallUsed() = doTest()
} }
@@ -1,53 +1,53 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.collection package org.jetbrains.kotlin.idea.debugger.sequence.psi.collection
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollectionSupportProvider import org.jetbrains.kotlin.idea.debugger.sequence.lib.collections.KotlinCollectionSupportProvider
import org.jetbrains.kotlin.idea.debugger.sequence.psi.TypedChainTestCase import org.jetbrains.kotlin.idea.debugger.sequence.psi.TypedChainTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class TypedCollectionChainTest : TypedChainTestCase("collection/positive/types") { class TypedCollectionChainTest : TypedChainTestCase("collection/positive/types") {
override val kotlinChainBuilder: StreamChainBuilder = KotlinCollectionSupportProvider().chainBuilder override val kotlinChainBuilder: StreamChainBuilder = KotlinCollectionSupportProvider().chainBuilder
fun testAny() = doTest(KotlinTypes.ANY) fun testAny() = doTest(KotlinTypes.ANY)
fun testNullableAny() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableAny() = doTest(KotlinTypes.NULLABLE_ANY)
fun testBoolean() = doTest(KotlinTypes.BOOLEAN) fun testBoolean() = doTest(KotlinTypes.BOOLEAN)
fun testNullableBoolean() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableBoolean() = doTest(KotlinTypes.NULLABLE_ANY)
fun testByte() = doTest(KotlinTypes.BYTE) fun testByte() = doTest(KotlinTypes.BYTE)
fun testNullableByte() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableByte() = doTest(KotlinTypes.NULLABLE_ANY)
fun testShort() = doTest(KotlinTypes.SHORT) fun testShort() = doTest(KotlinTypes.SHORT)
fun testNullableShort() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableShort() = doTest(KotlinTypes.NULLABLE_ANY)
fun testInt() = doTest(KotlinTypes.INT) fun testInt() = doTest(KotlinTypes.INT)
fun testNullableInt() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableInt() = doTest(KotlinTypes.NULLABLE_ANY)
fun testLong() = doTest(KotlinTypes.LONG) fun testLong() = doTest(KotlinTypes.LONG)
fun testNullableLong() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableLong() = doTest(KotlinTypes.NULLABLE_ANY)
fun testFloat() = doTest(KotlinTypes.FLOAT) fun testFloat() = doTest(KotlinTypes.FLOAT)
fun testNullableFloat() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableFloat() = doTest(KotlinTypes.NULLABLE_ANY)
fun testDouble() = doTest(KotlinTypes.DOUBLE) fun testDouble() = doTest(KotlinTypes.DOUBLE)
fun testNullableDouble() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableDouble() = doTest(KotlinTypes.NULLABLE_ANY)
fun testChar() = doTest(KotlinTypes.CHAR) fun testChar() = doTest(KotlinTypes.CHAR)
fun testNullableChar() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableChar() = doTest(KotlinTypes.NULLABLE_ANY)
fun testNullableAnyToPrimitive() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.BOOLEAN) fun testNullableAnyToPrimitive() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.BOOLEAN)
fun testPrimitiveToNullableAny() = doTest(KotlinTypes.INT, KotlinTypes.NULLABLE_ANY) fun testPrimitiveToNullableAny() = doTest(KotlinTypes.INT, KotlinTypes.NULLABLE_ANY)
fun testAnyToPrimitive() = doTest(KotlinTypes.ANY, KotlinTypes.INT) fun testAnyToPrimitive() = doTest(KotlinTypes.ANY, KotlinTypes.INT)
fun testPrimitiveToAny() = doTest(KotlinTypes.INT, KotlinTypes.ANY) fun testPrimitiveToAny() = doTest(KotlinTypes.INT, KotlinTypes.ANY)
fun testNullableToNotNull() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.INT) fun testNullableToNotNull() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.INT)
fun testNotNullToNullable() = doTest(KotlinTypes.DOUBLE, KotlinTypes.NULLABLE_ANY) fun testNotNullToNullable() = doTest(KotlinTypes.DOUBLE, KotlinTypes.NULLABLE_ANY)
fun testFewTransitions1() = doTest(KotlinTypes.BYTE, KotlinTypes.ANY, KotlinTypes.NULLABLE_ANY, KotlinTypes.INT) fun testFewTransitions1() = doTest(KotlinTypes.BYTE, KotlinTypes.ANY, KotlinTypes.NULLABLE_ANY, KotlinTypes.INT)
fun testFewTransitions2() = doTest(KotlinTypes.CHAR, KotlinTypes.BOOLEAN, KotlinTypes.DOUBLE, KotlinTypes.ANY) fun testFewTransitions2() = doTest(KotlinTypes.CHAR, KotlinTypes.BOOLEAN, KotlinTypes.DOUBLE, KotlinTypes.ANY)
} }
@@ -5,29 +5,29 @@ package org.jetbrains.kotlin.idea.debugger.sequence.psi.java
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class AmbiguousChainsTest : PositiveJavaStreamTest("ambiguous") { class AmbiguousChainsTest : PositiveJavaStreamTest("ambiguous") {
fun testSimpleExpression() = doTest(2) fun testSimpleExpression() = doTest(2)
fun testNestedExpression() = doTest(3) fun testNestedExpression() = doTest(3)
fun testSimpleFunctionParameter() = doTest(2) fun testSimpleFunctionParameter() = doTest(2)
fun testNestedFunctionParameters() = doTest(3) fun testNestedFunctionParameters() = doTest(3)
fun testNestedFunctionParametersReversed() = doTest(3) fun testNestedFunctionParametersReversed() = doTest(3)
fun testStreamProducerParameter() = doTest(2) fun testStreamProducerParameter() = doTest(2)
fun testStreamIntermediateCallParameter() = doTest(2) fun testStreamIntermediateCallParameter() = doTest(2)
fun testStreamTerminatorParameter() = doTest(2) fun testStreamTerminatorParameter() = doTest(2)
fun testStreamAllPositions() = doTest(4) fun testStreamAllPositions() = doTest(4)
fun testNestedStreamProducerParameter() = doTest(3) fun testNestedStreamProducerParameter() = doTest(3)
fun testNestedStreamIntermediateCallParameter() = doTest(3) fun testNestedStreamIntermediateCallParameter() = doTest(3)
fun testNestedStreamTerminatorCallParameter() = doTest(3) fun testNestedStreamTerminatorCallParameter() = doTest(3)
fun testNestedCallInLambda() = doTest(2) fun testNestedCallInLambda() = doTest(2)
fun testNestedCallInAnonymous() = doTest(2) fun testNestedCallInAnonymous() = doTest(2)
fun testLinkedChain() = doTest(3) fun testLinkedChain() = doTest(3)
private fun doTest(chainsCount: Int) { private fun doTest(chainsCount: Int) {
val chains = buildChains() val chains = buildChains()
assertEquals(chainsCount, chains.size) assertEquals(chainsCount, chains.size)
} }
} }
@@ -5,37 +5,37 @@ package org.jetbrains.kotlin.idea.debugger.sequence.psi.java
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class LocationPositiveChainTest : PositiveJavaStreamTest("location") { class LocationPositiveChainTest : PositiveJavaStreamTest("location") {
fun testAnonymousBody() = doTest() fun testAnonymousBody() = doTest()
fun testAssignExpression() = doTest() fun testAssignExpression() = doTest()
fun testFirstParameterOfFunction() = doTest() fun testFirstParameterOfFunction() = doTest()
fun testLambdaBody() = doTest() fun testLambdaBody() = doTest()
fun testParameterInAssignExpression() = doTest() fun testParameterInAssignExpression() = doTest()
fun testParameterInReturnExpression() = doTest() fun testParameterInReturnExpression() = doTest()
fun testReturnExpression() = doTest() fun testReturnExpression() = doTest()
fun testSecondParameterOfFunction() = doTest() fun testSecondParameterOfFunction() = doTest()
fun testSingleExpression() = doTest() fun testSingleExpression() = doTest()
fun testBeforeStatement() = doTest() fun testBeforeStatement() = doTest()
fun testBetweenChainCallsBeforeDot() = doTest() fun testBetweenChainCallsBeforeDot() = doTest()
fun testBetweenChainCallsAfterDot() = doTest() fun testBetweenChainCallsAfterDot() = doTest()
fun testInEmptyParameterList() = doTest() fun testInEmptyParameterList() = doTest()
fun testBetweenParametersBeforeComma() = doTest() fun testBetweenParametersBeforeComma() = doTest()
fun testBetweenParametersAfterComma() = doTest() fun testBetweenParametersAfterComma() = doTest()
fun testInAnyLambda() = doTest() fun testInAnyLambda() = doTest()
fun testInAnyAnonymous() = doTest() fun testInAnyAnonymous() = doTest()
fun testInString() = doTest() fun testInString() = doTest()
fun testInVariableName() = doTest() fun testInVariableName() = doTest()
fun testInMethodReference() = doTest() fun testInMethodReference() = doTest()
fun testAsMethodExpression() = doTest() fun testAsMethodExpression() = doTest()
} }
@@ -1,35 +1,35 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.java package org.jetbrains.kotlin.idea.debugger.sequence.psi.java
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class NegativeJavaStreamTest : KotlinPsiChainBuilderTestCase.Negative("streams/negative") { class NegativeJavaStreamTest : KotlinPsiChainBuilderTestCase.Negative("streams/negative") {
override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder
fun testFakeStream() = doTest() fun testFakeStream() = doTest()
fun testWithoutTerminalOperation() = doTest() fun testWithoutTerminalOperation() = doTest()
fun testNoBreakpoint() = doTest() fun testNoBreakpoint() = doTest()
fun testBreakpointOnMethod() = doTest() fun testBreakpointOnMethod() = doTest()
fun testBreakpointOnIfCondition() = doTest() fun testBreakpointOnIfCondition() = doTest()
fun testBreakpointOnNewScope() = doTest() fun testBreakpointOnNewScope() = doTest()
fun testBreakpointOnElseBranch() = doTest() fun testBreakpointOnElseBranch() = doTest()
fun testInLambda() = doTest() fun testInLambda() = doTest()
fun testInLambdaWithBody() = doTest() fun testInLambdaWithBody() = doTest()
fun testInAnonymous() = doTest() fun testInAnonymous() = doTest()
fun testAfterStatement() = doTest() fun testAfterStatement() = doTest()
fun testInPreviousStatement() = doTest() fun testInPreviousStatement() = doTest()
fun testInNextStatement() = doTest() fun testInNextStatement() = doTest()
fun testIdea173415() = doTest() fun testIdea173415() = doTest()
} }
@@ -1,13 +1,13 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.java package org.jetbrains.kotlin.idea.debugger.sequence.psi.java
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase import org.jetbrains.kotlin.idea.debugger.sequence.KotlinPsiChainBuilderTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
abstract class PositiveJavaStreamTest(subDirectory: String) : KotlinPsiChainBuilderTestCase.Positive("streams/positive/$subDirectory") { abstract class PositiveJavaStreamTest(subDirectory: String) : KotlinPsiChainBuilderTestCase.Positive("streams/positive/$subDirectory") {
override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder
} }
@@ -1,28 +1,28 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.java package org.jetbrains.kotlin.idea.debugger.sequence.psi.java
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider import org.jetbrains.kotlin.idea.debugger.sequence.lib.java.JavaStandardLibrarySupportProvider
import org.jetbrains.kotlin.idea.debugger.sequence.psi.TypedChainTestCase import org.jetbrains.kotlin.idea.debugger.sequence.psi.TypedChainTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.DOUBLE import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.DOUBLE
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.INT import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.INT
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.LONG import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.LONG
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.NULLABLE_ANY import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes.NULLABLE_ANY
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class TypedJavaChainTest : TypedChainTestCase("streams/positive/types") { class TypedJavaChainTest : TypedChainTestCase("streams/positive/types") {
override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder override val kotlinChainBuilder: StreamChainBuilder = JavaStandardLibrarySupportProvider().chainBuilder
fun testOneCall() = doTest(NULLABLE_ANY) fun testOneCall() = doTest(NULLABLE_ANY)
fun testMapToSame() = doTest(NULLABLE_ANY, NULLABLE_ANY) fun testMapToSame() = doTest(NULLABLE_ANY, NULLABLE_ANY)
fun testPrimitiveOneCall() = doTest(INT) fun testPrimitiveOneCall() = doTest(INT)
fun testPrimitiveMapToSame() = doTest(LONG, LONG) fun testPrimitiveMapToSame() = doTest(LONG, LONG)
fun testMapToPrimitive() = doTest(NULLABLE_ANY, DOUBLE) fun testMapToPrimitive() = doTest(NULLABLE_ANY, DOUBLE)
fun testMapToObj() = doTest(DOUBLE, NULLABLE_ANY) fun testMapToObj() = doTest(DOUBLE, NULLABLE_ANY)
fun testMapPrimitiveToPrimitive() = doTest(LONG, INT) fun testMapPrimitiveToPrimitive() = doTest(LONG, INT)
fun testFewTransitions() = doTest(NULLABLE_ANY, INT, NULLABLE_ANY, LONG, DOUBLE) fun testFewTransitions() = doTest(NULLABLE_ANY, INT, NULLABLE_ANY, LONG, DOUBLE)
} }
@@ -1,54 +1,54 @@
// 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 org.jetbrains.kotlin.idea.debugger.sequence.psi.sequence package org.jetbrains.kotlin.idea.debugger.sequence.psi.sequence
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
import org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence.KotlinSequenceSupportProvider import org.jetbrains.kotlin.idea.debugger.sequence.lib.sequence.KotlinSequenceSupportProvider
import org.jetbrains.kotlin.idea.debugger.sequence.psi.TypedChainTestCase import org.jetbrains.kotlin.idea.debugger.sequence.psi.TypedChainTestCase
import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes import org.jetbrains.kotlin.idea.debugger.sequence.trace.dsl.KotlinTypes
import com.intellij.debugger.streams.wrapper.StreamChainBuilder
/** /**
* @author Vitaliy.Bibaev * @author Vitaliy.Bibaev
*/ */
class TypedSequenceChain : TypedChainTestCase("sequence/positive/types") { class TypedSequenceChain : TypedChainTestCase("sequence/positive/types") {
override val kotlinChainBuilder: StreamChainBuilder = KotlinSequenceSupportProvider().chainBuilder override val kotlinChainBuilder: StreamChainBuilder = KotlinSequenceSupportProvider().chainBuilder
fun testAny() = doTest(KotlinTypes.ANY) fun testAny() = doTest(KotlinTypes.ANY)
fun testNullableAny() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableAny() = doTest(KotlinTypes.NULLABLE_ANY)
fun testBoolean() = doTest(KotlinTypes.BOOLEAN) fun testBoolean() = doTest(KotlinTypes.BOOLEAN)
fun testNullableBoolean() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableBoolean() = doTest(KotlinTypes.NULLABLE_ANY)
fun testByte() = doTest(KotlinTypes.BYTE) fun testByte() = doTest(KotlinTypes.BYTE)
fun testNullableByte() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableByte() = doTest(KotlinTypes.NULLABLE_ANY)
fun testShort() = doTest(KotlinTypes.SHORT) fun testShort() = doTest(KotlinTypes.SHORT)
fun testNullableShort() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableShort() = doTest(KotlinTypes.NULLABLE_ANY)
fun testInt() = doTest(KotlinTypes.INT) fun testInt() = doTest(KotlinTypes.INT)
fun testNullableInt() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableInt() = doTest(KotlinTypes.NULLABLE_ANY)
fun testLong() = doTest(KotlinTypes.LONG) fun testLong() = doTest(KotlinTypes.LONG)
fun testNullableLong() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableLong() = doTest(KotlinTypes.NULLABLE_ANY)
fun testFloat() = doTest(KotlinTypes.FLOAT) fun testFloat() = doTest(KotlinTypes.FLOAT)
fun testNullableFloat() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableFloat() = doTest(KotlinTypes.NULLABLE_ANY)
fun testDouble() = doTest(KotlinTypes.DOUBLE) fun testDouble() = doTest(KotlinTypes.DOUBLE)
fun testNullableDouble() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableDouble() = doTest(KotlinTypes.NULLABLE_ANY)
fun testChar() = doTest(KotlinTypes.CHAR) fun testChar() = doTest(KotlinTypes.CHAR)
fun testNullableChar() = doTest(KotlinTypes.NULLABLE_ANY) fun testNullableChar() = doTest(KotlinTypes.NULLABLE_ANY)
fun testNullableAnyToPrimitive() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.BOOLEAN) fun testNullableAnyToPrimitive() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.BOOLEAN)
fun testPrimitiveToNullableAny() = doTest(KotlinTypes.INT, KotlinTypes.NULLABLE_ANY) fun testPrimitiveToNullableAny() = doTest(KotlinTypes.INT, KotlinTypes.NULLABLE_ANY)
fun testAnyToPrimitive() = doTest(KotlinTypes.ANY, KotlinTypes.INT) fun testAnyToPrimitive() = doTest(KotlinTypes.ANY, KotlinTypes.INT)
fun testPrimitiveToAny() = doTest(KotlinTypes.INT, KotlinTypes.ANY) fun testPrimitiveToAny() = doTest(KotlinTypes.INT, KotlinTypes.ANY)
fun testNullableToNotNull() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.INT) fun testNullableToNotNull() = doTest(KotlinTypes.NULLABLE_ANY, KotlinTypes.INT)
fun testNotNullToNullable() = doTest(KotlinTypes.DOUBLE, KotlinTypes.NULLABLE_ANY) fun testNotNullToNullable() = doTest(KotlinTypes.DOUBLE, KotlinTypes.NULLABLE_ANY)
fun testFewTransitions1() = doTest(KotlinTypes.BYTE, KotlinTypes.ANY, KotlinTypes.NULLABLE_ANY, KotlinTypes.INT) fun testFewTransitions1() = doTest(KotlinTypes.BYTE, KotlinTypes.ANY, KotlinTypes.NULLABLE_ANY, KotlinTypes.INT)
fun testFewTransitions2() = doTest(KotlinTypes.CHAR, KotlinTypes.BOOLEAN, KotlinTypes.DOUBLE, KotlinTypes.ANY) fun testFewTransitions2() = doTest(KotlinTypes.CHAR, KotlinTypes.BOOLEAN, KotlinTypes.DOUBLE, KotlinTypes.ANY)
} }