mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
emulated method breakpoints now work in lambdas
This commit is contained in:
@@ -34,11 +34,6 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.sun.jdi.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class JumpToObjectAction extends DebuggerAction{
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.JumpToObjectAction");
|
||||
@@ -98,35 +93,19 @@ public class JumpToObjectAction extends DebuggerAction{
|
||||
}
|
||||
|
||||
try {
|
||||
if(type instanceof ArrayType) {
|
||||
if (type instanceof ArrayType) {
|
||||
type = ((ArrayType)type).componentType();
|
||||
}
|
||||
if(type instanceof ClassType) {
|
||||
final ClassType clsType = (ClassType)type;
|
||||
Location lambdaLocation = null;
|
||||
if (DebuggerUtilsEx.isLambdaClassName(clsType.name())) {
|
||||
List<Method> applicableMethods = ContainerUtil.filter(clsType.methods(), m -> m.isPublic() && !m.isBridge());
|
||||
if (applicableMethods.size() == 1) {
|
||||
AtomicReference<Location> locationRef = new AtomicReference<>();
|
||||
MethodBytecodeUtil.visit(clsType, applicableMethods.get(0), new MethodVisitor(Opcodes.API_VERSION) {
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
ReferenceType cls = ContainerUtil.getFirstItem(clsType.virtualMachine().classesByName(owner));
|
||||
if (cls != null) {
|
||||
Method method = ContainerUtil.getFirstItem(cls.methodsByName(name));
|
||||
if (method != null) {
|
||||
Location loc = ContainerUtil.getFirstItem(DebuggerUtilsEx.allLineLocations(method));
|
||||
if (loc != null) {
|
||||
locationRef.set(loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
lambdaLocation = locationRef.get();
|
||||
}
|
||||
if (type instanceof ClassType) {
|
||||
ClassType clsType = (ClassType)type;
|
||||
|
||||
Method lambdaMethod = MethodBytecodeUtil.getLambdaMethod(clsType);
|
||||
Location location = lambdaMethod != null ? ContainerUtil.getFirstItem(DebuggerUtilsEx.allLineLocations(lambdaMethod)) : null;
|
||||
|
||||
if (location == null) {
|
||||
location = ContainerUtil.getFirstItem(clsType.allLineLocations());
|
||||
}
|
||||
final Location location = lambdaLocation != null ? lambdaLocation : ContainerUtil.getFirstItem(clsType.allLineLocations());
|
||||
|
||||
if (location != null) {
|
||||
SourcePosition position = debugProcess.getPositionManager().getSourcePosition(location);
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() {
|
||||
|
||||
@@ -69,7 +69,7 @@ public class BasicStepMethodFilter implements NamedMethodFilter {
|
||||
Method method = location.method();
|
||||
String name = method.name();
|
||||
if (!myTargetMethodName.equals(name)) {
|
||||
if (LambdaMethodFilter.isLambdaName(name)) {
|
||||
if (DebuggerUtilsEx.isLambdaName(name)) {
|
||||
SourcePosition position = process.getPositionManager().getSourcePosition(location);
|
||||
return ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> {
|
||||
PsiElement psiMethod = DebuggerUtilsEx.getContainingMethod(position);
|
||||
|
||||
@@ -26,7 +26,7 @@ public class DefaultSyntheticProvider implements SyntheticTypeComponentProvider
|
||||
@Override
|
||||
public boolean isSynthetic(TypeComponent typeComponent) {
|
||||
String name = typeComponent.name();
|
||||
if (LambdaMethodFilter.isLambdaName(name)) {
|
||||
if (DebuggerUtilsEx.isLambdaName(name)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,8 +17,8 @@ package com.intellij.debugger.engine;
|
||||
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiCodeBlock;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiLambdaExpression;
|
||||
@@ -34,7 +34,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
* Date: 10/26/13
|
||||
*/
|
||||
public class LambdaMethodFilter implements BreakpointStepMethodFilter {
|
||||
public static final String LAMBDA_METHOD_PREFIX = "lambda$";
|
||||
private final int myLambdaOrdinal;
|
||||
@Nullable
|
||||
private final SourcePosition myFirstStatementPosition;
|
||||
@@ -82,7 +81,7 @@ public class LambdaMethodFilter implements BreakpointStepMethodFilter {
|
||||
public boolean locationMatches(DebugProcessImpl process, Location location) throws EvaluateException {
|
||||
final VirtualMachineProxyImpl vm = process.getVirtualMachineProxy();
|
||||
final Method method = location.method();
|
||||
return isLambdaName(method.name()) && (!vm.canGetSyntheticAttribute() || method.isSynthetic());
|
||||
return DebuggerUtilsEx.isLambdaName(method.name()) && (!vm.canGetSyntheticAttribute() || method.isSynthetic());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -91,10 +90,6 @@ public class LambdaMethodFilter implements BreakpointStepMethodFilter {
|
||||
return myCallingExpressionLines;
|
||||
}
|
||||
|
||||
public static boolean isLambdaName(@Nullable String name) {
|
||||
return !StringUtil.isEmpty(name) && name.startsWith(LAMBDA_METHOD_PREFIX);
|
||||
}
|
||||
|
||||
public static int getLambdaOrdinal(@NotNull String name) {
|
||||
int pos = name.lastIndexOf('$');
|
||||
if (pos > -1) {
|
||||
|
||||
@@ -192,11 +192,11 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
|
||||
}
|
||||
|
||||
int lambdaOrdinal = -1;
|
||||
if (LambdaMethodFilter.isLambdaName(method.name())) {
|
||||
if (DebuggerUtilsEx.isLambdaName(method.name())) {
|
||||
Set<Method> lambdas =
|
||||
ContainerUtil.map2SetNotNull(locationsOfLine(location.declaringType(), sourcePosition), location1 -> {
|
||||
Method method1 = location1.method();
|
||||
if (LambdaMethodFilter.isLambdaName(method1.name())) {
|
||||
if (DebuggerUtilsEx.isLambdaName(method1.name())) {
|
||||
return method1;
|
||||
}
|
||||
return null;
|
||||
@@ -233,7 +233,7 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
|
||||
return null;
|
||||
}
|
||||
else if (((method instanceof PsiMethod && myExpectedMethodName.equals(((PsiMethod)method).getName())) ||
|
||||
(method instanceof PsiLambdaExpression && LambdaMethodFilter.isLambdaName(myExpectedMethodName))) &&
|
||||
(method instanceof PsiLambdaExpression && DebuggerUtilsEx.isLambdaName(myExpectedMethodName))) &&
|
||||
insideBody(element, DebuggerUtilsEx.getBody(method))) {
|
||||
return element;
|
||||
}
|
||||
@@ -256,7 +256,7 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
|
||||
public SourcePosition compute() {
|
||||
PsiFile file = original.getFile();
|
||||
int line = original.getLine();
|
||||
if (LambdaMethodFilter.isLambdaName(myExpectedMethodName) && myLambdaOrdinal > -1) {
|
||||
if (DebuggerUtilsEx.isLambdaName(myExpectedMethodName) && myLambdaOrdinal > -1) {
|
||||
List<PsiLambdaExpression> lambdas = DebuggerUtilsEx.collectLambdas(original, true);
|
||||
|
||||
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
|
||||
|
||||
@@ -803,6 +803,10 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
|
||||
return StringUtil.substringBefore(typeName, "$$Lambda$");
|
||||
}
|
||||
|
||||
public static boolean isLambdaName(@Nullable String name) {
|
||||
return !StringUtil.isEmpty(name) && name.startsWith("lambda$");
|
||||
}
|
||||
|
||||
public static List<PsiLambdaExpression> collectLambdas(@NotNull SourcePosition position, final boolean onlyOnTheLine) {
|
||||
ApplicationManager.getApplication().assertReadAccessAllowed();
|
||||
PsiFile file = position.getFile();
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.NoDataException;
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.LambdaMethodFilter;
|
||||
import com.intellij.debugger.engine.PositionManagerImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
@@ -103,7 +102,7 @@ public class SourceCodeChecker {
|
||||
method.isBridge() ||
|
||||
method.isStaticInitializer() ||
|
||||
(method.declaringType() instanceof ClassType && ((ClassType)method.declaringType()).isEnum()) ||
|
||||
LambdaMethodFilter.isLambdaName(method.name())) {
|
||||
DebuggerUtilsEx.isLambdaName(method.name())) {
|
||||
return ThreeState.UNSURE;
|
||||
}
|
||||
List<Location> locations = DebuggerUtilsEx.allLineLocations(method);
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
package com.intellij.debugger.jdi;
|
||||
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import com.intellij.util.ThrowableConsumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.sun.jdi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -220,4 +222,27 @@ public class MethodBytecodeUtil {
|
||||
return OBJECT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Method getLambdaMethod(ReferenceType clsType) {
|
||||
Ref<Method> methodRef = Ref.create();
|
||||
if (DebuggerUtilsEx.isLambdaClassName(clsType.name())) {
|
||||
List<Method> applicableMethods = ContainerUtil.filter(clsType.methods(), m -> m.isPublic() && !m.isBridge());
|
||||
if (applicableMethods.size() == 1) {
|
||||
visit(clsType, applicableMethods.get(0), new MethodVisitor(Opcodes.API_VERSION) {
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
ReferenceType cls = ContainerUtil.getFirstItem(clsType.virtualMachine().classesByName(owner));
|
||||
if (cls != null) {
|
||||
Method method = ContainerUtil.getFirstItem(cls.methodsByName(name));
|
||||
if (method != null) {
|
||||
methodRef.set(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return methodRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,44 +153,50 @@ public class MethodBreakpoint extends BreakpointWithHighlighter<JavaMethodBreakp
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (Method method : classType.methods()) {
|
||||
if (getMethodName().equals(method.name()) && mySignature.getName(debugProcess).equals(method.signature())) {
|
||||
List<Location> allLineLocations = DebuggerUtilsEx.allLineLocations(method);
|
||||
if (!allLineLocations.isEmpty()) {
|
||||
if (isWatchEntry()) {
|
||||
createLocationBreakpointRequest(ContainerUtil.getFirstItem(allLineLocations), debugProcess);
|
||||
}
|
||||
if (isWatchExit()) {
|
||||
MethodBytecodeUtil.visit(classType, method, new MethodVisitor(Opcodes.API_VERSION) {
|
||||
int myLastLine = 0;
|
||||
@Override
|
||||
public void visitLineNumber(int line, Label start) {
|
||||
myLastLine = line;
|
||||
}
|
||||
Method method = MethodBytecodeUtil.getLambdaMethod(classType);
|
||||
if (method == null) {
|
||||
for (Method m : classType.methods()) {
|
||||
if (getMethodName().equals(m.name()) && mySignature.getName(debugProcess).equals(m.signature())) {
|
||||
method = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method != null) {
|
||||
List<Location> allLineLocations = DebuggerUtilsEx.allLineLocations(method);
|
||||
if (!allLineLocations.isEmpty()) {
|
||||
if (isWatchEntry()) {
|
||||
createLocationBreakpointRequest(ContainerUtil.getFirstItem(allLineLocations), debugProcess);
|
||||
}
|
||||
if (isWatchExit()) {
|
||||
MethodBytecodeUtil.visit(classType, method, new MethodVisitor(Opcodes.API_VERSION) {
|
||||
int myLastLine = 0;
|
||||
@Override
|
||||
public void visitLineNumber(int line, Label start) {
|
||||
myLastLine = line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
switch (opcode) {
|
||||
case Opcodes.RETURN:
|
||||
case Opcodes.IRETURN:
|
||||
case Opcodes.FRETURN:
|
||||
case Opcodes.ARETURN:
|
||||
case Opcodes.LRETURN:
|
||||
case Opcodes.DRETURN:
|
||||
//case Opcodes.ATHROW:
|
||||
allLineLocations.stream()
|
||||
.filter(l -> l.lineNumber() == myLastLine)
|
||||
.findFirst().ifPresent(location -> createLocationBreakpointRequest(location, debugProcess));
|
||||
}
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
switch (opcode) {
|
||||
case Opcodes.RETURN:
|
||||
case Opcodes.IRETURN:
|
||||
case Opcodes.FRETURN:
|
||||
case Opcodes.ARETURN:
|
||||
case Opcodes.LRETURN:
|
||||
case Opcodes.DRETURN:
|
||||
//case Opcodes.ATHROW:
|
||||
allLineLocations.stream()
|
||||
.filter(l -> l.lineNumber() == myLastLine)
|
||||
.findFirst().ifPresent(location -> createLocationBreakpointRequest(location, debugProcess));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (base) {
|
||||
// desired class found - now also track all new classes
|
||||
createRequestForSubClasses(debugProcess, classType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (base) {
|
||||
// desired class found - now also track all new classes
|
||||
createRequestForSubClasses(debugProcess, classType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,6 +364,9 @@ public class MethodBreakpoint extends BreakpointWithHighlighter<JavaMethodBreakp
|
||||
}
|
||||
|
||||
public boolean matchesEvent(@NotNull final LocatableEvent event, final DebugProcessImpl process) throws EvaluateException {
|
||||
if (isEmulated()) {
|
||||
return true;
|
||||
}
|
||||
if (getMethodName() == null || mySignature == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user