Debugger: get correct context for breakpoints inside lambdas
This commit is contained in:
@@ -83,18 +83,10 @@ public class CodeInsightUtils {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
|
||||
if (!parent.equals(element1)) {
|
||||
while (!parent.equals(element1.getParent())) {
|
||||
element1 = element1.getParent();
|
||||
}
|
||||
}
|
||||
element1 = getTopmostParentInside(element1, parent);
|
||||
if (startOffset != element1.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
if (!parent.equals(element2)) {
|
||||
while (!parent.equals(element2.getParent())) {
|
||||
element2 = element2.getParent();
|
||||
}
|
||||
}
|
||||
element2 = getTopmostParentInside(element2, parent);
|
||||
if (endOffset != element2.getTextRange().getEndOffset()) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
List<PsiElement> array = new ArrayList<PsiElement>();
|
||||
@@ -133,6 +125,47 @@ public class CodeInsightUtils {
|
||||
return jetExpression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement[] findElementsOfClassInRange(@NotNull PsiFile file, int startOffset, int endOffset, Class<? extends PsiElement> aClass) {
|
||||
PsiElement element1 = getElementAtOffsetIgnoreWhitespaceBefore(file, startOffset);
|
||||
PsiElement element2 = getElementAtOffsetIgnoreWhitespaceAfter(file, endOffset);
|
||||
|
||||
if (element1 == null || element2 == null) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
startOffset = element1.getTextRange().getStartOffset();
|
||||
endOffset = element2.getTextRange().getEndOffset();
|
||||
|
||||
PsiElement parent = PsiTreeUtil.findCommonParent(element1, element2);
|
||||
if (parent == null) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
element1 = getTopmostParentInside(element1, parent);
|
||||
if (startOffset != element1.getTextRange().getStartOffset()) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
element2 = getTopmostParentInside(element2, parent);
|
||||
if (endOffset != element2.getTextRange().getEndOffset()) return PsiElement.EMPTY_ARRAY;
|
||||
|
||||
PsiElement stopElement = element2.getNextSibling();
|
||||
List<PsiElement> array = new ArrayList<PsiElement>();
|
||||
for (PsiElement currentElement = element1; currentElement != stopElement; currentElement = currentElement.getNextSibling()) {
|
||||
if (aClass.isInstance(currentElement)) {
|
||||
array.add(currentElement);
|
||||
}
|
||||
array.addAll(PsiTreeUtil.findChildrenOfType(currentElement, aClass));
|
||||
}
|
||||
|
||||
return PsiUtilCore.toPsiElementArray(array);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiElement getTopmostParentInside(@NotNull PsiElement element, @NotNull PsiElement parent) {
|
||||
if (!parent.equals(element)) {
|
||||
while (!parent.equals(element.getParent())) {
|
||||
element = element.getParent();
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getElementAtOffsetIgnoreWhitespaceBefore(@NotNull PsiFile file, int offset) {
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
@@ -206,6 +239,15 @@ public class CodeInsightUtils {
|
||||
return CharArrayUtil.shiftForward(document.getCharsSequence(), lineStartOffset, " \t");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Integer getEndLineOffset(@NotNull PsiFile file, int line) {
|
||||
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
|
||||
if (document == null) return null;
|
||||
|
||||
int lineStartOffset = document.getLineEndOffset(line);
|
||||
return CharArrayUtil.shiftBackward(document.getCharsSequence(), lineStartOffset, " \t");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getTopmostElementAtOffset(@NotNull PsiElement element, int offset) {
|
||||
do {
|
||||
|
||||
@@ -56,6 +56,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.types.lang.InlineStrategy;
|
||||
import org.jetbrains.jet.lang.types.lang.InlineUtil;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
||||
import org.jetbrains.jet.plugin.codeInsight.CodeInsightUtils;
|
||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies;
|
||||
import org.jetbrains.jet.plugin.util.DebuggerUtils;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
@@ -93,12 +94,48 @@ public class JetPositionManager implements PositionManager {
|
||||
}
|
||||
|
||||
if (lineNumber >= 0) {
|
||||
JetFunctionLiteral lambdaIfInside = getLambdaIfInside(location, (JetFile) psiFile, lineNumber);
|
||||
if (lambdaIfInside != null) {
|
||||
return SourcePosition.createFromElement(lambdaIfInside.getBodyExpression().getStatements().get(0));
|
||||
}
|
||||
return SourcePosition.createFromLine(psiFile, lineNumber);
|
||||
}
|
||||
|
||||
throw new NoDataException();
|
||||
}
|
||||
|
||||
private JetFunctionLiteral getLambdaIfInside(@NotNull Location location, @NotNull JetFile file, int lineNumber) {
|
||||
String currentLocationFqName = location.declaringType().name();
|
||||
if (currentLocationFqName == null) return null;
|
||||
|
||||
Integer start = CodeInsightUtils.getStartLineOffset(file, lineNumber);
|
||||
Integer end = CodeInsightUtils.getEndLineOffset(file, lineNumber);
|
||||
if (start == null || end == null) return null;
|
||||
|
||||
PsiElement[] literals = CodeInsightUtils.findElementsOfClassInRange(file, start, end, JetFunctionLiteral.class);
|
||||
if (literals == null || literals.length == 0) return null;
|
||||
|
||||
boolean isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null;
|
||||
JetTypeMapper typeMapper = !isInLibrary
|
||||
? prepareTypeMapper(file)
|
||||
: createTypeMapperForLibraryFile(file.findElementAt(start), file);
|
||||
|
||||
String currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(new FqName(currentLocationFqName)).getInternalName();
|
||||
for (PsiElement literal : literals) {
|
||||
JetFunctionLiteral functionLiteral = (JetFunctionLiteral) literal;
|
||||
if (isInlinedLambda(functionLiteral, typeMapper.getBindingContext())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String internalClassName = getClassNameForElement(literal.getFirstChild(), typeMapper, file, isInLibrary);
|
||||
if (internalClassName.equals(currentLocationClassName)) {
|
||||
return functionLiteral;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiFile getPsiFileByLocation(@NotNull Location location) {
|
||||
String sourceName;
|
||||
@@ -142,7 +179,7 @@ public class JetPositionManager implements PositionManager {
|
||||
public void run() {
|
||||
JetFile file = (JetFile) sourcePosition.getFile();
|
||||
boolean isInLibrary = LibraryUtil.findLibraryEntry(file.getVirtualFile(), file.getProject()) != null;
|
||||
JetTypeMapper typeMapper = !isInLibrary ? prepareTypeMapper(file) : createTypeMapperForLibraryFile(sourcePosition);
|
||||
JetTypeMapper typeMapper = !isInLibrary ? prepareTypeMapper(file) : createTypeMapperForLibraryFile(sourcePosition.getElementAt(), file);
|
||||
result.set(getClassNameForElement(sourcePosition.getElementAt(), typeMapper, file, isInLibrary));
|
||||
}
|
||||
|
||||
@@ -217,11 +254,10 @@ public class JetPositionManager implements PositionManager {
|
||||
return typeMapper.mapClass(classDescriptor).getInternalName();
|
||||
}
|
||||
|
||||
private static JetTypeMapper createTypeMapperForLibraryFile(@NotNull SourcePosition position) {
|
||||
JetElement element = getElementToCreateTypeMapperForLibraryFile(position.getElementAt());
|
||||
private static JetTypeMapper createTypeMapperForLibraryFile(@Nullable PsiElement notPositionedElement, @NotNull JetFile file) {
|
||||
JetElement element = getElementToCreateTypeMapperForLibraryFile(notPositionedElement);
|
||||
ResolveSessionForBodies resolveSession = ResolvePackage.getLazyResolveSession(element);
|
||||
|
||||
JetFile file = (JetFile) position.getFile();
|
||||
GenerationState state = new GenerationState(file.getProject(), ClassBuilderFactories.THROW_EXCEPTION,
|
||||
resolveSession.getModuleDescriptor(),
|
||||
resolveSession.resolveToElement(element),
|
||||
|
||||
+52
-7
@@ -77,16 +77,11 @@ fun getFunctionForExtractedFragment(
|
||||
|
||||
val originalFile = breakpointFile as JetFile
|
||||
|
||||
val lineStart = CodeInsightUtils.getStartLineOffset(originalFile, breakpointLine)
|
||||
if (lineStart == null) return null
|
||||
|
||||
val tmpFile = originalFile.createTempCopy { it }
|
||||
tmpFile.skipVisibilityCheck = true
|
||||
|
||||
val elementAtOffset = tmpFile.findElementAt(lineStart)
|
||||
if (elementAtOffset == null) return null
|
||||
|
||||
val contextElement: PsiElement = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
|
||||
val contextElement = getExpressionToAddDebugExpressionBefore(tmpFile, codeFragment.getContext(), breakpointLine)
|
||||
if (contextElement == null) return null
|
||||
|
||||
// Don't evaluate smth when breakpoint is on package directive (ex. for package classes)
|
||||
if (contextElement is JetFile) {
|
||||
@@ -137,6 +132,52 @@ private fun addImportsToFile(newImportList: JetImportList?, tmpFile: JetFile) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetFile.getElementInCopy(e: PsiElement): PsiElement? {
|
||||
val offset = e.getTextRange()?.getStartOffset()
|
||||
if (offset == null) {
|
||||
return null
|
||||
}
|
||||
var elementAt = this.findElementAt(offset)
|
||||
while (elementAt == null || elementAt!!.getTextRange()?.getEndOffset() != e.getTextRange()?.getEndOffset()) {
|
||||
elementAt = elementAt?.getParent()
|
||||
}
|
||||
return elementAt
|
||||
}
|
||||
|
||||
private fun getExpressionToAddDebugExpressionBefore(tmpFile: JetFile, contextElement: PsiElement?, line: Int): PsiElement? {
|
||||
if (contextElement == null) {
|
||||
val lineStart = CodeInsightUtils.getStartLineOffset(tmpFile, line)
|
||||
if (lineStart == null) return null
|
||||
|
||||
val elementAtOffset = tmpFile.findElementAt(lineStart)
|
||||
if (elementAtOffset == null) return null
|
||||
|
||||
return CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, lineStart) ?: elementAtOffset
|
||||
}
|
||||
|
||||
fun shouldStop(el: PsiElement?, p: PsiElement?) = p is JetBlockExpression || el is JetDeclaration
|
||||
|
||||
var elementAt = tmpFile.getElementInCopy(contextElement)
|
||||
|
||||
var parent = elementAt?.getParent()
|
||||
if (shouldStop(elementAt, parent)) {
|
||||
return elementAt
|
||||
}
|
||||
|
||||
var parentOfParent = parent?.getParent()
|
||||
|
||||
while (parent != null && parentOfParent != null) {
|
||||
if (shouldStop(parent, parentOfParent)) {
|
||||
break
|
||||
}
|
||||
|
||||
parent = parent?.getParent()
|
||||
parentOfParent = parent?.getParent()
|
||||
}
|
||||
|
||||
return parent
|
||||
}
|
||||
|
||||
private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment, contextElement: PsiElement): JetExpression? {
|
||||
val psiFactory = JetPsiFactory(codeFragment)
|
||||
|
||||
@@ -144,6 +185,10 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment
|
||||
contextElement is JetProperty && !contextElement.isLocal() -> {
|
||||
wrapInRunFun(contextElement.getDelegateExpressionOrInitializer()!!)
|
||||
}
|
||||
contextElement is JetFunctionLiteral -> {
|
||||
val block = contextElement.getBodyExpression()!!
|
||||
block.getStatements().first ?: block.getLastChild()
|
||||
}
|
||||
contextElement is JetDeclarationWithBody && !contextElement.hasBlockBody()-> {
|
||||
wrapInRunFun(contextElement.getBodyExpression()!!)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at callableBug.kt:8
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! callableBug.CallableBugPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
callableBug.kt:7
|
||||
Compile bytecode for callable
|
||||
callableBug.kt:7
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at inlineLambda.kt:9
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! inlineLambda.InlineLambdaPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
inlineLambda.kt:8
|
||||
inlineLambda.kt:8
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,10 @@
|
||||
LineBreakpoint created at lambdaOnSecondLine.kt:10
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! lambdaOnSecondLine.LambdaOnSecondLinePackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
lambdaOnSecondLine.kt:9
|
||||
lambdaOnSecondLine.kt:14
|
||||
lambdaOnSecondLine.kt:9
|
||||
Compile bytecode for it
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,10 @@
|
||||
LineBreakpoint created at oneLineLambda.kt:9
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! oneLineLambda.OneLineLambdaPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
oneLineLambda.kt:8
|
||||
oneLineLambda.kt:13
|
||||
oneLineLambda.kt:8
|
||||
Compile bytecode for it
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,10 @@
|
||||
LineBreakpoint created at twoLambdasOnOneLineFirst.kt:9
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! twoLambdasOnOneLineFirst.TwoLambdasOnOneLineFirstPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
twoLambdasOnOneLineFirst.kt:8
|
||||
twoLambdasOnOneLineFirst.kt:13
|
||||
twoLambdasOnOneLineFirst.kt:8
|
||||
Compile bytecode for it
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,12 @@
|
||||
LineBreakpoint created at twoLambdasOnOneLineSecond.kt:9
|
||||
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! twoLambdasOnOneLineSecond.TwoLambdasOnOneLineSecondPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
twoLambdasOnOneLineSecond.kt:8
|
||||
twoLambdasOnOneLineSecond.kt:15
|
||||
twoLambdasOnOneLineSecond.kt:8
|
||||
twoLambdasOnOneLineSecond.kt:15
|
||||
twoLambdasOnOneLineSecond.kt:8
|
||||
Compile bytecode for it
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,12 @@
|
||||
package callableBug
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val callable = 1
|
||||
array(1, 2).map {
|
||||
it + 1
|
||||
//Breakpoint!
|
||||
}.forEach { it + 2 }
|
||||
}
|
||||
|
||||
// EXPRESSION: callable
|
||||
// RESULT: 1: I
|
||||
@@ -0,0 +1,11 @@
|
||||
package inlineLambda
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = array(1)
|
||||
// EXPRESSION: it
|
||||
// RESULT: Unresolved reference: it
|
||||
// STEP_INTO: 1
|
||||
//Breakpoint!
|
||||
a.map { it * 1 }
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package lambdaOnSecondLine
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = A()
|
||||
// EXPRESSION: it
|
||||
// RESULT: 1: I
|
||||
// STEP_INTO: 2
|
||||
a.foo { a }
|
||||
//Breakpoint!
|
||||
.foo { a }
|
||||
}
|
||||
|
||||
class A {
|
||||
fun foo(f: (Int) -> A): A {
|
||||
return f(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package oneLineLambda
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = A()
|
||||
// EXPRESSION: it
|
||||
// RESULT: 1: I
|
||||
// STEP_INTO: 2
|
||||
//Breakpoint!
|
||||
a.foo { a }
|
||||
}
|
||||
|
||||
class A {
|
||||
fun foo(f: (Int) -> A): A {
|
||||
return f(1)
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package twoLambdasOnOneLineFirst
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = A()
|
||||
// EXPRESSION: it
|
||||
// RESULT: 1: I
|
||||
// STEP_INTO: 2
|
||||
//Breakpoint!
|
||||
a.foo { a }.foo { a }
|
||||
}
|
||||
|
||||
class A {
|
||||
fun foo(f: (Int) -> A): A {
|
||||
return f(1)
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package twoLambdasOnOneLineSecond
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = A()
|
||||
// EXPRESSION: it
|
||||
// RESULT: 2: I
|
||||
// STEP_INTO: 4
|
||||
//Breakpoint!
|
||||
a.foo { counter++; a }.foo { a }
|
||||
}
|
||||
|
||||
var counter = 1
|
||||
|
||||
class A {
|
||||
fun foo(f: (Int) -> A): A {
|
||||
return f(counter)
|
||||
}
|
||||
}
|
||||
+10
-16
@@ -59,7 +59,7 @@ import com.intellij.debugger.DebuggerManagerEx
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
|
||||
public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestCase() {
|
||||
public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestBase() {
|
||||
private val logger = Logger.getLogger(javaClass<KotlinEvaluateExpressionCache>())!!
|
||||
|
||||
private val appender = object : AppenderSkeleton() {
|
||||
@@ -73,7 +73,7 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC
|
||||
private var oldLogLevel: Level? = null
|
||||
|
||||
override fun setUp() {
|
||||
super<KotlinDebuggerTestCase>.setUp()
|
||||
super.setUp()
|
||||
|
||||
oldLogLevel = logger.getLevel()
|
||||
logger.setLevel(Level.DEBUG)
|
||||
@@ -84,7 +84,7 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC
|
||||
logger.setLevel(oldLogLevel)
|
||||
logger.removeAppender(appender)
|
||||
|
||||
super<KotlinDebuggerTestCase>.tearDown()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
fun doSingleBreakpointTest(path: String) {
|
||||
@@ -102,6 +102,13 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC
|
||||
|
||||
createDebugProcess(path)
|
||||
|
||||
val count = InTextDirectivesUtils.getPrefixedInt(fileText, "// STEP_INTO: ") ?: 0
|
||||
if (count > 0) {
|
||||
for (i in 1..count) {
|
||||
onBreakpoint { stepInto() }
|
||||
}
|
||||
}
|
||||
|
||||
onBreakpoint {
|
||||
val exceptions = linkedMapOf<String, Throwable>()
|
||||
try {
|
||||
@@ -275,19 +282,6 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestC
|
||||
return mainFile.getParentFile()?.listFiles()?.filter { it.name.startsWith(mainFileName) && it.name != mainFileName } ?: Collections.emptyList()
|
||||
}
|
||||
|
||||
private fun onBreakpoint(doOnBreakpoint: SuspendContextImpl.() -> Unit) {
|
||||
super.onBreakpoint {
|
||||
super.printContext(it)
|
||||
it.doOnBreakpoint()
|
||||
}
|
||||
}
|
||||
|
||||
private fun finish() {
|
||||
onBreakpoint {
|
||||
resume(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SuspendContextImpl.evaluate(text: String, codeFragmentKind: CodeFragmentKind, expectedResult: String) {
|
||||
ApplicationManager.getApplication()?.runReadAction {
|
||||
val sourcePosition = ContextUtil.getSourcePosition(this)
|
||||
|
||||
+47
-1
@@ -35,7 +35,7 @@ import java.util.regex.Pattern;
|
||||
public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluateExpressionTest {
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({SingleBreakpoint.Frame.class})
|
||||
@InnerTestClasses({SingleBreakpoint.Frame.class, SingleBreakpoint.Lambdas.class})
|
||||
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
|
||||
public static class SingleBreakpoint extends AbstractKotlinEvaluateExpressionTest {
|
||||
@TestMetadata("abstractFunCall.kt")
|
||||
@@ -54,6 +54,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callableBug.kt")
|
||||
public void testCallableBug() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/callableBug.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("classFromAnotherPackage.kt")
|
||||
public void testClassFromAnotherPackage() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/classFromAnotherPackage.kt");
|
||||
@@ -262,6 +268,46 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
|
||||
public static class Lambdas extends AbstractKotlinEvaluateExpressionTest {
|
||||
public void testAllFilesPresentInLambdas() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineLambda.kt")
|
||||
public void testInlineLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/inlineLambda.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaOnSecondLine.kt")
|
||||
public void testLambdaOnSecondLine() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/lambdaOnSecondLine.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("oneLineLambda.kt")
|
||||
public void testOneLineLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/oneLineLambda.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("twoLambdasOnOneLineFirst.kt")
|
||||
public void testTwoLambdasOnOneLineFirst() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/twoLambdasOnOneLineFirst.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("twoLambdasOnOneLineSecond.kt")
|
||||
public void testTwoLambdasOnOneLineSecond() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/lambdas/twoLambdasOnOneLineSecond.kt");
|
||||
doSingleBreakpointTest(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints")
|
||||
|
||||
Reference in New Issue
Block a user