Support multiple breakpoints at one line (especially for lambdas)
This commit is contained in:
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.fileClasses.getInternalName
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
|
||||||
import org.jetbrains.kotlin.idea.decompiler.JetClsFile
|
import org.jetbrains.kotlin.idea.decompiler.JetClsFile
|
||||||
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
|
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
|
||||||
import org.jetbrains.kotlin.idea.util.DebuggerUtils
|
import org.jetbrains.kotlin.idea.util.DebuggerUtils
|
||||||
@@ -64,6 +65,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
|
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
|
import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
|
||||||
|
|
||||||
@@ -135,10 +137,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
|
|||||||
val end = CodeInsightUtils.getEndLineOffset(file, lineNumber)
|
val end = CodeInsightUtils.getEndLineOffset(file, lineNumber)
|
||||||
if (start == null || end == null) return null
|
if (start == null || end == null) return null
|
||||||
|
|
||||||
val literalsOrFunctions = CodeInsightUtils.
|
val literalsOrFunctions = getLambdasAtLineIfAny(file, lineNumber)
|
||||||
findElementsOfClassInRange(file, start, end, KtFunctionLiteral::class.java, KtNamedFunction::class.java).
|
|
||||||
filter { KtPsiUtil.getParentCallIfPresent(it as KtExpression) != null }
|
|
||||||
|
|
||||||
if (literalsOrFunctions.isEmpty()) return null;
|
if (literalsOrFunctions.isEmpty()) return null;
|
||||||
|
|
||||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||||
@@ -149,17 +148,16 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
|
|||||||
|
|
||||||
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
|
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
|
||||||
for (literal in literalsOrFunctions) {
|
for (literal in literalsOrFunctions) {
|
||||||
val functionLiteral = literal as KtFunction
|
if (isInlinedLambda(literal, typeMapper.bindingContext)) {
|
||||||
if (isInlinedLambda(functionLiteral, typeMapper.bindingContext)) {
|
if (isInsideInlineArgument(literal, location, myDebugProcess as DebugProcessImpl)) {
|
||||||
if (isInsideInlineArgument(functionLiteral, location, myDebugProcess as DebugProcessImpl)) {
|
return literal
|
||||||
return functionLiteral
|
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val internalClassName = getInternalClassNameForElement(literal.firstChild, typeMapper, file, isInLibrary).className
|
val internalClassName = getInternalClassNameForElement(literal.firstChild, typeMapper, file, isInLibrary).className
|
||||||
if (internalClassName == currentLocationClassName) {
|
if (internalClassName == currentLocationClassName) {
|
||||||
return functionLiteral
|
return literal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +230,7 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun classNameForPositionAndInlinedOnes(sourcePosition: SourcePosition): List<String> {
|
private fun classNameForPositionAndInlinedOnes(sourcePosition: SourcePosition): List<String> {
|
||||||
val result = arrayListOf<String>()
|
val result = hashSetOf<String>()
|
||||||
val name = classNameForPosition(sourcePosition)
|
val name = classNameForPosition(sourcePosition)
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
result.add(name)
|
result.add(name)
|
||||||
@@ -240,7 +238,22 @@ public class JetPositionManager(private val myDebugProcess: DebugProcess) : Mult
|
|||||||
val list = findInlinedCalls(sourcePosition.elementAt, sourcePosition.file)
|
val list = findInlinedCalls(sourcePosition.elementAt, sourcePosition.file)
|
||||||
result.addAll(list)
|
result.addAll(list)
|
||||||
|
|
||||||
return result;
|
val lambdas = findLambdas(sourcePosition)
|
||||||
|
result.addAll(lambdas)
|
||||||
|
|
||||||
|
return result.toReadOnlyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findLambdas(sourcePosition: SourcePosition): List<String> {
|
||||||
|
return runReadAction {
|
||||||
|
val lambdas = getLambdasAtLineIfAny(sourcePosition)
|
||||||
|
val file = sourcePosition.file.containingFile as KtFile
|
||||||
|
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||||
|
lambdas.map {
|
||||||
|
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(it, file)
|
||||||
|
getInternalClassNameForElement(it, typeMapper, file, isInLibrary).className
|
||||||
|
}.filterNotNull()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun classNameForPosition(sourcePosition: SourcePosition): String? {
|
public fun classNameForPosition(sourcePosition: SourcePosition): String? {
|
||||||
|
|||||||
+83
-4
@@ -17,17 +17,29 @@
|
|||||||
package org.jetbrains.kotlin.idea.debugger.breakpoints;
|
package org.jetbrains.kotlin.idea.debugger.breakpoints;
|
||||||
|
|
||||||
import com.intellij.debugger.SourcePosition;
|
import com.intellij.debugger.SourcePosition;
|
||||||
|
import com.intellij.debugger.ui.breakpoints.Breakpoint;
|
||||||
|
import com.intellij.debugger.ui.breakpoints.BreakpointManager;
|
||||||
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType;
|
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType;
|
||||||
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
|
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.Comparing;
|
import com.intellij.openapi.util.Comparing;
|
||||||
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.intellij.xdebugger.XSourcePosition;
|
||||||
|
import com.intellij.xdebugger.breakpoints.XBreakpoint;
|
||||||
|
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties;
|
||||||
|
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties;
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinIcons;
|
||||||
import org.jetbrains.kotlin.psi.KtFunction;
|
import org.jetbrains.kotlin.psi.KtFunction;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class KotlinLineBreakpointType extends JavaLineBreakpointType {
|
public class KotlinLineBreakpointType extends JavaLineBreakpointType {
|
||||||
public KotlinLineBreakpointType() {
|
public KotlinLineBreakpointType() {
|
||||||
super("kotlin-line", "Kotlin Line Breakpoints");
|
super("kotlin-line", "Kotlin Line Breakpoints");
|
||||||
@@ -35,11 +47,16 @@ public class KotlinLineBreakpointType extends JavaLineBreakpointType {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matchesPosition(@NotNull LineBreakpoint<?> breakpoint, @NotNull SourcePosition position) {
|
public boolean matchesPosition(@NotNull LineBreakpoint<?> breakpoint, @NotNull SourcePosition position) {
|
||||||
if (super.matchesPosition(breakpoint, position)) return true;
|
JavaBreakpointProperties properties = getProperties(breakpoint);
|
||||||
|
if (properties == null || properties instanceof JavaLineBreakpointProperties) {
|
||||||
|
if (properties != null && ((JavaLineBreakpointProperties)properties).getLambdaOrdinal() == null) return true;
|
||||||
|
|
||||||
PsiElement containingMethod = getContainingMethod(breakpoint);
|
PsiElement containingMethod = getContainingMethod(breakpoint);
|
||||||
if (containingMethod == null) return false;
|
if (containingMethod == null) return false;
|
||||||
return inTheMethod(position, containingMethod);
|
return inTheMethod(position, containingMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -48,9 +65,34 @@ public class KotlinLineBreakpointType extends JavaLineBreakpointType {
|
|||||||
SourcePosition position = breakpoint.getSourcePosition();
|
SourcePosition position = breakpoint.getSourcePosition();
|
||||||
if (position == null) return null;
|
if (position == null) return null;
|
||||||
|
|
||||||
|
JavaBreakpointProperties properties = getProperties(breakpoint);
|
||||||
|
if (properties instanceof JavaLineBreakpointProperties) {
|
||||||
|
Integer ordinal = ((JavaLineBreakpointProperties) properties).getLambdaOrdinal();
|
||||||
|
PsiElement lambda = getLambdaByOrdinal(position, ordinal);
|
||||||
|
if (lambda != null) return lambda;
|
||||||
|
}
|
||||||
|
|
||||||
return getContainingMethod(position.getElementAt());
|
return getContainingMethod(position.getElementAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static JavaBreakpointProperties getProperties(@NotNull LineBreakpoint<?> breakpoint) {
|
||||||
|
XBreakpoint<?> xBreakpoint = breakpoint.getXBreakpoint();
|
||||||
|
return xBreakpoint != null ? (JavaBreakpointProperties) xBreakpoint.getProperties() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static KtFunction getLambdaByOrdinal(SourcePosition position, Integer ordinal) {
|
||||||
|
if (ordinal != null && ordinal >= 0) {
|
||||||
|
List<KtFunction> lambdas = BreakpointTypeUtilsKt.getLambdasAtLineIfAny(position);
|
||||||
|
if (lambdas.size() >= ordinal) {
|
||||||
|
return lambdas.get(ordinal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static PsiElement getContainingMethod(@Nullable PsiElement elem) {
|
public static PsiElement getContainingMethod(@Nullable PsiElement elem) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
@@ -68,5 +110,42 @@ public class KotlinLineBreakpointType extends JavaLineBreakpointType {
|
|||||||
return BreakpointTypeUtilsKt.canPutAt(file, line, project, getClass());
|
return BreakpointTypeUtilsKt.canPutAt(file, line, project, getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<JavaBreakpointVariant> computeVariants(@NotNull Project project, @NotNull XSourcePosition position) {
|
||||||
|
return BreakpointTypeUtilsKt.computeVariants(project, position, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public TextRange getHighlightRange(XLineBreakpoint<JavaLineBreakpointProperties> breakpoint) {
|
||||||
|
JavaLineBreakpointProperties properties = breakpoint.getProperties();
|
||||||
|
if (properties != null) {
|
||||||
|
Integer ordinal = properties.getLambdaOrdinal();
|
||||||
|
if (ordinal != null) {
|
||||||
|
Breakpoint javaBreakpoint = BreakpointManager.getJavaBreakpoint(breakpoint);
|
||||||
|
if (javaBreakpoint instanceof LineBreakpoint) {
|
||||||
|
SourcePosition position = ((LineBreakpoint) javaBreakpoint).getSourcePosition();
|
||||||
|
if (position != null) {
|
||||||
|
KtFunction lambda = getLambdaByOrdinal(position, ordinal);
|
||||||
|
if (lambda != null) {
|
||||||
|
return lambda.getTextRange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExactKotlinJavaBreakpointVariant extends ExactJavaBreakpointVariant {
|
||||||
|
public ExactKotlinJavaBreakpointVariant(XSourcePosition position, KtFunction function, Integer lambdaOrdinal) {
|
||||||
|
super(position, function, lambdaOrdinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Icon getIcon() {
|
||||||
|
return KotlinIcons.LAMBDA;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,19 +16,32 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.breakpoints
|
package org.jetbrains.kotlin.idea.debugger.breakpoints
|
||||||
|
|
||||||
|
import com.intellij.debugger.SourcePosition
|
||||||
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType
|
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.PsiComment
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.xdebugger.XDebuggerUtil
|
import com.intellij.xdebugger.XDebuggerUtil
|
||||||
|
import com.intellij.xdebugger.XSourcePosition
|
||||||
|
import com.intellij.xdebugger.impl.XSourcePositionImpl
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.getLineEndOffset
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.getLineNumber
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.getLineStartOffset
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
fun canPutAt(file: VirtualFile, line: Int, project: Project, breakpointTypeClass: Class<*>): Boolean {
|
fun canPutAt(file: VirtualFile, line: Int, project: Project, breakpointTypeClass: Class<*>): Boolean {
|
||||||
val psiFile = PsiManager.getInstance(project).findFile(file)
|
val psiFile = PsiManager.getInstance(project).findFile(file)
|
||||||
@@ -80,4 +93,73 @@ fun canPutAt(file: VirtualFile, line: Int, project: Project, breakpointTypeClass
|
|||||||
return result == breakpointTypeClass
|
return result == breakpointTypeClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun computeVariants(
|
||||||
|
project: Project, position: XSourcePosition,
|
||||||
|
kotlinBreakpointType: KotlinLineBreakpointType
|
||||||
|
): List<JavaLineBreakpointType.JavaBreakpointVariant> {
|
||||||
|
val file = PsiManager.getInstance(project).findFile(position.file) as? KtFile ?: return emptyList()
|
||||||
|
|
||||||
|
val pos = SourcePosition.createFromLine(file, position.line)
|
||||||
|
val lambdas = getLambdasAtLineIfAny(pos)
|
||||||
|
if (lambdas.isEmpty()) return emptyList()
|
||||||
|
|
||||||
|
val result = LinkedList<JavaLineBreakpointType.JavaBreakpointVariant>()
|
||||||
|
|
||||||
|
val mainMethod = KotlinLineBreakpointType.getContainingMethod(pos.elementAt)
|
||||||
|
if (mainMethod != null) {
|
||||||
|
result.add((kotlinBreakpointType as JavaLineBreakpointType).ExactJavaBreakpointVariant(
|
||||||
|
XSourcePositionImpl.createByElement(mainMethod),
|
||||||
|
mainMethod, -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
lambdas.forEachIndexed { ordinal, lambda ->
|
||||||
|
result.add(kotlinBreakpointType.ExactKotlinJavaBreakpointVariant(
|
||||||
|
XSourcePositionImpl.createByElement(lambda.bodyExpression), lambda, ordinal))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.size > 1) {
|
||||||
|
val allBreakpoint = (kotlinBreakpointType as JavaLineBreakpointType).JavaBreakpointVariant(position)
|
||||||
|
result.addFirst(allBreakpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLambdasAtLineIfAny(sourcePosition: SourcePosition): List<KtFunction> {
|
||||||
|
val file = sourcePosition.file as? KtFile ?: return emptyList()
|
||||||
|
val lineNumber = sourcePosition.line
|
||||||
|
return getLambdasAtLineIfAny(file, lineNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLambdasAtLineIfAny(file: KtFile, line: Int): List<KtFunction> {
|
||||||
|
var lineStartOffset = file.getLineStartOffset(line) ?: return emptyList()
|
||||||
|
var lineEndOffset = file.getLineEndOffset(line) ?: return emptyList()
|
||||||
|
|
||||||
|
var topMostElement: PsiElement? = null
|
||||||
|
var elementAt: PsiElement?
|
||||||
|
while (topMostElement !is KtElement && lineStartOffset < lineEndOffset) {
|
||||||
|
elementAt = file.findElementAt(lineStartOffset)
|
||||||
|
if (elementAt != null) {
|
||||||
|
topMostElement = CodeInsightUtils.getTopmostElementAtOffset(elementAt, lineStartOffset)
|
||||||
|
}
|
||||||
|
lineStartOffset++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topMostElement !is KtElement) return emptyList()
|
||||||
|
|
||||||
|
val start = topMostElement.startOffset
|
||||||
|
val end = topMostElement.endOffset
|
||||||
|
|
||||||
|
val allInlineFunctionCalls = CodeInsightUtils.
|
||||||
|
findElementsOfClassInRange(file, start, end, KtFunction::class.java)
|
||||||
|
.filter { KtPsiUtil.getParentCallIfPresent(it as KtExpression) != null }
|
||||||
|
.filterIsInstance<KtFunction>()
|
||||||
|
.toSet()
|
||||||
|
|
||||||
|
return allInlineFunctionCalls.filter {
|
||||||
|
val statement = (it.bodyExpression as? KtBlockExpression)?.statements?.firstOrNull() ?: it
|
||||||
|
statement.getLineNumber() == line && statement.getLineNumber(false) == line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ public class KotlinLambdaMethodFilter(
|
|||||||
private val myLastStatementLine: Int
|
private val myLastStatementLine: Int
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (lambda.isMultiLine()) {
|
val body = lambda.bodyExpression
|
||||||
|
if (body != null && lambda.isMultiLine()) {
|
||||||
var firstStatementPosition: SourcePosition? = null
|
var firstStatementPosition: SourcePosition? = null
|
||||||
var lastStatementPosition: SourcePosition? = null
|
var lastStatementPosition: SourcePosition? = null
|
||||||
val body = lambda.bodyExpression as KtBlockExpression
|
val statements = (body as? KtBlockExpression)?.statements ?: listOf(body)
|
||||||
val statements = body.statements
|
|
||||||
if (statements.isNotEmpty()) {
|
if (statements.isNotEmpty()) {
|
||||||
firstStatementPosition = SourcePosition.createFromElement(statements.first())
|
firstStatementPosition = SourcePosition.createFromElement(statements.first())
|
||||||
if (firstStatementPosition != null) {
|
if (firstStatementPosition != null) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
LineBreakpoint created at ceAnonymousObjectCapturedInClosure.kt:7
|
LineBreakpoint created at ceAnonymousObjectCapturedInClosure.kt:7 lambdaOrdinal = -1
|
||||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ceAnonymousObjectCapturedInClosure.CeAnonymousObjectCapturedInClosureKt
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! ceAnonymousObjectCapturedInClosure.CeAnonymousObjectCapturedInClosureKt
|
||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
ceAnonymousObjectCapturedInClosure.kt:7
|
ceAnonymousObjectCapturedInClosure.kt:7
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:9 lambdaOrdinal = -1
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:14 lambdaOrdinal = 0
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:19 lambdaOrdinal = 1
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:30
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:38 lambdaOrdinal = -1
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:43 lambdaOrdinal = 0
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:48 lambdaOrdinal = 1
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:62
|
||||||
|
LineBreakpoint created at multipleBreakpointsAtLine.kt:67 lambdaOrdinal = 1
|
||||||
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! multipleBreakpointsAtLine.MultipleBreakpointsAtLineKt
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
multipleBreakpointsAtLine.kt:9
|
||||||
|
multipleBreakpointsAtLine.kt:14
|
||||||
|
Compile bytecode for it + 2
|
||||||
|
multipleBreakpointsAtLine.kt:19
|
||||||
|
Compile bytecode for it + 3
|
||||||
|
multipleBreakpointsAtLine.kt:30
|
||||||
|
multipleBreakpointsAtLine.kt:30
|
||||||
|
Compile bytecode for it + 5
|
||||||
|
multipleBreakpointsAtLine.kt:30
|
||||||
|
Compile bytecode for it + 6
|
||||||
|
multipleBreakpointsAtLine.kt:38
|
||||||
|
multipleBreakpointsAtLine.kt:38
|
||||||
|
multipleBreakpointsAtLine.kt:43
|
||||||
|
Compile bytecode for it + 9
|
||||||
|
multipleBreakpointsAtLine.kt:48
|
||||||
|
Compile bytecode for it + 10
|
||||||
|
multipleBreakpointsAtLine.kt:62
|
||||||
|
multipleBreakpointsAtLine.kt:62
|
||||||
|
Compile bytecode for it + 12
|
||||||
|
multipleBreakpointsAtLine.kt:62
|
||||||
|
multipleBreakpointsAtLine.kt:62
|
||||||
|
Compile bytecode for it + 14
|
||||||
|
multipleBreakpointsAtLine.kt:67
|
||||||
|
Compile bytecode for it + 15
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
LineBreakpoint created at severalFunLiterals.kt:6
|
LineBreakpoint created at severalFunLiterals.kt:6 lambdaOrdinal = -1
|
||||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! severalFunLiterals.SeveralFunLiteralsKt
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! severalFunLiterals.SeveralFunLiteralsKt
|
||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
severalFunLiterals.kt:6
|
severalFunLiterals.kt:6
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
LineBreakpoint created at severalFunLiteralsInClass.kt:20
|
LineBreakpoint created at severalFunLiteralsInClass.kt:20 lambdaOrdinal = -1
|
||||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! severalFunLiteralsInClass.SeveralFunLiteralsInClassKt
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! severalFunLiteralsInClass.SeveralFunLiteralsInClassKt
|
||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
severalFunLiteralsInClass.kt:20
|
severalFunLiteralsInClass.kt:20
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ LineBreakpoint created at smartStepIntoInlinedFunLiteral.kt:6
|
|||||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! smartStepIntoInlinedFunLiteral.SmartStepIntoInlinedFunLiteralKt
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! smartStepIntoInlinedFunLiteral.SmartStepIntoInlinedFunLiteralKt
|
||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
smartStepIntoInlinedFunLiteral.kt:6
|
smartStepIntoInlinedFunLiteral.kt:6
|
||||||
smartStepIntoInlinedFunLiteral.kt:9
|
smartStepIntoInlinedFunLiteral.kt:11
|
||||||
smartStepIntoInlinedFunLiteral.kt:10
|
smartStepIntoInlinedFunLiteral.kt:12
|
||||||
smartStepIntoInlinedFunLiteral.kt:13
|
smartStepIntoInlinedFunLiteral.kt:17
|
||||||
smartStepIntoInlinedFunLiteral.kt:14
|
|
||||||
smartStepIntoInlinedFunLiteral.kt:18
|
smartStepIntoInlinedFunLiteral.kt:18
|
||||||
smartStepIntoInlinedFunLiteral.kt:20
|
smartStepIntoInlinedFunLiteral.kt:24
|
||||||
|
smartStepIntoInlinedFunLiteral.kt:26
|
||||||
|
smartStepIntoInlinedFunLiteral.kt:32
|
||||||
|
smartStepIntoInlinedFunLiteral.kt:32
|
||||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
+7
-5
@@ -2,12 +2,14 @@ LineBreakpoint created at smartStepIntoInlinedFunctionalExpression.kt:6
|
|||||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! smartStepIntoInlinedFunctionalExpression.SmartStepIntoInlinedFunctionalExpressionKt
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! smartStepIntoInlinedFunctionalExpression.SmartStepIntoInlinedFunctionalExpressionKt
|
||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
smartStepIntoInlinedFunctionalExpression.kt:6
|
smartStepIntoInlinedFunctionalExpression.kt:6
|
||||||
smartStepIntoInlinedFunctionalExpression.kt:9
|
smartStepIntoInlinedFunctionalExpression.kt:11
|
||||||
smartStepIntoInlinedFunctionalExpression.kt:10
|
smartStepIntoInlinedFunctionalExpression.kt:12
|
||||||
smartStepIntoInlinedFunctionalExpression.kt:13
|
smartStepIntoInlinedFunctionalExpression.kt:17
|
||||||
smartStepIntoInlinedFunctionalExpression.kt:14
|
|
||||||
smartStepIntoInlinedFunctionalExpression.kt:18
|
smartStepIntoInlinedFunctionalExpression.kt:18
|
||||||
smartStepIntoInlinedFunctionalExpression.kt:20
|
smartStepIntoInlinedFunctionalExpression.kt:24
|
||||||
|
smartStepIntoInlinedFunctionalExpression.kt:26
|
||||||
|
smartStepIntoInlinedFunctionalExpression.kt:31
|
||||||
|
smartStepIntoInlinedFunctionalExpression.kt:31
|
||||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
LineBreakpoint created at twoLambdasOnOneLineFirst.kt:9
|
LineBreakpoint created at twoLambdasOnOneLineFirst.kt:9 lambdaOrdinal = -1
|
||||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! twoLambdasOnOneLineFirst.TwoLambdasOnOneLineFirstKt
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! twoLambdasOnOneLineFirst.TwoLambdasOnOneLineFirstKt
|
||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
twoLambdasOnOneLineFirst.kt:9
|
twoLambdasOnOneLineFirst.kt:9
|
||||||
|
|||||||
Vendored
+82
@@ -0,0 +1,82 @@
|
|||||||
|
package multipleBreakpointsAtLine
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
// EXPRESSION: it + 1
|
||||||
|
// RESULT: Unresolved reference: it
|
||||||
|
//Breakpoint! (-1)
|
||||||
|
a.foo(1) { 1 }.foo(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 2
|
||||||
|
// RESULT: 3: I
|
||||||
|
//Breakpoint! (0)
|
||||||
|
a.foo(1) { 1 }.foo(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 3
|
||||||
|
// RESULT: 5: I
|
||||||
|
//Breakpoint! (1)
|
||||||
|
a.foo(1) { 1 }.foo(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 4
|
||||||
|
// RESULT: Unresolved reference: it
|
||||||
|
|
||||||
|
// EXPRESSION: it + 5
|
||||||
|
// RESULT: 6: I
|
||||||
|
|
||||||
|
// EXPRESSION: it + 6
|
||||||
|
// RESULT: 8: I
|
||||||
|
//Breakpoint!
|
||||||
|
a.foo(1) { 1 }.foo(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 7
|
||||||
|
// RESULT: Unresolved reference: it
|
||||||
|
|
||||||
|
// EXPRESSION: it + 8
|
||||||
|
// RESULT: Unresolved reference: it
|
||||||
|
//Breakpoint! (-1)
|
||||||
|
a.bar(1) { 1 }.bar(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 9
|
||||||
|
// RESULT: 10: I
|
||||||
|
//Breakpoint! (0)
|
||||||
|
a.bar(1) { 1 }.bar(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 10
|
||||||
|
// RESULT: 12: I
|
||||||
|
//Breakpoint! (1)
|
||||||
|
a.bar(1) { 1 }.bar(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 11
|
||||||
|
// RESULT: Unresolved reference: it
|
||||||
|
|
||||||
|
// EXPRESSION: it + 12
|
||||||
|
// RESULT: 13: I
|
||||||
|
|
||||||
|
// EXPRESSION: it + 13
|
||||||
|
// RESULT: Unresolved reference: it
|
||||||
|
|
||||||
|
// EXPRESSION: it + 14
|
||||||
|
// RESULT: 16: I
|
||||||
|
//Breakpoint!
|
||||||
|
a.bar(1) { 1 }.bar(2) { 1 }
|
||||||
|
|
||||||
|
// EXPRESSION: it + 15
|
||||||
|
// RESULT: 17: I
|
||||||
|
//Breakpoint! (1)
|
||||||
|
a.bar(1) { 1 }.bar(2) { 1 + 1
|
||||||
|
1 + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun foo(i: Int, f: (i: Int) -> Int): A {
|
||||||
|
f(i)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun bar(i: Int, f: (i: Int) -> Int): A {
|
||||||
|
f(i)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -3,7 +3,7 @@ package ceAnonymousObjectCapturedInClosure
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val localObject = object { fun test() = 1 }
|
val localObject = object { fun test() = 1 }
|
||||||
var localObjectVar = object { fun test() = 1 }
|
var localObjectVar = object { fun test() = 1 }
|
||||||
//Breakpoint!
|
//Breakpoint! (-1)
|
||||||
lambda { localObjectVar.test() }
|
lambda { localObjectVar.test() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -5,7 +5,7 @@ fun main(args: Array<String>) {
|
|||||||
// EXPRESSION: it
|
// EXPRESSION: it
|
||||||
// RESULT: 1: I
|
// RESULT: 1: I
|
||||||
// STEP_INTO: 2
|
// STEP_INTO: 2
|
||||||
//Breakpoint!
|
//Breakpoint! (-1)
|
||||||
a.foo { a }.foo { a }
|
a.foo { a }.foo { a }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package severalFunLiterals
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val myClass = MyClass()
|
val myClass = MyClass()
|
||||||
//Breakpoint!
|
//Breakpoint! (-1)
|
||||||
myClass.f1 { test() }.f2 {
|
myClass.f1 { test() }.f2 {
|
||||||
test()
|
test()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ class MyClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun inClass() {
|
fun inClass() {
|
||||||
//Breakpoint!
|
//Breakpoint! (-1)
|
||||||
f1 { test() }.f2 {
|
f1 { test() }.f2 {
|
||||||
test()
|
test()
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-7
@@ -5,20 +5,31 @@ fun main(args: Array<String>) {
|
|||||||
//Breakpoint!
|
//Breakpoint!
|
||||||
val myClass = MyClass()
|
val myClass = MyClass()
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 4
|
||||||
// smart step into f2.invoke(), one-line lambda
|
// smart step into f2.invoke(), one-line lambda
|
||||||
myClass.f1 { test() }
|
myClass.f1 { test() }
|
||||||
.f2 { test() }
|
.f2 { test() }
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 2
|
||||||
// smart step into map.invoke(), multiline lambda
|
// smart step into map.invoke(), multiline lambda
|
||||||
array.map {
|
array.map {
|
||||||
it *2
|
it *2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 4
|
||||||
// smart step into filter.invoke()
|
// smart step into filter.invoke()
|
||||||
array.map { it * 2 }
|
array.map { it * 2 }
|
||||||
.filter {
|
.filter {
|
||||||
it > 2
|
it > 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 4
|
||||||
|
// smart step into f2.invoke(), one-line lambda
|
||||||
|
myClass.f1 { test() }.f2 { test() }
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyClass {
|
class MyClass {
|
||||||
@@ -36,10 +47,3 @@ class MyClass {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test() {}
|
fun test() {}
|
||||||
|
|
||||||
// STEP_OVER: 1
|
|
||||||
// SMART_STEP_INTO_BY_INDEX: 4
|
|
||||||
// STEP_OVER: 1
|
|
||||||
// SMART_STEP_INTO_BY_INDEX: 2
|
|
||||||
// STEP_OVER: 1
|
|
||||||
// SMART_STEP_INTO_BY_INDEX: 4
|
|
||||||
Vendored
+17
-7
@@ -5,20 +5,32 @@ fun main(args: Array<String>) {
|
|||||||
//Breakpoint!
|
//Breakpoint!
|
||||||
val myClass = MyClass()
|
val myClass = MyClass()
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 4
|
||||||
// smart step into f2.invoke(), one-line lambda
|
// smart step into f2.invoke(), one-line lambda
|
||||||
myClass.f1(fun () { test() })
|
myClass.f1(fun () { test() })
|
||||||
.f2(fun () { test() })
|
.f2(fun () { test() })
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 2
|
||||||
// smart step into map.invoke(), multiline lambda
|
// smart step into map.invoke(), multiline lambda
|
||||||
array.map(fun (it): Int {
|
array.map(fun (it): Int {
|
||||||
return it * 2
|
return it * 2
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 4
|
||||||
// smart step into filter.invoke()
|
// smart step into filter.invoke()
|
||||||
array.map(fun (it): Int { return it * 2 })
|
array.map(fun (it): Int { return it * 2 })
|
||||||
.filter(fun (it): Boolean {
|
.filter(fun (it): Boolean {
|
||||||
return it > 2
|
return it > 2
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// STEP_OVER: 1
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 2
|
||||||
|
myClass.f3(fun () = myClass.f3 {
|
||||||
|
println()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyClass {
|
class MyClass {
|
||||||
@@ -33,13 +45,11 @@ class MyClass {
|
|||||||
f1Param()
|
f1Param()
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun f3(f1Param: () -> Unit): Unit {
|
||||||
|
test()
|
||||||
|
f1Param()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun test() {}
|
fun test() {}
|
||||||
|
|
||||||
// STEP_OVER: 1
|
|
||||||
// SMART_STEP_INTO_BY_INDEX: 4
|
|
||||||
// STEP_OVER: 1
|
|
||||||
// SMART_STEP_INTO_BY_INDEX: 2
|
|
||||||
// STEP_OVER: 1
|
|
||||||
// SMART_STEP_INTO_BY_INDEX: 4
|
|
||||||
@@ -26,25 +26,28 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
|||||||
import com.intellij.debugger.impl.DebuggerContextImpl
|
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||||
import com.intellij.debugger.impl.PositionUtil
|
import com.intellij.debugger.impl.PositionUtil
|
||||||
import com.intellij.debugger.settings.DebuggerSettings
|
import com.intellij.debugger.settings.DebuggerSettings
|
||||||
|
import com.intellij.debugger.ui.breakpoints.Breakpoint
|
||||||
import com.intellij.debugger.ui.breakpoints.BreakpointManager
|
import com.intellij.debugger.ui.breakpoints.BreakpointManager
|
||||||
|
import com.intellij.debugger.ui.breakpoints.LineBreakpoint
|
||||||
import com.intellij.execution.process.ProcessOutputTypes
|
import com.intellij.execution.process.ProcessOutputTypes
|
||||||
import com.intellij.openapi.application.ModalityState
|
import com.intellij.openapi.application.ModalityState
|
||||||
import com.intellij.openapi.roots.JdkOrderEntry
|
import com.intellij.openapi.roots.JdkOrderEntry
|
||||||
import com.intellij.openapi.roots.libraries.LibraryUtil
|
import com.intellij.openapi.roots.libraries.LibraryUtil
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
import com.intellij.psi.search.FilenameIndex
|
import com.intellij.psi.search.FilenameIndex
|
||||||
import com.intellij.xdebugger.XDebuggerManager
|
import com.intellij.xdebugger.XDebuggerManager
|
||||||
import com.intellij.xdebugger.XDebuggerUtil
|
import com.intellij.xdebugger.XDebuggerUtil
|
||||||
import com.intellij.xdebugger.breakpoints.XBreakpoint
|
import com.intellij.xdebugger.breakpoints.*
|
||||||
import com.intellij.xdebugger.breakpoints.XBreakpointProperties
|
import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties
|
||||||
import com.intellij.xdebugger.breakpoints.XBreakpointType
|
import org.jetbrains.java.debugger.breakpoints.properties.JavaLineBreakpointProperties
|
||||||
import com.intellij.xdebugger.breakpoints.XLineBreakpointType
|
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.getLineNumber
|
import org.jetbrains.kotlin.idea.core.refactoring.getLineNumber
|
||||||
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpoint
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpoint
|
||||||
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointType
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointType
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinLineBreakpointType
|
||||||
import org.jetbrains.kotlin.idea.debugger.stepping.*
|
import org.jetbrains.kotlin.idea.debugger.stepping.*
|
||||||
import org.jetbrains.kotlin.idea.test.JetJdkAndLibraryProjectDescriptor
|
import org.jetbrains.kotlin.idea.test.JetJdkAndLibraryProjectDescriptor
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
@@ -261,49 +264,68 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createBreakpoints(file: PsiFile?) {
|
override fun createBreakpoints(file: PsiFile?) {
|
||||||
super.createBreakpoints(file)
|
|
||||||
|
|
||||||
if (file == null) return
|
if (file == null) return
|
||||||
|
|
||||||
val document = PsiDocumentManager.getInstance(myProject).getDocument(file) ?: return
|
val document = runReadAction { PsiDocumentManager.getInstance(myProject).getDocument(file) } ?: return
|
||||||
val breakpointManager = XDebuggerManager.getInstance(myProject).getBreakpointManager()
|
val breakpointManager = XDebuggerManager.getInstance(myProject).getBreakpointManager()
|
||||||
val breakpointType = javaClass<KotlinFieldBreakpointType>() as Class<out XBreakpointType<XBreakpoint<XBreakpointProperties<*>>, XBreakpointProperties<*>>>
|
val kotlinFieldBreakpointType = findBreakpointType(KotlinFieldBreakpointType::class.java)
|
||||||
val type = XDebuggerUtil.getInstance().findBreakpointType<XBreakpoint<XBreakpointProperties<*>>>(breakpointType) as KotlinFieldBreakpointType
|
val kotlinLineBreakpointType = findBreakpointType(KotlinLineBreakpointType::class.java)
|
||||||
val virtualFile = file.getVirtualFile()
|
val virtualFile = file.getVirtualFile()
|
||||||
|
|
||||||
val runnable = {
|
val runnable = {
|
||||||
var offset = -1;
|
var offset = -1;
|
||||||
while (true) {
|
while (true) {
|
||||||
val fileText = document.getText()
|
val fileText = document.getText()
|
||||||
offset = fileText.indexOf("FieldWatchpoint!", offset + 1)
|
offset = fileText.indexOf("point!", offset + 1)
|
||||||
if (offset == -1) break
|
if (offset == -1) break
|
||||||
|
|
||||||
val commentLine = document.getLineNumber(offset)
|
val commentLine = document.getLineNumber(offset)
|
||||||
|
|
||||||
val comment = fileText.substring(document.getLineStartOffset(commentLine), document.getLineEndOffset(commentLine))
|
val comment = fileText.substring(document.getLineStartOffset(commentLine), document.getLineEndOffset(commentLine)).trim()
|
||||||
|
|
||||||
val lineIndex = commentLine + 1
|
val lineIndex = commentLine + 1
|
||||||
val fieldName = comment.substringAfter("//FieldWatchpoint! (").substringBefore(")")
|
|
||||||
|
|
||||||
if (!type.canPutAt(virtualFile, lineIndex, myProject)) continue
|
if (comment.startsWith("//FieldWatchpoint!")) {
|
||||||
|
val javaBreakpoint = createBreakpointOfType(
|
||||||
val xBreakpoint = runWriteAction {
|
breakpointManager,
|
||||||
breakpointManager.addLineBreakpoint(
|
kotlinFieldBreakpointType as XLineBreakpointType<XBreakpointProperties<*>>,
|
||||||
type as XLineBreakpointType<XBreakpointProperties<*>>,
|
|
||||||
virtualFile.getUrl(),
|
|
||||||
lineIndex,
|
lineIndex,
|
||||||
type.createBreakpointProperties(virtualFile, lineIndex)
|
virtualFile)
|
||||||
)
|
if (javaBreakpoint is KotlinFieldBreakpoint) {
|
||||||
|
val fieldName = comment.substringAfter("//FieldWatchpoint! (").substringBefore(")")
|
||||||
|
javaBreakpoint.setFieldName(fieldName)
|
||||||
|
javaBreakpoint.setWatchAccess(fileText.getValueForSetting("WATCH_FIELD_ACCESS", true))
|
||||||
|
javaBreakpoint.setWatchModification(fileText.getValueForSetting("WATCH_FIELD_MODIFICATION", true))
|
||||||
|
javaBreakpoint.setWatchInitialization(fileText.getValueForSetting("WATCH_FIELD_INITIALISATION", false))
|
||||||
|
BreakpointManager.addBreakpoint(javaBreakpoint)
|
||||||
|
println("KotlinFieldBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}", ProcessOutputTypes.SYSTEM)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (comment.startsWith("//Breakpoint!")) {
|
||||||
|
val javaBreakpoint = createBreakpointOfType(
|
||||||
|
breakpointManager,
|
||||||
|
kotlinLineBreakpointType as XLineBreakpointType<XBreakpointProperties<*>>,
|
||||||
|
lineIndex,
|
||||||
|
virtualFile)
|
||||||
|
if (javaBreakpoint is LineBreakpoint<*>) {
|
||||||
|
|
||||||
val javaBreakpoint = BreakpointManager.getJavaBreakpoint(xBreakpoint)
|
if (comment.contains("(")) {
|
||||||
if (javaBreakpoint is KotlinFieldBreakpoint) {
|
val ordinal = comment.substringAfter("//Breakpoint! (").substringBefore(")").toInt()
|
||||||
javaBreakpoint.setFieldName(fieldName)
|
|
||||||
javaBreakpoint.setWatchAccess(fileText.getValueForSetting("WATCH_FIELD_ACCESS", true))
|
val properties = javaBreakpoint.xBreakpoint.properties as? JavaLineBreakpointProperties ?: continue
|
||||||
javaBreakpoint.setWatchModification(fileText.getValueForSetting("WATCH_FIELD_MODIFICATION", true))
|
properties.lambdaOrdinal = ordinal
|
||||||
javaBreakpoint.setWatchInitialization(fileText.getValueForSetting("WATCH_FIELD_INITIALISATION", false))
|
|
||||||
BreakpointManager.addBreakpoint(javaBreakpoint)
|
BreakpointManager.addBreakpoint(javaBreakpoint)
|
||||||
println("KotlinFieldBreakpoint created at ${file.getVirtualFile().getName()}:${lineIndex + 1}", ProcessOutputTypes.SYSTEM)
|
println("LineBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1} lambdaOrdinal = $ordinal", ProcessOutputTypes.SYSTEM)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BreakpointManager.addBreakpoint(javaBreakpoint)
|
||||||
|
println("LineBreakpoint created at ${file.virtualFile.name}:${lineIndex + 1}", ProcessOutputTypes.SYSTEM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw AssertionError("Cannot create breakpoint at line ${lineIndex + 1}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,6 +338,29 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createBreakpointOfType(
|
||||||
|
breakpointManager: XBreakpointManager,
|
||||||
|
breakpointType: XLineBreakpointType<XBreakpointProperties<*>>,
|
||||||
|
lineIndex: Int,
|
||||||
|
virtualFile: VirtualFile
|
||||||
|
): Breakpoint<out JavaBreakpointProperties<*>>? {
|
||||||
|
if (!breakpointType.canPutAt(virtualFile, lineIndex, myProject)) return null
|
||||||
|
val xBreakpoint = runWriteAction {
|
||||||
|
breakpointManager.addLineBreakpoint(
|
||||||
|
breakpointType,
|
||||||
|
virtualFile.url,
|
||||||
|
lineIndex,
|
||||||
|
breakpointType.createBreakpointProperties(virtualFile, lineIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return BreakpointManager.getJavaBreakpoint(xBreakpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified T> findBreakpointType(javaClass: Class<T>): T {
|
||||||
|
val kotlinFieldBreakpointTypeClass = javaClass as Class<out XBreakpointType<XBreakpoint<XBreakpointProperties<*>>, XBreakpointProperties<*>>>
|
||||||
|
return XDebuggerUtil.getInstance().findBreakpointType<XBreakpoint<XBreakpointProperties<*>>>(kotlinFieldBreakpointTypeClass) as T
|
||||||
|
}
|
||||||
|
|
||||||
protected fun createAdditionalBreakpoints(fileText: String) {
|
protected fun createAdditionalBreakpoints(fileText: String) {
|
||||||
val breakpoints = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// ADDITIONAL_BREAKPOINT: ")
|
val breakpoints = InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// ADDITIONAL_BREAKPOINT: ")
|
||||||
for (breakpoint in breakpoints) {
|
for (breakpoint in breakpoints) {
|
||||||
|
|||||||
+12
@@ -688,6 +688,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doMultipleBreakpointsTest(fileName);
|
doMultipleBreakpointsTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleBreakpointsAtLine.kt")
|
||||||
|
public void testMultipleBreakpointsAtLine() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/multipleBreakpointsAtLine.kt");
|
||||||
|
doMultipleBreakpointsTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("whenEntry.kt")
|
@TestMetadata("whenEntry.kt")
|
||||||
public void testWhenEntry() throws Exception {
|
public void testWhenEntry() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/whenEntry.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/whenEntry.kt");
|
||||||
@@ -706,6 +712,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doMultipleBreakpointsTest(fileName);
|
doMultipleBreakpointsTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withoutBodyProperties2.kt")
|
||||||
|
public void testWithoutBodyProperties2() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/withoutBodyProperties2.kt");
|
||||||
|
doMultipleBreakpointsTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("withoutBodyTypeParameters.kt")
|
@TestMetadata("withoutBodyTypeParameters.kt")
|
||||||
public void testWithoutBodyTypeParameters() throws Exception {
|
public void testWithoutBodyTypeParameters() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/withoutBodyTypeParameters.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/withoutBodyTypeParameters.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user