Debugger: Add breakpoint applicability tests
This commit adds a number of tests that check breakpoint placing behavior, and an inline action that work the same way as tests.
This commit is contained in:
@@ -53,10 +53,7 @@ import org.jetbrains.kotlin.idea.conversion.copy.AbstractLiteralKotlinToKotlinCo
|
|||||||
import org.jetbrains.kotlin.idea.conversion.copy.AbstractLiteralTextToKotlinCopyPasteTest
|
import org.jetbrains.kotlin.idea.conversion.copy.AbstractLiteralTextToKotlinCopyPasteTest
|
||||||
import org.jetbrains.kotlin.idea.conversion.copy.AbstractTextJavaToKotlinCopyPasteConversionTest
|
import org.jetbrains.kotlin.idea.conversion.copy.AbstractTextJavaToKotlinCopyPasteConversionTest
|
||||||
import org.jetbrains.kotlin.idea.coverage.AbstractKotlinCoverageOutputFilesTest
|
import org.jetbrains.kotlin.idea.coverage.AbstractKotlinCoverageOutputFilesTest
|
||||||
import org.jetbrains.kotlin.idea.debugger.AbstractFileRankingTest
|
import org.jetbrains.kotlin.idea.debugger.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.AbstractKotlinSteppingTest
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.AbstractPositionManagerTest
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.AbstractSmartStepIntoTest
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.*
|
import org.jetbrains.kotlin.idea.debugger.evaluate.*
|
||||||
import org.jetbrains.kotlin.idea.debugger.sequence.exec.AbstractSequenceTraceTestCase
|
import org.jetbrains.kotlin.idea.debugger.sequence.exec.AbstractSequenceTraceTestCase
|
||||||
import org.jetbrains.kotlin.idea.decompiler.navigation.AbstractNavigateToDecompiledLibraryTest
|
import org.jetbrains.kotlin.idea.decompiler.navigation.AbstractNavigateToDecompiledLibraryTest
|
||||||
@@ -625,6 +622,10 @@ fun main(args: Array<String>) {
|
|||||||
model("debugger/positionManager", recursive = false, extension = null, testClassName = "MultiFile")
|
model("debugger/positionManager", recursive = false, extension = null, testClassName = "MultiFile")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClass<AbstractBreakpointApplicabilityTest> {
|
||||||
|
model("debugger/breakpointApplicability")
|
||||||
|
}
|
||||||
|
|
||||||
testClass<AbstractKotlinExceptionFilterTest> {
|
testClass<AbstractKotlinExceptionFilterTest> {
|
||||||
model("debugger/exceptionFilter", pattern = """^([^\.]+)$""", recursive = false)
|
model("debugger/exceptionFilter", pattern = """^([^\.]+)$""", recursive = false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,16 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
|
||||||
fun PsiFile.getLineStartOffset(line: Int): Int? {
|
fun PsiFile.getLineStartOffset(line: Int): Int? {
|
||||||
|
return getLineStartOffset(line, skipWhitespace = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PsiFile.getLineStartOffset(line: Int, skipWhitespace: Boolean): Int? {
|
||||||
val doc = viewProvider.document ?: PsiDocumentManager.getInstance(project).getDocument(this)
|
val doc = viewProvider.document ?: PsiDocumentManager.getInstance(project).getDocument(this)
|
||||||
if (doc != null && line >= 0 && line < doc.lineCount) {
|
if (doc != null && line >= 0 && line < doc.lineCount) {
|
||||||
val startOffset = doc.getLineStartOffset(line)
|
val startOffset = doc.getLineStartOffset(line)
|
||||||
val element = findElementAt(startOffset) ?: return startOffset
|
val element = findElementAt(startOffset) ?: return startOffset
|
||||||
|
|
||||||
if (element is PsiWhiteSpace || element is PsiComment) {
|
if (skipWhitespace && (element is PsiWhiteSpace || element is PsiComment)) {
|
||||||
return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java, PsiComment::class.java)?.startOffset ?: startOffset
|
return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java, PsiComment::class.java)?.startOffset ?: startOffset
|
||||||
}
|
}
|
||||||
return startOffset
|
return startOffset
|
||||||
|
|||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger.breakpoints
|
||||||
|
|
||||||
|
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType
|
||||||
|
import com.intellij.openapi.extensions.Extensions
|
||||||
|
import com.intellij.xdebugger.breakpoints.XBreakpointType
|
||||||
|
import com.intellij.xdebugger.breakpoints.XLineBreakpointType
|
||||||
|
import org.jetbrains.debugger.SourceInfo
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class BreakpointChecker {
|
||||||
|
private companion object {
|
||||||
|
private val BREAKPOINT_TYPES = mapOf(
|
||||||
|
KotlinLineBreakpointType::class.java to BreakpointType.Line,
|
||||||
|
KotlinFieldBreakpointType::class.java to BreakpointType.Field,
|
||||||
|
KotlinFunctionBreakpointType::class.java to BreakpointType.Function,
|
||||||
|
JavaLineBreakpointType.LambdaJavaBreakpointVariant::class.java to BreakpointType.Lambda,
|
||||||
|
KotlinLineBreakpointType.LineKotlinBreakpointVariant::class.java to BreakpointType.Line,
|
||||||
|
KotlinLineBreakpointType.KotlinBreakpointVariant::class.java to BreakpointType.All
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class BreakpointType(val prefix: String) {
|
||||||
|
Line("L"),
|
||||||
|
Field("F"),
|
||||||
|
Function("M"), // method
|
||||||
|
Lambda("λ"),
|
||||||
|
All("*") // line & lambda
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("SimplifiableCall")
|
||||||
|
private val breakpointTypes: List<XLineBreakpointType<*>> = run {
|
||||||
|
val extensionPoint = Extensions.getArea(null)
|
||||||
|
.getExtensionPoint<XBreakpointType<*, *>>(XBreakpointType.EXTENSION_POINT_NAME.name)
|
||||||
|
|
||||||
|
extensionPoint.extensions
|
||||||
|
.filterIsInstance<XLineBreakpointType<*>>()
|
||||||
|
.filter { it is KotlinBreakpointType }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun check(file: KtFile, line: Int): EnumSet<BreakpointType> {
|
||||||
|
val actualBreakpointTypes = EnumSet.noneOf(BreakpointType::class.java)
|
||||||
|
|
||||||
|
for (breakpointType in breakpointTypes) {
|
||||||
|
val sign = BREAKPOINT_TYPES[breakpointType.javaClass] ?: continue
|
||||||
|
val isApplicable = breakpointType.canPutAt(file.virtualFile, line, file.project)
|
||||||
|
|
||||||
|
if (breakpointType is KotlinLineBreakpointType) {
|
||||||
|
if (isApplicable) {
|
||||||
|
val variants = breakpointType.computeVariants(file.project, SourceInfo(file.virtualFile, line))
|
||||||
|
if (variants.isNotEmpty()) {
|
||||||
|
actualBreakpointTypes += variants.mapNotNull { BREAKPOINT_TYPES[it.javaClass] }
|
||||||
|
} else {
|
||||||
|
actualBreakpointTypes += sign
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (isApplicable) {
|
||||||
|
actualBreakpointTypes += sign
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return actualBreakpointTypes
|
||||||
|
}
|
||||||
|
}
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger.breakpoints
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.TextAnnotationGutterProvider
|
||||||
|
import com.intellij.openapi.editor.colors.ColorKey
|
||||||
|
import com.intellij.openapi.editor.colors.EditorFontType
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.getLineCount
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.BreakpointChecker.BreakpointType
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import java.awt.Color
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class InspectBreakpointApplicabilityAction : AnAction() {
|
||||||
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
|
val data = e.getData() ?: return
|
||||||
|
|
||||||
|
if (data.editor.gutter.isAnnotationsShown) {
|
||||||
|
data.editor.gutter.closeAllAnnotations()
|
||||||
|
}
|
||||||
|
|
||||||
|
val checker = BreakpointChecker()
|
||||||
|
|
||||||
|
val lineCount = data.file.getLineCount()
|
||||||
|
val breakpoints = (0..lineCount).map { line -> checker.check(data.file, line) }
|
||||||
|
val gutterProvider = BreakpointsGutterProvider(breakpoints)
|
||||||
|
data.editor.gutter.registerTextAnnotation(gutterProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BreakpointsGutterProvider(private val breakpoints: List<EnumSet<BreakpointType>>) : TextAnnotationGutterProvider {
|
||||||
|
override fun getLineText(line: Int, editor: Editor?): String? {
|
||||||
|
val breakpoints = breakpoints.getOrNull(line) ?: return null
|
||||||
|
return breakpoints.map { it.prefix }.distinct().joinToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getToolTip(line: Int, editor: Editor?): String? = null
|
||||||
|
override fun getStyle(line: Int, editor: Editor?) = EditorFontType.PLAIN
|
||||||
|
|
||||||
|
override fun getPopupActions(line: Int, editor: Editor?) = emptyList<AnAction>()
|
||||||
|
override fun getColor(line: Int, editor: Editor?): ColorKey? = null
|
||||||
|
override fun getBgColor(line: Int, editor: Editor?): Color? = null
|
||||||
|
override fun gutterClosed() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(e: AnActionEvent) {
|
||||||
|
e.presentation.isVisible = ApplicationManager.getApplication().isInternal
|
||||||
|
e.presentation.isEnabled = e.getData() != null
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActionData(val editor: Editor, val file: KtFile)
|
||||||
|
|
||||||
|
private fun AnActionEvent.getData(): ActionData? {
|
||||||
|
val editor = getData(CommonDataKeys.EDITOR) ?: return null
|
||||||
|
val file = getData(CommonDataKeys.PSI_FILE) as? KtFile ?: return null
|
||||||
|
return ActionData(editor, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-3
@@ -45,9 +45,11 @@ import org.jetbrains.kotlin.psi.KtParameter
|
|||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
|
|
||||||
class KotlinFieldBreakpointType : JavaBreakpointType<KotlinPropertyBreakpointProperties>, XLineBreakpointType<KotlinPropertyBreakpointProperties>(
|
class KotlinFieldBreakpointType :
|
||||||
"kotlin-field", KotlinBundle.message("debugger.field.watchpoints.tab.title")
|
JavaBreakpointType<KotlinPropertyBreakpointProperties>,
|
||||||
) {
|
XLineBreakpointType<KotlinPropertyBreakpointProperties>("kotlin-field", KotlinBundle.message("debugger.field.watchpoints.tab.title")),
|
||||||
|
KotlinBreakpointType
|
||||||
|
{
|
||||||
override fun createJavaBreakpoint(project: Project, breakpoint: XBreakpoint<KotlinPropertyBreakpointProperties>): Breakpoint<KotlinPropertyBreakpointProperties> {
|
override fun createJavaBreakpoint(project: Project, breakpoint: XBreakpoint<KotlinPropertyBreakpointProperties>): Breakpoint<KotlinPropertyBreakpointProperties> {
|
||||||
return KotlinFieldBreakpoint(project, breakpoint)
|
return KotlinFieldBreakpoint(project, breakpoint)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -28,7 +28,10 @@ import static org.jetbrains.kotlin.idea.debugger.breakpoints.BreakpointTypeUtils
|
|||||||
// This class is copied from com.intellij.debugger.ui.breakpoints.MethodBreakpoint.
|
// This class is copied from com.intellij.debugger.ui.breakpoints.MethodBreakpoint.
|
||||||
// Changed parts are marked with '// MODIFICATION: ' comments.
|
// Changed parts are marked with '// MODIFICATION: ' comments.
|
||||||
// This should be deleted when IDEA opens the method breakpoint API (presumably in 193).
|
// This should be deleted when IDEA opens the method breakpoint API (presumably in 193).
|
||||||
public class KotlinFunctionBreakpointType extends JavaLineBreakpointTypeBase<JavaMethodBreakpointProperties> {
|
public class KotlinFunctionBreakpointType
|
||||||
|
extends JavaLineBreakpointTypeBase<JavaMethodBreakpointProperties>
|
||||||
|
implements KotlinBreakpointType
|
||||||
|
{
|
||||||
// MODIFICATION: Start Kotlin implementation
|
// MODIFICATION: Start Kotlin implementation
|
||||||
public KotlinFunctionBreakpointType() {
|
public KotlinFunctionBreakpointType() {
|
||||||
super("kotlin-function", KotlinBundle.message("debugger.function.breakpoints.tab.title"));
|
super("kotlin-function", KotlinBundle.message("debugger.function.breakpoints.tab.title"));
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static org.jetbrains.kotlin.idea.debugger.breakpoints.BreakpointTypeUtilsKt.isBreakpointApplicable;
|
import static org.jetbrains.kotlin.idea.debugger.breakpoints.BreakpointTypeUtilsKt.isBreakpointApplicable;
|
||||||
|
|
||||||
public class KotlinLineBreakpointType extends JavaLineBreakpointType {
|
public class KotlinLineBreakpointType extends JavaLineBreakpointType implements KotlinBreakpointType {
|
||||||
public KotlinLineBreakpointType() {
|
public KotlinLineBreakpointType() {
|
||||||
super("kotlin-line", KotlinBundle.message("debugger.line.breakpoints.tab.title"));
|
super("kotlin-line", KotlinBundle.message("debugger.line.breakpoints.tab.title"));
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.psi.psiUtil.*
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
interface KotlinBreakpointType
|
||||||
|
|
||||||
class ApplicabilityResult(val isApplicable: Boolean, val shouldStop: Boolean) {
|
class ApplicabilityResult(val isApplicable: Boolean, val shouldStop: Boolean) {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
@@ -74,6 +74,11 @@
|
|||||||
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
||||||
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
<action id="InspectBreakpointApplicability" class="org.jetbrains.kotlin.idea.debugger.breakpoints.InspectBreakpointApplicabilityAction"
|
||||||
|
text="Inspect Breakpoint Applicability" internal="true">
|
||||||
|
<add-to-group group-id="KotlinInternalGroup"/>
|
||||||
|
</action>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
|||||||
@@ -74,6 +74,11 @@
|
|||||||
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
||||||
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
<action id="InspectBreakpointApplicability" class="org.jetbrains.kotlin.idea.debugger.breakpoints.InspectBreakpointApplicabilityAction"
|
||||||
|
text="Inspect Breakpoint Applicability" internal="true">
|
||||||
|
<add-to-group group-id="KotlinInternalGroup"/>
|
||||||
|
</action>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
|||||||
@@ -74,6 +74,11 @@
|
|||||||
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
<reference ref="Kotlin.XDebugger.ToggleKotlinVariableView"/>
|
||||||
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
<add-to-group group-id="XDebugger.Watches.Tree.Toolbar" relative-to-action="XDebugger.SwitchWatchesInVariables" anchor="after"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
|
<action id="InspectBreakpointApplicability" class="org.jetbrains.kotlin.idea.debugger.breakpoints.InspectBreakpointApplicabilityAction"
|
||||||
|
text="Inspect Breakpoint Applicability" internal="true">
|
||||||
|
<add-to-group group-id="KotlinInternalGroup"/>
|
||||||
|
</action>
|
||||||
</actions>
|
</actions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Should stop on primary constructor invocation
|
||||||
|
class Foo1(val a: Int) /// M
|
||||||
|
|
||||||
|
class Foo2( /// M
|
||||||
|
val a: Int, /// F
|
||||||
|
val b: String /// F
|
||||||
|
)
|
||||||
|
|
||||||
|
class Foo3(val a: Int) { /// M
|
||||||
|
constructor(a: String) : this(a.toInt()) /// M
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializers are not currently recognized as functions
|
||||||
|
class Foo4 { /// M
|
||||||
|
init { /// L
|
||||||
|
println() /// L
|
||||||
|
} /// L
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo5 {
|
||||||
|
constructor(a: String) {} /// M
|
||||||
|
constructor(a: Int) {} /// M
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Intf
|
||||||
|
|
||||||
|
annotation class Anno
|
||||||
|
|
||||||
|
enum class Enum1 { /// M
|
||||||
|
FOO
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Enum2(val a: Int) { /// M
|
||||||
|
FOO(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Obj1
|
||||||
|
|
||||||
|
object Obj2 {}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Simple one-liners should have only method breakpoint
|
||||||
|
// Simple = no lambdas on a line
|
||||||
|
fun foo1() = println() /// M
|
||||||
|
|
||||||
|
fun foo2() {} /// M
|
||||||
|
|
||||||
|
// Lambdas should be available if present
|
||||||
|
fun foo3() = run { println() } /// *, L, M, λ
|
||||||
|
|
||||||
|
// Code blocks {} are not considered as expressions
|
||||||
|
fun foo4() { /// M
|
||||||
|
println() /// L
|
||||||
|
} /// L
|
||||||
|
|
||||||
|
// And parenthesis as well
|
||||||
|
fun foo5() = ( /// M
|
||||||
|
println() /// L
|
||||||
|
)
|
||||||
|
|
||||||
|
// For expression-body functions, a line breakpoint should be available
|
||||||
|
// if there is an expression on the first line
|
||||||
|
fun foo6() = when (2 + 3) { /// M, L
|
||||||
|
5 -> {} /// L
|
||||||
|
else -> {} /// L
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line breakpoint should not be displayed for lambda literal results
|
||||||
|
fun foo7() = { println() } /// M, λ
|
||||||
|
|
||||||
|
fun foo8() = (3 + 5).run { /// M, L
|
||||||
|
println() /// L
|
||||||
|
} /// L
|
||||||
|
|
||||||
|
// Expressions in default parameter values should be recognized
|
||||||
|
fun foo9(a: String = readLine()!!) = a /// M, L
|
||||||
|
|
||||||
|
// Lambdas in default parameter values also should be recognized
|
||||||
|
fun foo10(a: () -> Unit = { println() }) { /// *, L, M, λ
|
||||||
|
a() /// L
|
||||||
|
} /// L
|
||||||
|
|
||||||
|
// If a default parameter value is not just a lambda, but a function call with a lambda argument,
|
||||||
|
// there should be a line breakpoint as well
|
||||||
|
fun foo11(a: String = run { "foo" }) = a /// *, L, M, λ
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
fun foo1() {
|
||||||
|
// We don't support function breakpoints for local functions yet
|
||||||
|
fun local() { /// L
|
||||||
|
println() /// L
|
||||||
|
} /// L
|
||||||
|
} /// L
|
||||||
|
|
||||||
|
fun foo2() { /// M
|
||||||
|
val local = fun() { /// L
|
||||||
|
println() /// L
|
||||||
|
} /// L
|
||||||
|
} /// L
|
||||||
|
|
||||||
|
fun foo3() { /// M
|
||||||
|
val local = { /// L
|
||||||
|
println() /// L
|
||||||
|
} /// L
|
||||||
|
} /// L
|
||||||
|
|
||||||
|
fun foo4() { /// M
|
||||||
|
fun local(block: () -> Unit = { println() }) {} /// *, L, λ
|
||||||
|
} /// L
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class Foo1 {
|
||||||
|
val x: String /// F, L
|
||||||
|
get() = "foo" /// M
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo2 { /// M
|
||||||
|
val x: String = "foo" /// F, L
|
||||||
|
get() = field + "x" /// M
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package simple
|
||||||
|
|
||||||
|
fun main() { /// M
|
||||||
|
val a = 5 /// L
|
||||||
|
foo(a) /// L
|
||||||
|
} /// L
|
||||||
|
|
||||||
|
fun foo(a: Int) { /// M
|
||||||
|
val b = 6 /// L
|
||||||
|
} /// L
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.getLineCount
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.getLineEndOffset
|
||||||
|
import org.jetbrains.kotlin.idea.core.util.getLineStartOffset
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.*
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||||
|
import org.jetbrains.kotlin.idea.test.allKotlinFiles
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
abstract class AbstractBreakpointApplicabilityTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||||
|
private companion object {
|
||||||
|
private const val COMMENT = "///"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTestDataPath(): String {
|
||||||
|
return PluginTestCaseBase.getTestDataPathBase() + "/debugger/breakpointApplicability/"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
myFixture.testDataPath = PluginTestCaseBase.getTestDataPathBase()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getProjectDescriptor(): LightProjectDescriptor {
|
||||||
|
return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun doTest(path: String) {
|
||||||
|
myFixture.configureByFile(getPath(path))
|
||||||
|
|
||||||
|
val file = File(path)
|
||||||
|
val ktFile = project.allKotlinFiles().single()
|
||||||
|
|
||||||
|
val actualContents = checkBreakpoints(ktFile, BreakpointChecker())
|
||||||
|
KotlinTestUtils.assertEqualsToFile(file, actualContents)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkBreakpoints(file: KtFile, checker: BreakpointChecker): String {
|
||||||
|
val lineCount = file.getLineCount()
|
||||||
|
return (0..lineCount).joinToString("\n") { line -> checkLine(file, line, checker) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkLine(file: KtFile, line: Int, checker: BreakpointChecker): String {
|
||||||
|
val lineText = file.getLine(line)
|
||||||
|
val expectedBreakpointTypes = lineText.substringAfterLast(COMMENT).trim().split(",").map { it.trim() }.toSortedSet()
|
||||||
|
val actualBreakpointTypes = checker.check(file, line).map { it.prefix }.distinct().toSortedSet()
|
||||||
|
|
||||||
|
return if (expectedBreakpointTypes != actualBreakpointTypes) {
|
||||||
|
val lineWithoutComments = lineText.substringBeforeLast(COMMENT).trimEnd()
|
||||||
|
if (actualBreakpointTypes.isNotEmpty()) {
|
||||||
|
"$lineWithoutComments $COMMENT " + actualBreakpointTypes.joinToString()
|
||||||
|
} else {
|
||||||
|
lineWithoutComments
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lineText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiFile.getLine(line: Int): String {
|
||||||
|
val start = getLineStartOffset(line, skipWhitespace = false) ?: error("Cannot find start for line $line")
|
||||||
|
val end = getLineEndOffset(line) ?: error("Cannot find end for line $line")
|
||||||
|
if (start >= end) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.substring(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPath(path: String): String {
|
||||||
|
return path.substringAfter(PluginTestCaseBase.TEST_DATA_PROJECT_RELATIVE.drop(1), path)
|
||||||
|
}
|
||||||
|
}
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger
|
|
||||||
|
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger;
|
||||||
|
|
||||||
|
import com.intellij.testFramework.TestDataPath;
|
||||||
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
|
import org.jetbrains.kotlin.test.TargetBackend;
|
||||||
|
import org.jetbrains.kotlin.test.TestMetadata;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
@TestMetadata("idea/testData/debugger/breakpointApplicability")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public class BreakpointApplicabilityTestGenerated extends AbstractBreakpointApplicabilityTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInBreakpointApplicability() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/breakpointApplicability"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("constructors.kt")
|
||||||
|
public void testConstructors() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/breakpointApplicability/constructors.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functions.kt")
|
||||||
|
public void testFunctions() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/breakpointApplicability/functions.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("locals.kt")
|
||||||
|
public void testLocals() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/breakpointApplicability/locals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("properties.kt")
|
||||||
|
public void testProperties() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/breakpointApplicability/properties.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/breakpointApplicability/simple.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user