From f5ab6904f55853e4baf5c459eb38125b42338da7 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 12 Oct 2022 12:42:12 +0800 Subject: [PATCH 01/94] Bump version to 0.41.0 (#450) --- .project | 4 ++-- com.microsoft.java.debug.core/.project | 4 ++-- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/.project | 4 ++-- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/.project | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.project b/.project index d34865de3..f00ccfc41 100644 --- a/.project +++ b/.project @@ -16,12 +16,12 @@ - 1600224298170 + 1665543654766 30 org.eclipse.core.resources.regexFilterMatcher - node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ diff --git a/com.microsoft.java.debug.core/.project b/com.microsoft.java.debug.core/.project index a7480133e..353c44be5 100644 --- a/com.microsoft.java.debug.core/.project +++ b/com.microsoft.java.debug.core/.project @@ -28,12 +28,12 @@ - 1599036548523 + 1665543654702 30 org.eclipse.core.resources.regexFilterMatcher - node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 83fed3cc9..8bb9b9f47 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.40.0 + 0.41.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index b7e330e32..349cb7844 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/.project b/com.microsoft.java.debug.plugin/.project index 72ba17ff7..529a656dd 100644 --- a/com.microsoft.java.debug.plugin/.project +++ b/com.microsoft.java.debug.plugin/.project @@ -39,12 +39,12 @@ - 1599036548577 + 1665543654719 30 org.eclipse.core.resources.regexFilterMatcher - node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 9667f9e51..21e32bbde 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.40.0 +Bundle-Version: 0.41.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.40.0.jar + lib/com.microsoft.java.debug.core-0.41.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 56bb813e6..949512717 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.40.0 + 0.41.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.40.0 + 0.41.0 diff --git a/com.microsoft.java.debug.repository/.project b/com.microsoft.java.debug.repository/.project index 887e4a7a8..255908647 100644 --- a/com.microsoft.java.debug.repository/.project +++ b/com.microsoft.java.debug.repository/.project @@ -16,12 +16,12 @@ - 1600224298119 + 1665543654735 30 org.eclipse.core.resources.regexFilterMatcher - node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 7d8519073..27c76516b 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 43cd80e43..b8524fa90 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.40.0 + 0.41.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/pom.xml b/pom.xml index 2b0497f26..4d31432d9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.40.0 + 0.41.0 pom Java Debug Server for Visual Studio Code From c471efc6671adfb12538a94b13f659d590c06b4d Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Tue, 9 Aug 2022 20:50:57 +0200 Subject: [PATCH 02/94] Add support for StepInTarget request The change implement the StepInTarget request and also update the StepRequestHandler to support StepInTarget as well. --- .../java/debug/core/adapter/DebugAdapter.java | 3 + .../core/adapter/ISourceLookUpProvider.java | 52 +++++ .../handler/InitializeRequestHandler.java | 1 + .../handler/StepInTargetsRequestHandler.java | 81 ++++++++ .../adapter/handler/StepRequestHandler.java | 195 ++++++++++++------ .../java/debug/core/protocol/Requests.java | 6 + .../java/debug/core/protocol/Responses.java | 9 + .../java/debug/core/protocol/Types.java | 16 ++ .../microsoft/java/debug/BindingUtils.java | 74 +++++++ .../java/debug/BreakpointLocationLocator.java | 20 +- .../java/debug/LambdaExpressionLocator.java | 5 +- .../internal/JdtSourceLookUpProvider.java | 147 +++++++++---- .../internal/MethodInvocationLocator.java | 66 ++++++ 13 files changed, 551 insertions(+), 124 deletions(-) create mode 100644 com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java create mode 100644 com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java create mode 100644 com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java index edc771163..b853e0469 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java @@ -44,6 +44,7 @@ import com.microsoft.java.debug.core.adapter.handler.SetVariableRequestHandler; import com.microsoft.java.debug.core.adapter.handler.SourceRequestHandler; import com.microsoft.java.debug.core.adapter.handler.StackTraceRequestHandler; +import com.microsoft.java.debug.core.adapter.handler.StepInTargetsRequestHandler; import com.microsoft.java.debug.core.adapter.handler.StepRequestHandler; import com.microsoft.java.debug.core.adapter.handler.ThreadsRequestHandler; import com.microsoft.java.debug.core.adapter.handler.VariablesRequestHandler; @@ -131,6 +132,8 @@ private void initialize() { registerHandlerForDebug(new ProcessIdHandler()); registerHandlerForDebug(new SetFunctionBreakpointsRequestHandler()); registerHandlerForDebug(new BreakpointLocationsRequestHander()); + registerHandlerForDebug(new StepInTargetsRequestHandler()); + // NO_DEBUG mode only registerHandlerForNoDebug(new DisconnectRequestWithoutDebuggingHandler()); registerHandlerForNoDebug(new ProcessIdHandler()); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java index 9976fc16f..5e8d94451 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java @@ -11,10 +11,15 @@ package com.microsoft.java.debug.core.adapter; +import java.util.List; +import java.util.Objects; + import com.microsoft.java.debug.core.DebugException; import com.microsoft.java.debug.core.JavaBreakpointLocation; import com.microsoft.java.debug.core.protocol.Types.SourceBreakpoint; +import com.sun.jdi.StackFrame; + public interface ISourceLookUpProvider extends IProvider { boolean supportsRealtimeBreakpointVerification(); @@ -60,4 +65,51 @@ public interface ISourceLookUpProvider extends IProvider { default String getJavaRuntimeVersion(String projectName) { return null; } + + /** + * Return method invocation found in the statement as the given line number of + * the source file. + * + * @param stackframe The stack frame where the invocation must be searched. + * + * @return List of found method invocation or empty if not method invocations + * can be found. + */ + List findMethodInvocations(StackFrame stackframe); + + public static class MethodInvocation { + public String expression; + public String methodName; + public String methodSignature; + public String declaringTypeName; + public int lineStart; + public int lineEnd; + public int columnStart; + public int columnEnd; + + @Override + public int hashCode() { + return Objects.hash(columnEnd, columnStart, declaringTypeName, expression, lineEnd, lineStart, methodName, + methodSignature); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MethodInvocation other = (MethodInvocation) obj; + return columnEnd == other.columnEnd && columnStart == other.columnStart + && Objects.equals(declaringTypeName, other.declaringTypeName) + && Objects.equals(expression, other.expression) && lineEnd == other.lineEnd + && lineStart == other.lineStart && Objects.equals(methodName, other.methodName) + && Objects.equals(methodSignature, other.methodSignature); + } + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java index 19bbd7d62..bf60b6456 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java @@ -65,6 +65,7 @@ public CompletableFuture handle(Requests.Command command, Req caps.supportsFunctionBreakpoints = true; caps.supportsClipboardContext = true; caps.supportsBreakpointLocationsRequest = true; + caps.supportsStepInTargetsRequest = true; response.body = caps; return CompletableFuture.completedFuture(response); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java new file mode 100644 index 000000000..f61d2a8b9 --- /dev/null +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java @@ -0,0 +1,81 @@ +/******************************************************************************* +* Copyright (c) 2022 Microsoft Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Gayan Perera - initial API and implementation +*******************************************************************************/ +package com.microsoft.java.debug.core.adapter.handler; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; +import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; +import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider; +import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider.MethodInvocation; +import com.microsoft.java.debug.core.adapter.variables.StackFrameReference; +import com.microsoft.java.debug.core.protocol.Messages.Response; +import com.microsoft.java.debug.core.protocol.Requests.Arguments; +import com.microsoft.java.debug.core.protocol.Requests.Command; +import com.microsoft.java.debug.core.protocol.Requests.StepInTargetsArguments; +import com.microsoft.java.debug.core.protocol.Responses.StepInTargetsResponse; +import com.microsoft.java.debug.core.protocol.Types.StepInTarget; +import com.sun.jdi.StackFrame; + +public class StepInTargetsRequestHandler implements IDebugRequestHandler { + + @Override + public List getTargetCommands() { + return Arrays.asList(Command.STEPIN_TARGETS); + } + + @Override + public CompletableFuture handle(Command command, Arguments arguments, Response response, + IDebugAdapterContext context) { + final StepInTargetsArguments stepInTargetsArguments = (StepInTargetsArguments) arguments; + + final int frameId = stepInTargetsArguments.frameId; + return CompletableFuture.supplyAsync(() -> { + response.body = new StepInTargetsResponse( + findFrame(frameId, context).map(f -> findTargets(f.thread().uniqueID(), f, context)) + .orElse(Collections.emptyList()).toArray(StepInTarget[]::new)); + return response; + }); + } + + private Optional findFrame(int frameId, IDebugAdapterContext context) { + Object object = context.getRecyclableIdPool().getObjectById(frameId); + if (object instanceof StackFrameReference) { + return Optional.of(context.getStackFrameManager().getStackFrame((StackFrameReference) object)); + } + return Optional.empty(); + } + + private List findTargets(long threadId, StackFrame stackframe, IDebugAdapterContext context) { + ISourceLookUpProvider sourceLookUpProvider = context.getProvider(ISourceLookUpProvider.class); + List invocations = sourceLookUpProvider.findMethodInvocations(stackframe); + if (invocations.isEmpty()) { + return Collections.emptyList(); + } + + List targets = new ArrayList<>(invocations.size()); + for (MethodInvocation methodInvocation : invocations) { + int id = context.getRecyclableIdPool().addObject(threadId, methodInvocation); + StepInTarget target = new StepInTarget(id, methodInvocation.expression); + target.column = methodInvocation.columnStart; + target.endColumn = methodInvocation.columnEnd; + target.line = methodInvocation.lineStart; + target.endLine = methodInvocation.lineEnd; + targets.add(target); + } + return targets; + } +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java index 51e41bafc..f9baa0e5d 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java @@ -14,6 +14,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -29,19 +31,24 @@ import com.microsoft.java.debug.core.adapter.ErrorCode; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; +import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider.MethodInvocation; import com.microsoft.java.debug.core.protocol.Events; import com.microsoft.java.debug.core.protocol.Messages.Response; import com.microsoft.java.debug.core.protocol.Requests.Arguments; import com.microsoft.java.debug.core.protocol.Requests.Command; import com.microsoft.java.debug.core.protocol.Requests.StepArguments; import com.microsoft.java.debug.core.protocol.Requests.StepFilters; +import com.microsoft.java.debug.core.protocol.Requests.StepInArguments; +import com.sun.jdi.AbsentInformationException; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.Location; import com.sun.jdi.Method; import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadReference; import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; import com.sun.jdi.VoidValue; import com.sun.jdi.event.BreakpointEvent; import com.sun.jdi.event.Event; @@ -67,10 +74,13 @@ public List getTargetCommands() { public CompletableFuture handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) { if (context.getDebugSession() == null) { - return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.EMPTY_DEBUG_SESSION, "Debug Session doesn't exist."); + return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.EMPTY_DEBUG_SESSION, + "Debug Session doesn't exist."); } - long threadId = ((StepArguments) arguments).threadId; + StepArguments stepArguments = (StepArguments) arguments; + long threadId = stepArguments.threadId; + int targetId = (stepArguments instanceof StepInArguments) ? ((StepInArguments) stepArguments).targetId : 0; ThreadReference thread = context.getThreadCache().getThread(threadId); if (thread == null) { thread = DebugUtility.getThread(context.getDebugSession(), threadId); @@ -83,28 +93,34 @@ public CompletableFuture handle(Command command, Arguments arguments, ThreadState threadState = new ThreadState(); threadState.threadId = threadId; threadState.pendingStepType = command; + threadState.stackDepth = thread.frameCount(); + threadState.stepLocation = resolveLocation(thread, targetId, context); + threadState.targetStepIn = targetId > 0; threadState.eventSubscription = context.getDebugSession().getEventHub().events() - .filter(debugEvent -> (debugEvent.event instanceof StepEvent && debugEvent.event.request().equals(threadState.pendingStepRequest)) - || (debugEvent.event instanceof MethodExitEvent && debugEvent.event.request().equals(threadState.pendingMethodExitRequest)) - || debugEvent.event instanceof BreakpointEvent - || debugEvent.event instanceof ExceptionEvent) - .subscribe(debugEvent -> { - handleDebugEvent(debugEvent, context.getDebugSession(), context, threadState); - }); + .filter(debugEvent -> (debugEvent.event instanceof StepEvent + && debugEvent.event.request().equals(threadState.pendingStepRequest)) + || (debugEvent.event instanceof MethodExitEvent + && debugEvent.event.request().equals(threadState.pendingMethodExitRequest)) + || debugEvent.event instanceof BreakpointEvent + || debugEvent.event instanceof ExceptionEvent) + .subscribe(debugEvent -> { + handleDebugEvent(debugEvent, context.getDebugSession(), context, threadState); + }); if (command == Command.STEPIN) { threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, - context.getStepFilters().allowClasses, - context.getStepFilters().skipClasses); + context.getStepFilters().allowClasses, + context.getStepFilters().skipClasses); } else if (command == Command.STEPOUT) { threadState.pendingStepRequest = DebugUtility.createStepOutRequest(thread, - context.getStepFilters().allowClasses, - context.getStepFilters().skipClasses); + context.getStepFilters().allowClasses, + context.getStepFilters().skipClasses); } else { threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread, null); } - threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager().createMethodExitRequest(); + threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager() + .createMethodExitRequest(); threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); if (context.asyncJDWP()) { @@ -114,7 +130,8 @@ public CompletableFuture handle(Command command, Arguments arguments, // JDWP Command: TR_FRAMES threadState.topFrame = getTopFrame(targetThread); threadState.stepLocation = threadState.topFrame.location(); - threadState.pendingMethodExitRequest.addClassFilter(threadState.stepLocation.declaringType()); + threadState.pendingMethodExitRequest + .addClassFilter(threadState.stepLocation.declaringType()); if (targetThread.virtualMachine().canUseInstanceFilters()) { try { // JDWP Command: SF_THIS_OBJECT @@ -131,9 +148,8 @@ public CompletableFuture handle(Command command, Arguments arguments, } })); futures.add(AsyncJdwpUtils.runAsync( - // JDWP Command: OR_IS_COLLECTED - () -> threadState.pendingMethodExitRequest.addThreadFilter(targetThread) - )); + // JDWP Command: OR_IS_COLLECTED + () -> threadState.pendingMethodExitRequest.addThreadFilter(targetThread))); futures.add(AsyncJdwpUtils.runAsync(() -> { try { // JDWP Command: TR_FRAME_COUNT @@ -143,9 +159,8 @@ public CompletableFuture handle(Command command, Arguments arguments, } })); futures.add( - // JDWP Command: ER_SET - AsyncJdwpUtils.runAsync(() -> threadState.pendingStepRequest.enable()) - ); + // JDWP Command: ER_SET + AsyncJdwpUtils.runAsync(() -> threadState.pendingStepRequest.enable())); try { AsyncJdwpUtils.await(futures); @@ -184,39 +199,80 @@ public CompletableFuture handle(Command command, Arguments arguments, } catch (IncompatibleThreadStateException ex) { // Roll back the Exception info if stepping fails. context.getExceptionManager().setException(threadId, exception); - final String failureMessage = String.format("Failed to step because the thread '%s' is not suspended in the target VM.", thread.name()); + final String failureMessage = String.format( + "Failed to step because the thread '%s' is not suspended in the target VM.", thread.name()); throw AdapterUtils.createCompletionException( - failureMessage, - ErrorCode.STEP_FAILURE, - ex); + failureMessage, + ErrorCode.STEP_FAILURE, + ex); } catch (IndexOutOfBoundsException ex) { // Roll back the Exception info if stepping fails. context.getExceptionManager().setException(threadId, exception); - final String failureMessage = String.format("Failed to step because the thread '%s' doesn't contain any stack frame", thread.name()); + final String failureMessage = String.format( + "Failed to step because the thread '%s' doesn't contain any stack frame", thread.name()); throw AdapterUtils.createCompletionException( - failureMessage, - ErrorCode.STEP_FAILURE, - ex); + failureMessage, + ErrorCode.STEP_FAILURE, + ex); + } catch (AbsentInformationException ex) { + // Roll back the Exception info if stepping fails. + context.getExceptionManager().setException(threadId, exception); + final String failureMessage = String.format( + "Failed to step because the thread '%s' doesn't contain required line information in stack frame", + thread.name()); + throw AdapterUtils.createCompletionException( + failureMessage, + ErrorCode.STEP_FAILURE, + ex); } catch (Exception ex) { // Roll back the Exception info if stepping fails. context.getExceptionManager().setException(threadId, exception); - final String failureMessage = String.format("Failed to step because of the error '%s'", ex.getMessage()); + final String failureMessage = String.format("Failed to step because of the error '%s'", + ex.getMessage()); throw AdapterUtils.createCompletionException( - failureMessage, - ErrorCode.STEP_FAILURE, - ex.getCause() != null ? ex.getCause() : ex); + failureMessage, + ErrorCode.STEP_FAILURE, + ex.getCause() != null ? ex.getCause() : ex); } } return CompletableFuture.completedFuture(response); } + private Location resolveLocation(ThreadReference thread, int targetId, IDebugAdapterContext context) + throws IncompatibleThreadStateException, AbsentInformationException { + if (targetId > 0) { + Object value = context.getRecyclableIdPool().getObjectById(targetId); + if (value instanceof MethodInvocation) { + MethodInvocation invocation = (MethodInvocation) value; + VirtualMachine vm = thread.virtualMachine(); + List refTypes = vm.classesByName(invocation.declaringTypeName); + for (ReferenceType referenceType : refTypes) { + Optional location = referenceType.allLineLocations().stream() + .filter(l -> matchesLocation(l, invocation)) + .findFirst(); + if (location.isPresent()) { + return location.get(); + } + } + } + } + return getTopFrame(thread).location(); + } + + private boolean matchesLocation(Location l, MethodInvocation invocation) { + Method method = l.method(); + return method != null && Objects.equals(method.name(), invocation.methodName) + && Objects.equals(method.signature(), invocation.methodSignature); + } + private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, IDebugAdapterContext context, ThreadState threadState) { Event event = debugEvent.event; EventRequestManager eventRequestManager = debugSession.getVM().eventRequestManager(); - // When a breakpoint occurs, abort any pending step requests from the same thread. + // When a breakpoint occurs, abort any pending step requests from the same + // thread. if (event instanceof BreakpointEvent || event instanceof ExceptionEvent) { long threadId = ((LocatableEvent) event).thread().uniqueID(); if (threadId == threadState.threadId && threadState.pendingStepRequest != null) { @@ -230,19 +286,20 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, } else if (event instanceof StepEvent) { ThreadReference thread = ((StepEvent) event).thread(); threadState.deleteStepRequest(eventRequestManager); - if (isStepFiltersConfigured(context.getStepFilters())) { + if (isStepFiltersConfigured(context.getStepFilters()) || threadState.targetStepIn) { try { if (threadState.pendingStepType == Command.STEPIN) { int currentStackDepth = thread.frameCount(); Location currentStepLocation = getTopFrame(thread).location(); - - // If the ending step location is filtered, or same as the original location where the step into operation is originated, + // If the ending step location is filtered, or same as the original location + // where the step into operation is originated, // do another step of the same kind. if (shouldFilterLocation(threadState.stepLocation, currentStepLocation, context) - || shouldDoExtraStepInto(threadState.stackDepth, threadState.stepLocation, currentStackDepth, currentStepLocation)) { + || shouldDoExtraStepInto(threadState.stackDepth, threadState.stepLocation, + currentStackDepth, currentStepLocation, threadState.targetStepIn)) { threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, - context.getStepFilters().allowClasses, - context.getStepFilters().skipClasses); + context.getStepFilters().allowClasses, + context.getStepFilters().skipClasses); threadState.pendingStepRequest.enable(); debugEvent.shouldResume = true; return; @@ -262,7 +319,8 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, } else if (event instanceof MethodExitEvent) { MethodExitEvent methodExitEvent = (MethodExitEvent) event; long threadId = methodExitEvent.thread().uniqueID(); - if (threadId == threadState.threadId && methodExitEvent.method().equals(threadState.stepLocation.method())) { + if (threadId == threadState.threadId + && methodExitEvent.method().equals(threadState.stepLocation.method())) { Value returnValue = methodExitEvent.returnValue(); if (returnValue instanceof VoidValue) { context.getStepResultManager().removeMethodResult(threadId); @@ -280,22 +338,26 @@ private boolean isStepFiltersConfigured(StepFilters filters) { return false; } return ArrayUtils.isNotEmpty(filters.allowClasses) || ArrayUtils.isNotEmpty(filters.skipClasses) - || ArrayUtils.isNotEmpty(filters.classNameFilters) || filters.skipConstructors - || filters.skipStaticInitializers || filters.skipSynthetics; + || ArrayUtils.isNotEmpty(filters.classNameFilters) || filters.skipConstructors + || filters.skipStaticInitializers || filters.skipSynthetics; } /** - * Return true if the StepEvent's location is a Method that the user has indicated to filter. + * Return true if the StepEvent's location is a Method that the user has + * indicated to filter. * * @throws IncompatibleThreadStateException - * if the thread is not suspended in the target VM. + * if the thread is not suspended in + * the target VM. */ - private boolean shouldFilterLocation(Location originalLocation, Location currentLocation, IDebugAdapterContext context) + private boolean shouldFilterLocation(Location originalLocation, Location currentLocation, + IDebugAdapterContext context) throws IncompatibleThreadStateException { if (originalLocation == null || currentLocation == null) { return false; } - return !shouldFilterMethod(originalLocation.method(), context) && shouldFilterMethod(currentLocation.method(), context); + return !shouldFilterMethod(originalLocation.method(), context) + && shouldFilterMethod(currentLocation.method(), context); } private boolean shouldFilterMethod(Method method, IDebugAdapterContext context) { @@ -305,40 +367,50 @@ private boolean shouldFilterMethod(Method method, IDebugAdapterContext context) } /** - * Check if the current top stack is same as the original top stack. + * Check if the current top stack is same as the original top stack and if we + * are not in target step in we should not request an extra step in. But if we + * are processing a target step in, we only check if the original and current + * location are same. If they are not same we request a extra step in. * * @throws IncompatibleThreadStateException - * if the thread is not suspended in the target VM. + * if the thread is not suspended in + * the target VM. */ - private boolean shouldDoExtraStepInto(int originalStackDepth, Location originalLocation, int currentStackDepth, Location currentLocation) + private boolean shouldDoExtraStepInto(int originalStackDepth, Location originalLocation, int currentStackDepth, + Location currentLocation, boolean targetStepIn) throws IncompatibleThreadStateException { - if (originalStackDepth != currentStackDepth) { - return false; - } - if (originalLocation == null) { - return false; + if (!targetStepIn) { + if (originalStackDepth != currentStackDepth) { + return false; + } + if (originalLocation == null) { + return false; + } } + Method originalMethod = originalLocation.method(); Method currentMethod = currentLocation.method(); if (!originalMethod.equals(currentMethod)) { - return false; + return targetStepIn; } if (originalLocation.lineNumber() != currentLocation.lineNumber()) { - return false; + return targetStepIn; } - return true; + return !targetStepIn; } /** * Return the top stack frame of the target thread. * * @param thread - * the target thread. + * the target thread. * @return the top frame. * @throws IncompatibleThreadStateException - * if the thread is not suspended in the target VM. + * if the thread is not suspended in + * the target VM. * @throws IndexOutOfBoundsException - * if the thread doesn't contain any stack frame. + * if the thread doesn't contain any + * stack frame. */ private StackFrame getTopFrame(ThreadReference thread) throws IncompatibleThreadStateException { return thread.frame(0); @@ -353,6 +425,7 @@ class ThreadState { StackFrame topFrame = null; Location stepLocation = null; Disposable eventSubscription = null; + boolean targetStepIn = false; public void deleteMethodExitRequest(EventRequestManager manager) { DebugUtility.deleteEventRequestSafely(manager, this.pendingMethodExitRequest); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java index 0301bdb38..697eef93d 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java @@ -271,6 +271,10 @@ public static class StepOutArguments extends StepArguments { } + public static class StepInTargetsArguments extends Arguments { + public int frameId; + } + public static class PauseArguments extends Arguments { public long threadId; } @@ -423,6 +427,8 @@ public static enum Command { CONTINUE("continue", ContinueArguments.class), STEPIN("stepIn", StepInArguments.class), STEPOUT("stepOut", StepOutArguments.class), + STEPIN_TARGETS("stepInTargets", + StepInTargetsArguments.class), PAUSE("pause", PauseArguments.class), STACKTRACE("stackTrace", StackTraceArguments.class), RESTARTFRAME("restartFrame", RestartFrameArguments.class), diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Responses.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Responses.java index ea660f812..af701552e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Responses.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Responses.java @@ -17,6 +17,7 @@ import com.microsoft.java.debug.core.protocol.Types.DataBreakpointAccessType; import com.microsoft.java.debug.core.protocol.Types.ExceptionBreakMode; import com.microsoft.java.debug.core.protocol.Types.ExceptionDetails; +import com.microsoft.java.debug.core.protocol.Types.StepInTarget; import com.microsoft.java.debug.core.protocol.Types.Variable; /** @@ -364,4 +365,12 @@ public InlineValuesResponse(Variable[] variables) { this.variables = variables; } } + + public static class StepInTargetsResponse extends ResponseBody { + public StepInTarget[] targets; + + public StepInTargetsResponse(StepInTarget[] targets) { + this.targets = targets; + } + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java index 4781c7a57..33308af6d 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java @@ -433,5 +433,21 @@ public static class Capabilities { public boolean supportsFunctionBreakpoints; // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_BreakpointLocations public boolean supportsBreakpointLocationsRequest; + public boolean supportsStepInTargetsRequest; } + + public static class StepInTarget { + public int id; + public String label; + public int line; + public int column; + public int endLine; + public int endColumn; + + public StepInTarget(int id, String label) { + this.id = id; + this.label = label; + } + } + } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java new file mode 100644 index 000000000..e30b0dd30 --- /dev/null +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2017-2020 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package com.microsoft.java.debug; + +import org.eclipse.jdt.core.dom.IMethodBinding; + +/** + * Utility methods around working with JDT Bindings. + */ +public final class BindingUtils { + private BindingUtils() { + + } + + /** + * Return the method name from the binding using either the + * {@link IMethodBinding#getKey()} or {@link IMethodBinding#getName()}. The key + * can be used to find the name of a generated lambda method if the minding + * represents a lambda method. + * + * @param binding the binding to extract the name from. + * @param fromKey use binging key to resolve the method name. + * @return the name of the method. + */ + public static String getMethodName(IMethodBinding binding, boolean fromKey) { + if (fromKey) { + String key = binding.getKey(); + return key.substring(key.indexOf('.') + 1, key.indexOf('(')); + } else { + return binding.getName(); + } + } + + /** + * Returns the method signature of the method represented by the binding. Since + * this implementation use the {@link IMethodBinding#getKey()} to extract the + * signature from, the method name must be passed in. + * + * @param binding the binding which the signature must be resolved for. + * @param name the name of the method. + * @return the signature or null if the signature could not be resolved from the + * key. + */ + public static String toSignature(IMethodBinding binding, String name) { + // use key for now until JDT core provides a public API for this. + // "Ljava/util/Arrays;.asList([TT;)Ljava/util/List;" + // "([Ljava/lang/String;)V|Ljava/lang/InterruptedException;" + if (!binding.getName().equals(name)) { + throw new IllegalArgumentException("The method name and binding method name doesn't match."); + } + + String signatureString = binding.getKey(); + if (signatureString != null) { + int index = signatureString.indexOf(name); + if (index > -1) { + int exceptionIndex = signatureString.indexOf("|", signatureString.lastIndexOf(")")); + if (exceptionIndex > -1) { + return signatureString.substring(index + name.length(), exceptionIndex); + } + return signatureString.substring(index + name.length()); + } + } + return null; + } +} diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java index 00cffb766..68f593aff 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java @@ -46,7 +46,7 @@ public String getMethodSignature() { if (this.methodBinding == null) { return null; } - return toSignature(this.methodBinding, getMethodName()); + return BindingUtils.toSignature(this.methodBinding, getMethodName()); } /** @@ -70,22 +70,4 @@ public String getFullyQualifiedTypeName() { } return super.getFullyQualifiedTypeName(); } - - static String toSignature(IMethodBinding binding, String name) { - // use key for now until JDT core provides a public API for this. - // "Ljava/util/Arrays;.asList([TT;)Ljava/util/List;" - // "([Ljava/lang/String;)V|Ljava/lang/InterruptedException;" - String signatureString = binding.getKey(); - if (signatureString != null) { - int index = signatureString.indexOf(name); - if (index > -1) { - int exceptionIndex = signatureString.indexOf("|", signatureString.lastIndexOf(")")); - if (exceptionIndex > -1) { - return signatureString.substring(index + name.length(), exceptionIndex); - } - return signatureString.substring(index + name.length()); - } - } - return null; - } } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java index b37ff7b1f..afffd9741 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java @@ -71,7 +71,7 @@ public String getMethodSignature() { if (!this.found) { return null; } - return BreakpointLocationLocator.toSignature(this.lambdaMethodBinding, getMethodName()); + return BindingUtils.toSignature(this.lambdaMethodBinding, getMethodName()); } /** @@ -81,8 +81,7 @@ public String getMethodName() { if (!this.found) { return null; } - String key = this.lambdaMethodBinding.getKey(); - return key.substring(key.indexOf('.') + 1, key.indexOf('(')); + return BindingUtils.getMethodName(lambdaMethodBinding, true); } /** diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index 92ce9477a..eba9a42e6 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -15,11 +15,13 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -28,6 +30,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Stream; +import java.util.stream.Collectors; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; @@ -37,6 +40,7 @@ import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; @@ -45,11 +49,14 @@ import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.LambdaExpression; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.LibraryLocation; +import com.microsoft.java.debug.BindingUtils; import com.microsoft.java.debug.BreakpointLocationLocator; import com.microsoft.java.debug.LambdaExpressionLocator; import com.microsoft.java.debug.core.Configuration; @@ -62,6 +69,8 @@ import com.microsoft.java.debug.core.protocol.Types.BreakpointLocation; import com.microsoft.java.debug.core.protocol.Types.SourceBreakpoint; +import com.sun.jdi.StackFrame; + public class JdtSourceLookUpProvider implements ISourceLookUpProvider { private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); private static final String JDT_SCHEME = "jdt"; @@ -146,47 +155,7 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB return new JavaBreakpointLocation[0]; } - final ASTParser parser = ASTParser.newParser(this.latestASTLevel); - parser.setResolveBindings(true); - parser.setBindingsRecovery(true); - parser.setStatementsRecovery(true); - CompilationUnit astUnit = null; - String filePath = AdapterUtils.toPath(sourceUri); - // For file uri, read the file contents directly and pass them to the ast parser. - if (filePath != null && Files.isRegularFile(Paths.get(filePath))) { - String source = readFile(filePath); - parser.setSource(source.toCharArray()); - /** - * See the java doc for { @link ASTParser#setResolveBindings(boolean) }. - * Binding information is obtained from the Java model. This means that the compilation unit must be located relative to the Java model. - * This happens automatically when the source code comes from either setSource(ICompilationUnit) or setSource(IClassFile). - * When source is supplied by setSource(char[]), the location must be established explicitly - * by setting an environment using setProject(IJavaProject) or setEnvironment(String [], String [], String [], boolean) - * and a unit name setUnitName(String). - */ - parser.setEnvironment(new String[0], new String[0], null, true); - parser.setUnitName(Paths.get(filePath).getFileName().toString()); - /** - * See the java doc for { @link ASTParser#setSource(char[]) }, - * the user need specify the compiler options explicitly. - */ - Map javaOptions = JavaCore.getOptions(); - javaOptions.put(JavaCore.COMPILER_SOURCE, this.latestJavaVersion); - javaOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, this.latestJavaVersion); - javaOptions.put(JavaCore.COMPILER_COMPLIANCE, this.latestJavaVersion); - javaOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); - parser.setCompilerOptions(javaOptions); - astUnit = (CompilationUnit) parser.createAST(null); - } else { - // For non-file uri (e.g. jdt://contents/rt.jar/java.io/PrintStream.class), - // leverage jdt to load the source contents. - ITypeRoot typeRoot = resolveClassFile(sourceUri); - if (typeRoot != null) { - parser.setSource(typeRoot); - astUnit = (CompilationUnit) parser.createAST(null); - } - } - + CompilationUnit astUnit = asCompilationUnit(sourceUri); JavaBreakpointLocation[] sourceLocations = Stream.of(sourceBreakpoints) .map(sourceBreakpoint -> new JavaBreakpointLocation(sourceBreakpoint.line, sourceBreakpoint.column)) .toArray(JavaBreakpointLocation[]::new); @@ -281,6 +250,55 @@ public boolean visit(LambdaExpression node) { return locations.toArray(BreakpointLocation[]::new); } + private CompilationUnit asCompilationUnit(String uri) { + final ASTParser parser = ASTParser.newParser(this.latestASTLevel); + parser.setResolveBindings(true); + parser.setBindingsRecovery(true); + parser.setStatementsRecovery(true); + CompilationUnit astUnit = null; + String filePath = AdapterUtils.toPath(uri); + // For file uri, read the file contents directly and pass them to the ast + // parser. + if (filePath != null && Files.isRegularFile(Paths.get(filePath))) { + String source = readFile(filePath); + parser.setSource(source.toCharArray()); + /** + * See the java doc for { @link ASTParser#setResolveBindings(boolean) }. + * Binding information is obtained from the Java model. This means that the + * compilation unit must be located relative to the Java model. + * This happens automatically when the source code comes from either + * setSource(ICompilationUnit) or setSource(IClassFile). + * When source is supplied by setSource(char[]), the location must be + * established explicitly + * by setting an environment using setProject(IJavaProject) or + * setEnvironment(String [], String [], String [], boolean) + * and a unit name setUnitName(String). + */ + parser.setEnvironment(new String[0], new String[0], null, true); + parser.setUnitName(Paths.get(filePath).getFileName().toString()); + /** + * See the java doc for { @link ASTParser#setSource(char[]) }, + * the user need specify the compiler options explicitly. + */ + Map javaOptions = JavaCore.getOptions(); + javaOptions.put(JavaCore.COMPILER_SOURCE, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_COMPLIANCE, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); + parser.setCompilerOptions(javaOptions); + astUnit = (CompilationUnit) parser.createAST(null); + } else { + // For non-file uri (e.g. jdt://contents/rt.jar/java.io/PrintStream.class), + // leverage jdt to load the source contents. + ITypeRoot typeRoot = resolveClassFile(uri); + if (typeRoot != null) { + parser.setSource(typeRoot); + astUnit = (CompilationUnit) parser.createAST(null); + } + } + return astUnit; + } + @Override public String getSourceFileURI(String fullyQualifiedName, String sourcePath) { if (sourcePath == null) { @@ -431,4 +449,51 @@ private static String resolveSystemLibraryVersion(IJavaProject project, IVMInsta return null; } + + @Override + public List findMethodInvocations(StackFrame frame) { + if (frame == null) { + throw new IllegalArgumentException("frame is null"); + } + + IJavaProject project = JdtUtils.findProject(frame, getSourceContainers()); + if (project == null) { + logger.log(Level.WARNING, + String.format("Failed to resolve project for the frame: %s", frame)); + return Collections.emptyList(); + } + + String uri; + try { + IType type = project.findType(JdtUtils.getDeclaringTypeName(frame)); + uri = type.getResource().getLocationURI().toURL().toString(); + } catch (JavaModelException | DebugException | MalformedURLException e) { + logger.log(Level.SEVERE, + String.format("Failed to resolve type for the frame: %s", frame)); + return Collections.emptyList(); + } + + CompilationUnit astUnit = asCompilationUnit(uri); + if (astUnit == null) { + return Collections.emptyList(); + } + + MethodInvocationLocator locator = new MethodInvocationLocator(frame.location().lineNumber(), astUnit); + astUnit.accept(locator); + + return locator.getTargets().entrySet().stream().map(entry -> { + MethodInvocation invocation = new MethodInvocation(); + Expression expression = entry.getKey(); + invocation.expression = expression.toString(); + IMethodBinding binding = entry.getValue(); + invocation.methodName = binding.getName(); + invocation.declaringTypeName = binding.getDeclaringClass().getQualifiedName(); + invocation.methodSignature = BindingUtils.toSignature(binding, BindingUtils.getMethodName(binding, true)); + invocation.lineStart = astUnit.getLineNumber(expression.getStartPosition()); + invocation.lineEnd = astUnit.getLineNumber(expression.getStartPosition() + expression.getLength()); + invocation.columnStart = astUnit.getColumnNumber(expression.getStartPosition()); + invocation.columnEnd = astUnit.getColumnNumber(expression.getStartPosition() + expression.getLength()); + return invocation; + }).collect(Collectors.toList()); + } } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java new file mode 100644 index 000000000..ab6efdaa2 --- /dev/null +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java @@ -0,0 +1,66 @@ +/******************************************************************************* +* Copyright (c) 2022 Microsoft Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Gayan Perera (gayanper@gmail.com) - initial API and implementation +*******************************************************************************/ +package com.microsoft.java.debug.plugin.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.MethodInvocation; + +public class MethodInvocationLocator extends ASTVisitor { + private int line; + private CompilationUnit unit; + private Map targets; + + private boolean collectMethodInvocations = false; + + public MethodInvocationLocator(int line, CompilationUnit unit) { + super(false); + this.line = line; + this.unit = unit; + this.targets = new HashMap<>(); + } + + @Override + public boolean visit(ExpressionStatement node) { + int start = unit.getLineNumber(node.getStartPosition()); + int end = unit.getLineNumber(node.getStartPosition() + node.getLength()); + + if (line >= start && line <= end) { + collectMethodInvocations = true; + } + return collectMethodInvocations; + } + + @Override + public boolean visit(MethodInvocation node) { + int lineNumber = unit.getLineNumber(node.getStartPosition()); + if (lineNumber == this.line) { + targets.put(node, node.resolveMethodBinding()); + return true; + } + return false; + } + + @Override + public void endVisit(ExpressionStatement node) { + collectMethodInvocations = false; + } + + public Map getTargets() { + return targets; + } +} From 69230b339d68dfa2b3a1c251c29f3bd577fd0cf8 Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Fri, 19 Aug 2022 19:12:01 +0200 Subject: [PATCH 03/94] Fix and improve targets and stepin Improve to only show valid targets within an expression, also added support for stepin into unloaded classes by delaying the stepin. --- .../adapter/handler/StepRequestHandler.java | 256 ++++++++++-------- .../microsoft/java/debug/BindingUtils.java | 9 +- .../internal/JdtSourceLookUpProvider.java | 16 +- .../internal/MethodInvocationLocator.java | 29 +- 4 files changed, 193 insertions(+), 117 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java index f9baa0e5d..660d4bbdd 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java @@ -74,8 +74,7 @@ public List getTargetCommands() { public CompletableFuture handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) { if (context.getDebugSession() == null) { - return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.EMPTY_DEBUG_SESSION, - "Debug Session doesn't exist."); + return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.EMPTY_DEBUG_SESSION, "Debug Session doesn't exist."); } StepArguments stepArguments = (StepArguments) arguments; @@ -93,63 +92,59 @@ public CompletableFuture handle(Command command, Arguments arguments, ThreadState threadState = new ThreadState(); threadState.threadId = threadId; threadState.pendingStepType = command; - threadState.stackDepth = thread.frameCount(); - threadState.stepLocation = resolveLocation(thread, targetId, context); - threadState.targetStepIn = targetId > 0; threadState.eventSubscription = context.getDebugSession().getEventHub().events() - .filter(debugEvent -> (debugEvent.event instanceof StepEvent - && debugEvent.event.request().equals(threadState.pendingStepRequest)) - || (debugEvent.event instanceof MethodExitEvent - && debugEvent.event.request().equals(threadState.pendingMethodExitRequest)) - || debugEvent.event instanceof BreakpointEvent - || debugEvent.event instanceof ExceptionEvent) - .subscribe(debugEvent -> { - handleDebugEvent(debugEvent, context.getDebugSession(), context, threadState); - }); + .filter(debugEvent -> (debugEvent.event instanceof StepEvent && debugEvent.event.request().equals(threadState.pendingStepRequest)) + || (debugEvent.event instanceof MethodExitEvent && debugEvent.event.request().equals(threadState.pendingMethodExitRequest)) + || debugEvent.event instanceof BreakpointEvent + || debugEvent.event instanceof ExceptionEvent) + .subscribe(debugEvent -> { + handleDebugEvent(debugEvent, context.getDebugSession(), context, threadState); + }); if (command == Command.STEPIN) { + String[] allowedClasses = threadState.pendingTargetStepIn != null + ? new String[]{threadState.pendingTargetStepIn.declaringTypeName} + : context.getStepFilters().allowClasses; threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, - context.getStepFilters().allowClasses, - context.getStepFilters().skipClasses); + allowedClasses, + context.getStepFilters().skipClasses); } else if (command == Command.STEPOUT) { threadState.pendingStepRequest = DebugUtility.createStepOutRequest(thread, - context.getStepFilters().allowClasses, - context.getStepFilters().skipClasses); + context.getStepFilters().allowClasses, + context.getStepFilters().skipClasses); } else { threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread, null); } - threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager() - .createMethodExitRequest(); + threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager().createMethodExitRequest(); threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + LocationResponse locationResponse = resolveLocation(thread, targetId, context); if (context.asyncJDWP()) { List> futures = new ArrayList<>(); futures.add(AsyncJdwpUtils.runAsync(() -> { - try { - // JDWP Command: TR_FRAMES - threadState.topFrame = getTopFrame(targetThread); - threadState.stepLocation = threadState.topFrame.location(); - threadState.pendingMethodExitRequest - .addClassFilter(threadState.stepLocation.declaringType()); - if (targetThread.virtualMachine().canUseInstanceFilters()) { - try { - // JDWP Command: SF_THIS_OBJECT - ObjectReference thisObject = threadState.topFrame.thisObject(); - if (thisObject != null) { - threadState.pendingMethodExitRequest.addInstanceFilter(thisObject); - } - } catch (Exception e) { - // ignore + // JDWP Command: TR_FRAMES + threadState.stepLocation = locationResponse.location; + threadState.pendingTargetStepIn = locationResponse.methodInvocation; + threadState.targetStepIn = targetId > 0; + threadState.stepLocation = threadState.topFrame.location(); + threadState.pendingMethodExitRequest.addClassFilter(threadState.stepLocation.declaringType()); + if (targetThread.virtualMachine().canUseInstanceFilters()) { + try { + // JDWP Command: SF_THIS_OBJECT + ObjectReference thisObject = threadState.topFrame.thisObject(); + if (thisObject != null) { + threadState.pendingMethodExitRequest.addInstanceFilter(thisObject); } + } catch (Exception e) { + // ignore } - } catch (IncompatibleThreadStateException e) { - throw new CompletionException(e); } })); futures.add(AsyncJdwpUtils.runAsync( - // JDWP Command: OR_IS_COLLECTED - () -> threadState.pendingMethodExitRequest.addThreadFilter(targetThread))); + // JDWP Command: OR_IS_COLLECTED + () -> threadState.pendingMethodExitRequest.addThreadFilter(targetThread) + )); futures.add(AsyncJdwpUtils.runAsync(() -> { try { // JDWP Command: TR_FRAME_COUNT @@ -159,8 +154,9 @@ public CompletableFuture handle(Command command, Arguments arguments, } })); futures.add( - // JDWP Command: ER_SET - AsyncJdwpUtils.runAsync(() -> threadState.pendingStepRequest.enable())); + // JDWP Command: ER_SET + AsyncJdwpUtils.runAsync(() -> threadState.pendingStepRequest.enable()) + ); try { AsyncJdwpUtils.await(futures); @@ -175,7 +171,9 @@ public CompletableFuture handle(Command command, Arguments arguments, threadState.pendingMethodExitRequest.enable(); } else { threadState.stackDepth = targetThread.frameCount(); - threadState.topFrame = getTopFrame(targetThread); + threadState.stepLocation = locationResponse.location; + threadState.pendingTargetStepIn = locationResponse.methodInvocation; + threadState.targetStepIn = targetId > 0; threadState.stepLocation = threadState.topFrame.location(); threadState.pendingMethodExitRequest.addThreadFilter(thread); threadState.pendingMethodExitRequest.addClassFilter(threadState.stepLocation.declaringType()); @@ -199,81 +197,97 @@ public CompletableFuture handle(Command command, Arguments arguments, } catch (IncompatibleThreadStateException ex) { // Roll back the Exception info if stepping fails. context.getExceptionManager().setException(threadId, exception); - final String failureMessage = String.format( - "Failed to step because the thread '%s' is not suspended in the target VM.", thread.name()); + final String failureMessage = String.format("Failed to step because the thread '%s' is not suspended in the target VM.", thread.name()); throw AdapterUtils.createCompletionException( - failureMessage, - ErrorCode.STEP_FAILURE, - ex); + failureMessage, + ErrorCode.STEP_FAILURE, + ex); } catch (IndexOutOfBoundsException ex) { // Roll back the Exception info if stepping fails. context.getExceptionManager().setException(threadId, exception); - final String failureMessage = String.format( - "Failed to step because the thread '%s' doesn't contain any stack frame", thread.name()); - throw AdapterUtils.createCompletionException( - failureMessage, - ErrorCode.STEP_FAILURE, - ex); - } catch (AbsentInformationException ex) { - // Roll back the Exception info if stepping fails. - context.getExceptionManager().setException(threadId, exception); - final String failureMessage = String.format( - "Failed to step because the thread '%s' doesn't contain required line information in stack frame", - thread.name()); + final String failureMessage = String.format("Failed to step because the thread '%s' doesn't contain any stack frame", thread.name()); throw AdapterUtils.createCompletionException( - failureMessage, - ErrorCode.STEP_FAILURE, - ex); + failureMessage, + ErrorCode.STEP_FAILURE, + ex); } catch (Exception ex) { // Roll back the Exception info if stepping fails. context.getExceptionManager().setException(threadId, exception); - final String failureMessage = String.format("Failed to step because of the error '%s'", - ex.getMessage()); + final String failureMessage = String.format("Failed to step because of the error '%s'", ex.getMessage()); throw AdapterUtils.createCompletionException( - failureMessage, - ErrorCode.STEP_FAILURE, - ex.getCause() != null ? ex.getCause() : ex); + failureMessage, + ErrorCode.STEP_FAILURE, + ex.getCause() != null ? ex.getCause() : ex); } } return CompletableFuture.completedFuture(response); } - private Location resolveLocation(ThreadReference thread, int targetId, IDebugAdapterContext context) + private LocationResponse resolveLocation(ThreadReference thread, int targetId, IDebugAdapterContext context) throws IncompatibleThreadStateException, AbsentInformationException { if (targetId > 0) { Object value = context.getRecyclableIdPool().getObjectById(targetId); if (value instanceof MethodInvocation) { - MethodInvocation invocation = (MethodInvocation) value; - VirtualMachine vm = thread.virtualMachine(); - List refTypes = vm.classesByName(invocation.declaringTypeName); - for (ReferenceType referenceType : refTypes) { - Optional location = referenceType.allLineLocations().stream() - .filter(l -> matchesLocation(l, invocation)) - .findFirst(); - if (location.isPresent()) { - return location.get(); - } + return resolveLocation((MethodInvocation) value, thread); + } + } + return LocationResponse.absolute(getTopFrame(thread).location()); + } + + private LocationResponse resolveLocation(MethodInvocation invocation, ThreadReference thread) + throws AbsentInformationException, IncompatibleThreadStateException { + VirtualMachine vm = thread.virtualMachine(); + List refTypes = vm.classesByName(invocation.declaringTypeName); + + // if class is not yet loaded try to make the debugger step in until class is + // loaded. + if (refTypes.isEmpty()) { + return LocationResponse.waitFor(invocation, getTopFrame(thread).location()); + } else { + for (ReferenceType referenceType : refTypes) { + Optional location = referenceType.allLineLocations().stream() + .filter(l -> matchesLocation(l, invocation)) + .findFirst(); + if (location.isPresent()) { + return LocationResponse.absolute(location.get()); } } + return LocationResponse.absolute(getTopFrame(thread).location()); } - return getTopFrame(thread).location(); } private boolean matchesLocation(Location l, MethodInvocation invocation) { Method method = l.method(); - return method != null && Objects.equals(method.name(), invocation.methodName) + return method != null && Objects.equals(fixedName(method), invocation.methodName) && Objects.equals(method.signature(), invocation.methodSignature); } + /* + * Fix the name so for constructors we return empty to match the captured AST + * invocations. + */ + private String fixedName(Method method) { + String name = method.name(); + if ("".equals(name)) { + return ""; + } + return name; + } + private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, IDebugAdapterContext context, ThreadState threadState) { Event event = debugEvent.event; EventRequestManager eventRequestManager = debugSession.getVM().eventRequestManager(); - // When a breakpoint occurs, abort any pending step requests from the same - // thread. + // When a breakpoint occurs, abort any pending step requests from the same thread. if (event instanceof BreakpointEvent || event instanceof ExceptionEvent) { + // if we have a pending target step in then ignore and continue. + if (threadState.pendingTargetStepIn != null) { + debugEvent.shouldResume = true; + return; + } + long threadId = ((LocatableEvent) event).thread().uniqueID(); if (threadId == threadState.threadId && threadState.pendingStepRequest != null) { threadState.deleteStepRequest(eventRequestManager); @@ -291,21 +305,35 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, if (threadState.pendingStepType == Command.STEPIN) { int currentStackDepth = thread.frameCount(); Location currentStepLocation = getTopFrame(thread).location(); - // If the ending step location is filtered, or same as the original location - // where the step into operation is originated, + + // if we are in targetStepIn where the location was pending, then try to resolve + // the location and use it. + if (threadState.pendingTargetStepIn != null) { + LocationResponse newLocation = resolveLocation(threadState.pendingTargetStepIn, thread); + if (!newLocation.isLocationPending()) { + threadState.stepLocation = newLocation.location; + threadState.pendingTargetStepIn = null; + } + } + + // If the ending step location is filtered, or same as the original location where the step into operation is originated, // do another step of the same kind. if (shouldFilterLocation(threadState.stepLocation, currentStepLocation, context) || shouldDoExtraStepInto(threadState.stackDepth, threadState.stepLocation, - currentStackDepth, currentStepLocation, threadState.targetStepIn)) { + currentStackDepth, currentStepLocation, threadState.targetStepIn) + || threadState.pendingTargetStepIn != null) { + String[] allowedClasses = threadState.pendingTargetStepIn != null + ? new String[]{threadState.pendingTargetStepIn.declaringTypeName} + : context.getStepFilters().allowClasses; threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, - context.getStepFilters().allowClasses, - context.getStepFilters().skipClasses); + allowedClasses, + context.getStepFilters().skipClasses); threadState.pendingStepRequest.enable(); debugEvent.shouldResume = true; return; } } - } catch (IncompatibleThreadStateException | IndexOutOfBoundsException ex) { + } catch (IncompatibleThreadStateException | IndexOutOfBoundsException | AbsentInformationException ex) { // ignore. } } @@ -319,8 +347,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, } else if (event instanceof MethodExitEvent) { MethodExitEvent methodExitEvent = (MethodExitEvent) event; long threadId = methodExitEvent.thread().uniqueID(); - if (threadId == threadState.threadId - && methodExitEvent.method().equals(threadState.stepLocation.method())) { + if (threadId == threadState.threadId && methodExitEvent.method().equals(threadState.stepLocation.method())) { Value returnValue = methodExitEvent.returnValue(); if (returnValue instanceof VoidValue) { context.getStepResultManager().removeMethodResult(threadId); @@ -338,26 +365,22 @@ private boolean isStepFiltersConfigured(StepFilters filters) { return false; } return ArrayUtils.isNotEmpty(filters.allowClasses) || ArrayUtils.isNotEmpty(filters.skipClasses) - || ArrayUtils.isNotEmpty(filters.classNameFilters) || filters.skipConstructors - || filters.skipStaticInitializers || filters.skipSynthetics; + || ArrayUtils.isNotEmpty(filters.classNameFilters) || filters.skipConstructors + || filters.skipStaticInitializers || filters.skipSynthetics; } /** - * Return true if the StepEvent's location is a Method that the user has - * indicated to filter. + * Return true if the StepEvent's location is a Method that the user has indicated to filter. * * @throws IncompatibleThreadStateException - * if the thread is not suspended in - * the target VM. + * if the thread is not suspended in the target VM. */ - private boolean shouldFilterLocation(Location originalLocation, Location currentLocation, - IDebugAdapterContext context) + private boolean shouldFilterLocation(Location originalLocation, Location currentLocation, IDebugAdapterContext context) throws IncompatibleThreadStateException { if (originalLocation == null || currentLocation == null) { return false; } - return !shouldFilterMethod(originalLocation.method(), context) - && shouldFilterMethod(currentLocation.method(), context); + return !shouldFilterMethod(originalLocation.method(), context) && shouldFilterMethod(currentLocation.method(), context); } private boolean shouldFilterMethod(Method method, IDebugAdapterContext context) { @@ -387,7 +410,6 @@ private boolean shouldDoExtraStepInto(int originalStackDepth, Location originalL return false; } } - Method originalMethod = originalLocation.method(); Method currentMethod = currentLocation.method(); if (!originalMethod.equals(currentMethod)) { @@ -403,14 +425,12 @@ private boolean shouldDoExtraStepInto(int originalStackDepth, Location originalL * Return the top stack frame of the target thread. * * @param thread - * the target thread. + * the target thread. * @return the top frame. * @throws IncompatibleThreadStateException - * if the thread is not suspended in - * the target VM. + * if the thread is not suspended in the target VM. * @throws IndexOutOfBoundsException - * if the thread doesn't contain any - * stack frame. + * if the thread doesn't contain any stack frame. */ private StackFrame getTopFrame(ThreadReference thread) throws IncompatibleThreadStateException { return thread.frame(0); @@ -426,6 +446,7 @@ class ThreadState { Location stepLocation = null; Disposable eventSubscription = null; boolean targetStepIn = false; + MethodInvocation pendingTargetStepIn; public void deleteMethodExitRequest(EventRequestManager manager) { DebugUtility.deleteEventRequestSafely(manager, this.pendingMethodExitRequest); @@ -437,4 +458,27 @@ public void deleteStepRequest(EventRequestManager manager) { this.pendingStepRequest = null; } } + + static class LocationResponse { + Location location; + MethodInvocation methodInvocation; + + private LocationResponse(Location location, MethodInvocation methodInvocation) { + this.location = location; + this.methodInvocation = methodInvocation; + } + + public static LocationResponse waitFor(MethodInvocation invocation, Location location) { + return new LocationResponse(location, invocation); + } + + public static LocationResponse absolute(Location location) { + return new LocationResponse(location, null); + } + + boolean isLocationPending() { + return methodInvocation != null; + } + + } } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java index e30b0dd30..a6535715a 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java @@ -34,7 +34,14 @@ private BindingUtils() { public static String getMethodName(IMethodBinding binding, boolean fromKey) { if (fromKey) { String key = binding.getKey(); - return key.substring(key.indexOf('.') + 1, key.indexOf('(')); + int dotAt = key.indexOf('.'); + int end = key.indexOf('<', dotAt); + if (end == -1) { + end = key.indexOf('('); + } else { + end = Math.min(end, key.indexOf('(')); + } + return key.substring(dotAt + 1, end); } else { return binding.getName(); } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index eba9a42e6..eb3eb46f2 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.logging.Level; @@ -51,6 +52,7 @@ import org.eclipse.jdt.core.dom.LambdaExpression; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; @@ -487,13 +489,23 @@ public List findMethodInvocations(StackFrame frame) { invocation.expression = expression.toString(); IMethodBinding binding = entry.getValue(); invocation.methodName = binding.getName(); - invocation.declaringTypeName = binding.getDeclaringClass().getQualifiedName(); + if (binding.getDeclaringClass().isAnonymous()) { + ITypeBinding superclass = binding.getDeclaringClass().getSuperclass(); + if (superclass != null + && !superclass.isEqualTo(astUnit.getAST().resolveWellKnownType("java.lang.Object"))) { + invocation.declaringTypeName = superclass.getQualifiedName(); + } else { + return null; + } + } else { + invocation.declaringTypeName = binding.getDeclaringClass().getQualifiedName(); + } invocation.methodSignature = BindingUtils.toSignature(binding, BindingUtils.getMethodName(binding, true)); invocation.lineStart = astUnit.getLineNumber(expression.getStartPosition()); invocation.lineEnd = astUnit.getLineNumber(expression.getStartPosition() + expression.getLength()); invocation.columnStart = astUnit.getColumnNumber(expression.getStartPosition()); invocation.columnEnd = astUnit.getColumnNumber(expression.getStartPosition() + expression.getLength()); return invocation; - }).collect(Collectors.toList()); + }).filter(Objects::nonNull).collect(Collectors.toList()); } } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java index ab6efdaa2..f0364d98b 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java @@ -14,6 +14,7 @@ import java.util.Map; import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.ExpressionStatement; @@ -25,7 +26,7 @@ public class MethodInvocationLocator extends ASTVisitor { private CompilationUnit unit; private Map targets; - private boolean collectMethodInvocations = false; + private int expressionCount = 0; public MethodInvocationLocator(int line, CompilationUnit unit) { super(false); @@ -40,24 +41,36 @@ public boolean visit(ExpressionStatement node) { int end = unit.getLineNumber(node.getStartPosition() + node.getLength()); if (line >= start && line <= end) { - collectMethodInvocations = true; + expressionCount++; } - return collectMethodInvocations; + return expressionCount > 0; } @Override public boolean visit(MethodInvocation node) { - int lineNumber = unit.getLineNumber(node.getStartPosition()); - if (lineNumber == this.line) { + if (expressionCount > 0) { targets.put(node, node.resolveMethodBinding()); - return true; } - return false; + return expressionCount > 0; + } + + @Override + public boolean visit(ClassInstanceCreation node) { + if (expressionCount > 0) { + targets.put(node, node.resolveConstructorBinding()); + expressionCount--; + } + return expressionCount > 0; } @Override public void endVisit(ExpressionStatement node) { - collectMethodInvocations = false; + expressionCount--; + } + + @Override + public void endVisit(ClassInstanceCreation node) { + expressionCount++; } public Map getTargets() { From a6ca87a0572d55ac9c289ba5a5a0f16318883a44 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 25 Oct 2022 17:17:32 +0800 Subject: [PATCH 04/94] Enable stepInTarget feature on more use cases --- .../core/adapter/ISourceLookUpProvider.java | 27 +- .../handler/StackTraceRequestHandler.java | 8 +- .../handler/StepInTargetsRequestHandler.java | 75 ++++- .../adapter/handler/StepRequestHandler.java | 276 +++++++++--------- .../variables/StackFrameReference.java | 12 +- .../microsoft/java/debug/BindingUtils.java | 7 +- .../internal/JdtSourceLookUpProvider.java | 83 +++--- .../internal/MethodInvocationLocator.java | 199 +++++++++++-- 8 files changed, 459 insertions(+), 228 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java index 5e8d94451..ead10e33c 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java @@ -18,8 +18,6 @@ import com.microsoft.java.debug.core.JavaBreakpointLocation; import com.microsoft.java.debug.core.protocol.Types.SourceBreakpoint; -import com.sun.jdi.StackFrame; - public interface ISourceLookUpProvider extends IProvider { boolean supportsRealtimeBreakpointVerification(); @@ -70,17 +68,19 @@ default String getJavaRuntimeVersion(String projectName) { * Return method invocation found in the statement as the given line number of * the source file. * - * @param stackframe The stack frame where the invocation must be searched. + * @param uri The source file where the invocation must be searched. + * @param line The line number where the invocation must be searched. * * @return List of found method invocation or empty if not method invocations * can be found. */ - List findMethodInvocations(StackFrame stackframe); + List findMethodInvocations(String uri, int line); public static class MethodInvocation { public String expression; public String methodName; public String methodSignature; + public String methodGenericSignature; public String declaringTypeName; public int lineStart; public int lineEnd; @@ -89,8 +89,8 @@ public static class MethodInvocation { @Override public int hashCode() { - return Objects.hash(columnEnd, columnStart, declaringTypeName, expression, lineEnd, lineStart, methodName, - methodSignature); + return Objects.hash(expression, methodName, methodSignature, methodGenericSignature, declaringTypeName, + lineStart, lineEnd, columnStart, columnEnd); } @Override @@ -98,18 +98,15 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { + if (!(obj instanceof MethodInvocation)) { return false; } MethodInvocation other = (MethodInvocation) obj; - return columnEnd == other.columnEnd && columnStart == other.columnStart - && Objects.equals(declaringTypeName, other.declaringTypeName) - && Objects.equals(expression, other.expression) && lineEnd == other.lineEnd - && lineStart == other.lineStart && Objects.equals(methodName, other.methodName) - && Objects.equals(methodSignature, other.methodSignature); + return Objects.equals(expression, other.expression) && Objects.equals(methodName, other.methodName) + && Objects.equals(methodSignature, other.methodSignature) + && Objects.equals(methodGenericSignature, other.methodGenericSignature) + && Objects.equals(declaringTypeName, other.declaringTypeName) && lineStart == other.lineStart + && lineEnd == other.lineEnd && columnStart == other.columnStart && columnEnd == other.columnEnd; } } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index f22966b03..fbfce49ef 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -89,10 +89,12 @@ public CompletableFuture handle(Command command, Arguments arguments, StackFrame[] frames = context.getStackFrameManager().reloadStackFrames(thread, stacktraceArgs.startFrame, count); List jdiFrames = resolveStackFrameInfos(frames, context.asyncJDWP()); for (int i = 0; i < count; i++) { - StackFrameReference stackframe = new StackFrameReference(thread, stacktraceArgs.startFrame + i); - int frameId = context.getRecyclableIdPool().addObject(stacktraceArgs.threadId, stackframe); + StackFrameReference frameReference = new StackFrameReference(thread, stacktraceArgs.startFrame + i); + int frameId = context.getRecyclableIdPool().addObject(stacktraceArgs.threadId, frameReference); StackFrameInfo jdiFrame = jdiFrames.get(i); - result.add(convertDebuggerStackFrameToClient(jdiFrame, frameId, i == 0, context)); + Types.StackFrame lspFrame = convertDebuggerStackFrameToClient(jdiFrame, frameId, i == 0, context); + result.add(lspFrame); + frameReference.setSource(lspFrame.source); } } catch (IncompatibleThreadStateException | IndexOutOfBoundsException | URISyntaxException | AbsentInformationException | ObjectCollectedException diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java index f61d2a8b9..5b3b735fe 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepInTargetsRequestHandler.java @@ -10,13 +10,19 @@ *******************************************************************************/ package com.microsoft.java.debug.core.adapter.handler; +import java.io.File; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.microsoft.java.debug.core.Configuration; +import com.microsoft.java.debug.core.adapter.AdapterUtils; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider; @@ -27,10 +33,14 @@ import com.microsoft.java.debug.core.protocol.Requests.Command; import com.microsoft.java.debug.core.protocol.Requests.StepInTargetsArguments; import com.microsoft.java.debug.core.protocol.Responses.StepInTargetsResponse; +import com.microsoft.java.debug.core.protocol.Types.Source; import com.microsoft.java.debug.core.protocol.Types.StepInTarget; +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ReferenceType; import com.sun.jdi.StackFrame; public class StepInTargetsRequestHandler implements IDebugRequestHandler { + private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); @Override public List getTargetCommands() { @@ -45,37 +55,84 @@ public CompletableFuture handle(Command command, Arguments arguments, final int frameId = stepInTargetsArguments.frameId; return CompletableFuture.supplyAsync(() -> { response.body = new StepInTargetsResponse( - findFrame(frameId, context).map(f -> findTargets(f.thread().uniqueID(), f, context)) + findFrame(frameId, context).map(f -> findTargets(f, context)) .orElse(Collections.emptyList()).toArray(StepInTarget[]::new)); return response; }); } - private Optional findFrame(int frameId, IDebugAdapterContext context) { + private Optional findFrame(int frameId, IDebugAdapterContext context) { Object object = context.getRecyclableIdPool().getObjectById(frameId); if (object instanceof StackFrameReference) { - return Optional.of(context.getStackFrameManager().getStackFrame((StackFrameReference) object)); + return Optional.of((StackFrameReference) object); } return Optional.empty(); } - private List findTargets(long threadId, StackFrame stackframe, IDebugAdapterContext context) { + private List findTargets(StackFrameReference frameReference, IDebugAdapterContext context) { + StackFrame stackframe = context.getStackFrameManager().getStackFrame(frameReference); + if (stackframe == null) { + return Collections.emptyList(); + } + + Source source = frameReference.getSource() == null ? findSource(stackframe, context) : frameReference.getSource(); + if (source == null) { + return Collections.emptyList(); + } + + String sourceUri = AdapterUtils.convertPath(source.path, AdapterUtils.isUri(source.path), true); + if (sourceUri == null) { + return Collections.emptyList(); + } + ISourceLookUpProvider sourceLookUpProvider = context.getProvider(ISourceLookUpProvider.class); - List invocations = sourceLookUpProvider.findMethodInvocations(stackframe); + List invocations = sourceLookUpProvider.findMethodInvocations(sourceUri, stackframe.location().lineNumber()); if (invocations.isEmpty()) { return Collections.emptyList(); } + long threadId = stackframe.thread().uniqueID(); List targets = new ArrayList<>(invocations.size()); for (MethodInvocation methodInvocation : invocations) { int id = context.getRecyclableIdPool().addObject(threadId, methodInvocation); StepInTarget target = new StepInTarget(id, methodInvocation.expression); - target.column = methodInvocation.columnStart; - target.endColumn = methodInvocation.columnEnd; - target.line = methodInvocation.lineStart; - target.endLine = methodInvocation.lineEnd; + target.column = AdapterUtils.convertColumnNumber(methodInvocation.columnStart, + context.isDebuggerColumnsStartAt1(), context.isClientColumnsStartAt1()); + target.endColumn = AdapterUtils.convertColumnNumber(methodInvocation.columnEnd, + context.isDebuggerColumnsStartAt1(), context.isClientColumnsStartAt1()); + target.line = AdapterUtils.convertLineNumber(methodInvocation.lineStart, + context.isDebuggerLinesStartAt1(), context.isClientLinesStartAt1()); + target.endLine = AdapterUtils.convertLineNumber(methodInvocation.lineEnd, + context.isDebuggerLinesStartAt1(), context.isClientLinesStartAt1()); targets.add(target); } + + // TODO remove the executed method calls. return targets; } + + private Source findSource(StackFrame frame, IDebugAdapterContext context) { + ReferenceType declaringType = frame.location().declaringType(); + String typeName = declaringType.name(); + String sourceName = null; + String sourcePath = null; + try { + // When the .class file doesn't contain source information in meta data, + // invoking ReferenceType#sourceName() would throw AbsentInformationException. + sourceName = declaringType.sourceName(); + sourcePath = declaringType.sourcePaths(null).get(0); + } catch (AbsentInformationException e) { + String enclosingType = AdapterUtils.parseEnclosingType(typeName); + sourceName = enclosingType.substring(enclosingType.lastIndexOf('.') + 1) + ".java"; + sourcePath = enclosingType.replace('.', File.separatorChar) + ".java"; + } + + try { + return StackTraceRequestHandler.convertDebuggerSourceToClient(typeName, sourceName, sourcePath, context); + } catch (URISyntaxException e) { + logger.log(Level.SEVERE, "Failed to resolve the source info of the stack frame.", e); + } + + return null; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java index 660d4bbdd..bd324a7fa 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java @@ -15,7 +15,6 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -39,8 +38,9 @@ import com.microsoft.java.debug.core.protocol.Requests.StepArguments; import com.microsoft.java.debug.core.protocol.Requests.StepFilters; import com.microsoft.java.debug.core.protocol.Requests.StepInArguments; -import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ClassType; import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InterfaceType; import com.sun.jdi.Location; import com.sun.jdi.Method; import com.sun.jdi.ObjectReference; @@ -48,7 +48,6 @@ import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadReference; import com.sun.jdi.Value; -import com.sun.jdi.VirtualMachine; import com.sun.jdi.VoidValue; import com.sun.jdi.event.BreakpointEvent; import com.sun.jdi.event.Event; @@ -102,11 +101,8 @@ public CompletableFuture handle(Command command, Arguments arguments, }); if (command == Command.STEPIN) { - String[] allowedClasses = threadState.pendingTargetStepIn != null - ? new String[]{threadState.pendingTargetStepIn.declaringTypeName} - : context.getStepFilters().allowClasses; threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, - allowedClasses, + context.getStepFilters().allowClasses, context.getStepFilters().skipClasses); } else if (command == Command.STEPOUT) { threadState.pendingStepRequest = DebugUtility.createStepOutRequest(thread, @@ -119,26 +115,29 @@ public CompletableFuture handle(Command command, Arguments arguments, threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager().createMethodExitRequest(); threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); - LocationResponse locationResponse = resolveLocation(thread, targetId, context); + threadState.targetStepIn = targetId > 0 + ? (MethodInvocation) context.getRecyclableIdPool().getObjectById(targetId) : null; if (context.asyncJDWP()) { List> futures = new ArrayList<>(); futures.add(AsyncJdwpUtils.runAsync(() -> { // JDWP Command: TR_FRAMES - threadState.stepLocation = locationResponse.location; - threadState.pendingTargetStepIn = locationResponse.methodInvocation; - threadState.targetStepIn = targetId > 0; - threadState.stepLocation = threadState.topFrame.location(); - threadState.pendingMethodExitRequest.addClassFilter(threadState.stepLocation.declaringType()); - if (targetThread.virtualMachine().canUseInstanceFilters()) { - try { - // JDWP Command: SF_THIS_OBJECT - ObjectReference thisObject = threadState.topFrame.thisObject(); - if (thisObject != null) { - threadState.pendingMethodExitRequest.addInstanceFilter(thisObject); + try { + threadState.topFrame = getTopFrame(targetThread); + threadState.stepLocation = threadState.topFrame.location(); + threadState.pendingMethodExitRequest.addClassFilter(threadState.stepLocation.declaringType()); + if (targetThread.virtualMachine().canUseInstanceFilters()) { + try { + // JDWP Command: SF_THIS_OBJECT + ObjectReference thisObject = threadState.topFrame.thisObject(); + if (thisObject != null) { + threadState.pendingMethodExitRequest.addInstanceFilter(thisObject); + } + } catch (Exception e) { + // ignore } - } catch (Exception e) { - // ignore } + } catch (IncompatibleThreadStateException e1) { + throw new CompletionException(e1); } })); futures.add(AsyncJdwpUtils.runAsync( @@ -170,10 +169,8 @@ public CompletableFuture handle(Command command, Arguments arguments, // JDWP Command: ER_SET threadState.pendingMethodExitRequest.enable(); } else { + threadState.topFrame = getTopFrame(targetThread); threadState.stackDepth = targetThread.frameCount(); - threadState.stepLocation = locationResponse.location; - threadState.pendingTargetStepIn = locationResponse.methodInvocation; - threadState.targetStepIn = targetId > 0; threadState.stepLocation = threadState.topFrame.location(); threadState.pendingMethodExitRequest.addThreadFilter(thread); threadState.pendingMethodExitRequest.addClassFilter(threadState.stepLocation.declaringType()); @@ -224,57 +221,6 @@ public CompletableFuture handle(Command command, Arguments arguments, return CompletableFuture.completedFuture(response); } - private LocationResponse resolveLocation(ThreadReference thread, int targetId, IDebugAdapterContext context) - throws IncompatibleThreadStateException, AbsentInformationException { - if (targetId > 0) { - Object value = context.getRecyclableIdPool().getObjectById(targetId); - if (value instanceof MethodInvocation) { - return resolveLocation((MethodInvocation) value, thread); - } - } - return LocationResponse.absolute(getTopFrame(thread).location()); - } - - private LocationResponse resolveLocation(MethodInvocation invocation, ThreadReference thread) - throws AbsentInformationException, IncompatibleThreadStateException { - VirtualMachine vm = thread.virtualMachine(); - List refTypes = vm.classesByName(invocation.declaringTypeName); - - // if class is not yet loaded try to make the debugger step in until class is - // loaded. - if (refTypes.isEmpty()) { - return LocationResponse.waitFor(invocation, getTopFrame(thread).location()); - } else { - for (ReferenceType referenceType : refTypes) { - Optional location = referenceType.allLineLocations().stream() - .filter(l -> matchesLocation(l, invocation)) - .findFirst(); - if (location.isPresent()) { - return LocationResponse.absolute(location.get()); - } - } - return LocationResponse.absolute(getTopFrame(thread).location()); - } - } - - private boolean matchesLocation(Location l, MethodInvocation invocation) { - Method method = l.method(); - return method != null && Objects.equals(fixedName(method), invocation.methodName) - && Objects.equals(method.signature(), invocation.methodSignature); - } - - /* - * Fix the name so for constructors we return empty to match the captured AST - * invocations. - */ - private String fixedName(Method method) { - String name = method.name(); - if ("".equals(name)) { - return ""; - } - return name; - } - private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, IDebugAdapterContext context, ThreadState threadState) { Event event = debugEvent.event; @@ -283,7 +229,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, // When a breakpoint occurs, abort any pending step requests from the same thread. if (event instanceof BreakpointEvent || event instanceof ExceptionEvent) { // if we have a pending target step in then ignore and continue. - if (threadState.pendingTargetStepIn != null) { + if (threadState.targetStepIn != null) { debugEvent.shouldResume = true; return; } @@ -299,41 +245,62 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, } } else if (event instanceof StepEvent) { ThreadReference thread = ((StepEvent) event).thread(); + long threadId = thread.uniqueID(); threadState.deleteStepRequest(eventRequestManager); - if (isStepFiltersConfigured(context.getStepFilters()) || threadState.targetStepIn) { + if (isStepFiltersConfigured(context.getStepFilters()) || threadState.targetStepIn != null) { try { - if (threadState.pendingStepType == Command.STEPIN) { + if (threadState.pendingStepType == Command.STEPIN || threadState.targetStepIn != null) { int currentStackDepth = thread.frameCount(); - Location currentStepLocation = getTopFrame(thread).location(); - - // if we are in targetStepIn where the location was pending, then try to resolve - // the location and use it. - if (threadState.pendingTargetStepIn != null) { - LocationResponse newLocation = resolveLocation(threadState.pendingTargetStepIn, thread); - if (!newLocation.isLocationPending()) { - threadState.stepLocation = newLocation.location; - threadState.pendingTargetStepIn = null; + StackFrame topFrame = getTopFrame(thread); + Location currentStepLocation = topFrame.location(); + if (threadState.targetStepIn != null) { + if (isStoppedAtSelectedMethod(topFrame, threadState.targetStepIn)) { + // hit: send StoppedEvent + } else { + if (currentStackDepth > threadState.stackDepth) { + context.getStepResultManager().removeMethodResult(threadId); + threadState.pendingStepRequest = DebugUtility.createStepOutRequest(thread, + context.getStepFilters().allowClasses, + context.getStepFilters().skipClasses); + threadState.pendingStepRequest.enable(); + debugEvent.shouldResume = true; + return; + } else if (currentStackDepth == threadState.stackDepth) { + // If the ending step location is same as the original location where the step into operation is originated, + // do another step of the same kind. + if (isSameLocation(currentStepLocation, threadState.stepLocation)) { + context.getStepResultManager().removeMethodResult(threadId); + threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, + context.getStepFilters().allowClasses, + context.getStepFilters().skipClasses); + threadState.pendingStepRequest.enable(); + debugEvent.shouldResume = true; + return; + } + } } - } - - // If the ending step location is filtered, or same as the original location where the step into operation is originated, - // do another step of the same kind. - if (shouldFilterLocation(threadState.stepLocation, currentStepLocation, context) + } else if (shouldFilterLocation(threadState.stepLocation, currentStepLocation, context) || shouldDoExtraStepInto(threadState.stackDepth, threadState.stepLocation, - currentStackDepth, currentStepLocation, threadState.targetStepIn) - || threadState.pendingTargetStepIn != null) { - String[] allowedClasses = threadState.pendingTargetStepIn != null - ? new String[]{threadState.pendingTargetStepIn.declaringTypeName} - : context.getStepFilters().allowClasses; - threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, + currentStackDepth, currentStepLocation)) { + // If the ending step location is filtered, or same as the original location where the step into operation is originated, + // do another step of the same kind. + context.getStepResultManager().removeMethodResult(threadId); + String[] allowedClasses = context.getStepFilters().allowClasses; + if (currentStackDepth > threadState.stackDepth) { + threadState.pendingStepRequest = DebugUtility.createStepOutRequest(thread, allowedClasses, - context.getStepFilters().skipClasses); + context.getStepFilters().skipClasses); + } else { + threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, + allowedClasses, + context.getStepFilters().skipClasses); + } threadState.pendingStepRequest.enable(); debugEvent.shouldResume = true; return; } } - } catch (IncompatibleThreadStateException | IndexOutOfBoundsException | AbsentInformationException ex) { + } catch (IncompatibleThreadStateException | IndexOutOfBoundsException ex) { // ignore. } } @@ -360,6 +327,56 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, } } + private boolean isStoppedAtSelectedMethod(StackFrame frame, MethodInvocation selectedMethod) { + Method method = frame.location().method(); + if (method != null + && Objects.equals(method.name(), selectedMethod.methodName) + && (Objects.equals(method.signature(), selectedMethod.methodSignature) + || Objects.equals(method.genericSignature(), selectedMethod.methodGenericSignature))) { + ObjectReference thisObject = frame.thisObject(); + ReferenceType currentType = (thisObject == null) ? method.declaringType() : thisObject.referenceType(); + if ("java.lang.Object".equals(selectedMethod.declaringTypeName)) { + return true; + } + + return isSubType(currentType, selectedMethod.declaringTypeName); + } + + return false; + } + + private boolean isSubType(ReferenceType currentType, String baseType) { + if (baseType.equals(currentType.name())) { + return true; + } + + if (currentType instanceof ClassType) { + ClassType classType = (ClassType) currentType; + ClassType superClassType = classType.superclass(); + if (superClassType != null && isSubType(superClassType, baseType)) { + return true; + } + + List interfaces = classType.allInterfaces(); + for (InterfaceType iface : interfaces) { + if (isSubType(iface, baseType)) { + return true; + } + } + } + + if (currentType instanceof InterfaceType) { + List superInterfaces = ((InterfaceType) currentType).superinterfaces(); + for (InterfaceType superInterface : superInterfaces) { + if (isSubType(superInterface, baseType)) { + return true; + } + } + } + + return false; + } + private boolean isStepFiltersConfigured(StepFilters filters) { if (filters == null) { return false; @@ -400,25 +417,36 @@ private boolean shouldFilterMethod(Method method, IDebugAdapterContext context) * the target VM. */ private boolean shouldDoExtraStepInto(int originalStackDepth, Location originalLocation, int currentStackDepth, - Location currentLocation, boolean targetStepIn) + Location currentLocation) throws IncompatibleThreadStateException { - if (!targetStepIn) { - if (originalStackDepth != currentStackDepth) { - return false; - } - if (originalLocation == null) { - return false; - } + if (originalStackDepth != currentStackDepth) { + return false; + } + if (originalLocation == null) { + return false; } + Method originalMethod = originalLocation.method(); Method currentMethod = currentLocation.method(); if (!originalMethod.equals(currentMethod)) { - return targetStepIn; + return false; } if (originalLocation.lineNumber() != currentLocation.lineNumber()) { - return targetStepIn; + return false; } - return !targetStepIn; + + return true; + } + + private boolean isSameLocation(Location original, Location current) { + if (original == null || current == null) { + return false; + } + + Method originalMethod = original.method(); + Method currentMethod = current.method(); + return originalMethod.equals(currentMethod) + && original.lineNumber() == current.lineNumber(); } /** @@ -445,8 +473,7 @@ class ThreadState { StackFrame topFrame = null; Location stepLocation = null; Disposable eventSubscription = null; - boolean targetStepIn = false; - MethodInvocation pendingTargetStepIn; + MethodInvocation targetStepIn = null; public void deleteMethodExitRequest(EventRequestManager manager) { DebugUtility.deleteEventRequestSafely(manager, this.pendingMethodExitRequest); @@ -458,27 +485,4 @@ public void deleteStepRequest(EventRequestManager manager) { this.pendingStepRequest = null; } } - - static class LocationResponse { - Location location; - MethodInvocation methodInvocation; - - private LocationResponse(Location location, MethodInvocation methodInvocation) { - this.location = location; - this.methodInvocation = methodInvocation; - } - - public static LocationResponse waitFor(MethodInvocation invocation, Location location) { - return new LocationResponse(location, invocation); - } - - public static LocationResponse absolute(Location location) { - return new LocationResponse(location, null); - } - - boolean isLocationPending() { - return methodInvocation != null; - } - - } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/StackFrameReference.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/StackFrameReference.java index 4dc895007..46726cde8 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/StackFrameReference.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/StackFrameReference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Microsoft Corporation and others. + * Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,12 +11,14 @@ package com.microsoft.java.debug.core.adapter.variables; +import com.microsoft.java.debug.core.protocol.Types.Source; import com.sun.jdi.ThreadReference; public class StackFrameReference { private final int depth; private final int hash; private final ThreadReference thread; + private Source source; /** * Create a wrapper of JDI stackframe to keep the immutable properties of a stackframe, IStackFrameManager will use @@ -48,6 +50,14 @@ public ThreadReference getThread() { return thread; } + public Source getSource() { + return source; + } + + public void setSource(Source source) { + this.source = source; + } + @Override public int hashCode() { return hash; diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java index a6535715a..b696be049 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017-2020 Microsoft Corporation and others. + * Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -61,12 +61,9 @@ public static String toSignature(IMethodBinding binding, String name) { // use key for now until JDT core provides a public API for this. // "Ljava/util/Arrays;.asList([TT;)Ljava/util/List;" // "([Ljava/lang/String;)V|Ljava/lang/InterruptedException;" - if (!binding.getName().equals(name)) { - throw new IllegalArgumentException("The method name and binding method name doesn't match."); - } - String signatureString = binding.getKey(); if (signatureString != null) { + name = "." + name; int index = signatureString.indexOf(name); if (index > -1) { int exceptionIndex = signatureString.indexOf("|", signatureString.lastIndexOf(")")); diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index eb3eb46f2..c4d4fe318 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -15,7 +15,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; -import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; @@ -35,28 +34,31 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.URIUtil; import org.eclipse.debug.core.sourcelookup.ISourceContainer; import org.eclipse.jdt.core.IBuffer; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; -import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.LambdaExpression; -import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.LibraryLocation; +import org.eclipse.jdt.ls.core.internal.JDTUtils; import com.microsoft.java.debug.BindingUtils; import com.microsoft.java.debug.BreakpointLocationLocator; @@ -71,8 +73,6 @@ import com.microsoft.java.debug.core.protocol.Types.BreakpointLocation; import com.microsoft.java.debug.core.protocol.Types.SourceBreakpoint; -import com.sun.jdi.StackFrame; - public class JdtSourceLookUpProvider implements ISourceLookUpProvider { private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); private static final String JDT_SCHEME = "jdt"; @@ -452,60 +452,71 @@ private static String resolveSystemLibraryVersion(IJavaProject project, IVMInsta return null; } - @Override - public List findMethodInvocations(StackFrame frame) { - if (frame == null) { - throw new IllegalArgumentException("frame is null"); - } - - IJavaProject project = JdtUtils.findProject(frame, getSourceContainers()); - if (project == null) { - logger.log(Level.WARNING, - String.format("Failed to resolve project for the frame: %s", frame)); + public List findMethodInvocations(String uri, int line) { + if (uri == null) { return Collections.emptyList(); } - String uri; - try { - IType type = project.findType(JdtUtils.getDeclaringTypeName(frame)); - uri = type.getResource().getLocationURI().toURL().toString(); - } catch (JavaModelException | DebugException | MalformedURLException e) { - logger.log(Level.SEVERE, - String.format("Failed to resolve type for the frame: %s", frame)); - return Collections.emptyList(); + boolean useCache = false; + CompilationUnit cachedUnit = CoreASTProvider.getInstance().getCachedAST(); + if (cachedUnit != null) { + ITypeRoot cachedElement = cachedUnit.getTypeRoot(); + if (cachedElement != null && isSameURI(JDTUtils.toUri(cachedElement), uri)) { + useCache = true; + } } - CompilationUnit astUnit = asCompilationUnit(uri); + final CompilationUnit astUnit = useCache ? cachedUnit : asCompilationUnit(uri); if (astUnit == null) { return Collections.emptyList(); } - MethodInvocationLocator locator = new MethodInvocationLocator(frame.location().lineNumber(), astUnit); + MethodInvocationLocator locator = new MethodInvocationLocator(line, astUnit); astUnit.accept(locator); return locator.getTargets().entrySet().stream().map(entry -> { MethodInvocation invocation = new MethodInvocation(); - Expression expression = entry.getKey(); - invocation.expression = expression.toString(); - IMethodBinding binding = entry.getValue(); - invocation.methodName = binding.getName(); + ASTNode astNode = entry.getKey(); + invocation.expression = astNode.toString(); + IMethodBinding binding = entry.getValue().getMethodDeclaration(); + invocation.methodName = binding.isConstructor() ? "" : binding.getName(); if (binding.getDeclaringClass().isAnonymous()) { ITypeBinding superclass = binding.getDeclaringClass().getSuperclass(); if (superclass != null && !superclass.isEqualTo(astUnit.getAST().resolveWellKnownType("java.lang.Object"))) { - invocation.declaringTypeName = superclass.getQualifiedName(); + invocation.declaringTypeName = superclass.getBinaryName(); } else { return null; } } else { - invocation.declaringTypeName = binding.getDeclaringClass().getQualifiedName(); + // Keep consistent with JDI since JDI uses binary class name + invocation.declaringTypeName = binding.getDeclaringClass().getBinaryName(); } - invocation.methodSignature = BindingUtils.toSignature(binding, BindingUtils.getMethodName(binding, true)); - invocation.lineStart = astUnit.getLineNumber(expression.getStartPosition()); - invocation.lineEnd = astUnit.getLineNumber(expression.getStartPosition() + expression.getLength()); - invocation.columnStart = astUnit.getColumnNumber(expression.getStartPosition()); - invocation.columnEnd = astUnit.getColumnNumber(expression.getStartPosition() + expression.getLength()); + invocation.methodGenericSignature = BindingUtils.toSignature(binding, BindingUtils.getMethodName(binding, true)); + invocation.methodSignature = Signature.getTypeErasure(invocation.methodGenericSignature); + int startOffset = astNode.getStartPosition(); + if (astNode instanceof org.eclipse.jdt.core.dom.MethodInvocation) { + // The range covered by the stepIn target should start with the method name. + startOffset = ((org.eclipse.jdt.core.dom.MethodInvocation) astNode).getName().getStartPosition(); + } + invocation.lineStart = astUnit.getLineNumber(startOffset); + invocation.columnStart = astUnit.getColumnNumber(startOffset); + int endOffset = astNode.getStartPosition() + astNode.getLength(); + invocation.lineEnd = astUnit.getLineNumber(endOffset); + invocation.columnEnd = astUnit.getColumnNumber(endOffset); return invocation; }).filter(Objects::nonNull).collect(Collectors.toList()); } + + private boolean isSameURI(String uri1, String uri2) { + if (Objects.equals(uri1, uri2)) { + return true; + } + + try { + return URIUtil.sameURI(new URI(uri1), new URI(uri2)); + } catch (URISyntaxException e) { + return false; + } + } } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java index f0364d98b..a25fbc3f6 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java @@ -13,20 +13,44 @@ import java.util.HashMap; import java.util.Map; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.AssertStatement; +import org.eclipse.jdt.core.dom.BreakStatement; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EmptyStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.EnumDeclaration; import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.LabeledStatement; +import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.SynchronizedStatement; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.core.dom.YieldStatement; public class MethodInvocationLocator extends ASTVisitor { private int line; private CompilationUnit unit; - private Map targets; - - private int expressionCount = 0; + private Map targets; public MethodInvocationLocator(int line, CompilationUnit unit) { super(false); @@ -35,45 +59,174 @@ public MethodInvocationLocator(int line, CompilationUnit unit) { this.targets = new HashMap<>(); } + @Override + public boolean visit(FieldDeclaration node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(MethodDeclaration node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(TypeDeclaration node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(AnonymousClassDeclaration node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(EnumDeclaration node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(AnnotationTypeDeclaration node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + return shouldVisitNode(node); + } + @Override public boolean visit(ExpressionStatement node) { - int start = unit.getLineNumber(node.getStartPosition()); - int end = unit.getLineNumber(node.getStartPosition() + node.getLength()); + return shouldVisitNode(node); + } + + @Override + public boolean visit(AssertStatement node) { + return shouldVisitNode(node); - if (line >= start && line <= end) { - expressionCount++; - } - return expressionCount > 0; } @Override - public boolean visit(MethodInvocation node) { - if (expressionCount > 0) { - targets.put(node, node.resolveMethodBinding()); + public boolean visit(BreakStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(ContinueStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(DoStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(EmptyStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(EnhancedForStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(ForStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(IfStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(LabeledStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(ReturnStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(SwitchStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(SynchronizedStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(ThrowStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(TryStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(TypeDeclarationStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(WhileStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(YieldStatement node) { + return shouldVisitNode(node); + } + + @Override + public boolean visit(ConstructorInvocation node) { + if (shouldVisitNode(node)) { + targets.put(node, node.resolveConstructorBinding()); + return true; } - return expressionCount > 0; + return false; } @Override - public boolean visit(ClassInstanceCreation node) { - if (expressionCount > 0) { + public boolean visit(SuperConstructorInvocation node) { + if (shouldVisitNode(node)) { targets.put(node, node.resolveConstructorBinding()); - expressionCount--; + return true; } - return expressionCount > 0; + return false; } @Override - public void endVisit(ExpressionStatement node) { - expressionCount--; + public boolean visit(MethodInvocation node) { + targets.put(node, node.resolveMethodBinding()); + return true; } @Override - public void endVisit(ClassInstanceCreation node) { - expressionCount++; + public boolean visit(ClassInstanceCreation node) { + targets.put(node, node.resolveConstructorBinding()); + return true; + } + + private boolean shouldVisitNode(ASTNode node) { + int start = unit.getLineNumber(node.getStartPosition()); + int end = unit.getLineNumber(node.getStartPosition() + node.getLength()); + + if (line >= start && line <= end) { + return true; + } + + return false; } - public Map getTargets() { + public Map getTargets() { return targets; } } From ec39583b4b5ae79c0c220e4300ede4be5b87c928 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 31 Oct 2022 14:56:22 +0800 Subject: [PATCH 05/94] Conditional Breakpoint got error code in reply:504 (#453) --- .../debug/core/adapter/IStackFrameManager.java | 16 +++++++++++++++- .../debug/core/adapter/StackFrameManager.java | 16 +++++++++++++++- .../adapter/handler/ThreadsRequestHandler.java | 4 ++++ .../internal/eval/JdtEvaluationProvider.java | 2 +- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IStackFrameManager.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IStackFrameManager.java index abce2ff3e..8d6c74486 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IStackFrameManager.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IStackFrameManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017 Microsoft Corporation and others. + * Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -32,6 +32,15 @@ public interface IStackFrameManager { */ StackFrame[] reloadStackFrames(ThreadReference thread); + /** + * Refresh all stackframes from jdi thread. + * + * @param thread the jdi thread + * @param force Whether to load the whole frames if the thread's stackframes haven't been cached. + * @return all the stackframes in the specified thread + */ + StackFrame[] reloadStackFrames(ThreadReference thread, boolean force); + /** * Refersh the stackframes starting from the specified depth and length. * @@ -48,4 +57,9 @@ public interface IStackFrameManager { * @param thread the jdi thread */ void clearStackFrames(ThreadReference thread); + + /** + * Clear the whole stackframes cache. + */ + void clearStackFrames(); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/StackFrameManager.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/StackFrameManager.java index 2a9d1e47e..518cc7761 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/StackFrameManager.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/StackFrameManager.java @@ -32,10 +32,19 @@ public synchronized StackFrame getStackFrame(StackFrameReference ref) { @Override public synchronized StackFrame[] reloadStackFrames(ThreadReference thread) { + return reloadStackFrames(thread, true); + } + + @Override + public synchronized StackFrame[] reloadStackFrames(ThreadReference thread, boolean force) { return threadStackFrameMap.compute(thread.uniqueID(), (key, old) -> { try { if (old == null || old.length == 0) { - return thread.frames().toArray(new StackFrame[0]); + if (force) { + return thread.frames().toArray(new StackFrame[0]); + } else { + return new StackFrame[0]; + } } else { return thread.frames(0, old.length).toArray(new StackFrame[0]); } @@ -71,4 +80,9 @@ public synchronized StackFrame[] reloadStackFrames(ThreadReference thread, int s public synchronized void clearStackFrames(ThreadReference thread) { threadStackFrameMap.remove(thread.uniqueID()); } + + @Override + public synchronized void clearStackFrames() { + threadStackFrameMap.clear(); + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java index 7d404691c..fceac73a5 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java @@ -159,11 +159,13 @@ private CompletableFuture resume(Requests.ContinueArguments arguments, context.getExceptionManager().removeException(arguments.threadId); allThreadsContinued = false; DebugUtility.resumeThread(thread); + context.getStackFrameManager().clearStackFrames(thread); checkThreadRunningAndRecycleIds(thread, context); } else { context.getStepResultManager().removeAllMethodResults(); context.getExceptionManager().removeAllExceptions(); resumeVM(context); + context.getStackFrameManager().clearStackFrames(); context.getRecyclableIdPool().removeAllObjects(); } response.body = new Responses.ContinueResponseBody(allThreadsContinued); @@ -175,6 +177,7 @@ private CompletableFuture resumeAll(Requests.ThreadOperationArguments context.getExceptionManager().removeAllExceptions(); resumeVM(context); context.getProtocolServer().sendEvent(new Events.ContinuedEvent(arguments.threadId, true)); + context.getStackFrameManager().clearStackFrames(); context.getRecyclableIdPool().removeAllObjects(); return CompletableFuture.completedFuture(response); } @@ -280,6 +283,7 @@ private void resumeThread(ThreadReference thread, IDebugAdapterContext context) context.getExceptionManager().removeException(threadId); DebugUtility.resumeThread(thread, suspends); context.getProtocolServer().sendEvent(new Events.ContinuedEvent(threadId)); + context.getStackFrameManager().clearStackFrames(thread); checkThreadRunningAndRecycleIds(thread, context); } } catch (ObjectCollectedException ex) { diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/eval/JdtEvaluationProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/eval/JdtEvaluationProvider.java index d4fac9054..a48cf7ead 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/eval/JdtEvaluationProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/eval/JdtEvaluationProvider.java @@ -317,7 +317,7 @@ private JDIThread getMockJDIThread(ThreadReference thread) { @Override protected synchronized void invokeComplete(int restoreTimeout) { super.invokeComplete(restoreTimeout); - context.getStackFrameManager().reloadStackFrames(thread); + context.getStackFrameManager().reloadStackFrames(thread, false); } }); } From fbf15977219a45c2e0f3c3317a5dd422f627a253 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 31 Oct 2022 17:26:56 +0800 Subject: [PATCH 06/94] Bump version to 0.42.0 (#454) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- pom.xml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 8bb9b9f47..d9fb24c2e 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.41.0 + 0.42.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 21e32bbde..0858d90eb 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.41.0 +Bundle-Version: 0.42.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.41.0.jar + lib/com.microsoft.java.debug.core-0.42.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 949512717..c1b4144fa 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.41.0 + 0.42.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.41.0 + 0.42.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 27c76516b..ff39c1d7f 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index b8524fa90..c5a1f46a0 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.41.0 + 0.42.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/pom.xml b/pom.xml index 4d31432d9..2adb8badf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.41.0 + 0.42.0 pom Java Debug Server for Visual Studio Code From 4b773bd9b1891dbadd93a0e995656b575c80213a Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 8 Nov 2022 18:29:58 +0800 Subject: [PATCH 07/94] Fix version info in .classpath (#456) --- com.microsoft.java.debug.plugin/.classpath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 349cb7844..43f07f603 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + From de77ff37cb5e3a9301e4dc83ae47af211bd59be5 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 15 Nov 2022 10:29:11 +0800 Subject: [PATCH 08/94] "shortenCommandLine": "argfile|auto" should include "vmArgs" (#457) --- .../debug/core/adapter/handler/LaunchRequestHandler.java | 4 ++-- .../java/debug/core/adapter/handler/LaunchUtils.java | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java index e5b580f50..e99706bda 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java @@ -134,8 +134,8 @@ protected CompletableFuture handleLaunchCommand(Arguments arguments, R } } else if (launchArguments.shortenCommandLine == ShortenApproach.ARGFILE) { try { - Path tempfile = LaunchUtils.generateArgfile(launchArguments.classPaths, launchArguments.modulePaths); - launchArguments.vmArgs += " \"@" + tempfile.toAbsolutePath().toString() + "\""; + Path tempfile = LaunchUtils.generateArgfile(launchArguments.vmArgs, launchArguments.classPaths, launchArguments.modulePaths); + launchArguments.vmArgs = " \"@" + tempfile.toAbsolutePath().toString() + "\""; launchArguments.classPaths = new String[0]; launchArguments.modulePaths = new String[0]; context.setArgsfile(tempfile); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java index ca7d69a99..3be6fcbac 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java @@ -40,6 +40,7 @@ import com.microsoft.java.debug.core.adapter.AdapterUtils; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; public class LaunchUtils { @@ -81,10 +82,14 @@ public static synchronized Path generateClasspathJar(String[] classPaths) throws * @return the file path of the generated argfile * @throws IOException Some errors occur during generating the argfile */ - public static synchronized Path generateArgfile(String[] classPaths, String[] modulePaths) throws IOException { + public static synchronized Path generateArgfile(String vmArgs, String[] classPaths, String[] modulePaths) throws IOException { String argfile = ""; + if (StringUtils.isNotBlank(vmArgs)) { + argfile += vmArgs; + } + if (ArrayUtils.isNotEmpty(classPaths)) { - argfile = "-cp \"" + String.join(File.pathSeparator, classPaths) + "\""; + argfile += " -cp \"" + String.join(File.pathSeparator, classPaths) + "\""; } if (ArrayUtils.isNotEmpty(modulePaths)) { From 791cd97260f204e2cb851e79287881f6d634c1b4 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 16 Nov 2022 17:03:13 +0800 Subject: [PATCH 09/94] Use the system encoding to generate the *.argfile (#458) --- .../adapter/handler/LaunchRequestHandler.java | 52 ++++++++++++++++--- .../core/adapter/handler/LaunchUtils.java | 40 ++++++++++++-- 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java index e99706bda..b1daf1b01 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2018-2021 Microsoft Corporation and others. +* Copyright (c) 2018-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -16,6 +16,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -134,11 +135,50 @@ protected CompletableFuture handleLaunchCommand(Arguments arguments, R } } else if (launchArguments.shortenCommandLine == ShortenApproach.ARGFILE) { try { - Path tempfile = LaunchUtils.generateArgfile(launchArguments.vmArgs, launchArguments.classPaths, launchArguments.modulePaths); - launchArguments.vmArgs = " \"@" + tempfile.toAbsolutePath().toString() + "\""; - launchArguments.classPaths = new String[0]; - launchArguments.modulePaths = new String[0]; - context.setArgsfile(tempfile); + /** + * See the JDK spec https://docs.oracle.com/en/java/javase/18/docs/specs/man/java.html#java-command-line-argument-files. + * The argument file must contain only ASCII characters or characters in system default encoding that's ASCII friendly. + */ + Charset systemCharset = LaunchUtils.getSystemCharset(); + CharsetEncoder encoder = systemCharset.newEncoder(); + String vmArgsForShorten = null; + String[] classPathsForShorten = null; + String[] modulePathsForShorten = null; + if (StringUtils.isNotBlank(launchArguments.vmArgs)) { + if (!encoder.canEncode(launchArguments.vmArgs)) { + logger.warning(String.format("Cannot generate the 'vmArgs' argument into the argfile because it contains characters " + + "that cannot be encoded in the system charset '%s'.", systemCharset.displayName())); + } else { + vmArgsForShorten = launchArguments.vmArgs; + } + } + + if (ArrayUtils.isNotEmpty(launchArguments.classPaths)) { + if (!encoder.canEncode(String.join(File.pathSeparator, launchArguments.classPaths))) { + logger.warning(String.format("Cannot generate the '-cp' argument into the argfile because it contains characters " + + "that cannot be encoded in the system charset '%s'.", systemCharset.displayName())); + } else { + classPathsForShorten = launchArguments.classPaths; + } + } + + if (ArrayUtils.isNotEmpty(launchArguments.modulePaths)) { + if (!encoder.canEncode(String.join(File.pathSeparator, launchArguments.modulePaths))) { + logger.warning(String.format("Cannot generate the '--module-path' argument into the argfile because it contains characters " + + "that cannot be encoded in the system charset '%s'.", systemCharset.displayName())); + } else { + modulePathsForShorten = launchArguments.modulePaths; + } + } + + if (vmArgsForShorten != null || classPathsForShorten != null || modulePathsForShorten != null) { + Path tempfile = LaunchUtils.generateArgfile(vmArgsForShorten, classPathsForShorten, modulePathsForShorten, systemCharset); + launchArguments.vmArgs = (vmArgsForShorten == null ? launchArguments.vmArgs : "") + + " \"@" + tempfile.toAbsolutePath().toString() + "\""; + launchArguments.classPaths = (classPathsForShorten == null ? launchArguments.classPaths : new String[0]); + launchArguments.modulePaths = (modulePathsForShorten == null ? launchArguments.modulePaths : new String[0]); + context.setArgsfile(tempfile); + } } catch (IOException e) { logger.log(Level.SEVERE, String.format("Failed to create a temp argfile: %s", e.toString()), e); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java index 3be6fcbac..27fdb1813 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.math.BigInteger; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -36,16 +37,45 @@ import java.util.logging.Logger; import java.util.stream.Collectors; -import com.microsoft.java.debug.core.Configuration; -import com.microsoft.java.debug.core.adapter.AdapterUtils; - import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; +import com.microsoft.java.debug.core.Configuration; +import com.microsoft.java.debug.core.adapter.AdapterUtils; + public class LaunchUtils { private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); private static Set tempFilesInUse = new HashSet<>(); + private static final Charset SYSTEM_CHARSET; + + static { + Charset result = null; + try { + // JEP 400: Java 17+ populates this system property. + String encoding = System.getProperty("native.encoding"); //$NON-NLS-1$ + if (encoding != null && !encoding.isBlank()) { + result = Charset.forName(encoding); + } else { + // JVM internal property, works on older JVM's too + encoding = System.getProperty("sun.jnu.encoding"); //$NON-NLS-1$ + if (encoding != null && !encoding.isBlank()) { + result = Charset.forName(encoding); + } + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Error occurs during resolving system encoding", e); + } + if (result == null) { + // This is always UTF-8 on Java >= 18. + result = Charset.defaultCharset(); + } + SYSTEM_CHARSET = result; + } + + public static Charset getSystemCharset() { + return SYSTEM_CHARSET; + } /** * Generate the classpath parameters to a temporary classpath.jar. @@ -82,7 +112,7 @@ public static synchronized Path generateClasspathJar(String[] classPaths) throws * @return the file path of the generated argfile * @throws IOException Some errors occur during generating the argfile */ - public static synchronized Path generateArgfile(String vmArgs, String[] classPaths, String[] modulePaths) throws IOException { + public static synchronized Path generateArgfile(String vmArgs, String[] classPaths, String[] modulePaths, Charset encoding) throws IOException { String argfile = ""; if (StringUtils.isNotBlank(vmArgs)) { argfile += vmArgs; @@ -100,7 +130,7 @@ public static synchronized Path generateArgfile(String vmArgs, String[] classPat String baseName = "cp_" + getMd5(argfile); cleanupTempFiles(baseName, ".argfile"); Path tempfile = createTempFile(baseName, ".argfile"); - Files.write(tempfile, argfile.getBytes()); + Files.writeString(tempfile, argfile, encoding); lockTempLaunchFile(tempfile); return tempfile; From 4384d854bc60a9fffd95b90131f0ca1e98f79cfe Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 21 Nov 2022 10:08:17 +0800 Subject: [PATCH 10/94] Only pop-up build errors notification when the errors are on the running project's classpath (#459) --- .../java/debug/plugin/internal/Compile.java | 145 ++++++++++++++++++ .../JavaDebugDelegateCommandHandler.java | 10 +- 2 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java new file mode 100644 index 000000000..415456ce5 --- /dev/null +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + *******************************************************************************/ + +package com.microsoft.java.debug.plugin.internal; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.ls.core.internal.BuildWorkspaceStatus; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.ProjectUtils; +import org.eclipse.jdt.ls.core.internal.ResourceUtils; +import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; + +import com.microsoft.java.debug.core.Configuration; + +public class Compile { + private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); + + public static BuildWorkspaceStatus compile(CompileParams params, IProgressMonitor monitor) { + try { + if (monitor.isCanceled()) { + return BuildWorkspaceStatus.CANCELLED; + } + + long compileAt = System.currentTimeMillis(); + if (params != null && params.isFullBuild()) { + ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.CLEAN_BUILD, monitor); + ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, monitor); + } else { + ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); + } + logger.info("Time cost for ECJ: " + (System.currentTimeMillis() - compileAt) + "ms"); + + IProject mainProject = params == null ? null : ProjectUtils.getProject(params.getProjectName()); + IResource currentResource = mainProject; + if (isUnmanagedFolder(mainProject) && StringUtils.isNotBlank(params.getMainClass())) { + IType mainType = ProjectUtils.getJavaProject(mainProject).findType(params.getMainClass()); + if (mainType != null && mainType.getResource() != null) { + currentResource = mainType.getResource(); + } + } + + List problemMarkers = new ArrayList<>(); + if (currentResource != null) { + List markers = ResourceUtils.getErrorMarkers(currentResource); + if (markers != null) { + problemMarkers.addAll(markers); + } + + // Check if the referenced projects contain compilation errors. + if (currentResource instanceof IProject && ProjectUtils.isJavaProject((IProject) currentResource)) { + IJavaProject currentJavaProject = ProjectUtils.getJavaProject((IProject) currentResource); + IJavaProject[] javaProjects = ProjectUtils.getJavaProjects(); + for (IJavaProject otherJavaProject : javaProjects) { + IProject other = otherJavaProject.getProject(); + if (!other.equals(getDefaultProject()) && !other.equals((IProject) currentResource) + && currentJavaProject.isOnClasspath(otherJavaProject)) { + markers = ResourceUtils.getErrorMarkers(other); + if (markers != null) { + problemMarkers.addAll(markers); + } + } + } + } + } else { + IJavaProject[] javaProjects = ProjectUtils.getJavaProjects(); + for (IJavaProject javaProject : javaProjects) { + IProject project = javaProject.getProject(); + if (!project.equals(getDefaultProject())) { + List markers = ResourceUtils.getErrorMarkers(project); + if (markers != null) { + problemMarkers.addAll(markers); + } + } + } + } + + if (problemMarkers.isEmpty()) { + return BuildWorkspaceStatus.SUCCEED; + } + + return BuildWorkspaceStatus.WITH_ERROR; + } catch (CoreException e) { + JavaLanguageServerPlugin.logException("Failed to build workspace.", e); + return BuildWorkspaceStatus.FAILED; + } catch (OperationCanceledException e) { + return BuildWorkspaceStatus.CANCELLED; + } + } + + private static boolean isUnmanagedFolder(IProject project) { + return project != null && ProjectUtils.isUnmanagedFolder(project) + && ProjectUtils.isJavaProject(project); + } + + private static IProject getDefaultProject() { + return getWorkspaceRoot().getProject(ProjectsManager.DEFAULT_PROJECT_NAME); + } + + private static IWorkspaceRoot getWorkspaceRoot() { + return ResourcesPlugin.getWorkspace().getRoot(); + } + + class CompileParams { + String projectName; + String mainClass; + boolean isFullBuild = false; + + public String getMainClass() { + return mainClass; + } + + public boolean isFullBuild() { + return isFullBuild; + } + + public String getProjectName() { + return projectName; + } + } +} diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaDebugDelegateCommandHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaDebugDelegateCommandHandler.java index 1875d514e..f4e7b0ba3 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaDebugDelegateCommandHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaDebugDelegateCommandHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2017-2019 Microsoft Corporation and others. +* Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -64,8 +64,12 @@ public Object executeCommand(String commandId, List arguments, IProgress ResolveMainClassHandler resolveMainClassHandler = new ResolveMainClassHandler(); return resolveMainClassHandler.resolveMainClass(arguments); case BUILD_WORKSPACE: - // TODO - break; + Compile.CompileParams params = null; + if (arguments != null && !arguments.isEmpty()) { + params = JsonUtils.fromJson((String) arguments.get(0), Compile.CompileParams.class); + } + + return Compile.compile(params, progress); case FETCH_USER_DATA: return UsageDataStore.getInstance().fetchAll(); case UPDATE_DEBUG_SETTINGS: From 42f9ac7d4843b75b1fdde64762d8c5ce4a4c51b2 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 28 Nov 2022 16:14:19 +0800 Subject: [PATCH 11/94] Bump version to 0.43.0 (#461) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index d9fb24c2e..6d4f847a0 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.42.0 + 0.43.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 43f07f603..505cc54c2 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 0858d90eb..949581277 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.42.0 +Bundle-Version: 0.43.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.42.0.jar + lib/com.microsoft.java.debug.core-0.43.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index c1b4144fa..98bf36ba0 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.42.0 + 0.43.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.42.0 + 0.43.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index ff39c1d7f..f2141039b 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index c5a1f46a0..3670a20f1 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.42.0 + 0.43.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/pom.xml b/pom.xml index 2adb8badf..e75506938 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.42.0 + 0.43.0 pom Java Debug Server for Visual Studio Code From e0f2bd29a87eececabb2726f08d4d6d5479eb15b Mon Sep 17 00:00:00 2001 From: mozhuanzuojing <63572041+mozhuanzuojing@users.noreply.github.com> Date: Thu, 12 Jan 2023 22:20:19 +0800 Subject: [PATCH 12/94] prioritize lookup the project source code during debugging (#463) * prioritize lookup the project source code during debugging * fix null check --- .../java/debug/plugin/internal/InlineValueHandler.java | 2 +- .../com/microsoft/java/debug/plugin/internal/JdtUtils.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/InlineValueHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/InlineValueHandler.java index 5c2cf8834..15aeeb2b4 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/InlineValueHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/InlineValueHandler.java @@ -166,7 +166,7 @@ private static IMethod findMethodInLocalTypes(IMethod enclosingMethod, int stopp */ private static Position getPosition(IBuffer buffer, int offset) { int[] result = JsonRpcHelpers.toLine(buffer, offset); - if (result == null && result.length < 1) { + if (result == null || result.length < 1) { return new Position(-1, -1); } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java index 9a918112b..a4c06c6d4 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java @@ -213,10 +213,10 @@ public static ISourceContainer[] getSourceContainers(String projectName) { projects.stream().distinct().map(project -> JdtUtils.getJavaProject(project)) .filter(javaProject -> javaProject != null && javaProject.exists()) .forEach(javaProject -> { - // Add source containers associated with the project's runtime classpath entries. - containers.addAll(Arrays.asList(getSourceContainers(javaProject, calculated))); // Add source containers associated with the project's source folders. containers.add(new JavaProjectSourceContainer(javaProject)); + // Add source containers associated with the project's runtime classpath entries. + containers.addAll(Arrays.asList(getSourceContainers(javaProject, calculated))); }); return containers.toArray(new ISourceContainer[0]); From 6e294e1e7c00014eb1b0ec1e67aa643efd97e19f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 1 Feb 2023 10:33:52 +0800 Subject: [PATCH 13/94] Reject invalid DAP request (#466) --- .../core/adapter/DebugAdapterContext.java | 11 +++++++ .../java/debug/core/adapter/ErrorCode.java | 5 ++-- .../core/adapter/IDebugAdapterContext.java | 4 +++ .../handler/InitializeRequestHandler.java | 1 + .../adapter/handler/LaunchRequestHandler.java | 6 ++++ .../core/protocol/AbstractProtocolServer.java | 30 +++++++++++++++---- 6 files changed, 50 insertions(+), 7 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java index 345b2fcdf..f8ac01c3e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java @@ -56,6 +56,7 @@ public class DebugAdapterContext implements IDebugAdapterContext { private StepFilters stepFilters; private Path classpathJar = null; private Path argsfile = null; + private boolean isInitialized = false; private long shellProcessId = -1; private long processId = -1; @@ -407,4 +408,14 @@ public long getJDWPLatency() { public void setJDWPLatency(long baseLatency) { this.jdwpLatency = baseLatency; } + + @Override + public boolean isInitialized() { + return isInitialized; + } + + @Override + public void setInitialized(boolean isInitialized) { + this.isInitialized = isInitialized; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java index 1cdc4f9ce..6cfe523cf 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2017 Microsoft Corporation and others. +* Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -35,7 +35,8 @@ public enum ErrorCode { EXCEPTION_INFO_FAILURE(1018), EVALUATION_COMPILE_ERROR(2001), EVALUATE_NOT_SUSPENDED_THREAD(2002), - HCR_FAILURE(3001); + HCR_FAILURE(3001), + INVALID_DAP_HEADER(3002); private int id; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java index 9df539e1d..9a38e8598 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java @@ -154,4 +154,8 @@ public interface IDebugAdapterContext { long getJDWPLatency(); void setJDWPLatency(long baseLatency); + + boolean isInitialized(); + + void setInitialized(boolean isInitialized); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java index bf60b6456..6b9245166 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java @@ -67,6 +67,7 @@ public CompletableFuture handle(Requests.Command command, Req caps.supportsBreakpointLocationsRequest = true; caps.supportsStepInTargetsRequest = true; response.body = caps; + context.setInitialized(true); return CompletableFuture.completedFuture(response); } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java index b1daf1b01..e5662f936 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java @@ -77,6 +77,12 @@ public List getTargetCommands() { @Override public CompletableFuture handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) { + if (!context.isInitialized()) { + final String errorMessage = "'launch' request is rejected since the debug session has not been initialized yet."; + logger.log(Level.SEVERE, errorMessage); + return CompletableFuture.completedFuture( + AdapterUtils.setErrorResponse(response, ErrorCode.LAUNCH_FAILURE, errorMessage)); + } LaunchArguments launchArguments = (LaunchArguments) arguments; Map traceInfo = new HashMap<>(); traceInfo.put("asyncJDWP", context.asyncJDWP()); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java index 9bec3c228..61d57bd85 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2017 Microsoft Corporation and others. +* Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -33,6 +33,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.microsoft.java.debug.core.adapter.AdapterUtils; +import com.microsoft.java.debug.core.adapter.ErrorCode; import com.microsoft.java.debug.core.protocol.Events.DebugEvent; import io.reactivex.disposables.Disposable; @@ -54,6 +56,7 @@ public abstract class AbstractProtocolServer implements IProtocolServer { private ByteBuffer rawData; private int contentLength = -1; private AtomicInteger sequenceNumber = new AtomicInteger(1); + private boolean isValidDAPRequest = true; private PublishSubject responseSubject = PublishSubject.create(); private PublishSubject requestSubject = PublishSubject.create(); @@ -217,7 +220,14 @@ private void processData() { if (message.type.equals("request")) { Messages.Request request = JsonUtils.fromJson(messageData, Messages.Request.class); - requestSubject.onNext(request); + if (this.isValidDAPRequest) { + requestSubject.onNext(request); + } else { + Messages.Response response = new Messages.Response(request.seq, request.command); + sendResponse(AdapterUtils.setErrorResponse(response, + ErrorCode.INVALID_DAP_HEADER, + String.format("'%s' request is rejected due to not being a valid DAP message.", request.command))); + } } else if (message.type.equals("response")) { Messages.Response response = JsonUtils.fromJson(messageData, Messages.Response.class); responseSubject.onNext(response); @@ -235,10 +245,20 @@ private void processData() { if (idx != -1) { Matcher matcher = CONTENT_LENGTH_MATCHER.matcher(rawMessage); if (matcher.find()) { - this.contentLength = Integer.parseInt(matcher.group(1)); - int headerByteLength = rawMessage.substring(0, idx + TWO_CRLF.length()) - .getBytes(PROTOCOL_ENCODING).length; + final String contentLengthText = matcher.group(1); + this.contentLength = Integer.parseInt(contentLengthText); + final String headerMessage = rawMessage.substring(0, idx + TWO_CRLF.length()); + final int headerByteLength = headerMessage.getBytes(PROTOCOL_ENCODING).length; this.rawData.removeFirst(headerByteLength); // Remove the header from the raw message. + + int expectedHeaderLength = 16 /*"Content-Length: ".length()*/ + contentLengthText.length(); + int actualHeaderLength = idx; + if (expectedHeaderLength != actualHeaderLength) { + this.isValidDAPRequest = false; + logger.log(Level.SEVERE, String.format("Illegal DAP request is detected: %s", headerMessage)); + } else { + this.isValidDAPRequest = true; + } continue; } } From f329b41a61518463a40f176d980737abf6fef5d8 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 1 Feb 2023 14:59:55 +0800 Subject: [PATCH 14/94] Bump version to 0.44.0 (#467) --- .github/CODEOWNERS | 1 + com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..3f8625455 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @testforstephen @jdneo @Eskibear @CsCherrYY \ No newline at end of file diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 6d4f847a0..f253b45da 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.43.0 + 0.44.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 505cc54c2..3f86555d4 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 949581277..3bc8a69fc 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.43.0 +Bundle-Version: 0.44.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.43.0.jar + lib/com.microsoft.java.debug.core-0.44.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 98bf36ba0..75466e4df 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.43.0 + 0.44.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.43.0 + 0.44.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index f2141039b..cd199eabf 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 3670a20f1..48d8b7f68 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.43.0 + 0.44.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/pom.xml b/pom.xml index e75506938..6af31be29 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.43.0 + 0.44.0 pom Java Debug Server for Visual Studio Code From ed35d9a4584076950584b701344987ecdf51d619 Mon Sep 17 00:00:00 2001 From: Roland Grunberg Date: Mon, 6 Mar 2023 21:41:33 -0500 Subject: [PATCH 15/94] Add LSP4J 0.20.0 to the target platform. (#473) - JDT-LS now uses LSP4J 0.20.0, which is not available in Orbit or the main release repository Signed-off-by: Roland Grunberg --- pom.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6af31be29..f1c64e509 100644 --- a/pom.xml +++ b/pom.xml @@ -154,9 +154,9 @@ - 202112 + 202212 p2 - https://download.eclipse.org/releases/2021-12/202112081000/ + https://download.eclipse.org/releases/2022-12/202212071000/ oss.sonatype.org @@ -180,5 +180,10 @@ p2 https://download.eclipse.org/tools/orbit/R-builds/R20170516192513/repository/ + + lsp4j + p2 + https://download.eclipse.org/lsp4j/updates/releases/0.20.0/ + From 31cc03389a7890aa8ff5be6c897ca2575b910329 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 7 Mar 2023 16:09:04 +0800 Subject: [PATCH 16/94] Make pom.xml to reuse the tp file (#476) --- .../com.microsoft.java.debug.tp.target | 9 ++-- com.microsoft.java.debug.target/pom.xml | 12 +++++ javaConfig.json | 2 +- pom.xml | 44 ++++++++----------- 4 files changed, 38 insertions(+), 29 deletions(-) rename java.debug.target => com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target (86%) create mode 100644 com.microsoft.java.debug.target/pom.xml diff --git a/java.debug.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target similarity index 86% rename from java.debug.target rename to com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index dcb0b8c5e..187803840 100644 --- a/java.debug.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -16,12 +16,11 @@ - + - - + @@ -31,5 +30,9 @@ + + + + \ No newline at end of file diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml new file mode 100644 index 000000000..537f0ddcd --- /dev/null +++ b/com.microsoft.java.debug.target/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + + com.microsoft.java + java-debug-parent + 0.44.0 + + com.microsoft.java.debug.tp + ${base.name} :: Target Platform + eclipse-target-definition + diff --git a/javaConfig.json b/javaConfig.json index 91ccf4714..8ab611931 100644 --- a/javaConfig.json +++ b/javaConfig.json @@ -3,5 +3,5 @@ "com.microsoft.java.debug.core", "com.microsoft.java.debug.plugin" ], - "targetPlatform": "java.debug.target" + "targetPlatform": "com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target" } diff --git a/pom.xml b/pom.xml index f1c64e509..fcfa85628 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,7 @@ com.microsoft.java.debug.core com.microsoft.java.debug.plugin com.microsoft.java.debug.repository + com.microsoft.java.debug.target @@ -135,9 +136,27 @@ org.eclipse.tycho target-platform-configuration ${tycho-version} + + p2 + + + com.microsoft.java + com.microsoft.java.debug.tp + ${project.version} + + + + + + org.eclipse.tycho + tycho-maven-plugin + ${tycho-version} + true + + @@ -153,11 +172,6 @@ - - 202212 - p2 - https://download.eclipse.org/releases/2022-12/202212071000/ - oss.sonatype.org https://oss.sonatype.org/content/repositories/snapshots/ @@ -165,25 +179,5 @@ true - - JDT.LS - p2 - https://download.eclipse.org/jdtls/snapshots/repository/latest/ - - - JBOLL.TOOLS - p2 - https://download.jboss.org/jbosstools/updates/m2e-extensions/m2e-apt/1.5.3-2019-11-08_11-04-22-H22/ - - - orbit - p2 - https://download.eclipse.org/tools/orbit/R-builds/R20170516192513/repository/ - - - lsp4j - p2 - https://download.eclipse.org/lsp4j/updates/releases/0.20.0/ - From 9df6f5dbe303e6927d5abe4b559d32541d9880a7 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Sun, 23 Apr 2023 17:11:38 +0800 Subject: [PATCH 17/94] Support specifying the exception types you want to break on (#481) * support specifying the exception types you want to break on --- .github/CODEOWNERS | 2 +- .../java/debug/core/DebugSession.java | 98 ++++++++++++++++--- .../java/debug/core/DebugSettings.java | 4 +- .../java/debug/core/IDebugSession.java | 2 + ...SetExceptionBreakpointsRequestHandler.java | 7 +- .../java/debug/core/protocol/Requests.java | 9 ++ 6 files changed, 104 insertions(+), 18 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3f8625455..b11684f52 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @testforstephen @jdneo @Eskibear @CsCherrYY \ No newline at end of file +* @testforstephen @jdneo \ No newline at end of file diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java index 1c7990f16..9dfea1a98 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java @@ -16,16 +16,26 @@ import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.StringUtils; + import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ReferenceType; import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.request.ClassPrepareRequest; import com.sun.jdi.request.EventRequest; import com.sun.jdi.request.EventRequestManager; import com.sun.jdi.request.ExceptionRequest; +import io.reactivex.disposables.Disposable; + public class DebugSession implements IDebugSession { private VirtualMachine vm; private EventHub eventHub = new EventHub(); + private List eventRequests = new ArrayList<>(); + private List subscriptions = new ArrayList<>(); public DebugSession(VirtualMachine virtualMachine) { vm = virtualMachine; @@ -136,9 +146,27 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught @Override public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) { + setExceptionBreakpoints(notifyCaught, notifyUncaught, null, classFilters, classExclusionFilters); + } + + @Override + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, + String[] classFilters, String[] classExclusionFilters) { EventRequestManager manager = vm.eventRequestManager(); - ArrayList legacy = new ArrayList<>(manager.exceptionRequests()); - manager.deleteEventRequests(legacy); + + try { + ArrayList legacy = new ArrayList<>(manager.exceptionRequests()); + manager.deleteEventRequests(legacy); + manager.deleteEventRequests(eventRequests); + } catch (VMDisconnectedException ex) { + // ignore since removing breakpoints is meaningless when JVM is terminated. + } + subscriptions.forEach(subscription -> { + subscription.dispose(); + }); + subscriptions.clear(); + eventRequests.clear(); + // When no exception breakpoints are requested, no need to create an empty exception request. if (notifyCaught || notifyUncaught) { // from: https://www.javatips.net/api/REPLmode-master/src/jm/mode/replmode/REPLRunner.java @@ -153,20 +181,48 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught // a thread to be available, and queries it by calling allThreads(). // See org.eclipse.debug.jdi.tests.AbstractJDITest for the example. - // get only the uncaught exceptions - ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught); - request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); - if (classFilters != null) { - for (String classFilter : classFilters) { - request.addClassFilter(classFilter); + if (exceptionTypes == null || exceptionTypes.length == 0) { + ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + if (classFilters != null) { + for (String classFilter : classFilters) { + request.addClassFilter(classFilter); + } } + if (classExclusionFilters != null) { + for (String exclusionFilter : classExclusionFilters) { + request.addClassExclusionFilter(exclusionFilter); + } + } + request.enable(); + return; } - if (classExclusionFilters != null) { - for (String exclusionFilter : classExclusionFilters) { - request.addClassExclusionFilter(exclusionFilter); + + for (String exceptionType : exceptionTypes) { + if (StringUtils.isBlank(exceptionType)) { + continue; + } + + // register exception breakpoint in the future loaded classes. + ClassPrepareRequest classPrepareRequest = manager.createClassPrepareRequest(); + classPrepareRequest.addClassFilter(exceptionType); + classPrepareRequest.enable(); + eventRequests.add(classPrepareRequest); + + Disposable subscription = eventHub.events() + .filter(debugEvent -> debugEvent.event instanceof ClassPrepareEvent + && eventRequests.contains(debugEvent.event.request())) + .subscribe(debugEvent -> { + ClassPrepareEvent event = (ClassPrepareEvent) debugEvent.event; + createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, classFilters, classExclusionFilters); + }); + subscriptions.add(subscription); + + // register exception breakpoint in the loaded classes. + for (ReferenceType refType : vm.classesByName(exceptionType)) { + createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, classFilters, classExclusionFilters); } } - request.enable(); } } @@ -195,4 +251,22 @@ public IMethodBreakpoint createFunctionBreakpoint(String className, String funct int hitCount) { return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount); } + + private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught, + String[] classFilters, String[] classExclusionFilters) { + EventRequestManager manager = vm.eventRequestManager(); + ExceptionRequest request = manager.createExceptionRequest(refType, notifyCaught, notifyUncaught); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + if (classFilters != null) { + for (String classFilter : classFilters) { + request.addClassFilter(classFilter); + } + } + if (classExclusionFilters != null) { + for (String exclusionFilter : classExclusionFilters) { + request.addClassExclusionFilter(exclusionFilter); + } + } + request.enable(); + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java index f59f10043..eaafdd064 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java @@ -19,7 +19,7 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.annotations.SerializedName; import com.microsoft.java.debug.core.protocol.JsonUtils; -import com.microsoft.java.debug.core.protocol.Requests.ClassFilters; +import com.microsoft.java.debug.core.protocol.Requests.ExceptionFilters; import com.microsoft.java.debug.core.protocol.Requests.StepFilters; public final class DebugSettings { @@ -39,7 +39,7 @@ public final class DebugSettings { public String javaHome; public HotCodeReplace hotCodeReplace = HotCodeReplace.MANUAL; public StepFilters stepFilters = new StepFilters(); - public ClassFilters exceptionFilters = new ClassFilters(); + public ExceptionFilters exceptionFilters = new ExceptionFilters(); public boolean exceptionFiltersUpdated = false; public int limitOfVariablesPerJdwpRequest = 100; public int jdwpRequestTimeout = 3000; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java index 4e4078c87..f490fb0c0 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java @@ -38,6 +38,8 @@ public interface IDebugSession { void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters); + IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount); Process process(); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java index 3a4e642c8..62a30595a 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java @@ -26,8 +26,8 @@ import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; import com.microsoft.java.debug.core.protocol.Messages.Response; import com.microsoft.java.debug.core.protocol.Requests.Arguments; -import com.microsoft.java.debug.core.protocol.Requests.ClassFilters; import com.microsoft.java.debug.core.protocol.Requests.Command; +import com.microsoft.java.debug.core.protocol.Requests.ExceptionFilters; import com.microsoft.java.debug.core.protocol.Requests.SetExceptionBreakpointsArguments; import com.microsoft.java.debug.core.protocol.Types; import com.sun.jdi.event.VMDeathEvent; @@ -77,10 +77,11 @@ public synchronized CompletableFuture handle(Command command, Argument } private void setExceptionBreakpoints(IDebugSession debugSession, boolean notifyCaught, boolean notifyUncaught) { - ClassFilters exceptionFilters = DebugSettings.getCurrent().exceptionFilters; + ExceptionFilters exceptionFilters = DebugSettings.getCurrent().exceptionFilters; + String[] exceptionTypes = (exceptionFilters == null ? null : exceptionFilters.exceptionTypes); String[] classFilters = (exceptionFilters == null ? null : exceptionFilters.allowClasses); String[] classExclusionFilters = (exceptionFilters == null ? null : exceptionFilters.skipClasses); - debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, classFilters, classExclusionFilters); + debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); } @Override diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java index 697eef93d..09de7bfd9 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java @@ -67,6 +67,15 @@ public static class ClassFilters { public String[] skipClasses = new String[0]; } + public static class ExceptionFilters extends ClassFilters { + /** + * Specifies that exceptions which are instances of refType will be reported. + * Note: this will include instances of sub-types. If null, all instances + * will be reported. + */ + public String[] exceptionTypes = new String[0]; + } + public static class StepFilters extends ClassFilters { /** * Deprecated - please use {@link ClassFilters#skipClasses } instead. From 87fae71227a58888d56b54c68fc47eaf24087102 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 24 Apr 2023 13:05:08 +0800 Subject: [PATCH 18/94] Support set exception breakpoint asynchronously & bump veriosn to 0.45.0 (#482) * Support set exception breakpoint asynchronously & bump veriosn to 0.45.0 --- com.microsoft.java.debug.core/pom.xml | 2 +- .../com/microsoft/java/debug/core/DebugSession.java | 12 ++++++++++++ .../com/microsoft/java/debug/core/IDebugSession.java | 3 +++ .../SetExceptionBreakpointsRequestHandler.java | 4 +++- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 28 insertions(+), 11 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index f253b45da..a347b1883 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.44.0 + 0.45.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java index 9dfea1a98..fbad52fe2 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java @@ -226,6 +226,18 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught } } + @Override + public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, + String[] classFilters, String[] classExclusionFilters, boolean async) { + if (async) { + AsyncJdwpUtils.runAsync(() -> { + setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); + }); + } else { + setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); + } + } + @Override public Process process() { return vm.process(); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java index f490fb0c0..6cc3f3a46 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java @@ -40,6 +40,9 @@ public interface IDebugSession { void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters); + void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, + boolean async); + IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount); Process process(); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java index 62a30595a..b51c5fe27 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetExceptionBreakpointsRequestHandler.java @@ -38,6 +38,7 @@ public class SetExceptionBreakpointsRequestHandler implements IDebugRequestHandl private boolean isInitialized = false; private boolean notifyCaught = false; private boolean notifyUncaught = false; + private boolean asyncJDWP = false; @Override public List getTargetCommands() { @@ -53,6 +54,7 @@ public synchronized CompletableFuture handle(Command command, Argument if (!isInitialized) { isInitialized = true; debugSession = context.getDebugSession(); + asyncJDWP = context.asyncJDWP(); DebugSettings.addDebugSettingChangeListener(this); debugSession.getEventHub().events().subscribe(debugEvent -> { if (debugEvent.event instanceof VMDeathEvent @@ -81,7 +83,7 @@ private void setExceptionBreakpoints(IDebugSession debugSession, boolean notifyC String[] exceptionTypes = (exceptionFilters == null ? null : exceptionFilters.exceptionTypes); String[] classFilters = (exceptionFilters == null ? null : exceptionFilters.allowClasses); String[] classExclusionFilters = (exceptionFilters == null ? null : exceptionFilters.skipClasses); - debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters); + debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters, this.asyncJDWP); } @Override diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 3f86555d4..0fc9cfb6c 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 3bc8a69fc..f04641553 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.44.0 +Bundle-Version: 0.45.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.44.0.jar + lib/com.microsoft.java.debug.core-0.45.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 75466e4df..b8d0b7582 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.44.0 + 0.45.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.44.0 + 0.45.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index cd199eabf..38801a366 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 48d8b7f68..096a5ecc9 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.44.0 + 0.45.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 537f0ddcd..c333a4d02 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.44.0 + 0.45.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index fcfa85628..4eda39462 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.44.0 + 0.45.0 pom Java Debug Server for Visual Studio Code From 31f79a5f3ab7efb1d66904fcdfdceb547aae4b83 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 12 May 2023 11:28:27 +0800 Subject: [PATCH 19/94] Add a task to sign maven artifacts with gpg (#485) * Add a task to sign maven artifacts with gpg --- scripts/publishMaven.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/scripts/publishMaven.js b/scripts/publishMaven.js index 1f960766c..deb75fb8b 100644 --- a/scripts/publishMaven.js +++ b/scripts/publishMaven.js @@ -1,7 +1,8 @@ /** * Usage: - * node publishMaven.js -task [upload|promote] + * node publishMaven.js -task [gpg][upload|promote] * + * gpg: Sign artifacts with GPG. * upload: Upload artifacts to a nexus staging repo. * promote: Promote a repo to get it picked up by Maven Central. */ @@ -33,7 +34,9 @@ main(configs, artifactFolder); function main() { const argv = process.argv; const task = argv[argv.indexOf("-task") + 1]; - if (task === "upload") { + if (task === "gpg") { + gpgSign(configs, artifactFolder); + } else if (task === "upload") { uploadToStaging(configs, artifactFolder); } else if (task === "promote") { promoteToCentral(configs); @@ -43,6 +46,27 @@ function main() { } } +/** + * Task gpg: Sign artifacts with GPG. + * + * Required binaries: + * - gpg + * + * Required Environment Variables: + * - artifactFolder: folder containing *.jar/*.pom files. + * - GPGPASS: passphrase of GPG key. + */ +function gpgSign(configs, artifactFolder) { + const props = ["artifactFolder", "gpgpass" ]; + for (const prop of props) { + if (!configs[prop]) { + console.error(`${prop} is not set.`); + process.exit(1); + } + } + addChecksumsAndGpgSignature(configs, artifactFolder); +} + /** * Task upload: Upload artifacts to a nexus staging repo. * @@ -141,7 +165,7 @@ function addChecksumsAndGpgSignature(configs, artifactFolder) { fs.readdirSync(modulePath) .filter(name => name.endsWith(".md5") || name.endsWith(".sha1") || name.endsWith(".asc")) .forEach(name => fs.unlinkSync(path.join(modulePath, name))); - + const files = fs.readdirSync(modulePath); for (let file of files) { // calc md5. @@ -153,7 +177,7 @@ function addChecksumsAndGpgSignature(configs, artifactFolder) { const sha1 = childProcess.execSync(`sha1sum "${path.join(modulePath, file)}"`); const sha1Match = /([a-z0-9]{40})/.exec(sha1.toString()); fs.writeFileSync(path.join(modulePath, file + ".sha1"), sha1Match[0]); - + // gpg sign. childProcess.execSync(`gpg --batch --pinentry-mode loopback --passphrase "${configs.gpgpass}" -ab "${path.join(modulePath, file)}"`) } From a01104960e77323db7a80f1cc7b39f8787855c2a Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Wed, 24 May 2023 07:30:28 +0200 Subject: [PATCH 20/94] Improve lambda method discovery Fixes: #477 (#478) * Improve lambda method discovery Fixes: #477 --- .../microsoft/java/debug/BindingUtils.java | 31 +++++-------------- .../java/debug/BreakpointLocationLocator.java | 2 +- .../java/debug/LambdaExpressionLocator.java | 2 +- .../internal/JdtSourceLookUpProvider.java | 18 ++++++++--- 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java index b696be049..085bf0d4c 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BindingUtils.java @@ -12,10 +12,12 @@ package com.microsoft.java.debug; import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.internal.debug.core.breakpoints.LambdaLocationLocatorHelper; /** * Utility methods around working with JDT Bindings. */ +@SuppressWarnings("restriction") public final class BindingUtils { private BindingUtils() { @@ -48,31 +50,14 @@ public static String getMethodName(IMethodBinding binding, boolean fromKey) { } /** - * Returns the method signature of the method represented by the binding. Since - * this implementation use the {@link IMethodBinding#getKey()} to extract the - * signature from, the method name must be passed in. + * Returns the method signature of the method represented by the binding + * including the synthetic outer locals. * * @param binding the binding which the signature must be resolved for. - * @param name the name of the method. - * @return the signature or null if the signature could not be resolved from the - * key. + * @return the signature or null if the signature could not be resolved. */ - public static String toSignature(IMethodBinding binding, String name) { - // use key for now until JDT core provides a public API for this. - // "Ljava/util/Arrays;.asList([TT;)Ljava/util/List;" - // "([Ljava/lang/String;)V|Ljava/lang/InterruptedException;" - String signatureString = binding.getKey(); - if (signatureString != null) { - name = "." + name; - int index = signatureString.indexOf(name); - if (index > -1) { - int exceptionIndex = signatureString.indexOf("|", signatureString.lastIndexOf(")")); - if (exceptionIndex > -1) { - return signatureString.substring(index + name.length(), exceptionIndex); - } - return signatureString.substring(index + name.length()); - } - } - return null; + public static String toSignature(IMethodBinding binding) { + return LambdaLocationLocatorHelper.toMethodSignature(binding); } + } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java index 68f593aff..b14afde83 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java @@ -46,7 +46,7 @@ public String getMethodSignature() { if (this.methodBinding == null) { return null; } - return BindingUtils.toSignature(this.methodBinding, getMethodName()); + return BindingUtils.toSignature(this.methodBinding); } /** diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java index afffd9741..a5456809a 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/LambdaExpressionLocator.java @@ -71,7 +71,7 @@ public String getMethodSignature() { if (!this.found) { return null; } - return BindingUtils.toSignature(this.lambdaMethodBinding, getMethodName()); + return BindingUtils.toSignature(this.lambdaMethodBinding); } /** diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index c4d4fe318..6d42572e4 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -29,10 +29,12 @@ import java.util.jar.Manifest; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Stream; import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.URIUtil; import org.eclipse.debug.core.sourcelookup.ISourceContainer; @@ -50,10 +52,10 @@ import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; -import org.eclipse.jdt.core.dom.LambdaExpression; -import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.LambdaExpression; +import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; @@ -276,7 +278,13 @@ private CompilationUnit asCompilationUnit(String uri) { * setEnvironment(String [], String [], String [], boolean) * and a unit name setUnitName(String). */ - parser.setEnvironment(new String[0], new String[0], null, true); + IFile resource = (IFile) JDTUtils.findResource(JDTUtils.toURI(uri), + ResourcesPlugin.getWorkspace().getRoot()::findFilesForLocationURI); + if (resource != null && JdtUtils.isJavaProject(resource.getProject())) { + parser.setProject(JavaCore.create(resource.getProject())); + } else { + parser.setEnvironment(new String[0], new String[0], null, true); + } parser.setUnitName(Paths.get(filePath).getFileName().toString()); /** * See the java doc for { @link ASTParser#setSource(char[]) }, @@ -492,7 +500,7 @@ public List findMethodInvocations(String uri, int line) { // Keep consistent with JDI since JDI uses binary class name invocation.declaringTypeName = binding.getDeclaringClass().getBinaryName(); } - invocation.methodGenericSignature = BindingUtils.toSignature(binding, BindingUtils.getMethodName(binding, true)); + invocation.methodGenericSignature = BindingUtils.toSignature(binding); invocation.methodSignature = Signature.getTypeErasure(invocation.methodGenericSignature); int startOffset = astNode.getStartPosition(); if (astNode instanceof org.eclipse.jdt.core.dom.MethodInvocation) { From d37cb100fb3b47c70479306c4d855060eafaabbd Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Fri, 26 May 2023 09:45:14 +0200 Subject: [PATCH 21/94] Improve ASTParser options when project is resolved. Fix #488 (#490) * Improve ASTParser options when project is resolved. Fix #488 Co-authored-by: Jinbo Wang --- .../internal/JdtSourceLookUpProvider.java | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index 6d42572e4..bd41f99ca 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -100,7 +100,8 @@ public void initialize(IDebugAdapterContext context, Map props) throw new IllegalArgumentException("argument is null"); } options.putAll(props); - // During initialization, trigger a background job to load the source containers to improve the perf. + // During initialization, trigger a background job to load the source containers + // to improve the perf. new Thread(() -> { getSourceContainers(); }).start(); @@ -142,15 +143,16 @@ public String[] getFullyQualifiedName(String uri, int[] lines, int[] columns) th return Stream.of(locations).map(location -> { if (location.className() != null && location.methodName() != null) { return location.className() - .concat("#").concat(location.methodName()) - .concat("#").concat(location.methodSignature()); + .concat("#").concat(location.methodName()) + .concat("#").concat(location.methodSignature()); } return location.className(); }).toArray(String[]::new); } @Override - public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceBreakpoint[] sourceBreakpoints) throws DebugException { + public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceBreakpoint[] sourceBreakpoints) + throws DebugException { if (sourceUri == null) { throw new IllegalArgumentException("sourceUri is null"); } @@ -161,8 +163,8 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB CompilationUnit astUnit = asCompilationUnit(sourceUri); JavaBreakpointLocation[] sourceLocations = Stream.of(sourceBreakpoints) - .map(sourceBreakpoint -> new JavaBreakpointLocation(sourceBreakpoint.line, sourceBreakpoint.column)) - .toArray(JavaBreakpointLocation[]::new); + .map(sourceBreakpoint -> new JavaBreakpointLocation(sourceBreakpoint.line, sourceBreakpoint.column)) + .toArray(JavaBreakpointLocation[]::new); if (astUnit != null) { Map resolvedLocations = new HashMap<>(); for (JavaBreakpointLocation sourceLocation : sourceLocations) { @@ -171,7 +173,7 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB if (sourceColumn > -1) { // if we have a column, try to find the lambda expression at that column LambdaExpressionLocator lambdaExpressionLocator = new LambdaExpressionLocator(astUnit, - sourceLine, sourceColumn); + sourceLine, sourceColumn); astUnit.accept(lambdaExpressionLocator); if (lambdaExpressionLocator.isFound()) { sourceLocation.setClassName(lambdaExpressionLocator.getFullyQualifiedTypeName()); @@ -232,7 +234,8 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB private BreakpointLocation[] getInlineBreakpointLocations(final CompilationUnit astUnit, int sourceLine) { List locations = new ArrayList<>(); - // The starting position of each line is the default breakpoint location for that line. + // The starting position of each line is the default breakpoint location for + // that line. locations.add(new BreakpointLocation(sourceLine, 0)); astUnit.accept(new ASTVisitor() { @Override @@ -284,18 +287,18 @@ private CompilationUnit asCompilationUnit(String uri) { parser.setProject(JavaCore.create(resource.getProject())); } else { parser.setEnvironment(new String[0], new String[0], null, true); + /** + * See the java doc for { @link ASTParser#setSource(char[]) }, + * the user need specify the compiler options explicitly. + */ + Map javaOptions = JavaCore.getOptions(); + javaOptions.put(JavaCore.COMPILER_SOURCE, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_COMPLIANCE, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); + parser.setCompilerOptions(javaOptions); } parser.setUnitName(Paths.get(filePath).getFileName().toString()); - /** - * See the java doc for { @link ASTParser#setSource(char[]) }, - * the user need specify the compiler options explicitly. - */ - Map javaOptions = JavaCore.getOptions(); - javaOptions.put(JavaCore.COMPILER_SOURCE, this.latestJavaVersion); - javaOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, this.latestJavaVersion); - javaOptions.put(JavaCore.COMPILER_COMPLIANCE, this.latestJavaVersion); - javaOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); - parser.setCompilerOptions(javaOptions); astUnit = (CompilationUnit) parser.createAST(null); } else { // For non-file uri (e.g. jdt://contents/rt.jar/java.io/PrintStream.class), @@ -336,7 +339,8 @@ public String getJavaRuntimeVersion(String projectName) { return resolveSystemLibraryVersion(project, vmInstall); } catch (CoreException e) { - logger.log(Level.SEVERE, "Failed to get Java runtime version for project '" + projectName + "': " + e.getMessage(), e); + logger.log(Level.SEVERE, + "Failed to get Java runtime version for project '" + projectName + "': " + e.getMessage(), e); } } @@ -345,6 +349,7 @@ public String getJavaRuntimeVersion(String projectName) { /** * Get the project associated source containers. + * * @return the initialized source container list */ public synchronized ISourceContainer[] getSourceContainers() { @@ -373,7 +378,8 @@ private String getContents(IClassFile cf) { source = buffer.getContents(); } } catch (JavaModelException e) { - logger.log(Level.SEVERE, String.format("Failed to parse the source contents of the class file: %s", e.toString()), e); + logger.log(Level.SEVERE, + String.format("Failed to parse the source contents of the class file: %s", e.toString()), e); } if (source == null) { source = ""; @@ -388,7 +394,7 @@ private static String getFileURI(IClassFile classFile) { try { return new URI(JDT_SCHEME, "contents", PATH_SEPARATOR + jarName + PATH_SEPARATOR + packageName + PATH_SEPARATOR + classFile.getElementName(), classFile.getHandleIdentifier(), null) - .toASCIIString(); + .toASCIIString(); } catch (URISyntaxException e) { return null; } @@ -425,8 +431,7 @@ private static IClassFile resolveClassFile(String uriString) { private static String readFile(String filePath) { StringBuilder builder = new StringBuilder(); - try (BufferedReader bufferReader = - new BufferedReader(new InputStreamReader(new FileInputStream(filePath)))) { + try (BufferedReader bufferReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)))) { final int BUFFER_SIZE = 4096; char[] buffer = new char[BUFFER_SIZE]; while (true) { @@ -442,7 +447,8 @@ private static String readFile(String filePath) { return builder.toString(); } - private static String resolveSystemLibraryVersion(IJavaProject project, IVMInstall vmInstall) throws JavaModelException { + private static String resolveSystemLibraryVersion(IJavaProject project, IVMInstall vmInstall) + throws JavaModelException { LibraryLocation[] libraries = JavaRuntime.getLibraryLocations(vmInstall); if (libraries != null && libraries.length > 0) { IPackageFragmentRoot root = project.findPackageFragmentRoot(libraries[0].getSystemLibraryPath()); From 3e9adddd8c21a13b66114fb2b8f3bc711aa11ec0 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 30 May 2023 13:29:16 +0800 Subject: [PATCH 22/94] Bump version to 0.46.0 (#492) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index a347b1883..9faa391fb 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.45.0 + 0.46.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 0fc9cfb6c..d3415ec62 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index f04641553..e754ee286 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.45.0 +Bundle-Version: 0.46.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.45.0.jar + lib/com.microsoft.java.debug.core-0.46.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index b8d0b7582..c69609528 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.45.0 + 0.46.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.45.0 + 0.46.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 38801a366..4efab9fba 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 096a5ecc9..9ff9e2352 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.45.0 + 0.46.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index c333a4d02..61bb2fca2 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.45.0 + 0.46.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index 4eda39462..269077f6e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.45.0 + 0.46.0 pom Java Debug Server for Visual Studio Code From 25dd38f7202f0841ec8dd0686112e8809ee79c19 Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 13:06:22 +0800 Subject: [PATCH 23/94] Microsoft mandatory file (#493) Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> --- SECURITY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..e138ec5d6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + From 6f5a9b386035e0663c343abc898b2c9e9c31b69d Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 26 Jun 2023 15:27:49 +0800 Subject: [PATCH 24/94] Debug support on the decompiled source code (#495) * Debug support on the decompiled source code --- .../java/debug/core/DebugSettings.java | 8 ++ .../debug/core/JavaBreakpointLocation.java | 14 ++- .../java/debug/core/adapter/AdapterUtils.java | 54 ++++++++++ .../core/adapter/ISourceLookUpProvider.java | 20 ++++ .../handler/SetBreakpointsRequestHandler.java | 18 +++- .../handler/StackTraceRequestHandler.java | 10 ++ .../internal/JdtSourceLookUpProvider.java | 100 +++++++++++++++++- .../com.microsoft.java.debug.tp.target | 2 +- 8 files changed, 219 insertions(+), 7 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java index eaafdd064..0a3e05ec8 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java @@ -44,6 +44,7 @@ public final class DebugSettings { public int limitOfVariablesPerJdwpRequest = 100; public int jdwpRequestTimeout = 3000; public AsyncMode asyncJDWP = AsyncMode.OFF; + public Switch debugSupportOnDecompiledSource = Switch.OFF; public static DebugSettings getCurrent() { return current; @@ -97,6 +98,13 @@ public static enum AsyncMode { OFF } + public static enum Switch { + @SerializedName("on") + ON, + @SerializedName("off") + OFF + } + public static interface IDebugSettingChangeListener { public void update(DebugSettings oldSettings, DebugSettings newSettings); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/JavaBreakpointLocation.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/JavaBreakpointLocation.java index 820e80c9b..3dbc1a24d 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/JavaBreakpointLocation.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/JavaBreakpointLocation.java @@ -17,7 +17,11 @@ public class JavaBreakpointLocation { /** - * The source line of the breakpoint or logpoint. + * The line number in the source file. + */ + private int lineNumberInSourceFile = Integer.MIN_VALUE; + /** + * The line number in the class file. */ private int lineNumber; /** @@ -110,4 +114,12 @@ public Types.BreakpointLocation[] availableBreakpointLocations() { public void setAvailableBreakpointLocations(Types.BreakpointLocation[] availableBreakpointLocations) { this.availableBreakpointLocations = availableBreakpointLocations; } + + public int lineNumberInSourceFile() { + return lineNumberInSourceFile == Integer.MIN_VALUE ? lineNumber : lineNumberInSourceFile; + } + + public void setLineNumberInSourceFile(int lineNumberInSourceFile) { + this.lineNumberInSourceFile = lineNumberInSourceFile; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java index 9b972334d..c30aa8742 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java @@ -310,4 +310,58 @@ public static String decodeURIComponent(String uri) { return uri; } } + + /** + * Find the mapped lines based on the given line number. + * + * The line mappings format is as follows: + * - [i]: key + * - [i+1]: value + */ + public static int[] binarySearchMappedLines(int[] lineMappings, int targetLine) { + if (lineMappings == null || lineMappings.length == 0 || lineMappings.length % 2 != 0) { + return null; + } + + final int MAX = lineMappings.length / 2 - 1; + int low = 0; + int high = MAX; + int found = -1; + while (low <= high) { + int mid = low + (high - low) / 2; + int actualMid = mid * 2; + if (lineMappings[actualMid] == targetLine) { + found = mid; + break; + } + + if (lineMappings[actualMid] < targetLine) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + if (found == -1) { + return null; + } + + // Find the duplicates in the sorted array + int left = found; + while ((left - 1) >= 0 && lineMappings[(left - 1) * 2] == targetLine) { + left--; + } + + int right = found; + while ((right + 1) <= MAX && lineMappings[(right + 1) * 2] == targetLine) { + right++; + } + + int[] values = new int[right - left + 1]; + for (int i = 0; i < values.length; i++) { + values[i] = lineMappings[(left + i) * 2 + 1]; + } + + return values; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java index ead10e33c..5ffed6e0f 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java @@ -76,6 +76,26 @@ default String getJavaRuntimeVersion(String projectName) { */ List findMethodInvocations(String uri, int line); + /** + * Return the line mappings from the original line to the decompiled line. + * + * @param uri The uri + * @return the line mappings from the original line to the decompiled line. + */ + default int[] getOriginalLineMappings(String uri) { + return null; + } + + /** + * Return the line mappings from the decompiled line to the original line. + * + * @param uri The uri + * @return the line mappings from the decompiled line to the original line. + */ + default int[] getDecompiledLineMappings(String uri) { + return null; + } + public static class MethodInvocation { public String expression; public String methodName; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java index 7fe6c3fdd..a8774ad37 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java @@ -24,6 +24,8 @@ import com.microsoft.java.debug.core.Configuration; import com.microsoft.java.debug.core.DebugException; +import com.microsoft.java.debug.core.DebugSettings; +import com.microsoft.java.debug.core.DebugSettings.Switch; import com.microsoft.java.debug.core.IBreakpoint; import com.microsoft.java.debug.core.IDebugSession; import com.microsoft.java.debug.core.IEvaluatableBreakpoint; @@ -296,7 +298,8 @@ public static boolean handleEvaluationResult(IDebugAdapterContext context, Threa private Types.Breakpoint convertDebuggerBreakpointToClient(IBreakpoint breakpoint, IDebugAdapterContext context) { int id = (int) breakpoint.getProperty("id"); boolean verified = breakpoint.getProperty("verified") != null && (boolean) breakpoint.getProperty("verified"); - int lineNumber = AdapterUtils.convertLineNumber(breakpoint.getLineNumber(), context.isDebuggerLinesStartAt1(), context.isClientLinesStartAt1()); + int lineNumber = AdapterUtils.convertLineNumber(breakpoint.sourceLocation().lineNumberInSourceFile(), + context.isDebuggerLinesStartAt1(), context.isClientLinesStartAt1()); return new Types.Breakpoint(id, verified, lineNumber, ""); } @@ -318,6 +321,19 @@ private IBreakpoint[] convertClientBreakpointsToDebugger(String sourceFile, Type } catch (NumberFormatException e) { hitCount = 0; // If hitCount is an illegal number, ignore hitCount condition. } + + if (DebugSettings.getCurrent().debugSupportOnDecompiledSource == Switch.ON) { + // Align the decompiled line with the original line. + int[] lineMappings = sourceProvider.getDecompiledLineMappings(sourceFile); + if (locations[i] != null && lineMappings != null) { + int lineNumberInSourceFile = locations[i].lineNumber(); + int[] originalLines = AdapterUtils.binarySearchMappedLines(lineMappings, lineNumberInSourceFile); + if (originalLines != null && originalLines.length > 0) { + locations[i].setLineNumberInSourceFile(lineNumberInSourceFile); + locations[i].setLineNumber(originalLines[0]); + } + } + } breakpoints[i] = context.getDebugSession().createBreakpoint(locations[i], hitCount, sourceBreakpoints[i].condition, sourceBreakpoints[i].logMessage); if (sourceProvider.supportsRealtimeBreakpointVerification() && StringUtils.isNotBlank(locations[i].className())) { diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index fbfce49ef..601a29f56 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -25,8 +25,10 @@ import org.apache.commons.lang3.StringUtils; import com.microsoft.java.debug.core.AsyncJdwpUtils; +import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.DebugUtility; import com.microsoft.java.debug.core.IBreakpoint; +import com.microsoft.java.debug.core.DebugSettings.Switch; import com.microsoft.java.debug.core.adapter.AdapterUtils; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; @@ -189,6 +191,14 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra // display "Unknown Source" in the Call Stack View. clientSource = null; } + } else if (DebugSettings.getCurrent().debugSupportOnDecompiledSource == Switch.ON + && clientSource != null && clientSource.path != null) { + // Align the original line with the decompiled line. + int[] lineMappings = context.getProvider(ISourceLookUpProvider.class).getOriginalLineMappings(clientSource.path); + int[] renderLines = AdapterUtils.binarySearchMappedLines(lineMappings, clientLineNumber); + if (renderLines != null && renderLines.length > 0) { + clientLineNumber = renderLines[0]; + } } int clientColumnNumber = context.isClientColumnsStartAt1() ? 1 : 0; diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index bd41f99ca..f0c8795cc 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -36,6 +36,7 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.URIUtil; import org.eclipse.debug.core.sourcelookup.ISourceContainer; import org.eclipse.jdt.core.IBuffer; @@ -60,14 +61,19 @@ import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.LibraryLocation; +import org.eclipse.jdt.ls.core.internal.DecompilerResult; import org.eclipse.jdt.ls.core.internal.JDTUtils; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.managers.ContentProviderManager; import com.microsoft.java.debug.BindingUtils; import com.microsoft.java.debug.BreakpointLocationLocator; import com.microsoft.java.debug.LambdaExpressionLocator; import com.microsoft.java.debug.core.Configuration; import com.microsoft.java.debug.core.DebugException; +import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.JavaBreakpointLocation; +import com.microsoft.java.debug.core.DebugSettings.Switch; import com.microsoft.java.debug.core.adapter.AdapterUtils; import com.microsoft.java.debug.core.adapter.Constants; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; @@ -303,10 +309,42 @@ private CompilationUnit asCompilationUnit(String uri) { } else { // For non-file uri (e.g. jdt://contents/rt.jar/java.io/PrintStream.class), // leverage jdt to load the source contents. - ITypeRoot typeRoot = resolveClassFile(uri); - if (typeRoot != null) { - parser.setSource(typeRoot); - astUnit = (CompilationUnit) parser.createAST(null); + IClassFile typeRoot = resolveClassFile(uri); + try { + if (typeRoot != null && typeRoot.getSourceRange() != null) { + parser.setSource(typeRoot); + astUnit = (CompilationUnit) parser.createAST(null); + } else if (typeRoot != null && DebugSettings.getCurrent().debugSupportOnDecompiledSource == Switch.ON) { + ContentProviderManager contentProvider = JavaLanguageServerPlugin.getContentProviderManager(); + try { + String contents = contentProvider.getSource(typeRoot, new NullProgressMonitor()); + if (contents != null && !contents.isBlank()) { + IJavaProject javaProject = typeRoot.getJavaProject(); + if (javaProject != null) { + parser.setProject(javaProject); + } else { + parser.setEnvironment(new String[0], new String[0], null, true); + /** + * See the java doc for { @link ASTParser#setSource(char[]) }, + * the user need specify the compiler options explicitly. + */ + Map javaOptions = JavaCore.getOptions(); + javaOptions.put(JavaCore.COMPILER_SOURCE, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_COMPLIANCE, this.latestJavaVersion); + javaOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); + parser.setCompilerOptions(javaOptions); + } + parser.setUnitName(typeRoot.getElementName()); + parser.setSource(contents.toCharArray()); + astUnit = (CompilationUnit) parser.createAST(null); + } + } catch (Exception e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } + } + } catch (JavaModelException e) { + // ignore } } return astUnit; @@ -533,4 +571,58 @@ private boolean isSameURI(String uri1, String uri2) { return false; } } + + public int[] getOriginalLineMappings(String uri) { + IClassFile classFile = resolveClassFile(uri); + try { + if (classFile == null) { + return null; + } + + IPackageFragmentRoot packageRoot = (IPackageFragmentRoot) classFile.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); + if (packageRoot != null && packageRoot.getSourceAttachmentPath() != null) { + return null; + } + + if (classFile.getSourceRange() == null) { + ContentProviderManager contentProvider = JavaLanguageServerPlugin.getContentProviderManager(); + try { + DecompilerResult result = contentProvider.getSourceResult(classFile, new NullProgressMonitor()); + if (result != null) { + return result.getOriginalLineMappings(); + } + } catch (NoSuchMethodError e) { + // ignore it if old language server version is installed. + } catch (Exception e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } + } + } catch (JavaModelException e) { + // ignore + } + return null; + } + + public int[] getDecompiledLineMappings(String uri) { + IClassFile classFile = resolveClassFile(uri); + try { + if (classFile != null && classFile.getSourceRange() == null) { + ContentProviderManager contentProvider = JavaLanguageServerPlugin.getContentProviderManager(); + try { + DecompilerResult result = contentProvider.getSourceResult(classFile, new NullProgressMonitor()); + if (result != null) { + return result.getDecompiledLineMappings(); + } + } catch (NoSuchMethodError e) { + // ignore it if old Java language server version is installed. + } catch (Exception e) { + JavaLanguageServerPlugin.logException(e.getMessage(), e); + } + } + } catch (JavaModelException e) { + // ignore + } + + return null; + } } diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 187803840..fbc981533 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -31,7 +31,7 @@ - + From b6564781f1b212036d5fceed4e9b757d40cc0ce4 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 30 Jun 2023 09:57:33 +0800 Subject: [PATCH 25/94] Track the perf of stackTrace dap request (#496) --- .../handler/StackTraceRequestHandler.java | 15 ++++++++++++ .../java/debug/core/protocol/Events.java | 24 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index 601a29f56..6b44d52f5 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -24,6 +24,7 @@ import org.apache.commons.lang3.StringUtils; +import com.google.gson.JsonObject; import com.microsoft.java.debug.core.AsyncJdwpUtils; import com.microsoft.java.debug.core.DebugSettings; import com.microsoft.java.debug.core.DebugUtility; @@ -41,6 +42,7 @@ import com.microsoft.java.debug.core.protocol.Requests.StackTraceArguments; import com.microsoft.java.debug.core.protocol.Responses; import com.microsoft.java.debug.core.protocol.Types; +import com.microsoft.java.debug.core.protocol.Events.TelemetryEvent; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.LocalVariable; @@ -54,6 +56,7 @@ import com.sun.jdi.request.BreakpointRequest; public class StackTraceRequestHandler implements IDebugRequestHandler { + private ThreadLocal isDecompilerInvoked = new ThreadLocal<>(); @Override public List getTargetCommands() { @@ -62,6 +65,8 @@ public List getTargetCommands() { @Override public CompletableFuture handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) { + final long startAt = System.currentTimeMillis(); + isDecompilerInvoked.set(false); StackTraceArguments stacktraceArgs = (StackTraceArguments) arguments; List result = new ArrayList<>(); if (stacktraceArgs.startFrame < 0 || stacktraceArgs.levels < 0) { @@ -108,6 +113,15 @@ public CompletableFuture handle(Command command, Arguments arguments, } } response.body = new Responses.StackTraceResponseBody(result, totalFrames); + long duration = System.currentTimeMillis() - startAt; + JsonObject properties = new JsonObject(); + properties.addProperty("command", "stackTrace"); + properties.addProperty("duration", duration); + properties.addProperty("decompileSupport", DebugSettings.getCurrent().debugSupportOnDecompiledSource.toString()); + if (isDecompilerInvoked.get() != null) { + properties.addProperty("isDecompilerInvoked", Boolean.toString(isDecompilerInvoked.get())); + } + context.getProtocolServer().sendEvent(new TelemetryEvent("dap", properties)); return CompletableFuture.completedFuture(response); } @@ -198,6 +212,7 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra int[] renderLines = AdapterUtils.binarySearchMappedLines(lineMappings, clientLineNumber); if (renderLines != null && renderLines.length > 0) { clientLineNumber = renderLines[0]; + isDecompilerInvoked.set(true); } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java index 681ec543d..1973444b6 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java @@ -246,6 +246,30 @@ public UserNotificationEvent(NotificationType notifyType, String message) { } } + public static class TelemetryEvent extends DebugEvent { + /** + * The telemetry event name. + */ + public String name; + + /** + * The properties is an object as below. + * { + * [key: string]: string | number; + * } + */ + public Object properties; + + /** + * Constructor. + */ + public TelemetryEvent(String name, Object data) { + super("telemetry"); + this.name = name; + this.properties = data; + } + } + public static enum InvalidatedAreas { @SerializedName("all") ALL, From 7bdf2effd7be8f54745e04ea8334e337ed86b75b Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 30 Jun 2023 10:44:35 +0800 Subject: [PATCH 26/94] Bump version to 0.47.0 (#497) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 9faa391fb..3b1d57547 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.46.0 + 0.47.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index d3415ec62..5c303928d 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index e754ee286..0965d8ed5 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.46.0 +Bundle-Version: 0.47.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.46.0.jar + lib/com.microsoft.java.debug.core-0.47.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index c69609528..c41c9de3b 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.46.0 + 0.47.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.46.0 + 0.47.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 4efab9fba..20eac94c8 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 9ff9e2352..665b94a6a 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.46.0 + 0.47.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 61bb2fca2..6e22d46ab 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.46.0 + 0.47.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index 269077f6e..c296ce2c1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.46.0 + 0.47.0 pom Java Debug Server for Visual Studio Code From f9c02cffebf3f7b62ca5f980fa842033f3d53049 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 24 Jul 2023 13:57:20 +0800 Subject: [PATCH 27/94] Custom request 'refreshFrames' to refresh the thread's frames (#501) * Custom request 'refreshFrames' to refresh the thread's frames --- .../java/debug/core/adapter/DebugAdapter.java | 2 + .../java/debug/core/adapter/ThreadCache.java | 46 ++++++ .../ConfigurationDoneRequestHandler.java | 3 +- .../adapter/handler/RefreshFramesHandler.java | 136 ++++++++++++++++++ .../adapter/handler/RestartFrameHandler.java | 1 + .../handler/SetBreakpointsRequestHandler.java | 4 +- .../SetDataBreakpointsRequestHandler.java | 4 +- .../SetFunctionBreakpointsRequestHandler.java | 4 +- .../handler/StackTraceRequestHandler.java | 19 ++- .../adapter/handler/StepRequestHandler.java | 2 +- .../handler/ThreadsRequestHandler.java | 7 + .../java/debug/core/protocol/Events.java | 5 + .../java/debug/core/protocol/Requests.java | 10 ++ 13 files changed, 233 insertions(+), 10 deletions(-) create mode 100644 com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshFramesHandler.java diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java index b853e0469..10c0df902 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java @@ -34,6 +34,7 @@ import com.microsoft.java.debug.core.adapter.handler.InlineValuesRequestHandler; import com.microsoft.java.debug.core.adapter.handler.LaunchRequestHandler; import com.microsoft.java.debug.core.adapter.handler.ProcessIdHandler; +import com.microsoft.java.debug.core.adapter.handler.RefreshFramesHandler; import com.microsoft.java.debug.core.adapter.handler.RefreshVariablesHandler; import com.microsoft.java.debug.core.adapter.handler.RestartFrameHandler; import com.microsoft.java.debug.core.adapter.handler.ScopesRequestHandler; @@ -133,6 +134,7 @@ private void initialize() { registerHandlerForDebug(new SetFunctionBreakpointsRequestHandler()); registerHandlerForDebug(new BreakpointLocationsRequestHander()); registerHandlerForDebug(new StepInTargetsRequestHandler()); + registerHandlerForDebug(new RefreshFramesHandler()); // NO_DEBUG mode only registerHandlerForNoDebug(new DisconnectRequestWithoutDebuggingHandler()); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ThreadCache.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ThreadCache.java index ce1c17282..57d39154e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ThreadCache.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ThreadCache.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -32,6 +33,8 @@ protected boolean removeEldestEntry(java.util.Map.Entry eldest) { } }); private Map eventThreads = new ConcurrentHashMap<>(); + private Map> decompiledClassesByThread = new HashMap<>(); + private Map threadStoppedReasons = new HashMap<>(); public synchronized void resetThreads(List threads) { allThreads.clear(); @@ -80,6 +83,13 @@ public void addEventThread(ThreadReference thread) { eventThreads.put(thread.uniqueID(), thread); } + public void addEventThread(ThreadReference thread, String reason) { + eventThreads.put(thread.uniqueID(), thread); + if (reason != null) { + threadStoppedReasons.put(thread.uniqueID(), reason); + } + } + public void removeEventThread(long threadId) { eventThreads.remove(threadId); } @@ -113,4 +123,40 @@ public List visibleThreads(IDebugAdapterContext context) { return visibleThreads; } + + public Set getDecompiledClassesByThread(long threadId) { + return decompiledClassesByThread.get(threadId); + } + + public void setDecompiledClassesByThread(long threadId, Set decompiledClasses) { + if (decompiledClasses == null || decompiledClasses.isEmpty()) { + decompiledClassesByThread.remove(threadId); + return; + } + + decompiledClassesByThread.put(threadId, decompiledClasses); + } + + public String getThreadStoppedReason(long threadId) { + return threadStoppedReasons.get(threadId); + } + + public void setThreadStoppedReason(long threadId, String reason) { + if (reason == null) { + threadStoppedReasons.remove(threadId); + return; + } + + threadStoppedReasons.put(threadId, reason); + } + + public void clearThreadStoppedState(long threadId) { + threadStoppedReasons.remove(threadId); + decompiledClassesByThread.remove(threadId); + } + + public void clearAllThreadStoppedState() { + threadStoppedReasons.clear(); + decompiledClassesByThread.clear(); + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java index 6805073dc..1c543bce4 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java @@ -76,6 +76,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, if (context.isVmStopOnEntry()) { DebugUtility.stopOnEntry(debugSession, context.getMainClass()).thenAccept(threadId -> { context.getProtocolServer().sendEvent(new Events.StoppedEvent("entry", threadId)); + context.getThreadCache().setThreadStoppedReason(threadId, "entry"); }); } } else if (event instanceof VMDeathEvent) { @@ -117,7 +118,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, JdiExceptionReference jdiException = new JdiExceptionReference(((ExceptionEvent) event).exception(), ((ExceptionEvent) event).catchLocation() == null); context.getExceptionManager().setException(thread.uniqueID(), jdiException); - context.getThreadCache().addEventThread(thread); + context.getThreadCache().addEventThread(thread, "exception"); context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID())); debugEvent.shouldResume = false; } else { diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshFramesHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshFramesHandler.java new file mode 100644 index 000000000..b91daaf80 --- /dev/null +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RefreshFramesHandler.java @@ -0,0 +1,136 @@ +/******************************************************************************* +* Copyright (c) 2023 Microsoft Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v10.html +* +* Contributors: +* Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package com.microsoft.java.debug.core.adapter.handler; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +import com.microsoft.java.debug.core.AsyncJdwpUtils; +import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; +import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; +import com.microsoft.java.debug.core.protocol.Events.StoppedEvent; +import com.microsoft.java.debug.core.protocol.Messages.Response; +import com.microsoft.java.debug.core.protocol.Requests.Arguments; +import com.microsoft.java.debug.core.protocol.Requests.Command; +import com.microsoft.java.debug.core.protocol.Requests.RefreshFramesArguments; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ThreadReference; + +public class RefreshFramesHandler implements IDebugRequestHandler { + + @Override + public List getTargetCommands() { + return Arrays.asList(Command.REFRESHFRAMES); + } + + @Override + public CompletableFuture handle(Command command, Arguments arguments, Response response, + IDebugAdapterContext context) { + RefreshFramesArguments refreshArgs = (RefreshFramesArguments) arguments; + String[] affectedRootPaths = refreshArgs == null ? null : refreshArgs.affectedRootPaths; + List pausedThreads = getPausedThreads(context); + for (long threadId : pausedThreads) { + if (affectedRootPaths == null || affectedRootPaths.length == 0) { + refreshFrames(threadId, context); + continue; + } + + Set decompiledClasses = context.getThreadCache().getDecompiledClassesByThread(threadId); + if (decompiledClasses == null || decompiledClasses.isEmpty()) { + continue; + } + + if (anyInAffectedRootPaths(decompiledClasses, affectedRootPaths)) { + refreshFrames(threadId, context); + } + } + + return CompletableFuture.completedFuture(response); + } + + List getPausedThreads(IDebugAdapterContext context) { + List results = new ArrayList<>(); + List> futures = new ArrayList<>(); + List threads = context.getThreadCache().visibleThreads(context); + for (ThreadReference thread : threads) { + if (context.asyncJDWP()) { + futures.add(AsyncJdwpUtils.supplyAsync(() -> { + try { + if (thread.isSuspended()) { + return thread.uniqueID(); + } + } catch (ObjectCollectedException ex) { + // Ignore it if the thread is garbage collected. + } + + return -1L; + })); + } else { + try { + if (thread.isSuspended()) { + results.add(thread.uniqueID()); + } + } catch (ObjectCollectedException ex) { + // Ignore it if the thread is garbage collected. + } + } + } + + List awaitedResutls = AsyncJdwpUtils.await(futures); + for (Long threadId : awaitedResutls) { + if (threadId > 0) { + results.add(threadId); + } + } + + return results; + } + + /** + * See https://github.com/microsoft/vscode/issues/188606, + * VS Code doesn't provide a simple way to refetch the stack frames. + * We're going to resend a thread stopped event to trick the client + * into refetching the thread stack frames. + */ + void refreshFrames(long threadId, IDebugAdapterContext context) { + StoppedEvent stoppedEvent = new StoppedEvent(context.getThreadCache().getThreadStoppedReason(threadId), threadId); + stoppedEvent.preserveFocusHint = true; + context.getProtocolServer().sendEvent(stoppedEvent); + } + + boolean anyInAffectedRootPaths(Collection classes, String[] affectedRootPaths) { + if (affectedRootPaths == null || affectedRootPaths.length == 0) { + return true; + } + + for (String classUri : classes) { + // decompiled class uri is like 'jdt://contents/rt.jar/java.io/PrintStream.class?=1.helloworld/%5C/usr%5C/lib%5C/jvm%5C/ + // java-8-oracle%5C/jre%5C/lib%5C/rt.jar%3Cjava.io(PrintStream.class'. + if (classUri.startsWith("jdt://contents/")) { + String jarName = classUri.substring("jdt://contents/".length()); + int sep = jarName.indexOf("/"); + jarName = sep >= 0 ? jarName.substring(0, sep) : jarName; + for (String affectedRootPath : affectedRootPaths) { + if (affectedRootPath.endsWith("/" + jarName) || affectedRootPath.endsWith("\\" + jarName)) { + return true; + } + } + } + } + + return false; + } +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java index 2023209f4..164909656 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java @@ -122,6 +122,7 @@ private void stepInto(IDebugAdapterContext context, ThreadReference thread) { // Have to send two events to keep the UI sync with the step in operations: context.getProtocolServer().sendEvent(new Events.ContinuedEvent(thread.uniqueID())); context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", thread.uniqueID())); + context.getThreadCache().setThreadStoppedReason(thread.uniqueID(), "restartframe"); }); request.enable(); thread.resume(); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java index a8774ad37..09dafd1b0 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java @@ -211,14 +211,14 @@ private void registerBreakpointHandler(IDebugAdapterContext context) { if (resume) { debugEvent.eventSet.resume(); } else { - context.getThreadCache().addEventThread(bpThread); + context.getThreadCache().addEventThread(bpThread, breakpointName); context.getProtocolServer().sendEvent(new Events.StoppedEvent( breakpointName, bpThread.uniqueID())); } }); }); } else { - context.getThreadCache().addEventThread(bpThread); + context.getThreadCache().addEventThread(bpThread, breakpointName); context.getProtocolServer().sendEvent(new Events.StoppedEvent( breakpointName, bpThread.uniqueID())); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java index 6d3e8c0b1..373b1c31b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java @@ -151,13 +151,13 @@ private void registerWatchpointHandler(IDebugAdapterContext context) { if (resume) { debugEvent.eventSet.resume(); } else { - context.getThreadCache().addEventThread(bpThread); + context.getThreadCache().addEventThread(bpThread, "data breakpoint"); context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID())); } }); }); } else { - context.getThreadCache().addEventThread(bpThread); + context.getThreadCache().addEventThread(bpThread, "data breakpoint"); context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID())); } debugEvent.shouldResume = false; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java index 59a948d37..96a0e395b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java @@ -165,7 +165,7 @@ private void registerMethodBreakpointHandler(IDebugAdapterContext context) { if (resume) { debugEvent.eventSet.resume(); } else { - context.getThreadCache().addEventThread(bpThread); + context.getThreadCache().addEventThread(bpThread, "function breakpoint"); context.getProtocolServer().sendEvent(new Events.StoppedEvent( "function breakpoint", bpThread.uniqueID())); } @@ -173,7 +173,7 @@ private void registerMethodBreakpointHandler(IDebugAdapterContext context) { }); } else { - context.getThreadCache().addEventThread(bpThread); + context.getThreadCache().addEventThread(bpThread, "function breakpoint"); context.getProtocolServer() .sendEvent(new Events.StoppedEvent("function breakpoint", bpThread.uniqueID())); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index 6b44d52f5..0ba3b2004 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -15,8 +15,10 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -73,16 +75,23 @@ public CompletableFuture handle(Command command, Arguments arguments, response.body = new Responses.StackTraceResponseBody(result, 0); return CompletableFuture.completedFuture(response); } - ThreadReference thread = context.getThreadCache().getThread(stacktraceArgs.threadId); + long threadId = stacktraceArgs.threadId; + ThreadReference thread = context.getThreadCache().getThread(threadId); if (thread == null) { - thread = DebugUtility.getThread(context.getDebugSession(), stacktraceArgs.threadId); + thread = DebugUtility.getThread(context.getDebugSession(), threadId); } int totalFrames = 0; if (thread != null) { + Set decompiledClasses = new LinkedHashSet<>(); try { // Thread state has changed and then invalidate the stack frame cache. if (stacktraceArgs.startFrame == 0) { context.getStackFrameManager().clearStackFrames(thread); + } else { + Set existing = context.getThreadCache().getDecompiledClassesByThread(threadId); + if (existing != null) { + decompiledClasses.addAll(existing); + } } totalFrames = thread.frameCount(); @@ -102,6 +111,10 @@ public CompletableFuture handle(Command command, Arguments arguments, Types.StackFrame lspFrame = convertDebuggerStackFrameToClient(jdiFrame, frameId, i == 0, context); result.add(lspFrame); frameReference.setSource(lspFrame.source); + int jdiLineNumber = AdapterUtils.convertLineNumber(jdiFrame.lineNumber, context.isDebuggerLinesStartAt1(), context.isClientLinesStartAt1()); + if (jdiLineNumber != lspFrame.line) { + decompiledClasses.add(lspFrame.source.path); + } } } catch (IncompatibleThreadStateException | IndexOutOfBoundsException | URISyntaxException | AbsentInformationException | ObjectCollectedException @@ -110,6 +123,8 @@ public CompletableFuture handle(Command command, Arguments arguments, // 1. the vscode has wrong parameter/wrong uri // 2. the thread actually terminates // TODO: should record a error log here. + } finally { + context.getThreadCache().setDecompiledClassesByThread(threadId, decompiledClasses); } } response.body = new Responses.StackTraceResponseBody(result, totalFrames); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java index bd324a7fa..71f28355a 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java @@ -308,7 +308,7 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, if (threadState.eventSubscription != null) { threadState.eventSubscription.dispose(); } - context.getThreadCache().addEventThread(thread); + context.getThreadCache().addEventThread(thread, "step"); context.getProtocolServer().sendEvent(new Events.StoppedEvent("step", thread.uniqueID())); debugEvent.shouldResume = false; } else if (event instanceof MethodExitEvent) { diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java index fceac73a5..6573f11da 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java @@ -138,6 +138,7 @@ private CompletableFuture pause(Requests.PauseArguments arguments, Res context.getStepResultManager().removeAllMethodResults(); context.getDebugSession().suspend(); context.getProtocolServer().sendEvent(new Events.StoppedEvent("pause", arguments.threadId, true)); + context.getThreadCache().setThreadStoppedReason(arguments.threadId, "pause"); } return CompletableFuture.completedFuture(response); } @@ -158,12 +159,14 @@ private CompletableFuture resume(Requests.ContinueArguments arguments, context.getStepResultManager().removeMethodResult(arguments.threadId); context.getExceptionManager().removeException(arguments.threadId); allThreadsContinued = false; + context.getThreadCache().clearThreadStoppedState(arguments.threadId); DebugUtility.resumeThread(thread); context.getStackFrameManager().clearStackFrames(thread); checkThreadRunningAndRecycleIds(thread, context); } else { context.getStepResultManager().removeAllMethodResults(); context.getExceptionManager().removeAllExceptions(); + context.getThreadCache().clearAllThreadStoppedState(); resumeVM(context); context.getStackFrameManager().clearStackFrames(); context.getRecyclableIdPool().removeAllObjects(); @@ -175,6 +178,7 @@ private CompletableFuture resume(Requests.ContinueArguments arguments, private CompletableFuture resumeAll(Requests.ThreadOperationArguments arguments, Response response, IDebugAdapterContext context) { context.getStepResultManager().removeAllMethodResults(); context.getExceptionManager().removeAllExceptions(); + context.getThreadCache().clearAllThreadStoppedState(); resumeVM(context); context.getProtocolServer().sendEvent(new Events.ContinuedEvent(arguments.threadId, true)); context.getStackFrameManager().clearStackFrames(); @@ -190,6 +194,7 @@ private CompletableFuture resumeOthers(Requests.ThreadOperationArgumen continue; } + context.getThreadCache().clearThreadStoppedState(thread.uniqueID()); if (context.asyncJDWP()) { futures.add(AsyncJdwpUtils.runAsync(() -> resumeThread(thread, context))); } else { @@ -203,6 +208,7 @@ private CompletableFuture resumeOthers(Requests.ThreadOperationArgumen private CompletableFuture pauseAll(Requests.ThreadOperationArguments arguments, Response response, IDebugAdapterContext context) { context.getDebugSession().suspend(); context.getProtocolServer().sendEvent(new Events.StoppedEvent("pause", arguments.threadId, true)); + context.getThreadCache().setThreadStoppedReason(arguments.threadId, "pause"); return CompletableFuture.completedFuture(response); } @@ -300,6 +306,7 @@ private void pauseThread(ThreadReference thread, IDebugAdapterContext context) { context.getStepResultManager().removeMethodResult(threadId); thread.suspend(); context.getProtocolServer().sendEvent(new Events.StoppedEvent("pause", threadId)); + context.getThreadCache().setThreadStoppedReason(threadId, "pause"); } } catch (ObjectCollectedException ex) { // the thread is garbage collected. diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java index 1973444b6..e692e9b8d 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Events.java @@ -38,6 +38,11 @@ public static class StoppedEvent extends DebugEvent { public String description; public String text; public boolean allThreadsStopped; + /** + * A value of true hints to the client that this event should not change the + * focus. + */ + public Boolean preserveFocusHint; /** * Constructor. diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java index 09de7bfd9..1129d230e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java @@ -426,6 +426,15 @@ public static class BreakpointLocationsArguments extends Arguments { public int endColumn; } + public static class RefreshFramesArguments extends Arguments { + /** + * If provided, refresh the stack frames of the paused threads that previously + * requested decompiled sources for classes in the affected root paths. + * Otherwise, refresh all paused threads. + */ + public String[] affectedRootPaths; + } + public static enum Command { INITIALIZE("initialize", InitializeArguments.class), LAUNCH("launch", LaunchArguments.class), @@ -464,6 +473,7 @@ public static enum Command { REFRESHVARIABLES("refreshVariables", RefreshVariablesArguments.class), PROCESSID("processId", Arguments.class), BREAKPOINTLOCATIONS("breakpointLocations", BreakpointLocationsArguments.class), + REFRESHFRAMES("refreshFrames", RefreshFramesArguments.class), UNSUPPORTED("", Arguments.class); private String command; From 1d76af515d6926db737f89438c056c2d0d2150df Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 31 Jul 2023 12:13:50 +0800 Subject: [PATCH 28/94] Bump version to 0.48.0 (#502) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 3b1d57547..8ebf3fb5f 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.47.0 + 0.48.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 5c303928d..2f7e62dc3 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 0965d8ed5..520d7d0da 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.47.0 +Bundle-Version: 0.48.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.47.0.jar + lib/com.microsoft.java.debug.core-0.48.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index c41c9de3b..e50a7f992 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.47.0 + 0.48.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.47.0 + 0.48.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 20eac94c8..8cf6b4f60 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 665b94a6a..27132434c 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.47.0 + 0.48.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 6e22d46ab..c7fcc1716 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.47.0 + 0.48.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index c296ce2c1..55e421c19 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.47.0 + 0.48.0 pom Java Debug Server for Visual Studio Code From 5174aa3744281ad05531c1c1984631e2ff1c68de Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Fri, 4 Aug 2023 16:12:49 +0800 Subject: [PATCH 29/94] Only build main project for build server project (#503) * Only build main project for build server project * Add a dedicated error code for build server --------- Signed-off-by: Sheng Chen --- .../java/debug/plugin/internal/Compile.java | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java index 415456ce5..d38227785 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java @@ -18,9 +18,11 @@ import java.util.logging.Logger; import org.apache.commons.lang3.StringUtils; +import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceStatus; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; @@ -40,7 +42,42 @@ public class Compile { private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); - public static BuildWorkspaceStatus compile(CompileParams params, IProgressMonitor monitor) { + private static final int GRADLE_BS_COMPILATION_ERROR = 100; + + public static Object compile(CompileParams params, IProgressMonitor monitor) { + IProject mainProject = params == null ? null : ProjectUtils.getProject(params.getProjectName()); + if (mainProject == null) { + try { + // Q: is infer project by main class name necessary? perf impact? + List javaProjects = ResolveClasspathsHandler.getJavaProjectFromType(params.getMainClass()); + if (javaProjects.size() == 1) { + mainProject = javaProjects.get(0).getProject(); + } + } catch (CoreException e) { + JavaLanguageServerPlugin.logException("Failed to resolve project from main class name.", e); + } + } + + if (isBspProject(mainProject)) { + // Just need to trigger a build for the target project, the Gradle build server will + // handle the build dependencies for us. + try { + ResourcesPlugin.getWorkspace().build( + new IBuildConfiguration[]{mainProject.getActiveBuildConfig()}, + IncrementalProjectBuilder.INCREMENTAL_BUILD, + false /*buildReference*/, + monitor + ); + } catch (CoreException e) { + if (e.getStatus().getCode() == IResourceStatus.BUILD_FAILED) { + return GRADLE_BS_COMPILATION_ERROR; + } else { + return BuildWorkspaceStatus.FAILED; + } + } + return BuildWorkspaceStatus.SUCCEED; + } + try { if (monitor.isCanceled()) { return BuildWorkspaceStatus.CANCELLED; @@ -55,7 +92,6 @@ public static BuildWorkspaceStatus compile(CompileParams params, IProgressMonito } logger.info("Time cost for ECJ: " + (System.currentTimeMillis() - compileAt) + "ms"); - IProject mainProject = params == null ? null : ProjectUtils.getProject(params.getProjectName()); IResource currentResource = mainProject; if (isUnmanagedFolder(mainProject) && StringUtils.isNotBlank(params.getMainClass())) { IType mainType = ProjectUtils.getJavaProject(mainProject).findType(params.getMainClass()); @@ -117,6 +153,11 @@ private static boolean isUnmanagedFolder(IProject project) { && ProjectUtils.isJavaProject(project); } + private static boolean isBspProject(IProject project) { + return project != null && ProjectUtils.isJavaProject(project) + && ProjectUtils.hasNature(project, "com.microsoft.gradle.bs.importer.GradleBuildServerProjectNature"); + } + private static IProject getDefaultProject() { return getWorkspaceRoot().getProject(ProjectsManager.DEFAULT_PROJECT_NAME); } From 0e03327569c18a83d0c56f63bbb80ba404bb20b3 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 15 Aug 2023 12:46:31 +0800 Subject: [PATCH 30/94] Code completion: Use fully qualified name as needed in DEBUG CONSOLE (#504) --- .../internal/CompletionProposalRequestor.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java index be7932992..41b4da929 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java @@ -45,6 +45,7 @@ import org.eclipse.jdt.ls.core.internal.handlers.CompletionResponses; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; +import org.eclipse.lsp4j.CompletionItemLabelDetails; import com.google.common.collect.ImmutableSet; import com.microsoft.java.debug.core.Configuration; @@ -159,6 +160,8 @@ public CompletionItem toCompletionItem(CompletionProposal proposal, int index) { data.put(CompletionResolveHandler.DATA_FIELD_PROPOSAL_ID, String.valueOf(index)); $.setData(data); this.descriptionProvider.updateDescription(proposal, $); + // Use fully qualified name as needed. + $.setInsertText(String.valueOf(proposal.getCompletion())); adjustCompleteItem($); $.setSortText(SortTextHelper.computeSortText(proposal)); return $; @@ -166,6 +169,17 @@ public CompletionItem toCompletionItem(CompletionProposal proposal, int index) { private void adjustCompleteItem(CompletionItem item) { if (item.getKind() == CompletionItemKind.Function) { + // Merge the label details into the label property + // because the completion provider in DEBUG CONSOLE + // doesn't support the label details. + CompletionItemLabelDetails labelDetails = item.getLabelDetails(); + if (labelDetails != null && StringUtils.isNotBlank(labelDetails.getDetail())) { + item.setLabel(item.getLabel() + labelDetails.getDetail()); + } + if (labelDetails != null && StringUtils.isNotBlank(labelDetails.getDescription())) { + item.setLabel(item.getLabel() + " : " + labelDetails.getDescription()); + } + String text = item.getInsertText(); if (StringUtils.isNotBlank(text) && !text.endsWith(")")) { item.setInsertText(text + "()"); From f8b6db6eea40a6faab6be9c8ec8a8844584533ac Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 17 Aug 2023 14:35:42 +0800 Subject: [PATCH 31/94] Display the package name in the label property when suggesting types in DEBUG CONSOLE (#505) --- .../internal/CompletionProposalRequestor.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java index 41b4da929..1df752f24 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java @@ -28,6 +28,7 @@ import org.eclipse.jdt.core.CompletionContext; import org.eclipse.jdt.core.CompletionProposal; import org.eclipse.jdt.core.CompletionRequestor; +import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; @@ -154,7 +155,7 @@ public List getCompletionItems() { */ public CompletionItem toCompletionItem(CompletionProposal proposal, int index) { final CompletionItem $ = new CompletionItem(); - $.setKind(mapKind(proposal.getKind())); + $.setKind(mapKind(proposal.getKind(), proposal.getFlags())); Map data = new HashMap<>(); data.put(CompletionResolveHandler.DATA_FIELD_REQUEST_ID, String.valueOf(response.getId())); data.put(CompletionResolveHandler.DATA_FIELD_PROPOSAL_ID, String.valueOf(index)); @@ -168,7 +169,15 @@ public CompletionItem toCompletionItem(CompletionProposal proposal, int index) { } private void adjustCompleteItem(CompletionItem item) { - if (item.getKind() == CompletionItemKind.Function) { + CompletionItemKind itemKind = item.getKind(); + if (itemKind == CompletionItemKind.Class || itemKind == CompletionItemKind.Interface + || itemKind == CompletionItemKind.Enum) { + // Display the package name in the label property. + CompletionItemLabelDetails labelDetails = item.getLabelDetails(); + if (labelDetails != null && StringUtils.isNotBlank(labelDetails.getDescription())) { + item.setLabel(item.getLabel() + " - " + labelDetails.getDescription()); + } + } else if (itemKind == CompletionItemKind.Function) { // Merge the label details into the label property // because the completion provider in DEBUG CONSOLE // doesn't support the label details. @@ -195,7 +204,7 @@ public void acceptContext(CompletionContext context) { this.descriptionProvider = new CompletionProposalDescriptionProvider(context); } - private CompletionItemKind mapKind(final int kind) { + private CompletionItemKind mapKind(final int kind, final int flags) { // When a new CompletionItemKind is added, don't forget to update // SUPPORTED_KINDS switch (kind) { @@ -204,6 +213,11 @@ private CompletionItemKind mapKind(final int kind) { return CompletionItemKind.Constructor; case CompletionProposal.ANONYMOUS_CLASS_DECLARATION: case CompletionProposal.TYPE_REF: + if (Flags.isInterface(flags)) { + return CompletionItemKind.Interface; + } else if (Flags.isEnum(flags)) { + return CompletionItemKind.Enum; + } return CompletionItemKind.Class; case CompletionProposal.FIELD_IMPORT: case CompletionProposal.METHOD_IMPORT: @@ -213,6 +227,9 @@ private CompletionItemKind mapKind(final int kind) { return CompletionItemKind.Module; case CompletionProposal.FIELD_REF: case CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER: + if (Flags.isStatic(flags) && Flags.isFinal(flags)) { + return CompletionItemKind.Constant; + } return CompletionItemKind.Field; case CompletionProposal.KEYWORD: return CompletionItemKind.Keyword; From c0e8f92f54defe9af77c6d091bb96a57ff114ac1 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 28 Aug 2023 11:33:14 +0800 Subject: [PATCH 32/94] bump version to 0.49.0 (#506) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 8ebf3fb5f..5412d44a4 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.48.0 + 0.49.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 2f7e62dc3..c2b013548 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 520d7d0da..cdc8e2f81 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.48.0 +Bundle-Version: 0.49.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.48.0.jar + lib/com.microsoft.java.debug.core-0.49.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index e50a7f992..7fd392bbe 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.48.0 + 0.49.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.48.0 + 0.49.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 8cf6b4f60..dc3efd066 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 27132434c..0adda64ab 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.48.0 + 0.49.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index c7fcc1716..cfae4adb8 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.48.0 + 0.49.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index 55e421c19..c71560b64 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.48.0 + 0.49.0 pom Java Debug Server for Visual Studio Code From 8905c4a7367991a492ba280d8ba616f73fdea557 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Tue, 19 Sep 2023 00:51:18 -0700 Subject: [PATCH 33/94] Special handling build only when it's build server project and not buildship project (#511) Signed-off-by: Sheng Chen --- .../java/com/microsoft/java/debug/plugin/internal/Compile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java index d38227785..9cb6fbbfa 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java @@ -58,7 +58,7 @@ public static Object compile(CompileParams params, IProgressMonitor monitor) { } } - if (isBspProject(mainProject)) { + if (isBspProject(mainProject) && !ProjectUtils.isGradleProject(mainProject)) { // Just need to trigger a build for the target project, the Gradle build server will // handle the build dependencies for us. try { From 4f42baa62997c29507f930e009f28d4453f59596 Mon Sep 17 00:00:00 2001 From: Vladimir Makaev Date: Tue, 26 Sep 2023 09:50:31 +0100 Subject: [PATCH 34/94] Add extensibility points to DebugAdapter and ProtocolServer (#509) Co-authored-by: Vladimir Makayev Co-authored-by: Jinbo Wang --- .../java/debug/core/adapter/DebugAdapter.java | 9 +++++---- .../core/adapter/IDebugAdapterFactory.java | 19 +++++++++++++++++++ .../debug/core/adapter/ProtocolServer.java | 14 ++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterFactory.java diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java index 10c0df902..8f595151f 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapter.java @@ -102,7 +102,7 @@ public CompletableFuture dispatchRequest(Messages.Request req } } - private void initialize() { + protected void initialize() { // Register request handlers. // When there are multiple handlers registered for the same request, follow the rule "first register, first execute". registerHandler(new InitializeRequestHandler()); @@ -141,15 +141,15 @@ private void initialize() { registerHandlerForNoDebug(new ProcessIdHandler()); } - private void registerHandlerForDebug(IDebugRequestHandler handler) { + protected void registerHandlerForDebug(IDebugRequestHandler handler) { registerHandler(requestHandlersForDebug, handler); } - private void registerHandlerForNoDebug(IDebugRequestHandler handler) { + protected void registerHandlerForNoDebug(IDebugRequestHandler handler) { registerHandler(requestHandlersForNoDebug, handler); } - private void registerHandler(IDebugRequestHandler handler) { + protected void registerHandler(IDebugRequestHandler handler) { registerHandler(requestHandlersForDebug, handler); registerHandler(requestHandlersForNoDebug, handler); } @@ -165,4 +165,5 @@ private void registerHandler(Map> requestHan handlerList.add(handler); } } + } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterFactory.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterFactory.java new file mode 100644 index 000000000..d392d3b48 --- /dev/null +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterFactory.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2023 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Microsoft Corporation - initial API and implementation +*******************************************************************************/ + +package com.microsoft.java.debug.core.adapter; + +import com.microsoft.java.debug.core.protocol.IProtocolServer; + +@FunctionalInterface +public interface IDebugAdapterFactory { + public IDebugAdapter create(IProtocolServer server); +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ProtocolServer.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ProtocolServer.java index 0526293b9..9e503e0af 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ProtocolServer.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ProtocolServer.java @@ -52,6 +52,20 @@ public ProtocolServer(InputStream input, OutputStream output, IProviderContext c debugAdapter = new DebugAdapter(this, context); } + /** + * Constructs a protocol server instance based on the given input stream and output stream. + * @param input + * the input stream + * @param output + * the output stream + * @param debugAdapterFactory + * factory to create debug adapter that implements DAP communication + */ + public ProtocolServer(InputStream input, OutputStream output, IDebugAdapterFactory debugAdapterFactory) { + super(input, output); + debugAdapter = debugAdapterFactory.create(this); + } + /** * A while-loop to parse input data and send output data constantly. */ From 488a56ef9fe4c8766b47af6443986936283e1b7f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 1 Nov 2023 14:02:42 +0800 Subject: [PATCH 35/94] Bump version to 0.50.0 (#516) --- .mvn/wrapper/maven-wrapper.properties | 2 +- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- .../com.microsoft.java.debug.tp.target | 4 ++-- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 4 ++-- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 56bb0164e..9e0264d04 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip \ No newline at end of file +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip \ No newline at end of file diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 5412d44a4..635993d56 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.49.0 + 0.50.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index c2b013548..ca5f41e6f 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index cdc8e2f81..84a0ab36f 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.49.0 +Bundle-Version: 0.50.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.49.0.jar + lib/com.microsoft.java.debug.core-0.50.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 7fd392bbe..b895ffd28 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.49.0 + 0.50.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.49.0 + 0.50.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index dc3efd066..639d50082 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 0adda64ab..4f05eb331 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.49.0 + 0.50.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index fbc981533..1c10398c4 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -16,11 +16,11 @@ - + - + diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index cfae4adb8..80395f6dd 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.49.0 + 0.50.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index c71560b64..d562f82b5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,12 +6,12 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.49.0 + 0.50.0 pom Java Debug Server for Visual Studio Code UTF-8 - 2.7.3 + 4.0.3 ${basedir} From b0c70e3ddbf8cca9dc697f02f84914d7792b5982 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 21 Nov 2023 18:01:28 +0800 Subject: [PATCH 36/94] Update target platform dependencies to fix build errors (#518) --- .../com.microsoft.java.debug.tp.target | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 1c10398c4..ef0a5284e 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -16,11 +16,8 @@ - - - - + From 39046b7ab8b1acc47894745f517fcd5fe010cf64 Mon Sep 17 00:00:00 2001 From: John Olson <69521422+olsonjohn@users.noreply.github.com> Date: Sun, 10 Dec 2023 20:21:59 -0600 Subject: [PATCH 37/94] updated dependency location (#528) --- .../com.microsoft.java.debug.tp.target | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index ef0a5284e..2e7920ed7 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -17,7 +17,7 @@ - + @@ -32,4 +32,4 @@ - \ No newline at end of file + From 27f72fbdf79097794d8a546a1206e620ecdde863 Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Tue, 12 Dec 2023 03:24:24 +0100 Subject: [PATCH 38/94] Fix generic return type lambda breakpoint issue. Fix #1359 (#499) * Fix generic return type lambda breakpoint issue. Fix #1359 The fix tries to compare the runtime lambda method signature with none generic version of the method signature found from AST traversal as a additional comparison to what is there. --- .../microsoft/java/debug/core/Breakpoint.java | 25 ++++++++++++++++++- .../java/debug/core/BreakpointTest.java | 17 +++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/BreakpointTest.java diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java index dfdbad4bb..82859b268 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java @@ -325,7 +325,8 @@ private Location findMethodLocaiton(ReferenceType refType, String methodName, St for (Method method : methods) { if (!method.isAbstract() && !method.isNative() && methodName.equals(method.name()) - && (methodSiguature.equals(method.genericSignature()) || methodSiguature.equals(method.signature()))) { + && (methodSiguature.equals(method.genericSignature()) || methodSiguature.equals(method.signature()) + || toNoneGeneric(methodSiguature).equals(method.signature()))) { location = method.location(); break; } @@ -334,6 +335,28 @@ private Location findMethodLocaiton(ReferenceType refType, String methodName, St return location; } + static String toNoneGeneric(String genericSig) { + StringBuilder builder = new StringBuilder(); + boolean append = true; + int depth = 0; + char[] chars = genericSig.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (c == '<') { + depth++; + append = (depth == 0); + } + if (append) { + builder.append(c); + } + if (c == '>') { + depth--; + append = (depth == 0); + } + } + return builder.toString(); + } + private List findLocaitonsOfLine(Method method, int lineNumber) { try { return method.locationsOfLine(lineNumber); diff --git a/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/BreakpointTest.java b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/BreakpointTest.java new file mode 100644 index 000000000..5cc6fa3d7 --- /dev/null +++ b/com.microsoft.java.debug.core/src/test/java/com/microsoft/java/debug/core/BreakpointTest.java @@ -0,0 +1,17 @@ +package com.microsoft.java.debug.core; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class BreakpointTest { + @Test + public void testToNoneGeneric() { + assertEquals("Ljava.util.List;", Breakpoint.toNoneGeneric("Ljava.util.List;")); + assertEquals("(Ljava/util/Map;)Ljava/util/Map;", Breakpoint.toNoneGeneric( + "(Ljava/util/Map;>;)Ljava/util/Map;>;")); + assertEquals("(Ljava/util/Map;)Ljava/util/Map;", + Breakpoint.toNoneGeneric( + "(Ljava/util/Map;Ljava/util/List;>;)Ljava/util/Map;Ljava/util/List;>;")); + } +} From 9bdd9977860e5912a39b8efbaf62b9ee5577ec98 Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Wed, 13 Dec 2023 02:54:30 +0100 Subject: [PATCH 39/94] Improve inline breakpoint discovery when expression is multiline. Fix #521 (#522) * Improve inline breakpoint discovery when expression is multiline. Fix #521 --- .../microsoft/java/debug/BreakpointLocationLocator.java | 4 ++-- .../debug/plugin/internal/JdtSourceLookUpProvider.java | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java index b14afde83..97581242e 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/BreakpointLocationLocator.java @@ -22,8 +22,8 @@ public class BreakpointLocationLocator public BreakpointLocationLocator(CompilationUnit compilationUnit, int lineNumber, boolean bindingsResolved, - boolean bestMatch) { - super(compilationUnit, lineNumber, bindingsResolved, bestMatch); + boolean bestMatch, int offset, int end) { + super(compilationUnit, lineNumber, bindingsResolved, bestMatch, offset, end); } @Override diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index f0c8795cc..1ebf4c7c3 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -72,8 +72,8 @@ import com.microsoft.java.debug.core.Configuration; import com.microsoft.java.debug.core.DebugException; import com.microsoft.java.debug.core.DebugSettings; -import com.microsoft.java.debug.core.JavaBreakpointLocation; import com.microsoft.java.debug.core.DebugSettings.Switch; +import com.microsoft.java.debug.core.JavaBreakpointLocation; import com.microsoft.java.debug.core.adapter.AdapterUtils; import com.microsoft.java.debug.core.adapter.Constants; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; @@ -210,8 +210,11 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB // mark it as "unverified". // In future, we could consider supporting to update the breakpoint to a valid // location. + + // passing the offset to the constructor, it can recognize the multiline lambda + // expression well BreakpointLocationLocator locator = new BreakpointLocationLocator(astUnit, - sourceLine, true, true); + sourceLine, true, true, astUnit.getPosition(sourceLine, 0), 0); astUnit.accept(locator); // When the final valid line location is same as the original line, that // represents it's a valid breakpoint. From f8da9e2e2f55a2cefaf658ae24154c784eaa113e Mon Sep 17 00:00:00 2001 From: Vladimir Makaev Date: Mon, 8 Jan 2024 03:22:46 +0000 Subject: [PATCH 40/94] Allow ISourceLookUpProvider specify whether file is Local or Remote (#515) --- .../core/adapter/DebugAdapterContext.java | 4 +-- .../core/adapter/IDebugAdapterContext.java | 2 +- .../core/adapter/ISourceLookUpProvider.java | 28 ++++++++++----- .../java/debug/core/adapter/Source.java | 30 ++++++++++++++++ .../java/debug/core/adapter/SourceType.java | 16 +++++++++ .../handler/StackTraceRequestHandler.java | 35 +++++++++++++------ 6 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Source.java create mode 100644 com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/SourceType.java diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java index f8ac01c3e..bbf215c67 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java @@ -32,7 +32,7 @@ public class DebugAdapterContext implements IDebugAdapterContext { private static final int MAX_CACHE_ITEMS = 10000; private final StepFilters defaultFilters = new StepFilters(); - private Map sourceMappingCache = Collections.synchronizedMap(new LRUCache<>(MAX_CACHE_ITEMS)); + private Map sourceMappingCache = Collections.synchronizedMap(new LRUCache<>(MAX_CACHE_ITEMS)); private IProviderContext providerContext; private IProtocolServer server; @@ -212,7 +212,7 @@ public void setVariableFormatter(IVariableFormatter variableFormatter) { } @Override - public Map getSourceLookupCache() { + public Map getSourceLookupCache() { return sourceMappingCache; } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java index 9a38e8598..e65270eef 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java @@ -85,7 +85,7 @@ public interface IDebugAdapterContext { void setVariableFormatter(IVariableFormatter variableFormatter); - Map getSourceLookupCache(); + Map getSourceLookupCache(); void setDebuggeeEncoding(Charset encoding); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java index 5ffed6e0f..f33742852 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ISourceLookUpProvider.java @@ -8,7 +8,6 @@ * Contributors: * Microsoft Corporation - initial API and implementation *******************************************************************************/ - package com.microsoft.java.debug.core.adapter; import java.util.List; @@ -42,18 +41,31 @@ public interface ISourceLookUpProvider extends IProvider { JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceBreakpoint[] sourceBreakpoints) throws DebugException; /** - * Given a fully qualified class name and source file path, search the associated disk source file. - * - * @param fullyQualifiedName - * the fully qualified class name (e.g. com.microsoft.java.debug.core.adapter.ISourceLookUpProvider). - * @param sourcePath - * the qualified source file path (e.g. com\microsoft\java\debug\core\adapter\ISourceLookupProvider.java). - * @return the associated source file uri. + * Deprecated, please use {@link #getSource(String, String)} instead. */ + @Deprecated String getSourceFileURI(String fullyQualifiedName, String sourcePath); String getSourceContents(String uri); + /** + * Retrieves a {@link Source} object representing the source code associated with the given fully qualified class name and source file path. + * The implementation of this interface can determine a source is "local" or "remote". + * In case of "remote" a follow up "source" request will be issued by the client + * + * @param fullyQualifiedName + * the fully qualified class name, + * e.g., "com.microsoft.java.debug.core.adapter.ISourceLookUpProvider". + * @param sourcePath + * the qualified source file path, + * e.g., "com/microsoft/java/debug/core/adapter/ISourceLookupProvider.java". + * @return A {@link Source} object encapsulating the source file URI obtained from + * {@link #getSourceFileURI(String, String)} and the source type as {@link SourceType#LOCAL}. + */ + default Source getSource(String fullyQualifiedName, String sourcePath) { + return new Source(getSourceFileURI(fullyQualifiedName, sourcePath), SourceType.LOCAL); + } + /** * Returns the Java runtime that the specified project's build path used. * @param projectName diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Source.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Source.java new file mode 100644 index 000000000..d00b4cb4c --- /dev/null +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Source.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2017 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Microsoft Corporation - initial API and implementation + *******************************************************************************/ + +package com.microsoft.java.debug.core.adapter; + +public class Source { + public final String uri; + public final SourceType type; + + public Source(String uri, SourceType type) { + this.uri = uri; + this.type = type; + } + + public String getUri() { + return this.uri; + } + + public SourceType getType() { + return this.type; + } +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/SourceType.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/SourceType.java new file mode 100644 index 000000000..724bf3bda --- /dev/null +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/SourceType.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2017 Microsoft Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Microsoft Corporation - initial API and implementation + *******************************************************************************/ +package com.microsoft.java.debug.core.adapter; + +public enum SourceType { + REMOTE, + LOCAL +} diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index 0ba3b2004..49f304771 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -36,6 +36,8 @@ import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider; +import com.microsoft.java.debug.core.adapter.Source; +import com.microsoft.java.debug.core.adapter.SourceType; import com.microsoft.java.debug.core.adapter.formatter.SimpleTypeFormatter; import com.microsoft.java.debug.core.adapter.variables.StackFrameReference; import com.microsoft.java.debug.core.protocol.Messages.Response; @@ -141,7 +143,7 @@ public CompletableFuture handle(Command command, Arguments arguments, } private static List resolveStackFrameInfos(StackFrame[] frames, boolean async) - throws AbsentInformationException, IncompatibleThreadStateException { + throws AbsentInformationException, IncompatibleThreadStateException { List jdiFrames = new ArrayList<>(); List> futures = new ArrayList<>(); for (StackFrame frame : frames) { @@ -221,7 +223,7 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra clientSource = null; } } else if (DebugSettings.getCurrent().debugSupportOnDecompiledSource == Switch.ON - && clientSource != null && clientSource.path != null) { + && clientSource != null && clientSource.path != null) { // Align the original line with the decompiled line. int[] lineMappings = context.getProvider(ISourceLookUpProvider.class).getOriginalLineMappings(clientSource.path); int[] renderLines = AdapterUtils.binarySearchMappedLines(lineMappings, clientLineNumber); @@ -244,7 +246,7 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra }); if (match) { clientColumnNumber = AdapterUtils.convertColumnNumber(breakpoint.getColumnNumber(), - context.isDebuggerColumnsStartAt1(), context.isClientColumnsStartAt1()); + context.isDebuggerColumnsStartAt1(), context.isClientColumnsStartAt1()); } } } @@ -256,33 +258,44 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra /** * Find the source mapping for the specified source file name. */ - public static Types.Source convertDebuggerSourceToClient(String fullyQualifiedName, String sourceName, String relativeSourcePath, + public static Types.Source convertDebuggerSourceToClient(String fullyQualifiedName, String sourceName, + String relativeSourcePath, IDebugAdapterContext context) throws URISyntaxException { + // use a lru cache for better performance - String uri = context.getSourceLookupCache().computeIfAbsent(fullyQualifiedName, key -> { - String fromProvider = context.getProvider(ISourceLookUpProvider.class).getSourceFileURI(key, relativeSourcePath); - // avoid return null which will cause the compute function executed again - return StringUtils.isBlank(fromProvider) ? "" : fromProvider; + Source source = context.getSourceLookupCache().computeIfAbsent(fullyQualifiedName, key -> { + Source result = context.getProvider(ISourceLookUpProvider.class).getSource(key, relativeSourcePath); + if (result == null) { + return new Source("", SourceType.LOCAL); + } + return result; }); + Integer sourceReference = 0; + String uri = source.getUri(); + + if (source.getType().equals(SourceType.REMOTE)) { + sourceReference = context.createSourceReference(source.getUri()); + } + if (!StringUtils.isBlank(uri)) { // The Source.path could be a file system path or uri string. if (uri.startsWith("file:")) { String clientPath = AdapterUtils.convertPath(uri, context.isDebuggerPathsAreUri(), context.isClientPathsAreUri()); - return new Types.Source(sourceName, clientPath, 0); + return new Types.Source(sourceName, clientPath, sourceReference); } else { // If the debugger returns uri in the Source.path for the StackTrace response, VSCode client will try to find a TextDocumentContentProvider // to render the contents. // Language Support for Java by Red Hat extension has already registered a jdt TextDocumentContentProvider to parse the jdt-based uri. // The jdt uri looks like 'jdt://contents/rt.jar/java.io/PrintStream.class?=1.helloworld/%5C/usr%5C/lib%5C/jvm%5C/java-8-oracle%5C/jre%5C/ // lib%5C/rt.jar%3Cjava.io(PrintStream.class'. - return new Types.Source(sourceName, uri, 0); + return new Types.Source(sourceName, uri, sourceReference); } } else { // If the source lookup engine cannot find the source file, then lookup it in the source directories specified by user. String absoluteSourcepath = AdapterUtils.sourceLookup(context.getSourcePaths(), relativeSourcePath); if (absoluteSourcepath != null) { - return new Types.Source(sourceName, absoluteSourcepath, 0); + return new Types.Source(sourceName, absoluteSourcepath, sourceReference); } else { return null; } From b578b50078cef9ce7b37710966bd2c2496c1c00d Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Thu, 18 Jan 2024 15:39:43 +0800 Subject: [PATCH 41/94] Migrate to 1es pipelines (#532) --- .azure-pipelines/signjars-nightly.yml | 146 ++++++++++++++++ .azure-pipelines/signjars-rc.yml | 236 ++++++++++++++++++++++++++ 2 files changed, 382 insertions(+) create mode 100644 .azure-pipelines/signjars-nightly.yml create mode 100644 .azure-pipelines/signjars-rc.yml diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml new file mode 100644 index 000000000..bdaeea871 --- /dev/null +++ b/.azure-pipelines/signjars-nightly.yml @@ -0,0 +1,146 @@ +name: $(Date:yyyyMMdd).$(Rev:r) +variables: + - name: Codeql.Enabled + value: true +schedules: + - cron: 0 5 * * 1,2,3,4,5 + branches: + include: + - refs/heads/main +resources: + repositories: + - repository: self + type: git + ref: refs/heads/main + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release +trigger: none +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: + os: linux + name: 1ES_JavaTooling_Pool + image: 1ES_JavaTooling_Ubuntu-2004 + sdl: + sourceAnalysisPool: + name: 1ES_JavaTooling_Pool + image: 1ES_JavaTooling_Windows_2022 + os: windows + customBuildTags: + - MigrationTooling-mseng-VSJava-13474-Tool + stages: + - stage: Build + jobs: + - job: Job_1 + displayName: Sign-Jars-Nightly + templateContext: + outputs: + - output: pipelineArtifact + artifactName: plugin + targetPath: $(Build.ArtifactStagingDirectory) + displayName: "Publish Artifact: plugin" + steps: + - checkout: self + fetchTags: true + - task: JavaToolInstaller@0 + displayName: Use Java 17 + inputs: + versionSpec: "17" + jdkArchitectureOption: x64 + jdkSourceOption: PreInstalled + - task: CmdLine@2 + displayName: Parse the release version from pom.xml + inputs: + script: |- + #!/bin/bash + + sudo apt-get install xmlstarlet + xmlstarlet --version + RELEASE_VERSION=$(xmlstarlet sel -t -v "/_:project/_:version" pom.xml) + echo $RELEASE_VERSION + echo "##vso[task.setvariable variable=RELEASE_VERSION]$RELEASE_VERSION" + - task: CmdLine@2 + displayName: Build core.jar + inputs: + script: | + ./mvnw clean install -f com.microsoft.java.debug.core/pom.xml -Dmaven.repo.local=./.repository + + mkdir -p jars + mv .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/com.microsoft.java.debug.core*.jar jars/ + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + displayName: Sign core.jar + inputs: + ConnectedServiceName: vscjavaci_codesign + FolderPath: jars + Pattern: com.microsoft.java.debug.core*.jar + signConfigType: inlineSignParams + inlineOperation: |- + [ + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaSign", + "Parameters" : { + "SigAlg" : "SHA256withRSA", + "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + - task: CmdLine@2 + displayName: install signed core.jar + inputs: + script: cp jars/com.microsoft.java.debug.core*.jar .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/ + - task: CmdLine@2 + displayName: Build plugin.jar + inputs: + script: |- + ./mvnw clean install -f com.microsoft.java.debug.target/pom.xml -Dmaven.repo.local=./.repository + ./mvnw clean install -f com.microsoft.java.debug.plugin/pom.xml -Dmaven.repo.local=./.repository + + mkdir -p jars + mv .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/com.microsoft.java.debug.plugin*.jar jars/ + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + displayName: Sign plugin.jar + inputs: + ConnectedServiceName: vscjavaci_codesign + FolderPath: jars + Pattern: com.microsoft.java.debug.plugin*.jar + signConfigType: inlineSignParams + inlineOperation: |- + [ + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaSign", + "Parameters" : { + "SigAlg" : "SHA256withRSA", + "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + - task: CopyFiles@2 + displayName: "Copy plugin.jar to: $(Build.ArtifactStagingDirectory)" + inputs: + Contents: |+ + jars/com.microsoft.java.debug.plugin*.jar + + TargetFolder: $(Build.ArtifactStagingDirectory) diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml new file mode 100644 index 000000000..4e51eff7f --- /dev/null +++ b/.azure-pipelines/signjars-rc.yml @@ -0,0 +1,236 @@ +name: $(Date:yyyyMMdd).$(Rev:r) +variables: + - name: Codeql.Enabled + value: true +resources: + repositories: + - repository: self + type: git + ref: refs/heads/main + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release +trigger: none +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + pool: + os: linux + name: 1ES_JavaTooling_Pool + image: 1ES_JavaTooling_Ubuntu-2004 + sdl: + sourceAnalysisPool: + name: 1ES_JavaTooling_Pool + image: 1ES_JavaTooling_Windows_2022 + os: windows + customBuildTags: + - MigrationTooling-mseng-VSJava-9151-Tool + stages: + - stage: Build + jobs: + - job: Job_1 + displayName: Sign-Jars-RC + templateContext: + outputs: + - output: pipelineArtifact + artifactName: m2 + targetPath: $(Build.ArtifactStagingDirectory)/m2 + displayName: "Publish Artifact: m2" + - output: pipelineArtifact + artifactName: p2 + targetPath: $(Build.ArtifactStagingDirectory)/p2 + displayName: "Publish Artifact: p2" + steps: + - checkout: self + fetchTags: true + - task: JavaToolInstaller@0 + displayName: Use Java 17 + inputs: + versionSpec: "17" + jdkArchitectureOption: x64 + jdkSourceOption: PreInstalled + - task: CmdLine@2 + displayName: Parse the release version from pom.xml + inputs: + script: |- + #!/bin/bash + + sudo apt-get install xmlstarlet + xmlstarlet --version + RELEASE_VERSION=$(xmlstarlet sel -t -v "/_:project/_:version" pom.xml) + echo $RELEASE_VERSION + echo "##vso[task.setvariable variable=RELEASE_VERSION]$RELEASE_VERSION" + - task: CmdLine@2 + displayName: Build core.jar + inputs: + script: | + ./mvnw -N clean install -Dmaven.repo.local=./.repository + + ./mvnw clean install -f com.microsoft.java.debug.core/pom.xml -Dmaven.repo.local=./.repository + + mkdir -p jars + mv .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/com.microsoft.java.debug.core*.jar jars/ + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + displayName: Sign core.jar + inputs: + ConnectedServiceName: vscjavaci_codesign + FolderPath: jars + Pattern: com.microsoft.java.debug.core*.jar + signConfigType: inlineSignParams + inlineOperation: |- + [ + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaSign", + "Parameters" : { + "SigAlg" : "SHA256withRSA", + "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + - task: CmdLine@2 + displayName: install signed core.jar + inputs: + script: cp jars/com.microsoft.java.debug.core*.jar .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/ + - task: CmdLine@2 + displayName: Build plugin.jar + inputs: + script: |- + ./mvnw clean install -f com.microsoft.java.debug.target/pom.xml -Dmaven.repo.local=./.repository + ./mvnw clean install -f com.microsoft.java.debug.plugin/pom.xml -Dmaven.repo.local=./.repository + + mkdir -p jars + mv .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/com.microsoft.java.debug.plugin*.jar jars/ + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + displayName: Sign plugin.jar + inputs: + ConnectedServiceName: vscjavaci_codesign + FolderPath: jars + Pattern: com.microsoft.java.debug.plugin*.jar + signConfigType: inlineSignParams + inlineOperation: |- + [ + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaSign", + "Parameters" : { + "SigAlg" : "SHA256withRSA", + "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + - task: CmdLine@2 + displayName: install signed plugin.jar + inputs: + script: cp jars/com.microsoft.java.debug.plugin*.jar .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/ + - task: CmdLine@2 + displayName: Build p2 artifacts + inputs: + script: |- + # 3. Build the p2 artifacts. + ./mvnw clean package -f com.microsoft.java.debug.repository/pom.xml -Dmaven.repo.local=./.repository + + mkdir -p p2/target + cp -r com.microsoft.java.debug.repository/target/repository p2/target/ + cp com.microsoft.java.debug.repository/pushToBintray.sh p2/ + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + displayName: Sign p2 + inputs: + ConnectedServiceName: vscjavaci_codesign + FolderPath: p2 + Pattern: "*.jar" + signConfigType: inlineSignParams + inlineOperation: |- + [ + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaSign", + "Parameters" : { + "SigAlg" : "SHA256withRSA", + "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + - task: CmdLine@2 + displayName: build m2 artifacts + inputs: + script: | + ./mvnw source:jar -f com.microsoft.java.debug.core/pom.xml -Dmaven.repo.local=./.repository + ./mvnw javadoc:jar -f com.microsoft.java.debug.core/pom.xml -Ddoclint=none -Dmaven.repo.local=./.repository + + ./mvnw source:jar -f com.microsoft.java.debug.plugin/pom.xml -Dmaven.repo.local=./.repository + ./mvnw javadoc:jar -f com.microsoft.java.debug.plugin/pom.xml -Ddoclint=none -Dmaven.repo.local=./.repository + + mkdir -p m2/java-debug-parent + cp pom.xml m2/java-debug-parent/java-debug-parent-$RELEASE_VERSION.pom + + mkdir -p m2/com.microsoft.java.debug.core + cp com.microsoft.java.debug.core/target/com.microsoft.java.debug.core*.jar m2/com.microsoft.java.debug.core + cp com.microsoft.java.debug.core/pom.xml m2/com.microsoft.java.debug.core/com.microsoft.java.debug.core-$RELEASE_VERSION.pom + + mkdir -p m2/com.microsoft.java.debug.plugin + cp com.microsoft.java.debug.plugin/target/com.microsoft.java.debug.plugin*.jar m2/com.microsoft.java.debug.plugin + cp com.microsoft.java.debug.plugin/pom.xml m2/com.microsoft.java.debug.plugin/com.microsoft.java.debug.plugin-$RELEASE_VERSION.pom + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + displayName: Sign m2 + inputs: + ConnectedServiceName: vscjavaci_codesign + FolderPath: m2 + Pattern: "*.jar" + signConfigType: inlineSignParams + inlineOperation: |- + [ + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaSign", + "Parameters" : { + "SigAlg" : "SHA256withRSA", + "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-447347-Java", + "OperationCode" : "JavaVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + - task: CopyFiles@2 + displayName: "Copy p2/m2 to: $(Build.ArtifactStagingDirectory)" + inputs: + Contents: |+ + p2/** + m2/** + + TargetFolder: $(Build.ArtifactStagingDirectory) From 431de232d233783f2711a880d0c498a27baccb13 Mon Sep 17 00:00:00 2001 From: Gayan Perera Date: Tue, 30 Jan 2024 06:13:54 +0100 Subject: [PATCH 42/94] Fix the step-into target on multi line expression. Fix #519 (#520) * Fix the step-into target on multi line expression. Fix #519 --------- Co-authored-by: Jinbo Wang --- .../core/adapter/handler/StepRequestHandler.java | 11 ++++++++--- .../plugin/internal/MethodInvocationLocator.java | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java index 71f28355a..e8f782668 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StepRequestHandler.java @@ -268,7 +268,8 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, } else if (currentStackDepth == threadState.stackDepth) { // If the ending step location is same as the original location where the step into operation is originated, // do another step of the same kind. - if (isSameLocation(currentStepLocation, threadState.stepLocation)) { + if (isSameLocation(currentStepLocation, threadState.stepLocation, + threadState.targetStepIn)) { context.getStepResultManager().removeMethodResult(threadId); threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread, context.getStepFilters().allowClasses, @@ -438,15 +439,19 @@ private boolean shouldDoExtraStepInto(int originalStackDepth, Location originalL return true; } - private boolean isSameLocation(Location original, Location current) { + private boolean isSameLocation(Location current, Location original, MethodInvocation targetStepIn) { if (original == null || current == null) { return false; } Method originalMethod = original.method(); Method currentMethod = current.method(); + // if the lines doesn't match, check if the current line is still behind the + // target if a target exist. This handles where the target is part of a + // expression which is wrapped. return originalMethod.equals(currentMethod) - && original.lineNumber() == current.lineNumber(); + && (original.lineNumber() == current.lineNumber() + || (targetStepIn != null && targetStepIn.lineEnd >= current.lineNumber())); } /** diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java index a25fbc3f6..654cbb00b 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/MethodInvocationLocator.java @@ -217,7 +217,7 @@ public boolean visit(ClassInstanceCreation node) { private boolean shouldVisitNode(ASTNode node) { int start = unit.getLineNumber(node.getStartPosition()); - int end = unit.getLineNumber(node.getStartPosition() + node.getLength()); + int end = unit.getLineNumber(node.getStartPosition() + node.getLength() - 1); if (line >= start && line <= end) { return true; From fcfa80d2ba6b6e60da34d9451c4fc297fc821f0d Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 30 Jan 2024 13:59:01 +0800 Subject: [PATCH 43/94] Bump version to 0.51.0 (#533) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 635993d56..cd41ea9bc 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.50.0 + 0.51.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index ca5f41e6f..4d55efda0 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 84a0ab36f..077d85c95 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.50.0 +Bundle-Version: 0.51.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.50.0.jar + lib/com.microsoft.java.debug.core-0.51.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index b895ffd28..68e29fa33 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.50.0 + 0.51.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.50.0 + 0.51.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 639d50082..332d14f9e 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 4f05eb331..314b894cb 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.50.0 + 0.51.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 80395f6dd..42dbf2724 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.50.0 + 0.51.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index d562f82b5..46aece86b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.50.0 + 0.51.0 pom Java Debug Server for Visual Studio Code From b5bc37d18e885c686866b40fbf7e8f9ed82a7d47 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 6 Feb 2024 09:20:06 +0800 Subject: [PATCH 44/94] Fix build errors (#535) * Fix build errors --- .../internal/CompletionProposalRequestor.java | 20 ++++++++++++++++++- .../com.microsoft.java.debug.tp.target | 5 ++++- pom.xml | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java index 1df752f24..431c283f5 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/CompletionProposalRequestor.java @@ -72,6 +72,8 @@ public final class CompletionProposalRequestor extends CompletionRequestor { CompletionItemKind.Text); // @formatter:on + private static boolean isFilterFailed = false; + /** * Constructor. * @param typeRoot ITypeRoot @@ -321,7 +323,7 @@ private boolean isFiltered(CompletionProposal proposal) { case CompletionProposal.JAVADOC_TYPE_REF: case CompletionProposal.TYPE_REF: { char[] declaringType = getDeclaringType(proposal); - return declaringType != null && org.eclipse.jdt.ls.core.internal.contentassist.TypeFilter.isFiltered(declaringType); + return declaringType != null && isFiltered(declaringType); } default: // do nothing } @@ -332,6 +334,22 @@ private boolean isFiltered(CompletionProposal proposal) { return false; } + // Temp workaround for the completion error https://github.com/microsoft/java-debug/issues/534 + private static boolean isFiltered(char[] fullTypeName) { + if (isFilterFailed) { + return false; + } + + try { + return JavaLanguageServerPlugin.getInstance().getTypeFilter().filter(new String(fullTypeName)); + } catch (NoSuchMethodError ex) { + isFilterFailed = true; + JavaLanguageServerPlugin.logException("isFiltered for the completion failed.", ex); + } + + return false; + } + /** * copied from * org.eclipse.jdt.ui.text.java.CompletionProposalCollector.getDeclaringType(CompletionProposal) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 2e7920ed7..828da98a2 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -15,7 +15,10 @@ - + + + + diff --git a/pom.xml b/pom.xml index 46aece86b..8911c9d58 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ Java Debug Server for Visual Studio Code UTF-8 - 4.0.3 + 4.0.5 ${basedir} From f212c3a2f7aa2490c2df5dfa8dfda9fd0dd70d09 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 19 Feb 2024 11:27:03 +0800 Subject: [PATCH 45/94] Bump version to 0.51.1 (#536) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index cd41ea9bc..a7c2ca8ce 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.51.0 + 0.51.1 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 4d55efda0..b4fb64d7d 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 077d85c95..73af47a6d 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.51.0 +Bundle-Version: 0.51.1 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.51.0.jar + lib/com.microsoft.java.debug.core-0.51.1.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 68e29fa33..4657ab08b 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.51.0 + 0.51.1 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.51.0 + 0.51.1 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 332d14f9e..53e8bf963 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 314b894cb..68ff9fc42 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.51.0 + 0.51.1 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 42dbf2724..6977f1831 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.51.0 + 0.51.1 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index 8911c9d58..b039fe1c1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.51.0 + 0.51.1 pom Java Debug Server for Visual Studio Code From 6e064b0ca2e8d894ab66b6b341dae00f4060317a Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 19 Feb 2024 13:39:33 +0800 Subject: [PATCH 46/94] Update signjars-rc.yml for Azure Pipelines --- .azure-pipelines/signjars-rc.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index 4e51eff7f..a8f1d3268 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -74,7 +74,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign core.jar inputs: - ConnectedServiceName: vscjavaci_codesign + ConnectedServiceName: vscjavaci_codesign_token FolderPath: jars Pattern: com.microsoft.java.debug.core*.jar signConfigType: inlineSignParams @@ -114,7 +114,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign plugin.jar inputs: - ConnectedServiceName: vscjavaci_codesign + ConnectedServiceName: vscjavaci_codesign_token FolderPath: jars Pattern: com.microsoft.java.debug.plugin*.jar signConfigType: inlineSignParams @@ -155,7 +155,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign p2 inputs: - ConnectedServiceName: vscjavaci_codesign + ConnectedServiceName: vscjavaci_codesign_token FolderPath: p2 Pattern: "*.jar" signConfigType: inlineSignParams @@ -202,7 +202,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign m2 inputs: - ConnectedServiceName: vscjavaci_codesign + ConnectedServiceName: vscjavaci_codesign_token FolderPath: m2 Pattern: "*.jar" signConfigType: inlineSignParams From 5f0d1bb9109f2ebfcc1f8faf12eac77f59b5a380 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 19 Feb 2024 14:59:26 +0800 Subject: [PATCH 47/94] Update signjars-rc.yml for Azure Pipelines --- .azure-pipelines/signjars-rc.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index a8f1d3268..ebb333f70 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -74,7 +74,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign core.jar inputs: - ConnectedServiceName: vscjavaci_codesign_token + ConnectedServiceName: vscjavaci_esrp_codesign FolderPath: jars Pattern: com.microsoft.java.debug.core*.jar signConfigType: inlineSignParams @@ -114,7 +114,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign plugin.jar inputs: - ConnectedServiceName: vscjavaci_codesign_token + ConnectedServiceName: vscjavaci_esrp_codesign FolderPath: jars Pattern: com.microsoft.java.debug.plugin*.jar signConfigType: inlineSignParams @@ -155,7 +155,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign p2 inputs: - ConnectedServiceName: vscjavaci_codesign_token + ConnectedServiceName: vscjavaci_esrp_codesign FolderPath: p2 Pattern: "*.jar" signConfigType: inlineSignParams @@ -202,7 +202,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign m2 inputs: - ConnectedServiceName: vscjavaci_codesign_token + ConnectedServiceName: vscjavaci_esrp_codesign FolderPath: m2 Pattern: "*.jar" signConfigType: inlineSignParams From 6c2377eae78c308bf87fbc2a6438a93734b06f5f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 23 Feb 2024 14:18:08 +0800 Subject: [PATCH 48/94] Update signjars-nightly.yml for Azure Pipelines --- .azure-pipelines/signjars-nightly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index bdaeea871..cae5ac6d5 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -73,7 +73,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign core.jar inputs: - ConnectedServiceName: vscjavaci_codesign + ConnectedServiceName: vscjavaci_esrp_codesign FolderPath: jars Pattern: com.microsoft.java.debug.core*.jar signConfigType: inlineSignParams @@ -113,7 +113,7 @@ extends: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 displayName: Sign plugin.jar inputs: - ConnectedServiceName: vscjavaci_codesign + ConnectedServiceName: vscjavaci_esrp_codesign FolderPath: jars Pattern: com.microsoft.java.debug.plugin*.jar signConfigType: inlineSignParams From 98db4b16262488c5351a922f5781f7b95e1290d4 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 14 Mar 2024 13:58:54 +0800 Subject: [PATCH 49/94] Update com.microsoft.java.debug.tp.target to 4.31 release (#538) --- .../com.microsoft.java.debug.tp.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 828da98a2..55695f6a9 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -16,7 +16,7 @@ - + From 736dcacf41e4da79b7419e7b7067f9c886252530 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 18 Mar 2024 18:29:13 +0800 Subject: [PATCH 50/94] Update lsp4j to 0.22.0 (#541) --- .../com.microsoft.java.debug.tp.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 55695f6a9..200e532e3 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -31,7 +31,7 @@ - + From 56c014531273afd1c3a3b30712c2fb4d257e61f0 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 21 Mar 2024 20:34:44 +0800 Subject: [PATCH 51/94] Support debugging Java 21 instance main method and unnamed class (#542) * Support debugging Java 21 instance main method and unnamed class --- .github/workflows/build.yml | 4 +- .../internal/JdtSourceLookUpProvider.java | 32 ++++- .../internal/ResolveMainClassHandler.java | 124 ++++++++++-------- .../internal/ResolveMainMethodHandler.java | 51 ++++++- .../com.microsoft.java.debug.tp.target | 9 +- pom.xml | 2 +- 6 files changed, 158 insertions(+), 64 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 41c85cb62..1ace44224 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: ${{ runner.os }}-maven- - name: Verify - run: ./mvnw clean verify + run: ./mvnw clean verify -U - name: Checkstyle run: ./mvnw checkstyle:check @@ -85,7 +85,7 @@ jobs: ${{ runner.os }}-maven- - name: Verify - run: ./mvnw clean verify + run: ./mvnw clean verify -U - name: Checkstyle run: ./mvnw checkstyle:check diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index 1ebf4c7c3..c96b98342 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -32,6 +32,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; @@ -56,6 +57,7 @@ import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.LambdaExpression; +import org.eclipse.jdt.core.dom.UnnamedClass; import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jdt.launching.IVMInstall; @@ -172,6 +174,11 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB .map(sourceBreakpoint -> new JavaBreakpointLocation(sourceBreakpoint.line, sourceBreakpoint.column)) .toArray(JavaBreakpointLocation[]::new); if (astUnit != null) { + List types = astUnit.types(); + String unnamedClass = null; + if (types.size() == 1 && types.get(0) instanceof UnnamedClass) { + unnamedClass = inferPrimaryTypeName(sourceUri, astUnit); + } Map resolvedLocations = new HashMap<>(); for (JavaBreakpointLocation sourceLocation : sourceLocations) { int sourceLine = sourceLocation.lineNumber(); @@ -222,7 +229,7 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB // be hit in current implementation. if (sourceLine == locator.getLineLocation() && locator.getLocationType() == BreakpointLocationLocator.LOCATION_LINE) { - sourceLocation.setClassName(locator.getFullyQualifiedTypeName()); + sourceLocation.setClassName(StringUtils.isBlank(unnamedClass) ? locator.getFullyQualifiedTypeName() : unnamedClass); if (resolvedLocations.containsKey(sourceLine)) { sourceLocation.setAvailableBreakpointLocations(resolvedLocations.get(sourceLine)); } else { @@ -231,7 +238,7 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB resolvedLocations.put(sourceLine, inlineLocations); } } else if (locator.getLocationType() == BreakpointLocationLocator.LOCATION_METHOD) { - sourceLocation.setClassName(locator.getFullyQualifiedTypeName()); + sourceLocation.setClassName(StringUtils.isBlank(unnamedClass) ? locator.getFullyQualifiedTypeName() : unnamedClass); sourceLocation.setMethodName(locator.getMethodName()); sourceLocation.setMethodSignature(locator.getMethodSignature()); } @@ -241,6 +248,27 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB return sourceLocations; } + private String inferPrimaryTypeName(String uri, CompilationUnit astUnit) { + String fileName = ""; + String filePath = AdapterUtils.toPath(uri); + if (filePath != null && Files.isRegularFile(Paths.get(filePath))) { + fileName = Paths.get(filePath).getFileName().toString(); + } else if (astUnit.getTypeRoot() != null) { + fileName = astUnit.getTypeRoot().getElementName(); + } + + if (StringUtils.isNotBlank(fileName)) { + String[] extensions = JavaCore.getJavaLikeExtensions(); + for (String extension : extensions) { + if (fileName.endsWith("." + extension)) { + return fileName.substring(0, fileName.length() - 1 - extension.length()); + } + } + } + + return fileName; + } + private BreakpointLocation[] getInlineBreakpointLocations(final CompilationUnit astUnit, int sourceLine) { List locations = new ArrayList<>(); // The starting position of each line is the default breakpoint location for diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java index f70d0c044..38ad1532b 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java @@ -43,6 +43,7 @@ import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; +import org.eclipse.jdt.internal.core.SourceMethod; import org.eclipse.jdt.ls.core.internal.ProjectUtils; import org.eclipse.jdt.ls.core.internal.ResourceUtils; import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; @@ -101,8 +102,7 @@ private List resolveMainClassUnderPaths(List parentPaths) // Limit to search main method from source code only. IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(ProjectUtils.getJavaProjects(), IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.SOURCES); - SearchPattern pattern = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD, - IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH); + SearchPattern pattern = createMainMethodSearchPattern(); final List res = new ArrayList<>(); SearchRequestor requestor = new SearchRequestor() { @Override @@ -110,40 +110,36 @@ public void acceptSearchMatch(SearchMatch match) { Object element = match.getElement(); if (element instanceof IMethod) { IMethod method = (IMethod) element; - try { - if (method.isMainMethod()) { - IResource resource = method.getResource(); - if (resource != null) { - IProject project = resource.getProject(); - if (project != null) { - String mainClass = method.getDeclaringType().getFullyQualifiedName(); - IJavaProject javaProject = JdtUtils.getJavaProject(project); - if (javaProject != null) { - String moduleName = JdtUtils.getModuleName(javaProject); - if (moduleName != null) { - mainClass = moduleName + "/" + mainClass; - } + if (isMainMethod(method)) { + IResource resource = method.getResource(); + if (resource != null) { + IProject project = resource.getProject(); + if (project != null) { + String mainClass = method.getDeclaringType().getFullyQualifiedName(); + IJavaProject javaProject = JdtUtils.getJavaProject(project); + if (javaProject != null) { + String moduleName = JdtUtils.getModuleName(javaProject); + if (moduleName != null) { + mainClass = moduleName + "/" + mainClass; } - String projectName = ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getName()) ? null : project.getName(); - if (parentPaths.isEmpty() - || ResourceUtils.isContainedIn(project.getLocation(), parentPaths) - || isContainedInInvisibleProject(project, parentPaths)) { - String filePath = null; - - if (match.getResource() instanceof IFile) { - try { - filePath = match.getResource().getLocation().toOSString(); - } catch (Exception ex) { - // ignore - } + } + String projectName = ProjectsManager.DEFAULT_PROJECT_NAME.equals(project.getName()) ? null : project.getName(); + if (parentPaths.isEmpty() + || ResourceUtils.isContainedIn(project.getLocation(), parentPaths) + || isContainedInInvisibleProject(project, parentPaths)) { + String filePath = null; + + if (match.getResource() instanceof IFile) { + try { + filePath = match.getResource().getLocation().toOSString(); + } catch (Exception ex) { + // ignore } - res.add(new ResolutionItem(mainClass, projectName, filePath)); } + res.add(new ResolutionItem(mainClass, projectName, filePath)); } } } - } catch (JavaModelException e) { - // ignore } } } @@ -166,8 +162,7 @@ private List resolveMainClassUnderProject(final String projectNa IJavaProject javaProject = ProjectUtils.getJavaProject(projectName); IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(javaProject == null ? new IJavaProject[0] : new IJavaProject[] {javaProject}, IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.SOURCES); - SearchPattern pattern = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD, - IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH); + SearchPattern pattern = createMainMethodSearchPattern(); final List res = new ArrayList<>(); SearchRequestor requestor = new SearchRequestor() { @Override @@ -175,35 +170,31 @@ public void acceptSearchMatch(SearchMatch match) { Object element = match.getElement(); if (element instanceof IMethod) { IMethod method = (IMethod) element; - try { - if (method.isMainMethod()) { - IResource resource = method.getResource(); - if (resource != null) { - IProject project = resource.getProject(); - if (project != null) { - String mainClass = method.getDeclaringType().getFullyQualifiedName(); - IJavaProject javaProject = JdtUtils.getJavaProject(project); - if (javaProject != null) { - String moduleName = JdtUtils.getModuleName(javaProject); - if (moduleName != null) { - mainClass = moduleName + "/" + mainClass; - } + if (isMainMethod(method)) { + IResource resource = method.getResource(); + if (resource != null) { + IProject project = resource.getProject(); + if (project != null) { + String mainClass = method.getDeclaringType().getFullyQualifiedName(); + IJavaProject javaProject = JdtUtils.getJavaProject(project); + if (javaProject != null) { + String moduleName = JdtUtils.getModuleName(javaProject); + if (moduleName != null) { + mainClass = moduleName + "/" + mainClass; } + } - String filePath = null; - if (match.getResource() instanceof IFile) { - try { - filePath = match.getResource().getLocation().toOSString(); - } catch (Exception ex) { - // ignore - } + String filePath = null; + if (match.getResource() instanceof IFile) { + try { + filePath = match.getResource().getLocation().toOSString(); + } catch (Exception ex) { + // ignore } - res.add(new ResolutionItem(mainClass, projectName, filePath)); } + res.add(new ResolutionItem(mainClass, projectName, filePath)); } } - } catch (JavaModelException e) { - // ignore } } } @@ -221,6 +212,29 @@ public void acceptSearchMatch(SearchMatch match) { return resolutions; } + private SearchPattern createMainMethodSearchPattern() { + SearchPattern pattern1 = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD, + IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH); + SearchPattern pattern2 = SearchPattern.createPattern("main() void", IJavaSearchConstants.METHOD, + IJavaSearchConstants.DECLARATIONS, SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH); + return SearchPattern.createOrPattern(pattern1, pattern2); + } + + private boolean isMainMethod(IMethod method) { + try { + if (method instanceof SourceMethod + && ((SourceMethod) method).isMainMethodCandidate()) { + return true; + } + + return method.isMainMethod(); + } catch (JavaModelException e) { + // do nothing + } + + return false; + } + private boolean isContainedInInvisibleProject(IProject project, Collection rootPaths) { if (project == null) { return false; diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java index a3c61e814..fb8dfc33e 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java @@ -15,6 +15,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -30,7 +31,11 @@ import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.ISourceReference; import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.core.SourceMethod; import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.handlers.DocumentLifeCycleHandler; import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; @@ -104,16 +109,58 @@ private static List searchMainMethods(ICompilationUnit compilationUnit) * Returns the main method defined in the type. */ public static IMethod getMainMethod(IType type) throws JavaModelException { + boolean allowInstanceMethod = isInstanceMainMethodSupported(type); + List methods = new ArrayList<>(); for (IMethod method : type.getMethods()) { - // Have at most one main method in the member methods of the type. + if (method instanceof SourceMethod + && ((SourceMethod) method).isMainMethodCandidate()) { + methods.add(method); + } + if (method.isMainMethod()) { - return method; + methods.add(method); + } + + if (!allowInstanceMethod && !methods.isEmpty()) { + return methods.get(0); } } + if (!methods.isEmpty()) { + methods.sort((method1, method2) -> { + return getMainMethodPriority(method1) - getMainMethodPriority(method2); + }); + + return methods.get(0); + } + return null; } + private static boolean isInstanceMainMethodSupported(IType type) { + Map options = type.getJavaProject().getOptions(true); + return CompilerOptions.versionToJdkLevel(options.get(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM)) >= ClassFileConstants.JDK21; + } + + private static int getMainMethodPriority(IMethod method) { + int flags = 0; + try { + flags = method.getFlags(); + } catch (JavaModelException e) { + // do nothing + } + String[] params = method.getParameterTypes(); + if (Flags.isStatic(flags) && params.length == 1) { + return 1; + } else if (Flags.isStatic(flags)) { + return 2; + } else if (params.length == 1) { + return 3; + } + + return 4; + } + private static List getPotentialMainClassTypes(ICompilationUnit compilationUnit) throws JavaModelException { List result = new ArrayList<>(); IType[] topLevelTypes = compilationUnit.getTypes(); diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 200e532e3..a52901d01 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -14,13 +14,18 @@ - + + + + + + - + diff --git a/pom.xml b/pom.xml index b039fe1c1..2917f4092 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ Java Debug Server for Visual Studio Code UTF-8 - 4.0.5 + 4.0.6 ${basedir} From 1a06b1f6d27be3e765750433792da5ed02b9b0cd Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 25 Mar 2024 12:50:51 +0800 Subject: [PATCH 52/94] bump version to 0.52.0 (#543) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index a7c2ca8ce..3b42e40cb 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.51.1 + 0.52.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index b4fb64d7d..6de8860a5 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 73af47a6d..b45c99f7a 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.51.1 +Bundle-Version: 0.52.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.51.1.jar + lib/com.microsoft.java.debug.core-0.52.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 4657ab08b..6d58947b0 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.51.1 + 0.52.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.51.1 + 0.52.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 53e8bf963..fc6ff6a62 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 68ff9fc42..3d5537f13 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.51.1 + 0.52.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 6977f1831..e4ee29b92 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.51.1 + 0.52.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index 2917f4092..f2e4d0eef 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.51.1 + 0.52.0 pom Java Debug Server for Visual Studio Code From ae16f7ce3205047fd687aab9d877eeb78c62ace2 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 26 Mar 2024 10:45:23 +0800 Subject: [PATCH 53/94] Check the class name of ASTNode to see if it's unnamed class (#544) --- .../plugin/internal/JdtSourceLookUpProvider.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index c96b98342..5652b922e 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -20,11 +20,14 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.logging.Level; @@ -57,7 +60,6 @@ import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.LambdaExpression; -import org.eclipse.jdt.core.dom.UnnamedClass; import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jdt.launching.IVMInstall; @@ -87,6 +89,9 @@ public class JdtSourceLookUpProvider implements ISourceLookUpProvider { private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); private static final String JDT_SCHEME = "jdt"; private static final String PATH_SEPARATOR = "/"; + private static final Set IMPLICITLY_DECLARED_CLASSES = new HashSet<>( + Arrays.asList("org.eclipse.jdt.core.dom.UnnamedClass", + "org.eclipse.jdt.core.dom.ImplicitTypeDeclaration")); private ISourceContainer[] sourceContainers = null; private HashMap options = new HashMap(); @@ -176,7 +181,10 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB if (astUnit != null) { List types = astUnit.types(); String unnamedClass = null; - if (types.size() == 1 && types.get(0) instanceof UnnamedClass) { + // See https://github.com/eclipse-jdt/eclipse.jdt.core/pull/2220 + // Given that the JDT plans to rename UnamedClass to ImplicitTypeDeclaration, we will check + // the class name of the ASTNode to prevent the potential breaking in the future. + if (types.size() == 1 && IMPLICITLY_DECLARED_CLASSES.contains(types.get(0).getClass().getName())) { unnamedClass = inferPrimaryTypeName(sourceUri, astUnit); } Map resolvedLocations = new HashMap<>(); From 37d4e66c5717179b1487ff72fcbc8622b31a3648 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 26 Mar 2024 12:47:07 +0800 Subject: [PATCH 54/94] Update signjars-nightly.yml for Azure Pipelines --- .azure-pipelines/signjars-nightly.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index cae5ac6d5..0e53a4219 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -105,6 +105,7 @@ extends: displayName: Build plugin.jar inputs: script: |- + ./mvnw clean install -N -f pom.xml -Dmaven.repo.local=./.repository ./mvnw clean install -f com.microsoft.java.debug.target/pom.xml -Dmaven.repo.local=./.repository ./mvnw clean install -f com.microsoft.java.debug.plugin/pom.xml -Dmaven.repo.local=./.repository From 83403a458e0d01fba5a3871fea81af742460bdf0 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 10 Apr 2024 15:59:06 +0800 Subject: [PATCH 55/94] fix Java 22 main method searching order (#548) --- .../internal/ResolveMainMethodHandler.java | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java index fb8dfc33e..be1092bb3 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java @@ -142,23 +142,15 @@ private static boolean isInstanceMainMethodSupported(IType type) { return CompilerOptions.versionToJdkLevel(options.get(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM)) >= ClassFileConstants.JDK21; } + /** + * See Java 22 JEP 463 https://openjdk.org/jeps/463. + * It searches the main method in the launched class by following a specific order: + * - If the launched class contains a main method with a String[] parameter then choose that method. + * - Otherwise, if the class contains a main method with no parameters then choose that method. + */ private static int getMainMethodPriority(IMethod method) { - int flags = 0; - try { - flags = method.getFlags(); - } catch (JavaModelException e) { - // do nothing - } String[] params = method.getParameterTypes(); - if (Flags.isStatic(flags) && params.length == 1) { - return 1; - } else if (Flags.isStatic(flags)) { - return 2; - } else if (params.length == 1) { - return 3; - } - - return 4; + return params.length == 1 ? 1 : 2; } private static List getPotentialMainClassTypes(ICompilationUnit compilationUnit) throws JavaModelException { From 36572435d0518cb2566ab9705c3d2b8e2a797402 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Fri, 14 Jun 2024 16:04:40 +0800 Subject: [PATCH 56/94] Support HCR for gradle build server projects (#555) * Support HCR for gradle build server projects * Fix checkstyle violations * Fix NPE when auto build is disabled Signed-off-by: Sheng Chen * Address comments * Fix checkstyle violations * Use isNotBlank() --------- Signed-off-by: Sheng Chen --- .../java/debug/plugin/internal/Compile.java | 78 ++++++++++--------- .../internal/JavaHotCodeReplaceProvider.java | 45 +++++++++++ .../java/debug/plugin/internal/JdtUtils.java | 34 ++++++++ 3 files changed, 120 insertions(+), 37 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java index 9cb6fbbfa..245281816 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/Compile.java @@ -14,6 +14,7 @@ package com.microsoft.java.debug.plugin.internal; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; @@ -28,14 +29,16 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.ls.core.internal.BuildWorkspaceStatus; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.ProjectUtils; import org.eclipse.jdt.ls.core.internal.ResourceUtils; +import org.eclipse.jdt.ls.core.internal.handlers.BuildWorkspaceHandler; import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager; +import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.eclipse.lsp4j.extended.ProjectBuildParams; import com.microsoft.java.debug.core.Configuration; @@ -45,20 +48,12 @@ public class Compile { private static final int GRADLE_BS_COMPILATION_ERROR = 100; public static Object compile(CompileParams params, IProgressMonitor monitor) { - IProject mainProject = params == null ? null : ProjectUtils.getProject(params.getProjectName()); - if (mainProject == null) { - try { - // Q: is infer project by main class name necessary? perf impact? - List javaProjects = ResolveClasspathsHandler.getJavaProjectFromType(params.getMainClass()); - if (javaProjects.size() == 1) { - mainProject = javaProjects.get(0).getProject(); - } - } catch (CoreException e) { - JavaLanguageServerPlugin.logException("Failed to resolve project from main class name.", e); - } + if (params == null) { + throw new IllegalArgumentException("The compile parameters should not be null."); } - if (isBspProject(mainProject) && !ProjectUtils.isGradleProject(mainProject)) { + IProject mainProject = JdtUtils.getMainProject(params.getProjectName(), params.getMainClass()); + if (JdtUtils.isBspProject(mainProject) && !ProjectUtils.isGradleProject(mainProject)) { // Just need to trigger a build for the target project, the Gradle build server will // handle the build dependencies for us. try { @@ -78,20 +73,37 @@ public static Object compile(CompileParams params, IProgressMonitor monitor) { return BuildWorkspaceStatus.SUCCEED; } - try { - if (monitor.isCanceled()) { - return BuildWorkspaceStatus.CANCELLED; - } + if (monitor.isCanceled()) { + return BuildWorkspaceStatus.CANCELLED; + } - long compileAt = System.currentTimeMillis(); - if (params != null && params.isFullBuild()) { - ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.CLEAN_BUILD, monitor); - ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, monitor); - } else { - ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, monitor); + ProjectBuildParams buildParams = new ProjectBuildParams(); + List identifiers = new LinkedList<>(); + buildParams.setFullBuild(params.isFullBuild); + for (IJavaProject javaProject : ProjectUtils.getJavaProjects()) { + if (ProjectsManager.getDefaultProject().equals(javaProject.getProject())) { + continue; } - logger.info("Time cost for ECJ: " + (System.currentTimeMillis() - compileAt) + "ms"); + // we only build project which is not a BSP project, in case that the compile request is triggered by + // HCR with auto-build disabled, the build for BSP projects will be triggered by JavaHotCodeReplaceProvider. + if (!JdtUtils.isBspProject(javaProject.getProject())) { + identifiers.add(new TextDocumentIdentifier(javaProject.getProject().getLocationURI().toString())); + } + } + if (identifiers.size() == 0) { + return BuildWorkspaceStatus.SUCCEED; + } + buildParams.setIdentifiers(identifiers); + long compileAt = System.currentTimeMillis(); + BuildWorkspaceHandler buildWorkspaceHandler = new BuildWorkspaceHandler(JavaLanguageServerPlugin.getProjectsManager()); + BuildWorkspaceStatus status = buildWorkspaceHandler.buildProjects(buildParams, monitor); + logger.info("Time cost for ECJ: " + (System.currentTimeMillis() - compileAt) + "ms"); + if (status == BuildWorkspaceStatus.FAILED || status == BuildWorkspaceStatus.CANCELLED) { + return status; + } + + try { IResource currentResource = mainProject; if (isUnmanagedFolder(mainProject) && StringUtils.isNotBlank(params.getMainClass())) { IType mainType = ProjectUtils.getJavaProject(mainProject).findType(params.getMainClass()); @@ -135,17 +147,14 @@ public static Object compile(CompileParams params, IProgressMonitor monitor) { } } - if (problemMarkers.isEmpty()) { - return BuildWorkspaceStatus.SUCCEED; + if (!problemMarkers.isEmpty()) { + return BuildWorkspaceStatus.WITH_ERROR; } - - return BuildWorkspaceStatus.WITH_ERROR; } catch (CoreException e) { - JavaLanguageServerPlugin.logException("Failed to build workspace.", e); - return BuildWorkspaceStatus.FAILED; - } catch (OperationCanceledException e) { - return BuildWorkspaceStatus.CANCELLED; + JavaLanguageServerPlugin.log(e); } + + return BuildWorkspaceStatus.SUCCEED; } private static boolean isUnmanagedFolder(IProject project) { @@ -153,11 +162,6 @@ private static boolean isUnmanagedFolder(IProject project) { && ProjectUtils.isJavaProject(project); } - private static boolean isBspProject(IProject project) { - return project != null && ProjectUtils.isJavaProject(project) - && ProjectUtils.hasNature(project, "com.microsoft.gradle.bs.importer.GradleBuildServerProjectNature"); - } - private static IProject getDefaultProject() { return getWorkspaceRoot().getProject(ProjectsManager.DEFAULT_PROJECT_NAME); } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaHotCodeReplaceProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaHotCodeReplaceProvider.java index 2bf905c89..3a2b2f3df 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaHotCodeReplaceProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JavaHotCodeReplaceProvider.java @@ -34,16 +34,20 @@ import java.util.logging.Level; import java.util.logging.Logger; +import org.eclipse.core.resources.IBuildConfiguration; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; @@ -55,6 +59,7 @@ import org.eclipse.jdt.core.util.ISourceAttribute; import org.eclipse.jdt.internal.core.util.Util; import org.eclipse.jdt.ls.core.internal.JobHelpers; +import org.eclipse.jdt.ls.core.internal.ProjectUtils; import com.microsoft.java.debug.core.Configuration; import com.microsoft.java.debug.core.DebugException; @@ -63,6 +68,7 @@ import com.microsoft.java.debug.core.IDebugSession; import com.microsoft.java.debug.core.StackFrameUtility; import com.microsoft.java.debug.core.adapter.AdapterUtils; +import com.microsoft.java.debug.core.adapter.Constants; import com.microsoft.java.debug.core.adapter.ErrorCode; import com.microsoft.java.debug.core.adapter.HotCodeReplaceEvent; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; @@ -104,6 +110,8 @@ public class JavaHotCodeReplaceProvider implements IHotCodeReplaceProvider, IRes private List deltaClassNames = new ArrayList<>(); + private String mainProjectName = ""; + /** * Visitor for resource deltas. */ @@ -269,6 +277,7 @@ public void initialize(IDebugAdapterContext context, Map options } this.context = context; currentDebugSession = context.getDebugSession(); + this.mainProjectName = ((String) options.get(Constants.PROJECT_NAME)); } @Override @@ -319,6 +328,7 @@ public void onClassRedefined(Consumer> consumer) { @Override public CompletableFuture> redefineClasses() { + triggerBuildForBspProject(); JobHelpers.waitForBuildJobs(10 * 1000); return CompletableFuture.supplyAsync(() -> { List classNames = new ArrayList<>(); @@ -737,4 +747,39 @@ private List getStackFrames(ThreadReference thread, boolean refresh) } }); } + + /** + * Trigger build separately if the main project is a BSP project. + * This is because auto build for BSP project will not update the class files to disk. + */ + private void triggerBuildForBspProject() { + // check if the workspace contains BSP project first. This is for performance consideration. + // Due to that getJavaProjectFromType() is a heavy operation. + if (!containsBspProjects()) { + return; + } + + IProject mainProject = JdtUtils.getMainProject(this.mainProjectName, context.getMainClass()); + if (mainProject != null && JdtUtils.isBspProject(mainProject)) { + try { + ResourcesPlugin.getWorkspace().build( + new IBuildConfiguration[]{mainProject.getActiveBuildConfig()}, + IncrementalProjectBuilder.INCREMENTAL_BUILD, + false /*buildReference*/, + new NullProgressMonitor() + ); + } catch (CoreException e) { + // ignore compilation errors + } + } + } + + private boolean containsBspProjects() { + for (IJavaProject javaProject : ProjectUtils.getJavaProjects()) { + if (JdtUtils.isBspProject(javaProject.getProject())) { + return true; + } + } + return false; + } } diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java index a4c06c6d4..66562ae74 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java @@ -40,6 +40,8 @@ import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.sourcelookup.containers.JavaProjectSourceContainer; import org.eclipse.jdt.launching.sourcelookup.containers.PackageFragmentRootSourceContainer; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.ProjectUtils; import com.microsoft.java.debug.core.DebugException; import com.microsoft.java.debug.core.StackFrameUtility; @@ -415,4 +417,36 @@ public static boolean isSameFile(IResource resource1, IResource resource2) { return Objects.equals(resource1.getLocation(), resource2.getLocation()); } + + /** + * Check if the project is managed by Gradle Build Server. + */ + public static boolean isBspProject(IProject project) { + return project != null && ProjectUtils.isJavaProject(project) + && ProjectUtils.hasNature(project, "com.microsoft.gradle.bs.importer.GradleBuildServerProjectNature"); + } + + /** + * Get main project according to the main project name or main class name, + * or return null if the main project cannot be resolved. + */ + public static IProject getMainProject(String mainProjectName, String mainClassName) { + IProject mainProject = null; + if (StringUtils.isNotBlank(mainProjectName)) { + mainProject = ProjectUtils.getProject(mainProjectName); + } + + if (mainProject == null && StringUtils.isNotBlank(mainClassName)) { + try { + List javaProjects = ResolveClasspathsHandler.getJavaProjectFromType(mainClassName); + if (javaProjects.size() == 1) { + mainProject = javaProjects.get(0).getProject(); + } + } catch (CoreException e) { + JavaLanguageServerPlugin.logException("Failed to resolve project from main class name.", e); + } + } + + return mainProject; + } } From 6511f97c76d4dd562f94c3ac503a982407d211a3 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 17 Jun 2024 16:50:27 +0800 Subject: [PATCH 57/94] Update tp to fix the build failure (#556) --- .../com.microsoft.java.debug.tp.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index a52901d01..6edb44dec 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -15,7 +15,7 @@ - + From e06a1b686625b28a66e0bd6a22f4668fb4f02b4d Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 27 Jun 2024 10:31:27 +0800 Subject: [PATCH 58/94] bump version to 0.53.0 (#557) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 3b42e40cb..bb1449401 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.52.0 + 0.53.0 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index 6de8860a5..dc81da8e6 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index b45c99f7a..192908dcf 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.52.0 +Bundle-Version: 0.53.0 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.52.0.jar + lib/com.microsoft.java.debug.core-0.53.0.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 6d58947b0..93323db5c 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.52.0 + 0.53.0 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.52.0 + 0.53.0 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index fc6ff6a62..b09605569 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 3d5537f13..edb1c9891 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.52.0 + 0.53.0 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index e4ee29b92..2dc407f6c 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.52.0 + 0.53.0 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index f2e4d0eef..c277e8a98 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.52.0 + 0.53.0 pom Java Debug Server for Visual Studio Code From 24c61a7b06b2e3dec661b97688f9b6d033de5fab Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 19 Jul 2024 13:34:22 +0800 Subject: [PATCH 59/94] Remove the deprecated debug parameters from the launching connector (#562) --- .../java/debug/plugin/internal/AdvancedLaunchingConnector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java index 3551ab2e6..087f0fae7 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java @@ -195,7 +195,7 @@ private static String[] constructLaunchCommand(Map l StringBuilder execString = new StringBuilder(); execString.append("\"" + javaHome + slash + "bin" + slash + javaExec + "\""); - execString.append(" -Xdebug -Xnoagent -Djava.compiler=NONE"); + execString.append(" -Djava.compiler=NONE"); execString.append(" -Xrunjdwp:transport=dt_socket,address=" + address + ",server=n,suspend=" + (suspend ? "y" : "n")); if (javaOptions != null) { execString.append(" " + javaOptions); From 1b669f8c4c92c179acf89498cd14bcb8397bd3b5 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 19 Jul 2024 14:36:08 +0800 Subject: [PATCH 60/94] Adopt the new code sign job in the pipeline (#563) --- .azure-pipelines/signjars-nightly.yml | 18 +++++++++++--- .azure-pipelines/signjars-rc.yml | 36 +++++++++++++++++++++------ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index 0e53a4219..2c0373aab 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -70,10 +70,15 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/com.microsoft.java.debug.core*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: Sign core.jar inputs: - ConnectedServiceName: vscjavaci_esrp_codesign + ConnectedServiceName: $(ConnectedServiceName) + AppRegistrationClientId: $(AppRegistrationClientId) + AppRegistrationTenantId: $(AppRegistrationTenantId) + AuthAKVName: $(AuthAKVName) + AuthCertName: $(AuthCertName) + AuthSignCertName: $(AuthSignCertName) FolderPath: jars Pattern: com.microsoft.java.debug.core*.jar signConfigType: inlineSignParams @@ -111,10 +116,15 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/com.microsoft.java.debug.plugin*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: Sign plugin.jar inputs: - ConnectedServiceName: vscjavaci_esrp_codesign + ConnectedServiceName: $(ConnectedServiceName) + AppRegistrationClientId: $(AppRegistrationClientId) + AppRegistrationTenantId: $(AppRegistrationTenantId) + AuthAKVName: $(AuthAKVName) + AuthCertName: $(AuthCertName) + AuthSignCertName: $(AuthSignCertName) FolderPath: jars Pattern: com.microsoft.java.debug.plugin*.jar signConfigType: inlineSignParams diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index ebb333f70..851b73775 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -71,10 +71,15 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/com.microsoft.java.debug.core*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: Sign core.jar inputs: - ConnectedServiceName: vscjavaci_esrp_codesign + ConnectedServiceName: $(ConnectedServiceName) + AppRegistrationClientId: $(AppRegistrationClientId) + AppRegistrationTenantId: $(AppRegistrationTenantId) + AuthAKVName: $(AuthAKVName) + AuthCertName: $(AuthCertName) + AuthSignCertName: $(AuthSignCertName) FolderPath: jars Pattern: com.microsoft.java.debug.core*.jar signConfigType: inlineSignParams @@ -111,10 +116,15 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/com.microsoft.java.debug.plugin*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: Sign plugin.jar inputs: - ConnectedServiceName: vscjavaci_esrp_codesign + ConnectedServiceName: $(ConnectedServiceName) + AppRegistrationClientId: $(AppRegistrationClientId) + AppRegistrationTenantId: $(AppRegistrationTenantId) + AuthAKVName: $(AuthAKVName) + AuthCertName: $(AuthCertName) + AuthSignCertName: $(AuthSignCertName) FolderPath: jars Pattern: com.microsoft.java.debug.plugin*.jar signConfigType: inlineSignParams @@ -152,10 +162,15 @@ extends: mkdir -p p2/target cp -r com.microsoft.java.debug.repository/target/repository p2/target/ cp com.microsoft.java.debug.repository/pushToBintray.sh p2/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: Sign p2 inputs: - ConnectedServiceName: vscjavaci_esrp_codesign + ConnectedServiceName: $(ConnectedServiceName) + AppRegistrationClientId: $(AppRegistrationClientId) + AppRegistrationTenantId: $(AppRegistrationTenantId) + AuthAKVName: $(AuthAKVName) + AuthCertName: $(AuthCertName) + AuthSignCertName: $(AuthSignCertName) FolderPath: p2 Pattern: "*.jar" signConfigType: inlineSignParams @@ -199,10 +214,15 @@ extends: mkdir -p m2/com.microsoft.java.debug.plugin cp com.microsoft.java.debug.plugin/target/com.microsoft.java.debug.plugin*.jar m2/com.microsoft.java.debug.plugin cp com.microsoft.java.debug.plugin/pom.xml m2/com.microsoft.java.debug.plugin/com.microsoft.java.debug.plugin-$RELEASE_VERSION.pom - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2 + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: Sign m2 inputs: - ConnectedServiceName: vscjavaci_esrp_codesign + ConnectedServiceName: $(ConnectedServiceName) + AppRegistrationClientId: $(AppRegistrationClientId) + AppRegistrationTenantId: $(AppRegistrationTenantId) + AuthAKVName: $(AuthAKVName) + AuthCertName: $(AuthCertName) + AuthSignCertName: $(AuthSignCertName) FolderPath: m2 Pattern: "*.jar" signConfigType: inlineSignParams From 26daf612fb03f8dd7befaa980feb327644ee43a7 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 22 Jul 2024 10:07:30 +0800 Subject: [PATCH 61/94] Remove the obselete parameter '-Djava.compiler=NONE' from launching command (#564) --- .../java/debug/plugin/internal/AdvancedLaunchingConnector.java | 1 - 1 file changed, 1 deletion(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java index 087f0fae7..24c65785d 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java @@ -195,7 +195,6 @@ private static String[] constructLaunchCommand(Map l StringBuilder execString = new StringBuilder(); execString.append("\"" + javaHome + slash + "bin" + slash + javaExec + "\""); - execString.append(" -Djava.compiler=NONE"); execString.append(" -Xrunjdwp:transport=dt_socket,address=" + address + ",server=n,suspend=" + (suspend ? "y" : "n")); if (javaOptions != null) { execString.append(" " + javaOptions); From 3691f3b5f2cae05b06b43333dc435c172e27f1a8 Mon Sep 17 00:00:00 2001 From: bsolar17 Date: Thu, 8 Aug 2024 03:49:58 +0200 Subject: [PATCH 62/94] Update lsp4j dependency to version 0.23.1 (#565) New version of jdtls core requires lsp4j 0.23 or greater. --- .../com.microsoft.java.debug.tp.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 6edb44dec..41215e0ba 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -36,7 +36,7 @@ - + From e54f5c20c9cac846eab9f4af0f4fef671727b919 Mon Sep 17 00:00:00 2001 From: Vincentius Adrian Date: Wed, 18 Sep 2024 14:36:52 +0700 Subject: [PATCH 63/94] Update eclipse to use v4.33 (#571) --- .../com.microsoft.java.debug.tp.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 41215e0ba..5c386e467 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -15,7 +15,7 @@ - + From d4afc7e55107b333c3a1126fbf42c18c0dfd69cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:32:24 +0800 Subject: [PATCH 64/94] Bump commons-io:commons-io in /com.microsoft.java.debug.core (#573) Bumps commons-io:commons-io from 2.11.0 to 2.14.0. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- com.microsoft.java.debug.core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index bb1449401..d8dae21e7 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -62,7 +62,7 @@ commons-io commons-io - 2.11.0 + 2.14.0 From 5c7562ade22977b15f76f46d13c098e82cc58ced Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 31 Oct 2024 14:38:24 +0800 Subject: [PATCH 65/94] bump version to 0.53.1 (#574) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index d8dae21e7..64827ab13 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.53.0 + 0.53.1 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index dc81da8e6..dbf84ced8 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 192908dcf..ea6b7127e 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.53.0 +Bundle-Version: 0.53.1 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.11.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.53.0.jar + lib/com.microsoft.java.debug.core-0.53.1.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index 93323db5c..dde9c7ec6 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.53.0 + 0.53.1 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.53.0 + 0.53.1 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index b09605569..5d3e664df 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index edb1c9891..40519fce2 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.53.0 + 0.53.1 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 2dc407f6c..737decee1 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.53.0 + 0.53.1 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index c277e8a98..53aec5c9c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.53.0 + 0.53.1 pom Java Debug Server for Visual Studio Code From 4cb23d2493aae8f17618764591fb37d71a178d0f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 27 Feb 2025 18:49:15 -0800 Subject: [PATCH 66/94] Update CI to run against jdk 21 (#581) --- .azure-pipelines/signjars-nightly.yml | 4 ++-- .azure-pipelines/signjars-rc.yml | 4 ++-- .github/workflows/build.yml | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index 2c0373aab..8f405a725 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -46,9 +46,9 @@ extends: - checkout: self fetchTags: true - task: JavaToolInstaller@0 - displayName: Use Java 17 + displayName: Use Java 21 inputs: - versionSpec: "17" + versionSpec: "21" jdkArchitectureOption: x64 jdkSourceOption: PreInstalled - task: CmdLine@2 diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index 851b73775..c0c11e6cc 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -45,9 +45,9 @@ extends: - checkout: self fetchTags: true - task: JavaToolInstaller@0 - displayName: Use Java 17 + displayName: Use Java 21 inputs: - versionSpec: "17" + versionSpec: "21" jdkArchitectureOption: x64 jdkSourceOption: PreInstalled - task: CmdLine@2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1ace44224..c147c4838 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,10 +14,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: '17' + java-version: '21' - name: Cache local Maven repository uses: actions/cache@v2 @@ -45,10 +45,10 @@ jobs: - uses: actions/checkout@v2 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: '17' + java-version: '21' - name: Cache local Maven repository uses: actions/cache@v2 @@ -71,10 +71,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v1 with: - java-version: '17' + java-version: '21' - name: Cache local Maven repository uses: actions/cache@v2 From dff3538d4f741e7e05a304614e3d5d9e7e0bfb0b Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 28 Feb 2025 07:13:49 +0000 Subject: [PATCH 67/94] Attempt to terminate the process normally (#579) Fixes https://github.com/microsoft/vscode-java-debug/issues/1274 --- .../main/java/com/microsoft/java/debug/core/DebugSession.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java index fbad52fe2..38a234fa9 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java @@ -119,7 +119,9 @@ public void detach() { @Override public void terminate() { - if (vm.process() == null || vm.process().isAlive()) { + if (vm.process() != null && vm.process().isAlive()) { + vm.process().destroy(); + } else if (vm.process() == null || vm.process().isAlive()) { vm.exit(0); } } From 31b22551b27712d265694c7afbe21d0eabccd1d1 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 21 Mar 2025 16:31:31 +0800 Subject: [PATCH 68/94] Onboard pipelines to MicroBuild (#583) * Onboard pipelines to MicroBuild * onboard code sign to microbuild * remove p2 copy logic * remove p2 buildartifact dir * use MicroBuild to publish to maven * fix m2 sign path * upgrade to actions/cache@v4 --- .azure-pipelines/publish-to-maven.yml | 100 ++++++++++++++ .azure-pipelines/signjars-nightly.yml | 97 +++++-------- .azure-pipelines/signjars-rc.yml | 187 +++++++------------------- .github/workflows/build.yml | 6 +- 4 files changed, 183 insertions(+), 207 deletions(-) create mode 100644 .azure-pipelines/publish-to-maven.yml diff --git a/.azure-pipelines/publish-to-maven.yml b/.azure-pipelines/publish-to-maven.yml new file mode 100644 index 000000000..58dc58cf2 --- /dev/null +++ b/.azure-pipelines/publish-to-maven.yml @@ -0,0 +1,100 @@ +name: $(Date:yyyyMMdd).$(Rev:r) +resources: + repositories: + - repository: MicroBuildTemplate + type: git + name: 1ESPipelineTemplates/MicroBuildTemplate + ref: refs/tags/release +trigger: none +extends: + template: azure-pipelines/1ES.Official.Publish.yml@MicroBuildTemplate + parameters: + pool: + os: linux + name: 1ES_JavaTooling_Pool + image: 1ES_JavaTooling_Ubuntu-2004 + sdl: + sourceAnalysisPool: + name: 1ES_JavaTooling_Pool + image: 1ES_JavaTooling_Windows_2022 + os: windows + stages: + - stage: PublishToMaven + jobs: + - job: PublishToMaven + steps: + - task: DownloadBuildArtifacts@1 + displayName: 'Download Jar Artifacts' + inputs: + buildType: specific + project: 'a4d27ce2-a42d-4b71-8eef-78cee9a9728e' + pipeline: 16486 + downloadType: specific + extractTars: false + itemPattern: 'm2/**' + - script: | + echo "import public key" + echo $GPG_PUBLIC_B64 | base64 -d | gpg --import + + echo "import secret key" + echo $GPG_SECRET_B64 | base64 -d | gpg --batch --passphrase $GPGPASS --import + displayName: 'import GPG keys' + env: + GPG_PUBLIC_B64: $(GPG_PUBLIC_B64) + GPG_SECRET_B64: $(GPG_SECRET_B64) + GPGPASS: $(GPGPASS) + - task: NodeTool@0 + displayName: 'Use Node 20.x' + inputs: + versionSpec: 20.x + - script: | + cd $(System.ArtifactsDirectory)/m2 + pluginJarFile=$(basename -- java-debug-parent/*.pom) + + # remove .* from end + noExt=${pluginJarFile%.*} + + # remove *- from start + export releaseVersion=${noExt##*-} + echo $releaseVersion + + export artifactFolder=$(pwd .) + wget https://raw.githubusercontent.com/microsoft/java-debug/master/scripts/publishMaven.js + + export GPG_TTY=$(tty) + node publishMaven.js -task gpg + displayName: 'sign artifacts' + env: + GPG_PUBLIC_B64: $(GPG_PUBLIC_B64) + GPG_SECRET_B64: $(GPG_SECRET_B64) + GPGPASS: $(GPGPASS) + NEXUS_OSSRHPASS: $(NEXUS_OSSRHPASS) + NEXUS_OSSRHUSER: $(NEXUS_OSSRHUSER) + NEXUS_STAGINGPROFILEID: $(NEXUS_STAGINGPROFILEID) + - template: MicroBuild.Publish.yml@MicroBuildTemplate + parameters: + intent: 'PackageDistribution' + contentType: 'Maven' + contentSource: 'Folder' + folderLocation: '$(System.ArtifactsDirectory)/m2/java-debug-parent' + waitForReleaseCompletion: true + owners: 'jinbwan@microsoft.com' + approvers: 'roml@microsoft.com' + - template: MicroBuild.Publish.yml@MicroBuildTemplate + parameters: + intent: 'PackageDistribution' + contentType: 'Maven' + contentSource: 'Folder' + folderLocation: '$(System.ArtifactsDirectory)/m2/com.microsoft.java.debug.core' + waitForReleaseCompletion: true + owners: 'jinbwan@microsoft.com' + approvers: 'roml@microsoft.com' + - template: MicroBuild.Publish.yml@MicroBuildTemplate + parameters: + intent: 'PackageDistribution' + contentType: 'Maven' + contentSource: 'Folder' + folderLocation: '$(System.ArtifactsDirectory)/m2/com.microsoft.java.debug.plugin' + waitForReleaseCompletion: true + owners: 'jinbwan@microsoft.com' + approvers: 'roml@microsoft.com' \ No newline at end of file diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index 8f405a725..19ab29baf 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -45,6 +45,23 @@ extends: steps: - checkout: self fetchTags: true + - task: UsePythonVersion@0 + displayName: 'Use Python 3.11.x' + inputs: + versionSpec: 3.11.x + - task: UseDotNet@2 + displayName: 'Use .NET Core 3.1.x' + inputs: + packageType: 'sdk' + version: '3.1.x' + - task: MicroBuildSigningPlugin@4 + displayName: 'Install Signing Plugin' + inputs: + signType: real + azureSubscription: 'MicroBuild Signing Task (MSEng)' + feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: JavaToolInstaller@0 displayName: Use Java 21 inputs: @@ -70,38 +87,16 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/com.microsoft.java.debug.core*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 - displayName: Sign core.jar + - task: CmdLine@2 + displayName: Sign core jars inputs: - ConnectedServiceName: $(ConnectedServiceName) - AppRegistrationClientId: $(AppRegistrationClientId) - AppRegistrationTenantId: $(AppRegistrationTenantId) - AuthAKVName: $(AuthAKVName) - AuthCertName: $(AuthCertName) - AuthSignCertName: $(AuthSignCertName) - FolderPath: jars - Pattern: com.microsoft.java.debug.core*.jar - signConfigType: inlineSignParams - inlineOperation: |- - [ - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaSign", - "Parameters" : { - "SigAlg" : "SHA256withRSA", - "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" - }, - "ToolName" : "sign", - "ToolVersion" : "1.0" - }, - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaVerify", - "Parameters" : {}, - "ToolName" : "sign", - "ToolVersion" : "1.0" - } - ] + script: | + files=$(find . -type f -name "com.microsoft.java.debug.core*.jar") + for file in $files; do + fileName=$(basename "$file") + dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 + done + workingDirectory: 'jars' - task: CmdLine@2 displayName: install signed core.jar inputs: @@ -116,38 +111,16 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/com.microsoft.java.debug.plugin*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 - displayName: Sign plugin.jar + - task: CmdLine@2 + displayName: Sign plugin jars inputs: - ConnectedServiceName: $(ConnectedServiceName) - AppRegistrationClientId: $(AppRegistrationClientId) - AppRegistrationTenantId: $(AppRegistrationTenantId) - AuthAKVName: $(AuthAKVName) - AuthCertName: $(AuthCertName) - AuthSignCertName: $(AuthSignCertName) - FolderPath: jars - Pattern: com.microsoft.java.debug.plugin*.jar - signConfigType: inlineSignParams - inlineOperation: |- - [ - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaSign", - "Parameters" : { - "SigAlg" : "SHA256withRSA", - "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" - }, - "ToolName" : "sign", - "ToolVersion" : "1.0" - }, - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaVerify", - "Parameters" : {}, - "ToolName" : "sign", - "ToolVersion" : "1.0" - } - ] + script: | + files=$(find . -type f -name "com.microsoft.java.debug.plugin*.jar") + for file in $files; do + fileName=$(basename "$file") + dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 + done + workingDirectory: 'jars' - task: CopyFiles@2 displayName: "Copy plugin.jar to: $(Build.ArtifactStagingDirectory)" inputs: diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index c0c11e6cc..201ff20f8 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -37,13 +37,26 @@ extends: artifactName: m2 targetPath: $(Build.ArtifactStagingDirectory)/m2 displayName: "Publish Artifact: m2" - - output: pipelineArtifact - artifactName: p2 - targetPath: $(Build.ArtifactStagingDirectory)/p2 - displayName: "Publish Artifact: p2" steps: - checkout: self fetchTags: true + - task: UsePythonVersion@0 + displayName: 'Use Python 3.11.x' + inputs: + versionSpec: 3.11.x + - task: UseDotNet@2 + displayName: 'Use .NET Core 3.1.x' + inputs: + packageType: 'sdk' + version: '3.1.x' + - task: MicroBuildSigningPlugin@4 + displayName: 'Install Signing Plugin' + inputs: + signType: real + azureSubscription: 'MicroBuild Signing Task (MSEng)' + feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: JavaToolInstaller@0 displayName: Use Java 21 inputs: @@ -71,38 +84,16 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.core/$RELEASE_VERSION/com.microsoft.java.debug.core*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 - displayName: Sign core.jar + - task: CmdLine@2 + displayName: Sign core jars inputs: - ConnectedServiceName: $(ConnectedServiceName) - AppRegistrationClientId: $(AppRegistrationClientId) - AppRegistrationTenantId: $(AppRegistrationTenantId) - AuthAKVName: $(AuthAKVName) - AuthCertName: $(AuthCertName) - AuthSignCertName: $(AuthSignCertName) - FolderPath: jars - Pattern: com.microsoft.java.debug.core*.jar - signConfigType: inlineSignParams - inlineOperation: |- - [ - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaSign", - "Parameters" : { - "SigAlg" : "SHA256withRSA", - "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" - }, - "ToolName" : "sign", - "ToolVersion" : "1.0" - }, - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaVerify", - "Parameters" : {}, - "ToolName" : "sign", - "ToolVersion" : "1.0" - } - ] + script: | + files=$(find . -type f -name "com.microsoft.java.debug.core*.jar") + for file in $files; do + fileName=$(basename "$file") + dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 + done + workingDirectory: 'jars' - task: CmdLine@2 displayName: install signed core.jar inputs: @@ -116,84 +107,20 @@ extends: mkdir -p jars mv .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/com.microsoft.java.debug.plugin*.jar jars/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 - displayName: Sign plugin.jar + - task: CmdLine@2 + displayName: Sign plugin jars inputs: - ConnectedServiceName: $(ConnectedServiceName) - AppRegistrationClientId: $(AppRegistrationClientId) - AppRegistrationTenantId: $(AppRegistrationTenantId) - AuthAKVName: $(AuthAKVName) - AuthCertName: $(AuthCertName) - AuthSignCertName: $(AuthSignCertName) - FolderPath: jars - Pattern: com.microsoft.java.debug.plugin*.jar - signConfigType: inlineSignParams - inlineOperation: |- - [ - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaSign", - "Parameters" : { - "SigAlg" : "SHA256withRSA", - "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" - }, - "ToolName" : "sign", - "ToolVersion" : "1.0" - }, - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaVerify", - "Parameters" : {}, - "ToolName" : "sign", - "ToolVersion" : "1.0" - } - ] + script: | + files=$(find . -type f -name "com.microsoft.java.debug.plugin*.jar") + for file in $files; do + fileName=$(basename "$file") + dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 + done + workingDirectory: 'jars' - task: CmdLine@2 displayName: install signed plugin.jar inputs: script: cp jars/com.microsoft.java.debug.plugin*.jar .repository/com/microsoft/java/com.microsoft.java.debug.plugin/$RELEASE_VERSION/ - - task: CmdLine@2 - displayName: Build p2 artifacts - inputs: - script: |- - # 3. Build the p2 artifacts. - ./mvnw clean package -f com.microsoft.java.debug.repository/pom.xml -Dmaven.repo.local=./.repository - - mkdir -p p2/target - cp -r com.microsoft.java.debug.repository/target/repository p2/target/ - cp com.microsoft.java.debug.repository/pushToBintray.sh p2/ - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 - displayName: Sign p2 - inputs: - ConnectedServiceName: $(ConnectedServiceName) - AppRegistrationClientId: $(AppRegistrationClientId) - AppRegistrationTenantId: $(AppRegistrationTenantId) - AuthAKVName: $(AuthAKVName) - AuthCertName: $(AuthCertName) - AuthSignCertName: $(AuthSignCertName) - FolderPath: p2 - Pattern: "*.jar" - signConfigType: inlineSignParams - inlineOperation: |- - [ - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaSign", - "Parameters" : { - "SigAlg" : "SHA256withRSA", - "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" - }, - "ToolName" : "sign", - "ToolVersion" : "1.0" - }, - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaVerify", - "Parameters" : {}, - "ToolName" : "sign", - "ToolVersion" : "1.0" - } - ] - task: CmdLine@2 displayName: build m2 artifacts inputs: @@ -214,43 +141,19 @@ extends: mkdir -p m2/com.microsoft.java.debug.plugin cp com.microsoft.java.debug.plugin/target/com.microsoft.java.debug.plugin*.jar m2/com.microsoft.java.debug.plugin cp com.microsoft.java.debug.plugin/pom.xml m2/com.microsoft.java.debug.plugin/com.microsoft.java.debug.plugin-$RELEASE_VERSION.pom - - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 - displayName: Sign m2 + - task: CmdLine@2 + displayName: Sign m2 jars inputs: - ConnectedServiceName: $(ConnectedServiceName) - AppRegistrationClientId: $(AppRegistrationClientId) - AppRegistrationTenantId: $(AppRegistrationTenantId) - AuthAKVName: $(AuthAKVName) - AuthCertName: $(AuthCertName) - AuthSignCertName: $(AuthSignCertName) - FolderPath: m2 - Pattern: "*.jar" - signConfigType: inlineSignParams - inlineOperation: |- - [ - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaSign", - "Parameters" : { - "SigAlg" : "SHA256withRSA", - "Timestamp" : "-tsa http://sha256timestamp.ws.digicert.com/sha256/timestamp" - }, - "ToolName" : "sign", - "ToolVersion" : "1.0" - }, - { - "KeyCode" : "CP-447347-Java", - "OperationCode" : "JavaVerify", - "Parameters" : {}, - "ToolName" : "sign", - "ToolVersion" : "1.0" - } - ] + script: | + files=$(find . -type f -name "*.jar") + for file in $files; do + # fileName=$(basename "$file") + dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$file" /certs:100010171 + done + workingDirectory: 'm2' - task: CopyFiles@2 - displayName: "Copy p2/m2 to: $(Build.ArtifactStagingDirectory)" + displayName: "Copy m2 to: $(Build.ArtifactStagingDirectory)" inputs: Contents: |+ - p2/** m2/** - TargetFolder: $(Build.ArtifactStagingDirectory) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c147c4838..71d726f63 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: java-version: '21' - name: Cache local Maven repository - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -51,7 +51,7 @@ jobs: java-version: '21' - name: Cache local Maven repository - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: $HOME/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -77,7 +77,7 @@ jobs: java-version: '21' - name: Cache local Maven repository - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} From b98d4936c52ea933b00faacfac67fd4fcb86e790 Mon Sep 17 00:00:00 2001 From: Roland Grunberg Date: Thu, 17 Apr 2025 03:47:29 -0400 Subject: [PATCH 69/94] Update target platform to more closely follow JDT-LS. (#585) - Update Apache Commons IO from 2.11.0 to 2.19.0 Signed-off-by: Roland Grunberg --- com.microsoft.java.debug.plugin/.classpath | 2 +- .../META-INF/MANIFEST.MF | 2 +- com.microsoft.java.debug.plugin/pom.xml | 2 +- .../com.microsoft.java.debug.tp.target | 42 ++++--------------- 4 files changed, 11 insertions(+), 37 deletions(-) diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index dbf84ced8..a83e822fe 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -7,7 +7,7 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index ea6b7127e..073c31c8e 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -21,7 +21,7 @@ Require-Bundle: org.eclipse.core.runtime, org.apache.commons.lang3, org.eclipse.lsp4j, com.google.guava -Bundle-ClassPath: lib/commons-io-2.11.0.jar, +Bundle-ClassPath: lib/commons-io-2.19.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index dde9c7ec6..d2d7b9aa4 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -51,7 +51,7 @@ commons-io commons-io - 2.11.0 + 2.19.0 com.microsoft.java diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 5c386e467..8a85443a4 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -1,43 +1,17 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - + + + + + + From b77b590ad89345557c87c975a4b41c5f648e65f1 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 23 Apr 2025 13:39:54 +0800 Subject: [PATCH 70/94] Override MicroBuild Output Folder (#586) * Override MicroBuild Output Folder * Use env to override MicroBuildOutputFolder --- .azure-pipelines/signjars-nightly.yml | 1 + .azure-pipelines/signjars-rc.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index 19ab29baf..b2ab77ab7 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -62,6 +62,7 @@ extends: feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) + MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' - task: JavaToolInstaller@0 displayName: Use Java 21 inputs: diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index 201ff20f8..8e639bafb 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -57,6 +57,7 @@ extends: feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) + MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' - task: JavaToolInstaller@0 displayName: Use Java 21 inputs: From 54058b9eb466576a7a77c9303963ca88967ec58b Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Sun, 27 Apr 2025 10:50:06 +0800 Subject: [PATCH 71/94] Bump version to 0.53.2 (#587) --- com.microsoft.java.debug.core/pom.xml | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF | 4 ++-- com.microsoft.java.debug.plugin/pom.xml | 4 ++-- com.microsoft.java.debug.repository/category.xml | 2 +- com.microsoft.java.debug.repository/pom.xml | 2 +- com.microsoft.java.debug.target/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index 64827ab13..d63b93c01 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.53.1 + 0.53.2 com.microsoft.java.debug.core jar diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index a83e822fe..de9b5e366 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -11,6 +11,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 073c31c8e..442e9bb17 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true -Bundle-Version: 0.53.1 +Bundle-Version: 0.53.2 Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin @@ -25,4 +25,4 @@ Bundle-ClassPath: lib/commons-io-2.19.0.jar, ., lib/rxjava-2.2.21.jar, lib/reactive-streams-1.0.4.jar, - lib/com.microsoft.java.debug.core-0.53.1.jar + lib/com.microsoft.java.debug.core-0.53.2.jar diff --git a/com.microsoft.java.debug.plugin/pom.xml b/com.microsoft.java.debug.plugin/pom.xml index d2d7b9aa4..2e2c0e6a8 100644 --- a/com.microsoft.java.debug.plugin/pom.xml +++ b/com.microsoft.java.debug.plugin/pom.xml @@ -5,7 +5,7 @@ com.microsoft.java java-debug-parent - 0.53.1 + 0.53.2 com.microsoft.java.debug.plugin eclipse-plugin @@ -56,7 +56,7 @@ com.microsoft.java com.microsoft.java.debug.core - 0.53.1 + 0.53.2 diff --git a/com.microsoft.java.debug.repository/category.xml b/com.microsoft.java.debug.repository/category.xml index 5d3e664df..f30a2f4c4 100644 --- a/com.microsoft.java.debug.repository/category.xml +++ b/com.microsoft.java.debug.repository/category.xml @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.repository/pom.xml b/com.microsoft.java.debug.repository/pom.xml index 40519fce2..573aff2ac 100644 --- a/com.microsoft.java.debug.repository/pom.xml +++ b/com.microsoft.java.debug.repository/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.53.1 + 0.53.2 com.microsoft.java.debug.repository eclipse-repository diff --git a/com.microsoft.java.debug.target/pom.xml b/com.microsoft.java.debug.target/pom.xml index 737decee1..8e49b638b 100644 --- a/com.microsoft.java.debug.target/pom.xml +++ b/com.microsoft.java.debug.target/pom.xml @@ -4,7 +4,7 @@ com.microsoft.java java-debug-parent - 0.53.1 + 0.53.2 com.microsoft.java.debug.tp ${base.name} :: Target Platform diff --git a/pom.xml b/pom.xml index 53aec5c9c..9f59485d9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ${base.name} :: Parent The Java Debug Server is an implementation of Visual Studio Code (VSCode) Debug Protocol. It can be used in Visual Studio Code to debug Java programs. https://github.com/Microsoft/java-debug - 0.53.1 + 0.53.2 pom Java Debug Server for Visual Studio Code From bccb4808571f2fcdce497e5585320ff62491c9f5 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 26 Jun 2025 09:54:18 +0800 Subject: [PATCH 72/94] switch sha256 to calculate temp file name (#592) --- .../debug/core/adapter/handler/LaunchUtils.java | 15 +++++++++------ .../com.microsoft.java.debug.tp.target | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java index 27fdb1813..7370328b2 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchUtils.java @@ -95,7 +95,7 @@ public static synchronized Path generateClasspathJar(String[] classPaths) throws // In jar manifest, the absolute path C:\a.jar should be converted to the url style file:///C:/a.jar String classpathValue = String.join(" ", classpathUrls); attributes.put(Attributes.Name.CLASS_PATH, classpathValue); - String baseName = "cp_" + getMd5(classpathValue); + String baseName = "cp_" + getSha256(classpathValue); cleanupTempFiles(baseName, ".jar"); Path tempfile = createTempFile(baseName, ".jar"); JarOutputStream jar = new JarOutputStream(new FileOutputStream(tempfile.toFile()), manifest); @@ -127,7 +127,7 @@ public static synchronized Path generateArgfile(String vmArgs, String[] classPat } argfile = argfile.replace("\\", "\\\\"); - String baseName = "cp_" + getMd5(argfile); + String baseName = "cp_" + getSha256(argfile); cleanupTempFiles(baseName, ".argfile"); Path tempfile = createTempFile(baseName, ".argfile"); Files.writeString(tempfile, argfile, encoding); @@ -364,12 +364,15 @@ private static Path createTempFile(String baseName, String suffix) throws IOExce } } - private static String getMd5(String input) { + private static String getSha256(String input) { try { - MessageDigest md = MessageDigest.getInstance("MD5"); + MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] messageDigest = md.digest(input.getBytes()); - BigInteger md5 = new BigInteger(1, messageDigest); - return md5.toString(Character.MAX_RADIX); + // Use only first 16 bytes to keep filename shorter + byte[] truncated = new byte[16]; + System.arraycopy(messageDigest, 0, truncated, 0, 16); + BigInteger hash = new BigInteger(1, truncated); + return hash.toString(Character.MAX_RADIX); } catch (NoSuchAlgorithmException e) { return Integer.toString(input.hashCode(), Character.MAX_RADIX); } diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 8a85443a4..1d322d84c 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -2,7 +2,7 @@ - + From a1f68f4265458e9386bf16d107c2383b68690e43 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 27 Jun 2025 15:01:25 +0800 Subject: [PATCH 73/94] Update codesign task (#593) --- .azure-pipelines/signjars-nightly.yml | 10 ++++++---- .azure-pipelines/signjars-rc.yml | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index b2ab77ab7..2045f54ce 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -45,20 +45,22 @@ extends: steps: - checkout: self fetchTags: true - - task: UsePythonVersion@0 - displayName: 'Use Python 3.11.x' - inputs: - versionSpec: 3.11.x - task: UseDotNet@2 displayName: 'Use .NET Core 3.1.x' inputs: packageType: 'sdk' version: '3.1.x' + - task: UseDotNet@2 + displayName: 'Use .NET Core 8.0.x' + inputs: + packageType: 'sdk' + version: '8.0.x' - task: MicroBuildSigningPlugin@4 displayName: 'Install Signing Plugin' inputs: signType: real azureSubscription: 'MicroBuild Signing Task (MSEng)' + useEsrpCli: true feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index 8e639bafb..cd3377cfd 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -40,20 +40,22 @@ extends: steps: - checkout: self fetchTags: true - - task: UsePythonVersion@0 - displayName: 'Use Python 3.11.x' - inputs: - versionSpec: 3.11.x - task: UseDotNet@2 displayName: 'Use .NET Core 3.1.x' inputs: packageType: 'sdk' version: '3.1.x' + - task: UseDotNet@2 + displayName: 'Use .NET Core 8.0.x' + inputs: + packageType: 'sdk' + version: '8.0.x' - task: MicroBuildSigningPlugin@4 displayName: 'Install Signing Plugin' inputs: signType: real azureSubscription: 'MicroBuild Signing Task (MSEng)' + useEsrpCli: true feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) From 36a6b3f3606bd500fd7b257c55ae2572893d319e Mon Sep 17 00:00:00 2001 From: chagong Date: Wed, 13 Aug 2025 14:35:29 +0800 Subject: [PATCH 74/94] Update CODEOWNERS (#599) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b11684f52..9d7579633 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @testforstephen @jdneo \ No newline at end of file +* @testforstephen @jdneo @chagong @wenytang-ms From c7642bc738b2dbfeefa0ea85e338d9eefd0ebc25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 15:09:45 +0800 Subject: [PATCH 75/94] Bump org.apache.commons:commons-lang3 in /com.microsoft.java.debug.core (#594) Bumps org.apache.commons:commons-lang3 from 3.6 to 3.18.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-version: 3.18.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: chagong --- com.microsoft.java.debug.core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml index d63b93c01..8bfdb7292 100644 --- a/com.microsoft.java.debug.core/pom.xml +++ b/com.microsoft.java.debug.core/pom.xml @@ -42,7 +42,7 @@ org.apache.commons commons-lang3 - 3.6 + 3.18.0 com.google.code.gson From a209e39b9e07e5b2eacb74a2a2250da99c6751e3 Mon Sep 17 00:00:00 2001 From: Snjeza Date: Wed, 13 Aug 2025 09:18:31 +0200 Subject: [PATCH 76/94] Improve ResolveMainClassHandler.resolveMainClassUnderPaths (#596) Co-authored-by: wenyt <75360946+wenytang-ms@users.noreply.github.com> --- .../plugin/internal/ResolveMainClassHandler.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java index 38ad1532b..fc8189445 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java @@ -35,6 +35,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; @@ -100,8 +101,18 @@ private List resolveMainClassCore(List arguments) { private List resolveMainClassUnderPaths(List parentPaths) { // Limit to search main method from source code only. - IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(ProjectUtils.getJavaProjects(), - IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.SOURCES); + IJavaProject[] projects; + if (parentPaths == null || parentPaths.isEmpty()) { + projects = ProjectUtils.getJavaProjects(); + } else { + projects = Stream.of(ProjectUtils.getAllProjects()) + .filter(p -> ProjectUtils.isJavaProject(p) && p.getLocation() != null && ResourceUtils.isContainedIn(p.getLocation(), parentPaths)) + .map(p -> JavaCore.create(p)) + .filter(p -> p.exists()) + .toArray(IJavaProject[]::new); + } + IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(projects, + IJavaSearchScope.SOURCES); SearchPattern pattern = createMainMethodSearchPattern(); final List res = new ArrayList<>(); SearchRequestor requestor = new SearchRequestor() { From 65dcd3d77c548bd842a74e472c8b25cd8489905a Mon Sep 17 00:00:00 2001 From: wenyt <75360946+wenytang-ms@users.noreply.github.com> Date: Thu, 21 Aug 2025 10:24:44 +0800 Subject: [PATCH 77/94] ci: update the pipeline to do publish (#602) --- .azure-pipelines/publish-to-maven.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.azure-pipelines/publish-to-maven.yml b/.azure-pipelines/publish-to-maven.yml index 58dc58cf2..a1ef0a204 100644 --- a/.azure-pipelines/publish-to-maven.yml +++ b/.azure-pipelines/publish-to-maven.yml @@ -22,6 +22,10 @@ extends: - stage: PublishToMaven jobs: - job: PublishToMaven + displayName: Maven Release job + templateContext: + type: releaseJob + isProduction: true steps: - task: DownloadBuildArtifacts@1 displayName: 'Download Jar Artifacts' From 3bec8be6525ff8ced06d57157c847870adc2bc49 Mon Sep 17 00:00:00 2001 From: wenyt <75360946+wenytang-ms@users.noreply.github.com> Date: Mon, 25 Aug 2025 11:27:00 +0800 Subject: [PATCH 78/94] ci: support PME to do code sign (#603) --- .azure-pipelines/signjars-nightly.yml | 1 + .azure-pipelines/signjars-rc.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index 2045f54ce..70fe81be2 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -61,6 +61,7 @@ extends: signType: real azureSubscription: 'MicroBuild Signing Task (MSEng)' useEsrpCli: true + ConnectedPMEServiceName: 0e38ce24-f885-4c86-b997-5887b97a1899 feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index cd3377cfd..819d39de7 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -56,6 +56,7 @@ extends: signType: real azureSubscription: 'MicroBuild Signing Task (MSEng)' useEsrpCli: true + ConnectedPMEServiceName: 0e38ce24-f885-4c86-b997-5887b97a1899 feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' env: SYSTEM_ACCESSTOKEN: $(System.AccessToken) From 77d10aa0e8030da7570bdde8400f2d0fb3aa9e7d Mon Sep 17 00:00:00 2001 From: wenyt <75360946+wenytang-ms@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:16:24 +0800 Subject: [PATCH 79/94] ci: sign jar with access token (#604) --- .azure-pipelines/signjars-nightly.yml | 4 ++++ .azure-pipelines/signjars-rc.yml | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml index 70fe81be2..8b1e8d12a 100644 --- a/.azure-pipelines/signjars-nightly.yml +++ b/.azure-pipelines/signjars-nightly.yml @@ -101,6 +101,8 @@ extends: dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 done workingDirectory: 'jars' + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: CmdLine@2 displayName: install signed core.jar inputs: @@ -125,6 +127,8 @@ extends: dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 done workingDirectory: 'jars' + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: CopyFiles@2 displayName: "Copy plugin.jar to: $(Build.ArtifactStagingDirectory)" inputs: diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml index 819d39de7..e87444603 100644 --- a/.azure-pipelines/signjars-rc.yml +++ b/.azure-pipelines/signjars-rc.yml @@ -98,6 +98,8 @@ extends: dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 done workingDirectory: 'jars' + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: CmdLine@2 displayName: install signed core.jar inputs: @@ -121,6 +123,8 @@ extends: dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171 done workingDirectory: 'jars' + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: CmdLine@2 displayName: install signed plugin.jar inputs: @@ -155,6 +159,8 @@ extends: dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$file" /certs:100010171 done workingDirectory: 'm2' + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: CopyFiles@2 displayName: "Copy m2 to: $(Build.ArtifactStagingDirectory)" inputs: From 614b10df99acc34ced35fc50b9b70a8191719e2c Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:30:26 +0800 Subject: [PATCH 80/94] Add AI triage workflow and LLM documentation for automated issue management (#606) * Initial plan * Add triage agent workflow and LLM documentation from vscode-gradle Co-authored-by: chagong <831821+chagong@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: chagong <831821+chagong@users.noreply.github.com> --- .github/llms.md | 38 +++++++++ .github/workflows/triage-agent.yml | 122 +++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 .github/llms.md create mode 100644 .github/workflows/triage-agent.yml diff --git a/.github/llms.md b/.github/llms.md new file mode 100644 index 000000000..55d69b238 --- /dev/null +++ b/.github/llms.md @@ -0,0 +1,38 @@ +# Extension Pack for Java +Extension Pack for Java is a collection of popular extensions that can help write, test and debug Java applications in Visual Studio Code. By installing Extension Pack for Java, the following extensions are installed: + +- [📦 Language Support for Java™ by Red Hat ](https://marketplace.visualstudio.com/items?itemName=redhat.java) + - Code Navigation + - Auto Completion + - Refactoring + - Code Snippets +- [📦 Debugger for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-debug) + - Debugging +- [📦 Test Runner for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test) + - Run & Debug JUnit/TestNG Test Cases +- [📦 Maven for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-maven) + - Project Scaffolding + - Custom Goals +- [📦 Gradle for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-gradle) + - View Gradle tasks and project dependencies + - Gradle file authoring + - Import Gradle projects via [Gradle Build Server](https://github.com/microsoft/build-server-for-gradle) +- [📦 Project Manager for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-dependency) + - Manage Java projects, referenced libraries, resource files, packages, classes, and class members +- [📦 Visual Studio IntelliCode](https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode) + - AI-assisted development + - Completion list ranked by AI + +## Label +When labeling an issue, follow the rules below per label category: +### General Rules +- Analyze if the issue is related with the scope of using extensions for Java development. If not, STOP labelling IMMEDIATELY. +- Assign label per category. +- If a category is not applicable or you're unsure, you may skip it. +- Do not assign multiple labels within the same category, unless explicitly allowed as an exception. + +### Issue Type Labels +- [bug]: Primary label for real bug issues +- [enhancement]: Primary label for enhancement issues +- [documentation]: Primary label for documentation issues +- [question]: Primary label for question issues \ No newline at end of file diff --git a/.github/workflows/triage-agent.yml b/.github/workflows/triage-agent.yml new file mode 100644 index 000000000..185cf8f32 --- /dev/null +++ b/.github/workflows/triage-agent.yml @@ -0,0 +1,122 @@ +name: AI Triage - Label and Comment on New Issues +on: + issues: + types: [opened] + workflow_dispatch: + inputs: + issue_number: + description: 'Issue number to triage (manual run). e.g. 123' + required: true + +permissions: + issues: write + contents: read + +jobs: + label_and_comment: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Get issue data + id: get_issue + uses: actions/github-script@v6 + with: + script: | + const eventName = context.eventName; + let issue; + if (eventName === 'workflow_dispatch') { + const inputs = context.payload.inputs || {}; + const issueNumber = inputs.issue_number || inputs.issueNumber; + if (!issueNumber) core.setFailed('Input issue_number is required for manual run.'); + const { data } = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: parseInt(issueNumber, 10), + }); + issue = data; + } else if (context.payload.issue) { + issue = context.payload.issue; + } else { + core.setFailed('No issue information found in the event payload.'); + } + core.setOutput('id', String(issue.number)); + core.setOutput('user', String((issue.user && issue.user.login) || '')); + core.setOutput('title', String(issue.title || '')); + core.setOutput('body', String(issue.body || '')); + const labelNames = (issue.labels || []).map(label => label.name); + core.setOutput('labels', JSON.stringify(labelNames)); + + - name: Call Azure Function + id: call_azure_function + env: + PAYLOAD: >- + { + "authToken": "${{ secrets.GITHUB_TOKEN }}", + "repoId": "microsoft/java-debug", + "issueData": { + "id": ${{ steps.get_issue.outputs.id }}, + "user": ${{ toJson(steps.get_issue.outputs.user) }}, + "title": ${{ toJson(steps.get_issue.outputs.title) }}, + "body": ${{ toJson(steps.get_issue.outputs.body) }}, + "labels": ${{ steps.get_issue.outputs.labels }} + }, + "mode": "DirectUpdate" + } + + run: | + # Make the HTTP request with improved error handling and timeouts + echo "Making request to triage agent..." + + # Add timeout handling and better error detection + set +e # Don't exit on curl failure + response=$(timeout ${{ vars.TRIAGE_AGENT_TIMEOUT }} curl \ + --max-time 0 \ + --connect-timeout 30 \ + --fail-with-body \ + --silent \ + --show-error \ + --write-out "HTTPSTATUS:%{http_code}" \ + --header "Content-Type: application/json" \ + --request POST \ + --data "$PAYLOAD" \ + ${{ secrets.TRIAGE_FUNCTION_LINK }} 2>&1) + + curl_exit_code=$? + set -e # Re-enable exit on error + + echo "Curl exit code: $curl_exit_code" + + # Check if curl command timed out or failed + if [ $curl_exit_code -eq 124 ]; then + echo "❌ Request timed out after 650 seconds" + exit 1 + elif [ $curl_exit_code -ne 0 ]; then + echo "❌ Curl command failed with exit code: $curl_exit_code" + echo "Response: $response" + exit 1 + fi + + # Extract HTTP status code and response body + http_code=$(echo "$response" | grep -o "HTTPSTATUS:[0-9]*" | cut -d: -f2) + response_body=$(echo "$response" | sed 's/HTTPSTATUS:[0-9]*$//') + + echo "HTTP Status Code: $http_code" + + # Validate HTTP status code + if [ -z "$http_code" ]; then + echo "❌ Failed to extract HTTP status code from response" + echo "Raw response: $response" + exit 1 + fi + + # Check if the request was successful + if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then + echo "✅ Azure Function call succeeded" + else + echo "❌ Azure Function call failed with status code: $http_code" + echo "Response: $response_body" + exit 1 + fi \ No newline at end of file From ab5d534f5af932fc2fcb3f3c54be9777151b5c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Fu=C3=9Fenegger?= Date: Sat, 11 Oct 2025 04:33:46 +0200 Subject: [PATCH 81/94] Update target platform to 4.38 (#607) The 4.37 builds disappeared, breaking the build. --- .../com.microsoft.java.debug.tp.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index 1d322d84c..baf2807df 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -2,7 +2,7 @@ - + From 4c80493fa08dd31f4adc22722b8423ed148837ff Mon Sep 17 00:00:00 2001 From: Karl-Erik Enkelmann <110300169+playdohface@users.noreply.github.com> Date: Mon, 3 Nov 2025 09:24:35 +0100 Subject: [PATCH 82/94] Handle unavailable sources in compliance with DAP spec (#609) --- .../debug/core/adapter/handler/StackTraceRequestHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index 49f304771..3fa0a9a9b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -220,8 +220,10 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra } else { // For other unavailable method, such as lambda expression's built-in methods run/accept/apply, // display "Unknown Source" in the Call Stack View. - clientSource = null; + clientSource = new Types.Source("Unknown Source", "unknown", 0); } + // DAP specifies lineNumber to be set to 0 when unavailable + clientLineNumber = 0; } else if (DebugSettings.getCurrent().debugSupportOnDecompiledSource == Switch.ON && clientSource != null && clientSource.path != null) { // Align the original line with the decompiled line. From 6ff846580e33dd5f935d86da80674a4de15f1527 Mon Sep 17 00:00:00 2001 From: mozhuanzuojing <63572041+mozhuanzuojing@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:49:23 +0800 Subject: [PATCH 83/94] Update tycho-version 5.0.0 (#598) * Update tycho-version 4.0.13 upgrade tycho * bump JavaSE-11 to JavaSE-21 of eclipse config * Update maven-wrapper.properties bump maven wrapper 3.0.11 * Update pom.xml bump tycho 5.0.0 * mvn wrapper:wrapper -Dmaven=3.9.11 --------- Co-authored-by: Changyong Gong --- .mvn/wrapper/maven-wrapper.jar | Bin 47774 -> 0 bytes .mvn/wrapper/maven-wrapper.properties | 3 +- com.microsoft.java.debug.core/.classpath | 2 +- com.microsoft.java.debug.plugin/.classpath | 2 +- .../META-INF/MANIFEST.MF | 2 +- .../com.microsoft.java.debug.tp.target | 5 +- mvnw | 394 ++++++++++-------- mvnw.cmd | 332 ++++++++------- pom.xml | 2 +- 9 files changed, 430 insertions(+), 312 deletions(-) delete mode 100644 .mvn/wrapper/maven-wrapper.jar diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 41c70a7e0b7da7ecbbcf53b62aacdf8bc81e10b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47774 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 Be7*nx diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 9e0264d04..44f3cf2c1 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1,2 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip \ No newline at end of file +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip diff --git a/com.microsoft.java.debug.core/.classpath b/com.microsoft.java.debug.core/.classpath index 9ba41a249..b6fe6b96c 100644 --- a/com.microsoft.java.debug.core/.classpath +++ b/com.microsoft.java.debug.core/.classpath @@ -13,7 +13,7 @@ - + diff --git a/com.microsoft.java.debug.plugin/.classpath b/com.microsoft.java.debug.plugin/.classpath index de9b5e366..b2be945c8 100644 --- a/com.microsoft.java.debug.plugin/.classpath +++ b/com.microsoft.java.debug.plugin/.classpath @@ -1,6 +1,6 @@ - + diff --git a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF index 442e9bb17..f2ceffb53 100644 --- a/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF +++ b/com.microsoft.java.debug.plugin/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Java Debug Server Plugin Bundle-SymbolicName: com.microsoft.java.debug.plugin;singleton:=true Bundle-Version: 0.53.2 -Bundle-RequiredExecutionEnvironment: JavaSE-11 +Bundle-RequiredExecutionEnvironment: JavaSE-21 Bundle-ActivationPolicy: lazy Bundle-Activator: com.microsoft.java.debug.plugin.internal.JavaDebuggerServerPlugin Bundle-Vendor: Microsoft diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index baf2807df..deabb9f3e 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -1,4 +1,6 @@ - + + + @@ -14,4 +16,5 @@ + diff --git a/mvnw b/mvnw index e96ccd5fb..e9cf8d330 100755 --- a/mvnw +++ b/mvnw @@ -19,209 +19,277 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.3 # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac -fi +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 fi fi - ;; -esac + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" +} - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - saveddir=`pwd` +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac - M2_HOME=`dirname "$PRG"`/.. +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} - cd "$saveddir" - # echo Using m2 at $M2_HOME +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" fi -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" fi -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" fi -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true fi else - JAVACMD="`which java`" + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 fi fi -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" fi +fi - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi fi - # end of workaround done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; + set -f fi -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" fi -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 019bd74d7..3fd2be860 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,143 +1,189 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" - -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.3 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml index 9f59485d9..b8320ef8f 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ Java Debug Server for Visual Studio Code UTF-8 - 4.0.6 + 5.0.0 ${basedir} From dabcc49979f45e34216a83dd9fbd126852f6ec1f Mon Sep 17 00:00:00 2001 From: mozhuanzuojing <63572041+mozhuanzuojing@users.noreply.github.com> Date: Mon, 10 Nov 2025 10:14:04 +0800 Subject: [PATCH 84/94] Update build.yml add distribution: 'temurin' of `JDK` (#600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update build.yml add distribution: 'temurin' of `JDK` add distribution: 'temurin' of JavaSE-21 * upgrade actions v4 、v5 * format yml --------- Co-authored-by: Changyong Gong Co-authored-by: wenyt <75360946+wenytang-ms@users.noreply.github.com> --- .github/workflows/build.yml | 115 ++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 71d726f63..553d95a9a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,80 +12,83 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - - name: Set up JDK 21 - uses: actions/setup-java@v1 - with: - java-version: '21' + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' - - name: Cache local Maven repository - uses: actions/cache@v4 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- + - name: Cache local Maven repository + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - - name: Verify - run: ./mvnw clean verify -U + - name: Verify + run: ./mvnw clean verify -U - - name: Checkstyle - run: ./mvnw checkstyle:check + - name: Checkstyle + run: ./mvnw checkstyle:check windows: name: Windows runs-on: windows-latest timeout-minutes: 30 steps: - - name: Set git to use LF - run: | - git config --global core.autocrlf false - git config --global core.eol lf + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - - name: Set up JDK 21 - uses: actions/setup-java@v1 - with: - java-version: '21' + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' - - name: Cache local Maven repository - uses: actions/cache@v4 - with: - path: $HOME/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- + - name: Cache local Maven repository + uses: actions/cache@v4 + with: + path: $HOME/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - - name: Verify - run: ./mvnw.cmd clean verify + - name: Verify + run: ./mvnw.cmd clean verify - - name: Checkstyle - run: ./mvnw.cmd checkstyle:check + - name: Checkstyle + run: ./mvnw.cmd checkstyle:check darwin: name: macOS runs-on: macos-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v2 - - - name: Set up JDK 21 - uses: actions/setup-java@v1 - with: - java-version: '21' - - - name: Cache local Maven repository - uses: actions/cache@v4 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - - name: Verify - run: ./mvnw clean verify -U - - - name: Checkstyle - run: ./mvnw checkstyle:check + - uses: actions/checkout@v5 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'temurin' + + - name: Cache local Maven repository + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Verify + run: ./mvnw clean verify -U + + - name: Checkstyle + run: ./mvnw checkstyle:check From 905c7ba292bf52e7ed324a8fab80669b3806a6e5 Mon Sep 17 00:00:00 2001 From: Changyong Gong Date: Tue, 11 Nov 2025 13:46:33 +0800 Subject: [PATCH 85/94] chore: add triage open issues workflow (#613) --- .github/workflows/triage-agent.yml | 5 +- .github/workflows/triage-all-open-issues.yml | 145 +++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/triage-all-open-issues.yml diff --git a/.github/workflows/triage-agent.yml b/.github/workflows/triage-agent.yml index 185cf8f32..f1df6e117 100644 --- a/.github/workflows/triage-agent.yml +++ b/.github/workflows/triage-agent.yml @@ -1,4 +1,4 @@ -name: AI Triage - Label and Comment on New Issues +name: AI Triage on: issues: types: [opened] @@ -8,6 +8,9 @@ on: description: 'Issue number to triage (manual run). e.g. 123' required: true +run-name: >- + AI Triage for Issue #${{ github.event.issue.number || github.event.inputs.issue_number }} + permissions: issues: write contents: read diff --git a/.github/workflows/triage-all-open-issues.yml b/.github/workflows/triage-all-open-issues.yml new file mode 100644 index 000000000..092f4ef70 --- /dev/null +++ b/.github/workflows/triage-all-open-issues.yml @@ -0,0 +1,145 @@ +name: AI Triage - Process All Open Issues +on: + workflow_dispatch: + inputs: + dry_run: + description: 'Dry run mode - only list issues without processing' + required: false + default: false + type: boolean + max_issues: + description: 'Maximum number of issues to process (0 = all)' + required: false + default: '0' + type: string + +permissions: + issues: write + contents: read + actions: write + +jobs: + get_open_issues: + runs-on: ubuntu-latest + outputs: + issue_numbers: ${{ steps.get_issues.outputs.issue_numbers }} + total_count: ${{ steps.get_issues.outputs.total_count }} + + steps: + - name: Get all open issues + id: get_issues + uses: actions/github-script@v6 + with: + script: | + // Use Search API to filter issues at API level + const { data } = await github.rest.search.issuesAndPullRequests({ + q: `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open -label:ai-triaged -label:invalid`, + sort: 'created', + order: 'asc', + per_page: 100 + }); + + const actualIssues = data.items; + + let issuesToProcess = actualIssues; + const maxIssues = parseInt('${{ inputs.max_issues }}' || '0'); + + if (maxIssues > 0 && actualIssues.length > maxIssues) { + issuesToProcess = actualIssues.slice(0, maxIssues); + console.log(`Limiting to first ${maxIssues} issues out of ${actualIssues.length} total`); + } + + const issueNumbers = issuesToProcess.map(issue => issue.number); + const totalCount = issuesToProcess.length; + + console.log(`Found ${actualIssues.length} open issues, processing ${totalCount}:`); + issuesToProcess.forEach(issue => { + console.log(` #${issue.number}: ${issue.title}`); + }); + + core.setOutput('issue_numbers', JSON.stringify(issueNumbers)); + core.setOutput('total_count', totalCount); + + process_issues: + runs-on: ubuntu-latest + needs: get_open_issues + if: needs.get_open_issues.outputs.total_count > 0 + + strategy: + # Process issues one by one (max-parallel: 1) + max-parallel: 1 + matrix: + issue_number: ${{ fromJSON(needs.get_open_issues.outputs.issue_numbers) }} + + steps: + - name: Log current issue being processed + run: | + echo "🔄 Processing issue #${{ matrix.issue_number }}" + echo "Total issues to process: ${{ needs.get_open_issues.outputs.total_count }}" + + - name: Check if dry run mode + if: inputs.dry_run == true + run: | + echo "🔍 DRY RUN MODE: Would process issue #${{ matrix.issue_number }}" + echo "Skipping actual triage processing" + + - name: Trigger triage workflow for issue + if: inputs.dry_run != true + uses: actions/github-script@v6 + with: + script: | + const issueNumber = '${{ matrix.issue_number }}'; + + try { + console.log(`Triggering triage workflow for issue #${issueNumber}`); + + const response = await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'triage-agent.yml', + ref: 'main', + inputs: { + issue_number: issueNumber + } + }); + + console.log(`✅ Successfully triggered triage workflow for issue #${issueNumber}`); + + } catch (error) { + console.error(`❌ Failed to trigger triage workflow for issue #${issueNumber}:`, error); + core.setFailed(`Failed to process issue #${issueNumber}: ${error.message}`); + } + + - name: Wait for workflow completion + if: inputs.dry_run != true + run: | + echo "⏳ Waiting for triage workflow to complete for issue #${{ matrix.issue_number }}..." + echo "Timeout: ${{ vars.TRIAGE_AGENT_TIMEOUT }} seconds" + sleep ${{ vars.TRIAGE_AGENT_TIMEOUT }} # Wait for triage workflow completion + + summary: + runs-on: ubuntu-latest + needs: [get_open_issues, process_issues] + if: always() + + steps: + - name: Print summary + run: | + echo "## Triage Processing Summary" + echo "Total open issues found: ${{ needs.get_open_issues.outputs.total_count }}" + + if [ "${{ inputs.dry_run }}" == "true" ]; then + echo "Mode: DRY RUN (no actual processing performed)" + else + echo "Mode: FULL PROCESSING" + fi + + if [ "${{ needs.process_issues.result }}" == "success" ]; then + echo "✅ All issues processed successfully" + elif [ "${{ needs.process_issues.result }}" == "failure" ]; then + echo "❌ Some issues failed to process" + elif [ "${{ needs.process_issues.result }}" == "skipped" ]; then + echo "⏭️ Processing was skipped (no open issues found)" + else + echo "⚠️ Processing completed with status: ${{ needs.process_issues.result }}" + fi From b62897e444a5b522b68dfb2c73aae21614d1fe30 Mon Sep 17 00:00:00 2001 From: Karl-Erik Enkelmann <110300169+playdohface@users.noreply.github.com> Date: Mon, 24 Nov 2025 07:49:45 +0100 Subject: [PATCH 86/94] Set source to null when unavailable in a StackTrace (#614) --- .../debug/core/adapter/handler/StackTraceRequestHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index 3fa0a9a9b..3bb319a01 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -220,7 +220,7 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra } else { // For other unavailable method, such as lambda expression's built-in methods run/accept/apply, // display "Unknown Source" in the Call Stack View. - clientSource = new Types.Source("Unknown Source", "unknown", 0); + clientSource = null; } // DAP specifies lineNumber to be set to 0 when unavailable clientLineNumber = 0; From 81339de8108b50dfc93d2dc47dc48c72d8904902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Fu=C3=9Fenegger?= Date: Tue, 9 Dec 2025 02:13:35 +0100 Subject: [PATCH 87/94] Fix lspFrame.source NPE on stackTrace request (#616) * Fix lspFrame.source NPE on stackTrace request Follow up to: - https://github.com/microsoft/java-debug/pull/614 - https://github.com/microsoft/java-debug/pull/609 With the change to set the line number to 0 the jdiLineNumber != lspFrame.line comparison can evaluate to true: dap> lspFrame Types$StackFrame@78 column: 1 id: 6 line: 0 name: "0x000000002f0bc000.invokeVirtual(Object,Object)" presentationHint: "subtle" source: null dap> jdiLineNumber -1 `source` being null caused an NPE * Fix line number comparison in StackTraceRequestHandler --------- Co-authored-by: Changyong Gong --- .../core/adapter/handler/StackTraceRequestHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index 3bb319a01..f63d1b24e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -29,9 +29,9 @@ import com.google.gson.JsonObject; import com.microsoft.java.debug.core.AsyncJdwpUtils; import com.microsoft.java.debug.core.DebugSettings; +import com.microsoft.java.debug.core.DebugSettings.Switch; import com.microsoft.java.debug.core.DebugUtility; import com.microsoft.java.debug.core.IBreakpoint; -import com.microsoft.java.debug.core.DebugSettings.Switch; import com.microsoft.java.debug.core.adapter.AdapterUtils; import com.microsoft.java.debug.core.adapter.IDebugAdapterContext; import com.microsoft.java.debug.core.adapter.IDebugRequestHandler; @@ -40,13 +40,13 @@ import com.microsoft.java.debug.core.adapter.SourceType; import com.microsoft.java.debug.core.adapter.formatter.SimpleTypeFormatter; import com.microsoft.java.debug.core.adapter.variables.StackFrameReference; +import com.microsoft.java.debug.core.protocol.Events.TelemetryEvent; import com.microsoft.java.debug.core.protocol.Messages.Response; import com.microsoft.java.debug.core.protocol.Requests.Arguments; import com.microsoft.java.debug.core.protocol.Requests.Command; import com.microsoft.java.debug.core.protocol.Requests.StackTraceArguments; import com.microsoft.java.debug.core.protocol.Responses; import com.microsoft.java.debug.core.protocol.Types; -import com.microsoft.java.debug.core.protocol.Events.TelemetryEvent; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.LocalVariable; @@ -114,7 +114,7 @@ public CompletableFuture handle(Command command, Arguments arguments, result.add(lspFrame); frameReference.setSource(lspFrame.source); int jdiLineNumber = AdapterUtils.convertLineNumber(jdiFrame.lineNumber, context.isDebuggerLinesStartAt1(), context.isClientLinesStartAt1()); - if (jdiLineNumber != lspFrame.line) { + if (jdiLineNumber >= 0 && jdiLineNumber != lspFrame.line) { decompiledClasses.add(lspFrame.source.path); } } From 9623b8ff69b188c5d0325110a5977a2623a67ea1 Mon Sep 17 00:00:00 2001 From: Changyong Gong Date: Tue, 16 Dec 2025 15:42:19 +0800 Subject: [PATCH 88/94] fix: lspFrame.source.path is null (#618) * fix: lspFrame.source.path is null * fix: update bundle location --- .../debug/core/adapter/handler/StackTraceRequestHandler.java | 2 +- .../com.microsoft.java.debug.tp.target | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java index f63d1b24e..6f54bcedb 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/StackTraceRequestHandler.java @@ -114,7 +114,7 @@ public CompletableFuture handle(Command command, Arguments arguments, result.add(lspFrame); frameReference.setSource(lspFrame.source); int jdiLineNumber = AdapterUtils.convertLineNumber(jdiFrame.lineNumber, context.isDebuggerLinesStartAt1(), context.isClientLinesStartAt1()); - if (jdiLineNumber >= 0 && jdiLineNumber != lspFrame.line) { + if (jdiLineNumber != lspFrame.line && lspFrame.source != null && lspFrame.source.path != null) { decompiledClasses.add(lspFrame.source.path); } } diff --git a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target index deabb9f3e..31462a770 100644 --- a/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target +++ b/com.microsoft.java.debug.target/com.microsoft.java.debug.tp.target @@ -4,7 +4,7 @@ - + From 31dd8ee33403f7365937cf77c653f2f5ec0960ba Mon Sep 17 00:00:00 2001 From: Changyong Gong Date: Thu, 29 Jan 2026 12:35:31 +0800 Subject: [PATCH 89/94] feat: support suspend all setting (#619) * feat: support suspend all setting * fix: handle stoppedEvent for suspend policy change * fix: not allow change policy during a live debug session * fix: format issue * fix: let step command execute for current thread * fix: remove unused import * fix: apply suspend policy to exception breakpoint * fix: improve naming --- .../microsoft/java/debug/core/Breakpoint.java | 41 +++++++++++++++---- .../java/debug/core/DebugSession.java | 20 ++++++--- .../java/debug/core/DebugSettings.java | 1 + .../java/debug/core/DebugUtility.java | 3 +- .../debug/core/EvaluatableBreakpoint.java | 20 ++++----- .../java/debug/core/IBreakpoint.java | 7 ++++ .../java/debug/core/IDebugSession.java | 6 +++ .../java/debug/core/MethodBreakpoint.java | 6 ++- .../microsoft/java/debug/core/Watchpoint.java | 15 ++++--- .../ConfigurationDoneRequestHandler.java | 5 ++- .../adapter/handler/RestartFrameHandler.java | 4 +- .../handler/SetBreakpointsRequestHandler.java | 8 +++- .../SetDataBreakpointsRequestHandler.java | 9 +++- .../SetFunctionBreakpointsRequestHandler.java | 9 +++- .../handler/ThreadsRequestHandler.java | 5 +++ 15 files changed, 117 insertions(+), 42 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java index 82859b268..d8316c2e3 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java @@ -42,24 +42,28 @@ public class Breakpoint implements IBreakpoint { private String condition = null; private String logMessage = null; private HashMap propertyMap = new HashMap<>(); + private final boolean suspendAllThreads; private boolean async = false; - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) { - this(vm, eventHub, className, lineNumber, 0, null); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) { - this(vm, eventHub, className, lineNumber, hitCount, null); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition) { - this(vm, eventHub, className, lineNumber, hitCount, condition, null); + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, + String condition, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads); } - Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, + String condition, String logMessage, boolean suspendAllThreads) { this.vm = vm; this.eventHub = eventHub; + this.suspendAllThreads = suspendAllThreads; String contextClass = className; String methodName = null; String methodSignature = null; @@ -79,13 +83,15 @@ public class Breakpoint implements IBreakpoint { this.logMessage = logMessage; } - Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { + Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, + String condition, String logMessage, boolean suspendAllThreads) { this.vm = vm; this.eventHub = eventHub; this.sourceLocation = sourceLocation; this.hitCount = hitCount; this.condition = condition; this.logMessage = logMessage; + this.suspendAllThreads = suspendAllThreads; } // IDebugResource @@ -203,6 +209,19 @@ public void setAsync(boolean async) { this.async = async; } + @Override + public void setSuspendPolicy(String policy) { + } + + @Override + public String getSuspendPolicy() { + return suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD"; + } + + protected boolean suspendAllThreads() { + return suspendAllThreads; + } + @Override public CompletableFuture install() { // It's possible that different class loaders create new class with the same name. @@ -412,7 +431,11 @@ private CompletableFuture> createBreakpointRequests(List newLocations.forEach(location -> { BreakpointRequest request = vm.eventRequestManager().createBreakpointRequest(location); - request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); + if ("SUSPEND_ALL".equals(getSuspendPolicy())) { + request.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); + } else { + request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD); + } if (hitCount > 0) { request.addCountFilter(hitCount); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java index 38a234fa9..d5b8ceb47 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java @@ -36,9 +36,12 @@ public class DebugSession implements IDebugSession { private EventHub eventHub = new EventHub(); private List eventRequests = new ArrayList<>(); private List subscriptions = new ArrayList<>(); + private final boolean suspendAllThreads; public DebugSession(VirtualMachine virtualMachine) { vm = virtualMachine; + // Capture suspend policy at session start - this persists for the session lifetime + this.suspendAllThreads = DebugSettings.getCurrent().suspendAllThreads; } @Override @@ -128,17 +131,17 @@ public void terminate() { @Override public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) { - return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage); + return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage, suspendAllThreads); } @Override public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) { - return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage); + return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage, suspendAllThreads); } @Override public IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount) { - return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount); + return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount, suspendAllThreads); } @Override @@ -185,7 +188,7 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught if (exceptionTypes == null || exceptionTypes.length == 0) { ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught); - request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); if (classFilters != null) { for (String classFilter : classFilters) { request.addClassFilter(classFilter); @@ -260,17 +263,22 @@ public VirtualMachine getVM() { return vm; } + @Override + public boolean shouldSuspendAllThreads() { + return suspendAllThreads; + } + @Override public IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount) { - return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount); + return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount, suspendAllThreads); } private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) { EventRequestManager manager = vm.eventRequestManager(); ExceptionRequest request = manager.createExceptionRequest(refType, notifyCaught, notifyUncaught); - request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); if (classFilters != null) { for (String classFilter : classFilters) { request.addClassFilter(classFilter); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java index 0a3e05ec8..b422f6801 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSettings.java @@ -45,6 +45,7 @@ public final class DebugSettings { public int jdwpRequestTimeout = 3000; public AsyncMode asyncJDWP = AsyncMode.OFF; public Switch debugSupportOnDecompiledSource = Switch.OFF; + public boolean suspendAllThreads = false; public static DebugSettings getCurrent() { return current; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java index 4a2a49e9b..8a31792f0 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java @@ -394,6 +394,7 @@ private static StepRequest createStepRequest(ThreadReference thread, int stepSiz request.addClassExclusionFilter(exclusionFilter); } } + // Note: suspend policy will be set by the caller (StepRequestHandler) based on session settings request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); request.addCountFilter(1); @@ -415,7 +416,7 @@ public static CompletableFuture stopOnEntry(IDebugSession debugSession, St EventRequestManager manager = debugSession.getVM().eventRequestManager(); MethodEntryRequest request = manager.createMethodEntryRequest(); request.addClassFilter(mainClass); - request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(debugSession.shouldSuspendAllThreads() ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); debugSession.getEventHub().events().filter(debugEvent -> { return debugEvent.event instanceof MethodEntryEvent && request.equals(debugEvent.event.request()); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java index 723e2cadf..d5a909f0b 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/EvaluatableBreakpoint.java @@ -29,28 +29,28 @@ public class EvaluatableBreakpoint extends Breakpoint implements IEvaluatableBre private Object compiledLogpointExpression = null; private Map compiledExpressions = new ConcurrentHashMap<>(); - EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) { - this(vm, eventHub, className, lineNumber, 0, null); + EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads); } - EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) { - this(vm, eventHub, className, lineNumber, hitCount, null); + EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads); } EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition) { - this(vm, eventHub, className, lineNumber, hitCount, condition, null); + String condition, boolean suspendAllThreads) { + this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads); } EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, - String condition, String logMessage) { - super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage); + String condition, String logMessage, boolean suspendAllThreads) { + super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage, suspendAllThreads); this.eventHub = eventHub; } EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, - String condition, String logMessage) { - super(vm, eventHub, sourceLocation, hitCount, condition, logMessage); + String condition, String logMessage, boolean suspendAllThreads) { + super(vm, eventHub, sourceLocation, hitCount, condition, logMessage, suspendAllThreads); this.eventHub = eventHub; } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java index 40995e9dd..ec3ea818a 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java @@ -55,4 +55,11 @@ default void setAsync(boolean async) { default boolean async() { return false; } + + default void setSuspendPolicy(String policy) { + } + + default String getSuspendPolicy() { + return null; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java index 6cc3f3a46..afc2283f0 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java @@ -52,4 +52,10 @@ void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, Strin IEventHub getEventHub(); VirtualMachine getVM(); + + /** + * Returns whether breakpoints should suspend all threads or just the event thread. + * This value is captured at session start and persists for the session lifetime. + */ + boolean shouldSuspendAllThreads(); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java index 7a6e74c6b..bc46fd96f 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/MethodBreakpoint.java @@ -44,6 +44,7 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi private String condition; private int hitCount; private boolean async = false; + private final boolean suspendAllThreads; private HashMap propertyMap = new HashMap<>(); private Object compiledConditionalExpression = null; @@ -53,7 +54,7 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi private List subscriptions = new ArrayList<>(); public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, String functionName, - String condition, int hitCount) { + String condition, int hitCount, boolean suspendAllThreads) { Objects.requireNonNull(vm); Objects.requireNonNull(eventHub); Objects.requireNonNull(className); @@ -64,6 +65,7 @@ public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, this.functionName = functionName; this.condition = condition; this.hitCount = hitCount; + this.suspendAllThreads = suspendAllThreads; } @Override @@ -262,7 +264,7 @@ private Optional createMethodEntryRequest0(ReferenceType typ MethodEntryRequest request = vm.eventRequestManager().createMethodEntryRequest(); request.addClassFilter(type); - request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); if (hitCount > 0) { request.addCountFilter(hitCount); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java index 3de321ec8..fdb2354a9 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Watchpoint.java @@ -46,20 +46,22 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint { private HashMap propertyMap = new HashMap<>(); private Object compiledConditionalExpression = null; private Map compiledExpressions = new ConcurrentHashMap<>(); + private final boolean suspendAllThreads; // IDebugResource private List requests = new ArrayList<>(); private List subscriptions = new ArrayList<>(); - Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName) { - this(vm, eventHub, className, fieldName, "write"); + Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, boolean suspendAllThreads) { + this(vm, eventHub, className, fieldName, "write", suspendAllThreads); } - Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType) { - this(vm, eventHub, className, fieldName, accessType, null, 0); + Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, boolean suspendAllThreads) { + this(vm, eventHub, className, fieldName, accessType, null, 0, suspendAllThreads); } - Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, String condition, int hitCount) { + Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, + String condition, int hitCount, boolean suspendAllThreads) { Objects.requireNonNull(vm); Objects.requireNonNull(eventHub); Objects.requireNonNull(className); @@ -71,6 +73,7 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint { this.accessType = accessType; this.condition = condition; this.hitCount = hitCount; + this.suspendAllThreads = suspendAllThreads; } @Override @@ -212,7 +215,7 @@ private List createWatchpointRequests(ReferenceType type) { } watchpointRequests.forEach(request -> { - request.setSuspendPolicy(WatchpointRequest.SUSPEND_EVENT_THREAD); + request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD); if (hitCount > 0) { request.addCountFilter(hitCount); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java index 1c543bce4..308adddb6 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java @@ -40,6 +40,7 @@ import com.sun.jdi.event.ThreadStartEvent; import com.sun.jdi.event.VMDeathEvent; import com.sun.jdi.event.VMDisconnectEvent; +import com.sun.jdi.request.EventRequest; import com.sun.jdi.event.VMStartEvent; public class ConfigurationDoneRequestHandler implements IDebugRequestHandler { @@ -119,7 +120,9 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, ((ExceptionEvent) event).catchLocation() == null); context.getExceptionManager().setException(thread.uniqueID(), jdiException); context.getThreadCache().addEventThread(thread, "exception"); - context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID())); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; + context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), allThreadsStopped)); debugEvent.shouldResume = false; } else { isImportantEvent = false; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java index 164909656..26ebefaee 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/RestartFrameHandler.java @@ -33,6 +33,7 @@ import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadReference; +import com.sun.jdi.request.EventRequest; import com.sun.jdi.request.StepRequest; /** @@ -121,7 +122,8 @@ private void stepInto(IDebugAdapterContext context, ThreadReference thread) { debugEvent.shouldResume = false; // Have to send two events to keep the UI sync with the step in operations: context.getProtocolServer().sendEvent(new Events.ContinuedEvent(thread.uniqueID())); - context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", thread.uniqueID())); + boolean allThreadsStopped = request.suspendPolicy() == EventRequest.SUSPEND_ALL; + context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", thread.uniqueID(), allThreadsStopped)); context.getThreadCache().setThreadStoppedReason(thread.uniqueID(), "restartframe"); }); request.enable(); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java index 09dafd1b0..0f171486e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java @@ -212,15 +212,19 @@ private void registerBreakpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - breakpointName, bpThread.uniqueID())); + breakpointName, bpThread.uniqueID(), allThreadsStopped)); } }); }); } else { context.getThreadCache().addEventThread(bpThread, breakpointName); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - breakpointName, bpThread.uniqueID())); + breakpointName, bpThread.uniqueID(), allThreadsStopped)); } debugEvent.shouldResume = false; } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java index 373b1c31b..c7c0995fe 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetDataBreakpointsRequestHandler.java @@ -41,6 +41,7 @@ import com.sun.jdi.ThreadReference; import com.sun.jdi.event.Event; import com.sun.jdi.event.WatchpointEvent; +import com.sun.jdi.request.EventRequest; public class SetDataBreakpointsRequestHandler implements IDebugRequestHandler { private boolean registered = false; @@ -152,13 +153,17 @@ private void registerWatchpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, "data breakpoint"); - context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID())); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; + context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID(), allThreadsStopped)); } }); }); } else { context.getThreadCache().addEventThread(bpThread, "data breakpoint"); - context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID())); + boolean allThreadsStopped = event.request() != null + && event.request().suspendPolicy() == EventRequest.SUSPEND_ALL; + context.getProtocolServer().sendEvent(new Events.StoppedEvent("data breakpoint", bpThread.uniqueID(), allThreadsStopped)); } debugEvent.shouldResume = false; }); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java index 96a0e395b..01b5e9619 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetFunctionBreakpointsRequestHandler.java @@ -40,6 +40,7 @@ import com.microsoft.java.debug.core.protocol.Types.FunctionBreakpoint; import com.sun.jdi.ThreadReference; import com.sun.jdi.event.MethodEntryEvent; +import com.sun.jdi.request.EventRequest; public class SetFunctionBreakpointsRequestHandler implements IDebugRequestHandler { private boolean registered = false; @@ -166,16 +167,20 @@ private void registerMethodBreakpointHandler(IDebugAdapterContext context) { debugEvent.eventSet.resume(); } else { context.getThreadCache().addEventThread(bpThread, "function breakpoint"); + boolean allThreadsStopped = methodEntryEvent.request() != null + && methodEntryEvent.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer().sendEvent(new Events.StoppedEvent( - "function breakpoint", bpThread.uniqueID())); + "function breakpoint", bpThread.uniqueID(), allThreadsStopped)); } }); }); } else { context.getThreadCache().addEventThread(bpThread, "function breakpoint"); + boolean allThreadsStopped = methodEntryEvent.request() != null + && methodEntryEvent.request().suspendPolicy() == EventRequest.SUSPEND_ALL; context.getProtocolServer() - .sendEvent(new Events.StoppedEvent("function breakpoint", bpThread.uniqueID())); + .sendEvent(new Events.StoppedEvent("function breakpoint", bpThread.uniqueID(), allThreadsStopped)); } debugEvent.shouldResume = false; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java index 6573f11da..5c4770391 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ThreadsRequestHandler.java @@ -149,6 +149,11 @@ private CompletableFuture resume(Requests.ContinueArguments arguments, if (thread == null) { thread = DebugUtility.getThread(context.getDebugSession(), arguments.threadId); } + + if (context.getDebugSession().shouldSuspendAllThreads()) { + thread = null; + } + /** * See the jdi doc https://docs.oracle.com/javase/7/docs/jdk/api/jpda/jdi/com/sun/jdi/ThreadReference.html#resume(), * suspends of both the virtual machine and individual threads are counted. Before a thread will run again, it must From b35f033a14d35ae12c257405b88ac382720abc1f Mon Sep 17 00:00:00 2001 From: Snjeza Date: Thu, 12 Mar 2026 08:06:15 +0100 Subject: [PATCH 90/94] Provide graceful shutdown on debug stop action (#620) --- .../debug/core/adapter/handler/DisconnectRequestHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/DisconnectRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/DisconnectRequestHandler.java index a615e8963..eed3cc2e2 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/DisconnectRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/DisconnectRequestHandler.java @@ -26,6 +26,7 @@ public void destroyDebugSession(Command command, Arguments arguments, Response r IDebugSession debugSession = context.getDebugSession(); if (debugSession != null) { if (disconnectArguments.terminateDebuggee && !context.isAttached()) { + debugSession.detach(); debugSession.terminate(); } else { debugSession.detach(); From 26b05eb1d70f3421f4235f3c0d65d56dfbb2e05f Mon Sep 17 00:00:00 2001 From: wenyt <75360946+wenytang-ms@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:35:18 +0800 Subject: [PATCH 91/94] Exclude Map.Entry from lazy loading to show key:value inline (#621) Map.Entry objects were incorrectly treated as lazy-loading candidates because they are included in COLLECTION_TYPES. This caused the debugger to display entries as 'HashMap$Node@id' instead of showing the actual key:value details inline. Map.Entry's details computation (getKey + getValue) is lightweight, so eager evaluation is safe and significantly improves UX when debugging large Maps. Fixes https://github.com/microsoft/vscode-java-debug/issues/1605 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../debug/core/adapter/variables/VariableDetailUtils.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableDetailUtils.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableDetailUtils.java index c6d0d38e0..3fd060625 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableDetailUtils.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/VariableDetailUtils.java @@ -163,6 +163,13 @@ public static boolean isLazyLoadingSupported(Value value) { return false; } String inheritedType = findInheritedType(value, COLLECTION_TYPES); + // Map.Entry should not use lazy loading because its details computation + // (getKey + getValue) is lightweight and showing "key:value" inline + // significantly improves UX for large Maps. See + // https://github.com/microsoft/vscode-java-debug/issues/1605 + if (Objects.equals(inheritedType, ENTRY_TYPE)) { + return false; + } if (inheritedType == null && !containsToStringMethod((ObjectReference) value)) { return false; } From 07b1e4ca5c7ec01fe1948f0f90ecb4101feaeabd Mon Sep 17 00:00:00 2001 From: wenyt <75360946+wenytang-ms@users.noreply.github.com> Date: Mon, 30 Mar 2026 17:17:23 +0800 Subject: [PATCH 92/94] Use JDTUtils.toUri() for decompiled class file URIs (#624) Replace manual jdt:// URI construction in getFileURI(IClassFile) with JDTUtils.toUri(classFile) to align with eclipse.jdt.ls PR #3666. This ensures the debugger generates the same URI format as the language server, fixing the issue where classes with source code are opened twice (once as .java, once as .class) during debugging. Fixes microsoft/java-debug#623 Related: eclipse-jdtls/eclipse.jdt.ls#3729 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../debug/plugin/internal/JdtSourceLookUpProvider.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java index 5652b922e..2c39425ed 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtSourceLookUpProvider.java @@ -466,15 +466,7 @@ private String getContents(IClassFile cf) { } private static String getFileURI(IClassFile classFile) { - String packageName = classFile.getParent().getElementName(); - String jarName = classFile.getParent().getParent().getElementName(); - try { - return new URI(JDT_SCHEME, "contents", PATH_SEPARATOR + jarName + PATH_SEPARATOR + packageName - + PATH_SEPARATOR + classFile.getElementName(), classFile.getHandleIdentifier(), null) - .toASCIIString(); - } catch (URISyntaxException e) { - return null; - } + return JDTUtils.toUri(classFile); } private static String getFileURI(IResource resource) { From a4c27fbf506a7d929a708ff55c01e9953a2a2c1e Mon Sep 17 00:00:00 2001 From: wenyt <75360946+wenytang-ms@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:04:23 +0800 Subject: [PATCH 93/94] fix: handle NoSuchMethodError for isMainMethodCandidate() on older JDT Core (#622) Catch NoSuchMethodError when calling SourceMethod.isMainMethodCandidate() in ResolveMainClassHandler and ResolveMainMethodHandler. This method was added in JDT Core 3.36 and is unavailable on older versions, causing the debugger to fail entirely when resolving main classes. Fixes microsoft/vscode-java-debug#1598 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Changyong Gong --- .../debug/plugin/internal/ResolveMainClassHandler.java | 7 +++++++ .../plugin/internal/ResolveMainMethodHandler.java | 10 +++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java index fc8189445..af9cdbc57 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainClassHandler.java @@ -241,6 +241,13 @@ private boolean isMainMethod(IMethod method) { return method.isMainMethod(); } catch (JavaModelException e) { // do nothing + } catch (NoSuchMethodError e) { + // isMainMethodCandidate() was added in JDT Core 3.36, fall back to isMainMethod() + try { + return method.isMainMethod(); + } catch (JavaModelException ex) { + // do nothing + } } return false; diff --git a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java index be1092bb3..820bddd54 100644 --- a/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java +++ b/com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveMainMethodHandler.java @@ -112,9 +112,13 @@ public static IMethod getMainMethod(IType type) throws JavaModelException { boolean allowInstanceMethod = isInstanceMainMethodSupported(type); List methods = new ArrayList<>(); for (IMethod method : type.getMethods()) { - if (method instanceof SourceMethod - && ((SourceMethod) method).isMainMethodCandidate()) { - methods.add(method); + try { + if (method instanceof SourceMethod + && ((SourceMethod) method).isMainMethodCandidate()) { + methods.add(method); + } + } catch (NoSuchMethodError e) { + // isMainMethodCandidate() was added in JDT Core 3.36, skip if unavailable } if (method.isMainMethod()) { From ae2847eaab3a158ddf6601ecc15c1159e6fd24b0 Mon Sep 17 00:00:00 2001 From: Daniel Pfeffer Date: Mon, 20 Apr 2026 05:08:16 +0200 Subject: [PATCH 94/94] Added attributes to VariablePresentationHint as specified in protocol definition (#625) * added attributes to VariablePresentationHint as specified in protocol definition * Fixed issue with lazy VariablePresentationHint. Restricted constant to Primitive & StringRefs --- .../handler/VariablesRequestHandler.java | 40 +++++++++++++++++-- .../java/debug/core/protocol/Types.java | 24 +++++------ 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java index 11a6391de..47854528f 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java @@ -65,6 +65,8 @@ import com.sun.jdi.StringReference; import com.sun.jdi.Type; import com.sun.jdi.Value; +import com.sun.jdi.PrimitiveType; +import com.sun.jdi.ClassNotLoadedException; public class VariablesRequestHandler implements IDebugRequestHandler { protected static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME); @@ -82,7 +84,7 @@ public class VariablesRequestHandler implements IDebugRequestHandler { * single-threaded JDWP request processing strategy, * a single JDWP latency is about 10ms. */ - static final long USABLE_JDWP_LATENCY = 10/**ms*/; + static final long USABLE_JDWP_LATENCY = 10/*ms*/; @Override public List getTargetCommands() { @@ -370,10 +372,12 @@ public CompletableFuture handle(Command command, Arguments arguments, referenceId = context.getRecyclableIdPool().addObject(containerNode.getThreadId(), varProxy); } + String[] rawAttributes = extractAttributes(javaVariable); + Types.Variable typedVariables = new Types.Variable(name, valueString, typeString, referenceId, evaluateName); typedVariables.indexedVariables = Math.max(indexedVariables, 0); - if (varProxy != null && varProxy.isLazyVariable()) { - typedVariables.presentationHint = new VariablePresentationHint(true); + if ((varProxy != null && varProxy.isLazyVariable()) || (rawAttributes.length > 0)) { + typedVariables.presentationHint = new VariablePresentationHint(varProxy != null && varProxy.isLazyVariable(), rawAttributes); } if (detailsValue != null) { @@ -391,6 +395,36 @@ public CompletableFuture handle(Command command, Arguments arguments, return CompletableFuture.completedFuture(response); } + private String[] extractAttributes(Variable variable) { + final List attributes = new ArrayList<>(); + if (variable.field != null) { + if (variable.field.isStatic()) { + attributes.add("static"); + } + if (variable.field.isFinal()) { + // static final Primitive or StringRef fields are compile-time constants in Java + boolean isPrimitive; + try { + isPrimitive = variable.field.type() instanceof PrimitiveType; + } catch (ClassNotLoadedException e) { /* type() not yet loaded indicates some ReferenceType */ + isPrimitive = false; + } + boolean canBeTrueConstant = (isPrimitive || variable.field instanceof StringReference); + if (variable.field.isStatic() && canBeTrueConstant) { + attributes.add("constant"); + } + attributes.add("readOnly"); + } + } + // local 'final' variables get inlined by the compiler and do not appear + + if (variable.value instanceof StringReference) { + attributes.add("rawString"); + } + + return attributes.toArray(new String[0]); + } + private boolean supportsLogicStructureView(IDebugAdapterContext context) { return (!useAsyncJDWP(context) || context.getJDWPLatency() <= USABLE_JDWP_LATENCY) && DebugSettings.getCurrent().showLogicalStructure; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java index 33308af6d..9d32d4783 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java @@ -49,19 +49,13 @@ public static class StackFrame { /** * Constructs a StackFrame with the given information. * - * @param id - * the stack frame id - * @param name - * the stack frame name - * @param src - * source info of the stack frame - * @param ln - * line number of the stack frame - * @param col - * column number of the stack frame - * @param presentationHint - * An optional hint for how to present this frame in the UI. - * Values: 'normal', 'label', 'subtle' + * @param id the stack frame id + * @param name the stack frame name + * @param src source info of the stack frame + * @param ln line number of the stack frame + * @param col column number of the stack frame + * @param presentationHint An optional hint for how to present this frame in the UI. + * Values: 'normal', 'label', 'subtle' */ public StackFrame(int id, String name, Source src, int ln, int col, String presentationHint) { this.id = id; @@ -408,9 +402,11 @@ public static class ExceptionDetails { public static class VariablePresentationHint { public boolean lazy; + public String[] attributes; - public VariablePresentationHint(boolean lazy) { + public VariablePresentationHint(boolean lazy, String[] attributes) { this.lazy = lazy; + this.attributes = attributes; } }