diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java index ce1c22c5e037..cac1fd7a0add 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JumpToObjectAction.java @@ -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 applicableMethods = ContainerUtil.filter(clsType.methods(), m -> m.isPublic() && !m.isBridge()); - if (applicableMethods.size() == 1) { - AtomicReference 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() { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java b/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java index 22a50c1bf81b..bde59d9d3d73 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/BasicStepMethodFilter.java @@ -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)() -> { PsiElement psiMethod = DebuggerUtilsEx.getContainingMethod(position); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DefaultSyntheticProvider.java b/java/debugger/impl/src/com/intellij/debugger/engine/DefaultSyntheticProvider.java index fd162f12a07c..088660ee1d15 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DefaultSyntheticProvider.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DefaultSyntheticProvider.java @@ -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 { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java b/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java index 31e0ff4ce719..b54190967af1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/LambdaMethodFilter.java @@ -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) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 50336f6bb012..83871413ea84 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -192,11 +192,11 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio } int lambdaOrdinal = -1; - if (LambdaMethodFilter.isLambdaName(method.name())) { + if (DebuggerUtilsEx.isLambdaName(method.name())) { Set 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 lambdas = DebuggerUtilsEx.collectLambdas(original, true); Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java index 4f7894429347..3c49b4446f71 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java @@ -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 collectLambdas(@NotNull SourcePosition position, final boolean onlyOnTheLine) { ApplicationManager.getApplication().assertReadAccessAllowed(); PsiFile file = position.getFile(); diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/SourceCodeChecker.java b/java/debugger/impl/src/com/intellij/debugger/impl/SourceCodeChecker.java index 87d229c438e2..b863e0a2b034 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/SourceCodeChecker.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/SourceCodeChecker.java @@ -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 locations = DebuggerUtilsEx.allLineLocations(method); diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java b/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java index e2954617b8b2..e3809bf89fc3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java @@ -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 methodRef = Ref.create(); + if (DebuggerUtilsEx.isLambdaClassName(clsType.name())) { + List 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(); + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java index 71708b2ab9d7..358cb7918d0c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java @@ -153,44 +153,50 @@ public class MethodBreakpoint extends BreakpointWithHighlighter 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 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