Skip to content

Commit

Permalink
Merge branch 'master' into nullable-annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
Shadow-Devil authored Dec 10, 2024
2 parents 9bfe92f + d3b078c commit abce447
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
import java.util.Map;
import java.util.Optional;

import static org.ballerinalang.debugadapter.JBallerinaDebugServer.isBalStackFrame;
import static org.ballerinalang.debugadapter.evaluation.utils.EvaluationUtils.STRAND_VAR_NAME;
import static org.ballerinalang.debugadapter.utils.ServerUtils.isBalStackFrame;
import static org.ballerinalang.debugadapter.variable.VariableUtils.isService;
import static org.ballerinalang.debugadapter.variable.VariableUtils.removeRedundantQuotes;
import static org.wso2.ballerinalang.compiler.parser.BLangAnonymousModelHelper.LAMBDA;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import java.util.concurrent.TimeoutException;

import static org.ballerinalang.debugadapter.utils.PackageUtils.getQualifiedClassName;
import static org.ballerinalang.debugadapter.utils.ServerUtils.supportsBreakpointVerification;

/**
* Implementation of Ballerina breakpoint processor. The existing implementation is capable of processing advanced
Expand Down Expand Up @@ -202,7 +203,7 @@ void activateUserBreakPoints(ReferenceType referenceType, boolean shouldNotify)
bpReq.enable();

// verifies the breakpoint reachability and notifies the client if required.
if (!breakpoint.isVerified()) {
if (supportsBreakpointVerification(context) && !breakpoint.isVerified()) {
breakpoint.setVerified(true);
if (shouldNotify) {
notifyBreakPointChangesToClient(breakpoint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.ballerinalang.debugadapter.runner.BProgramRunner;
import org.ballerinalang.debugadapter.runner.BSingleFileRunner;
import org.ballerinalang.debugadapter.utils.PackageUtils;
import org.ballerinalang.debugadapter.utils.ServerUtils;
import org.ballerinalang.debugadapter.variable.BCompoundVariable;
import org.ballerinalang.debugadapter.variable.BSimpleVariable;
import org.ballerinalang.debugadapter.variable.BVariable;
Expand Down Expand Up @@ -83,7 +84,6 @@
import org.eclipse.lsp4j.debug.SetBreakpointsArguments;
import org.eclipse.lsp4j.debug.SetBreakpointsResponse;
import org.eclipse.lsp4j.debug.SetExceptionBreakpointsArguments;
import org.eclipse.lsp4j.debug.Source;
import org.eclipse.lsp4j.debug.SourceArguments;
import org.eclipse.lsp4j.debug.SourceBreakpoint;
import org.eclipse.lsp4j.debug.SourceResponse;
Expand Down Expand Up @@ -133,10 +133,13 @@
import static org.ballerinalang.debugadapter.completion.util.CompletionUtil.getTriggerCharacters;
import static org.ballerinalang.debugadapter.completion.util.CompletionUtil.getVisibleSymbolCompletions;
import static org.ballerinalang.debugadapter.completion.util.CompletionUtil.triggerCharactersFound;
import static org.ballerinalang.debugadapter.utils.PackageUtils.BAL_FILE_EXT;
import static org.ballerinalang.debugadapter.utils.PackageUtils.GENERATED_VAR_PREFIX;
import static org.ballerinalang.debugadapter.utils.PackageUtils.INIT_CLASS_NAME;
import static org.ballerinalang.debugadapter.utils.PackageUtils.getQualifiedClassName;
import static org.ballerinalang.debugadapter.utils.ServerUtils.isBalStackFrame;
import static org.ballerinalang.debugadapter.utils.ServerUtils.isBalStrand;
import static org.ballerinalang.debugadapter.utils.ServerUtils.isNoDebugMode;
import static org.ballerinalang.debugadapter.utils.ServerUtils.toBalBreakpoint;

/**
* JBallerina debug server implementation.
Expand Down Expand Up @@ -180,7 +183,7 @@ public ExecutionContext getContext() {
return context;
}

ClientConfigHolder getClientConfigHolder() {
public ClientConfigHolder getClientConfigHolder() {
return clientConfigHolder;
}

Expand Down Expand Up @@ -223,12 +226,13 @@ public CompletableFuture<Capabilities> initialize(InitializeRequestArguments arg
public CompletableFuture<SetBreakpointsResponse> setBreakpoints(SetBreakpointsArguments args) {
return CompletableFuture.supplyAsync(() -> {
SetBreakpointsResponse bpResponse = new SetBreakpointsResponse();
if (isNoDebugMode()) {
if (isNoDebugMode(context)) {
return bpResponse;
}

BalBreakpoint[] balBreakpoints = Arrays.stream(args.getBreakpoints())
.map((SourceBreakpoint sourceBreakpoint) -> toBalBreakpoint(sourceBreakpoint, args.getSource()))
.map((SourceBreakpoint sourceBreakpoint) -> toBalBreakpoint(context, sourceBreakpoint,
args.getSource()))
.toArray(BalBreakpoint[]::new);

LinkedHashMap<Integer, BalBreakpoint> breakpointsMap = new LinkedHashMap<>();
Expand Down Expand Up @@ -350,7 +354,7 @@ public CompletableFuture<StackTraceResponse> stackTrace(StackTraceArguments args
} else {
StackFrame[] validFrames = activeThread.frames().stream()
.map(this::toDapStackFrame)
.filter(JBallerinaDebugServer::isValidFrame)
.filter(ServerUtils::isValidFrame)
.toArray(StackFrame[]::new);
stackTraceResponse.setStackFrames(validFrames);
threadStackTraces.put(activeThread.uniqueID(), validFrames);
Expand Down Expand Up @@ -792,13 +796,6 @@ private StackFrame toDapStackFrame(StackFrameProxyImpl stackFrameProxy) {
}
}

private BalBreakpoint toBalBreakpoint(SourceBreakpoint sourceBreakpoint, Source source) {
BalBreakpoint breakpoint = new BalBreakpoint(source, sourceBreakpoint.getLine());
breakpoint.setCondition(sourceBreakpoint.getCondition());
breakpoint.setLogMessage(sourceBreakpoint.getLogMessage());
return breakpoint;
}

/**
* Returns a map of all currently running threads in the remote VM, against their unique ID.
* <p>
Expand Down Expand Up @@ -848,47 +845,6 @@ && isBalStrand(threadReference)
return balStrandThreads;
}

/**
* Validates whether the given DAP thread reference represents a ballerina strand.
* <p>
*
* @param threadReference DAP thread reference
* @return true if the given DAP thread reference represents a ballerina strand.
*/
private static boolean isBalStrand(ThreadReference threadReference) {
// Todo - Refactor to use thread proxy implementation
try {
return isBalStackFrame(threadReference.frames().getFirst());
} catch (Exception e) {
return false;
}
}

/**
* Validates whether the given DAP stack frame represents a ballerina call stack frame.
*
* @param frame DAP stack frame
* @return true if the given DAP stack frame represents a ballerina call stack frame.
*/
static boolean isBalStackFrame(com.sun.jdi.StackFrame frame) {
// Todo - Refactor to use stack frame proxy implementation
try {
return frame.location().sourceName().endsWith(BAL_FILE_EXT);
} catch (Exception e) {
return false;
}
}

/**
* Validates a given ballerina stack frame for its source information.
*
* @param stackFrame ballerina stack frame
* @return true if its a valid ballerina frame
*/
static boolean isValidFrame(StackFrame stackFrame) {
return stackFrame != null && stackFrame.getSource() != null && stackFrame.getLine() > 0;
}

/**
* Asynchronously listens to remote debuggee stdout + error streams and redirects the output to the client debug
* console.
Expand Down Expand Up @@ -982,11 +938,6 @@ private void prepareFor(DebugInstruction instruction, int threadId) {
context.setPrevInstruction(instruction);
}

private boolean isNoDebugMode() {
ClientConfigHolder confHolder = context.getAdapter().getClientConfigHolder();
return confHolder instanceof ClientLaunchConfigHolder launchConfigHolder && launchConfigHolder.isNoDebugMode();
}

private Variable[] computeGlobalScopeVariables(VariablesArguments requestArgs) {
int stackFrameReference = requestArgs.getVariablesReference();
String classQName = PackageUtils.getQualifiedClassName(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.ballerinalang.debugadapter.breakpoint.BalBreakpoint;
import org.ballerinalang.debugadapter.jdi.StackFrameProxyImpl;
import org.ballerinalang.debugadapter.jdi.ThreadReferenceProxyImpl;
import org.ballerinalang.debugadapter.utils.ServerUtils;
import org.eclipse.lsp4j.debug.ContinuedEventArguments;
import org.eclipse.lsp4j.debug.StoppedEventArguments;
import org.eclipse.lsp4j.debug.StoppedEventArgumentsReason;
Expand All @@ -48,8 +49,8 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;

import static org.ballerinalang.debugadapter.JBallerinaDebugServer.isBalStackFrame;
import static org.ballerinalang.debugadapter.utils.PackageUtils.BAL_FILE_EXT;
import static org.ballerinalang.debugadapter.utils.ServerUtils.isBalStackFrame;

/**
* JDI Event processor implementation.
Expand Down Expand Up @@ -226,7 +227,7 @@ List<BallerinaStackFrame> filterValidBallerinaFrames(List<StackFrameProxyImpl> j
if (balStackFrame.getAsDAPStackFrame().isEmpty()) {
continue;
}
if (JBallerinaDebugServer.isValidFrame(balStackFrame.getAsDAPStackFrame().get())) {
if (ServerUtils.isValidFrame(balStackFrame.getAsDAPStackFrame().get())) {
validFrames.add(balStackFrame);
}
} catch (Exception ignored) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class BalBreakpoint {
private String condition;
private LogMessage logMessage;
private boolean isVerified;
private boolean supportsVerification;

private static final AtomicInteger nextID = new AtomicInteger(0);

Expand All @@ -48,6 +49,7 @@ public BalBreakpoint(Source source, int line) {
this.source = source;
this.line = line;
this.isVerified = false;
this.supportsVerification = false;
}

public Integer getLine() {
Expand Down Expand Up @@ -91,11 +93,15 @@ public Breakpoint getAsDAPBreakpoint() {
breakpoint.setId(id);
breakpoint.setLine(line);
breakpoint.setSource(source);
breakpoint.setVerified(isVerified);
breakpoint.setVerified(!supportsVerification || isVerified);
return breakpoint;
}

private boolean isTemplate(String logMessage) {
return logMessage != null && Pattern.compile(INTERPOLATION_REGEX).matcher(logMessage).find();
}

public void setSupportsVerification(boolean supportsVerification) {
this.supportsVerification = supportsVerification;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class ClientConfigHolder {
protected static final String ARG_DEBUGGEE_PORT = "debuggeePort";
private static final String ARG_CAPABILITIES = "capabilities";
private static final String ARG_SUPPORT_READONLY_EDITOR = "supportsReadOnlyEditors";
private static final String ARG_SUPPORT_BP_VERIFICATION = "supportsBreakpointVerification";
private static final String ARG_TERMINAL_KIND = "terminal";
private static final String INTEGRATED_TERMINAL_KIND = "INTEGRATED";
private static final String EXTERNAL_TERMINAL_KIND = "EXTERNAL";
Expand Down Expand Up @@ -89,6 +90,15 @@ public Optional<ExtendedClientCapabilities> getExtendedCapabilities() {
extendedClientCapabilities.setSupportsReadOnlyEditors(false);
}

Object bpVerificationConfig = capabilities.get(ARG_SUPPORT_BP_VERIFICATION);
if (bpVerificationConfig instanceof Boolean b) {
extendedClientCapabilities.setSupportsBreakpointVerification(b);
} else if (bpVerificationConfig instanceof String s) {
extendedClientCapabilities.setSupportsBreakpointVerification(Boolean.parseBoolean(s));
} else {
extendedClientCapabilities.setSupportsBreakpointVerification(false);
}

return Optional.ofNullable(extendedClientCapabilities);
}

Expand Down Expand Up @@ -124,6 +134,7 @@ public enum ClientConfigKind {
public static class ExtendedClientCapabilities {

private boolean supportsReadOnlyEditors = false;
private boolean supportsBreakpointVerification = false;

public boolean supportsReadOnlyEditors() {
return supportsReadOnlyEditors;
Expand All @@ -132,5 +143,13 @@ public boolean supportsReadOnlyEditors() {
public void setSupportsReadOnlyEditors(boolean supportsReadOnlyEditors) {
this.supportsReadOnlyEditors = supportsReadOnlyEditors;
}

public boolean supportsBreakpointVerification() {
return supportsBreakpointVerification;
}

public void setSupportsBreakpointVerification(boolean supportsBreakpointVerification) {
this.supportsBreakpointVerification = supportsBreakpointVerification;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://wso2.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ballerinalang.debugadapter.utils;

import com.sun.jdi.ThreadReference;
import org.ballerinalang.debugadapter.ExecutionContext;
import org.ballerinalang.debugadapter.breakpoint.BalBreakpoint;
import org.ballerinalang.debugadapter.config.ClientConfigHolder;
import org.ballerinalang.debugadapter.config.ClientLaunchConfigHolder;
import org.eclipse.lsp4j.debug.Source;
import org.eclipse.lsp4j.debug.SourceBreakpoint;
import org.eclipse.lsp4j.debug.StackFrame;

import java.util.Objects;

import static org.ballerinalang.debugadapter.utils.PackageUtils.BAL_FILE_EXT;

/**
* Ballerina debug server related utility functions.
*
* @since 2201.11.0
*/
public class ServerUtils {

/**
* Checks whether the debug server should run in no-debug mode.
*
* @param context debug context
* @return true if the debug mode is no-debug mode
*/
public static boolean isNoDebugMode(ExecutionContext context) {
ClientConfigHolder confHolder = context.getAdapter().getClientConfigHolder();
return confHolder instanceof ClientLaunchConfigHolder launchConfigHolder && launchConfigHolder.isNoDebugMode();
}

/**
* Validates whether the given DAP thread reference represents a ballerina strand.
*
* @param threadReference DAP thread reference
* @return true if the given DAP thread reference represents a ballerina strand
*/
public static boolean isBalStrand(ThreadReference threadReference) {
// Todo - Refactor to use thread proxy implementation
try {
return isBalStackFrame(threadReference.frames().getFirst());
} catch (Exception e) {
return false;
}
}

/**
* Validates whether the given DAP stack frame represents a ballerina call stack frame.
*
* @param frame DAP stack frame
* @return true if the given DAP stack frame represents a ballerina call stack frame
*/
public static boolean isBalStackFrame(com.sun.jdi.StackFrame frame) {
// Todo - Refactor to use stack frame proxy implementation
try {
return frame.location().sourceName().endsWith(BAL_FILE_EXT);
} catch (Exception e) {
return false;
}
}

/**
* Validates a given ballerina stack frame for its source information.
*
* @param stackFrame ballerina stack frame
* @return true if it's a valid ballerina frame
*/
public static boolean isValidFrame(StackFrame stackFrame) {
return stackFrame != null && stackFrame.getSource() != null && stackFrame.getLine() > 0;
}

/**
* Converts a given DAP source breakpoint instance to a ballerina breakpoint instance.
*
* @param context debug context
* @param sourceBp source breakpoint
* @param source source
* @return ballerina breakpoint
*/
public static BalBreakpoint toBalBreakpoint(ExecutionContext context, SourceBreakpoint sourceBp, Source source) {
BalBreakpoint breakpoint = new BalBreakpoint(source, sourceBp.getLine());
breakpoint.setCondition(sourceBp.getCondition());
breakpoint.setLogMessage(sourceBp.getLogMessage());
// If the debug client doesn't support breakpoint verification, mark the breakpoint as verified by default.
if (supportsBreakpointVerification(context)) {
breakpoint.setSupportsVerification(true);
}

return breakpoint;
}

/**
* Checks whether the connected debug client supports breakpoint verification.
*
* @param context debug context
* @return true if the connected debug client supports breakpoint verification
*/
public static boolean supportsBreakpointVerification(ExecutionContext context) {
ClientConfigHolder configHolder = context.getAdapter().getClientConfigHolder();

return Objects.nonNull(configHolder) && configHolder.getExtendedCapabilities()
.map(ClientConfigHolder.ExtendedClientCapabilities::supportsBreakpointVerification)
.orElse(false);
}
}
Loading

0 comments on commit abce447

Please sign in to comment.