From 04a549e4bb6aeadb4ae7309be4c9c6cae531bae4 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 5 Apr 2017 15:02:59 +0300 Subject: [PATCH] IDEA-165155 Java conditional breakpoint on expression or single-line lambda does not give access to lambda parameters --- .../debugger/engine/PositionManagerImpl.java | 64 ++++++++++--------- .../engine/RemappedSourcePosition.java | 4 +- .../debugger/impl/DebuggerUtilsEx.java | 14 ++++ .../BreakpointWithHighlighter.java | 14 ++-- .../breakpoints/JavaLineBreakpointType.java | 58 ++++++++++++----- .../breakpoints/XLineBreakpointType.java | 6 +- .../impl/breakpoints/XLineBreakpointImpl.java | 17 ++--- 7 files changed, 109 insertions(+), 68 deletions(-) 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 808a2fd701a5..cc0248b49442 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -25,6 +25,7 @@ import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.debugger.requests.ClassPrepareRequestor; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; @@ -203,18 +204,26 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio return new JavaSourcePosition(sourcePosition, location.declaringType(), method, lambdaOrdinal); } - private static class JavaSourcePosition extends RemappedSourcePosition { + public static class JavaSourcePosition extends RemappedSourcePosition { private final String myExpectedClassName; private final String myExpectedMethodName; private final int myLambdaOrdinal; - public JavaSourcePosition(SourcePosition delegate, ReferenceType declaringType, Method method, int lambdaOrdinal) { + public JavaSourcePosition(@NotNull SourcePosition delegate, ReferenceType declaringType, Method method, int lambdaOrdinal) { super(delegate); myExpectedClassName = declaringType != null ? declaringType.name() : null; myExpectedMethodName = method != null ? method.name() : null; myLambdaOrdinal = lambdaOrdinal; } + public JavaSourcePosition(@NotNull SourcePosition delegate, int lambdaOrdinal) { + super(delegate); + assert lambdaOrdinal > -1; + myExpectedClassName = null; + myExpectedMethodName = "lambda$"; // fake lambda name + myLambdaOrdinal = lambdaOrdinal; + } + private PsiElement remapElement(PsiElement element) { String name = JVMNameUtil.getClassVMName(getEnclosingClass(element)); if (name != null && !name.equals(myExpectedClassName)) { @@ -244,37 +253,34 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio @Override public SourcePosition mapDelegate(final SourcePosition original) { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public SourcePosition compute() { - PsiFile file = original.getFile(); - int line = original.getLine(); - if (DebuggerUtilsEx.isLambdaName(myExpectedMethodName) && myLambdaOrdinal > -1) { - List lambdas = DebuggerUtilsEx.collectLambdas(original, true); + return ReadAction.compute(() -> { + PsiFile file = original.getFile(); + int line = original.getLine(); + if (DebuggerUtilsEx.isLambdaName(myExpectedMethodName) && myLambdaOrdinal > -1) { + List lambdas = DebuggerUtilsEx.collectLambdas(original, true); - Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); - if (document == null || line >= document.getLineCount()) { - return original; - } - if (myLambdaOrdinal < lambdas.size()) { - PsiElement firstElem = DebuggerUtilsEx.getFirstElementOnTheLine(lambdas.get(myLambdaOrdinal), document, line); - if (firstElem != null) { - return SourcePosition.createFromElement(firstElem); - } + Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); + if (document == null || line >= document.getLineCount()) { + return original; + } + if (myLambdaOrdinal < lambdas.size()) { + PsiElement firstElem = DebuggerUtilsEx.getFirstElementOnTheLine(lambdas.get(myLambdaOrdinal), document, line); + if (firstElem != null) { + return SourcePosition.createFromElement(firstElem); } } - else { - // There may be more than one class/method code on the line, so we need to find out the correct place - for (PsiElement elem : getLineElements(file, line)) { - PsiElement remappedElement = remapElement(elem); - if (remappedElement != null) { - if (remappedElement.getTextOffset() <= original.getOffset()) break; - return SourcePosition.createFromElement(remappedElement); - } - } - } - return original; } + else { + // There may be more than one class/method code on the line, so we need to find out the correct place + for (PsiElement elem : getLineElements(file, line)) { + PsiElement remappedElement = remapElement(elem); + if (remappedElement != null) { + if (remappedElement.getTextOffset() <= original.getOffset()) break; + return SourcePosition.createFromElement(remappedElement); + } + } + } + return original; }); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/RemappedSourcePosition.java b/java/debugger/impl/src/com/intellij/debugger/engine/RemappedSourcePosition.java index 8fb462314bd9..51d2bd00017e 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/RemappedSourcePosition.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/RemappedSourcePosition.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -28,7 +28,7 @@ abstract class RemappedSourcePosition extends SourcePosition { private SourcePosition myDelegate; private boolean myMapped = false; - public RemappedSourcePosition(SourcePosition delegate) { + public RemappedSourcePosition(@NotNull SourcePosition delegate) { myDelegate = delegate; } 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 63e3db1c90f1..7ea837515204 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java @@ -761,6 +761,20 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils { return null; } + @Nullable + public static SourcePosition toSourcePosition(@Nullable XSourcePosition position, Project project) { + if (position != null) { + if (position instanceof JavaXSourcePosition) { + return ((JavaXSourcePosition)position).mySourcePosition; + } + PsiFile psiFile = PsiManager.getInstance(project).findFile(position.getFile()); + if (psiFile != null) { + return SourcePosition.createFromLine(psiFile, position.getLine()); + } + } + return null; + } + private static class JavaXSourcePosition implements XSourcePosition, ExecutionPointHighlighter.HighlighterProvider { private final SourcePosition mySourcePosition; @NotNull private final VirtualFile myFile; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java index 2e4ec9617827..628309e30364 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -23,6 +23,7 @@ import com.intellij.debugger.engine.JVMNameUtil; import com.intellij.debugger.engine.events.DebuggerCommandImpl; import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.impl.DebuggerContextImpl; +import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -235,14 +236,9 @@ public abstract class BreakpointWithHighlighter

computeVariants(@NotNull Project project, @NotNull XSourcePosition position) { - PsiFile file = PsiManager.getInstance(project).findFile(position.getFile()); - if (file == null) { + SourcePosition pos = DebuggerUtilsEx.toSourcePosition(position, project); + if (pos == null) { return Collections.emptyList(); } - SourcePosition pos = SourcePosition.createFromLine(file, position.getLine()); List lambdas = DebuggerUtilsEx.collectLambdas(pos, true); if (lambdas.isEmpty()) { return Collections.emptyList(); @@ -116,7 +117,7 @@ public class JavaLineBreakpointType extends JavaLineBreakpointTypeBase breakpoint) { - JavaLineBreakpointProperties properties = breakpoint.getProperties(); - if (properties != null) { - Integer ordinal = properties.getLambdaOrdinal(); - if (ordinal != null) { - Breakpoint javaBreakpoint = BreakpointManager.getJavaBreakpoint(breakpoint); - if (javaBreakpoint instanceof LineBreakpoint) { - PsiElement method = getContainingMethod((LineBreakpoint)javaBreakpoint); - if (method != null) { - return method.getTextRange(); - } + Integer ordinal = getLambdaOrdinal(breakpoint); + if (ordinal != null) { + Breakpoint javaBreakpoint = BreakpointManager.getJavaBreakpoint(breakpoint); + if (javaBreakpoint instanceof LineBreakpoint) { + PsiElement method = getContainingMethod((LineBreakpoint)javaBreakpoint); + if (method != null) { + return method.getTextRange(); } } } return null; } + @Override + public XSourcePosition getSourcePosition(@NotNull XBreakpoint breakpoint) { + Integer ordinal = getLambdaOrdinal(breakpoint); + if (ordinal != null && ordinal > -1) { + SourcePosition linePosition = createLineSourcePosition((XLineBreakpointImpl)breakpoint); + if (linePosition != null) { + return DebuggerUtilsEx.toXSourcePosition(new PositionManagerImpl.JavaSourcePosition(linePosition, ordinal)); + } + } + return null; + } + + @Nullable + private static Integer getLambdaOrdinal(XBreakpoint breakpoint) { + JavaLineBreakpointProperties properties = breakpoint.getProperties(); + return properties != null ? properties.getLambdaOrdinal() : null; + } + + @Nullable + private static SourcePosition createLineSourcePosition(XLineBreakpointImpl breakpoint) { + VirtualFile file = breakpoint.getFile(); + if (file != null) { + PsiFile psiFile = PsiManager.getInstance(breakpoint.getProject()).findFile(file); + if (psiFile != null) { + return SourcePosition.createFromLine(psiFile, breakpoint.getLine()); + } + } + return null; + } + @Override public boolean canBeHitInOtherPlaces() { return true; // line breakpoints could be hit in other versions of the same classes diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java index d526ead2df76..47320ec0354d 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -76,10 +76,10 @@ public abstract class XLineBreakpointType

exten } /** - * Source position for line breakpoint is determined by its file and line + * Source position for line breakpoint by default is determined by its file and line */ @Override - public final XSourcePosition getSourcePosition(@NotNull XBreakpoint

breakpoint) { + public XSourcePosition getSourcePosition(@NotNull XBreakpoint

breakpoint) { return null; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java index 47d67064a56b..9ca82c47ad7a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,6 @@ package com.intellij.xdebugger.impl.breakpoints; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.application.Result; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; @@ -148,7 +146,7 @@ public class XLineBreakpointImpl

extends XBreak } @Nullable - private VirtualFile getFile() { + public VirtualFile getFile() { return VirtualFileManager.getInstance().findFileByUrl(getFileUrl()); } @@ -191,13 +189,12 @@ public class XLineBreakpointImpl

extends XBreak @Override public XSourcePosition getSourcePosition() { + if (mySourcePosition != null) { + return mySourcePosition; + } + mySourcePosition = super.getSourcePosition(); if (mySourcePosition == null) { - new ReadAction() { - @Override - protected void run(@NotNull Result result) { - mySourcePosition = XDebuggerUtil.getInstance().createPosition(getFile(), getLine()); - } - }.execute(); + mySourcePosition = XDebuggerUtil.getInstance().createPosition(getFile(), getLine()); } return mySourcePosition; }