feat(debugger): Kotlin breakpoints through the Kotlin Debug Adapter (#434)

Kotlin line breakpoints never verified through java-debug because jdtls cannot resolve classes for .kt files. Kotlin Application configurations and JDWP attach for modules with Kotlin sources now use the official Kotlin Debug Adapter (installable from the debugger prompt, running on the language-server JDK); pure Java keeps java-debug.

The adapter resolves classes from source paths, so sources whose directories don't match their package are mirrored package-aligned outside the project (symlinks, copies where links fail) and paths are mapped back for breakpoints and stack frames; files that can't be mirrored are skipped rather than failing the session. Kotlin applications start with JDWP suspend=y and a session-owned JDWP relay holds the adapter's early resume until attach completes, so breakpoints are installed before the program runs.

Limitations (docs/kotlin-debugging.md): @file:JvmName facades are not resolved; package/source-root changes need a new session. Not verified on a real Windows machine.

Fixes #374
This commit is contained in:
l0ng-ai
2026-10-30 18:15:42 +08:00
committed by GitHub
parent 92b3ae508c
commit 379a52d6e7
23 changed files with 850 additions and 14 deletions
+3 -3
View File
@@ -18,7 +18,7 @@ const isMavenTestGoal = (a: string) =>
const isGradleJvmTask = (a: string) => /(^|:)(test|bootRun|run|integrationTest|check)$/.test(a);
/** A plugin goal that runs the application in Maven's own JVM (`tomcat7:run`, `jetty:run-war`, `exec:java`). */
const isMavenInProcessGoal = (a: string) => /^[\w.-]+(:[\w.-]+)*:(run|run-war|run-exploded|java)$/.test(a);
const JAVA_ADAPTER = "java-debug";
const JVM_ADAPTERS = ["java-debug", "kotlin-debug-adapter"];
function withOption(env: Record<string, string>, key: string, value: string): Record<string, string> {
const current = env[key]?.trim();
@@ -50,7 +50,7 @@ export function jdwpLaunch(config: RunConfig): RunConfig | null {
if (failsafe) out = withProperty(out, "maven.failsafe.debug", JDWP_AGENT);
return { ...config, args: out };
}
if (config.debugAdapter === JAVA_ADAPTER || args.some(isMavenInProcessGoal))
if (JVM_ADAPTERS.includes(config.debugAdapter ?? "") || args.some(isMavenInProcessGoal))
return { ...config, env: withOption(config.env, "MAVEN_OPTS", JDWP_AGENT) };
return null;
}
@@ -59,7 +59,7 @@ export function jdwpLaunch(config: RunConfig): RunConfig | null {
return args.includes("--debug-jvm") ? config : { ...config, args: [...args, "--debug-jvm"] };
}
// Application / Spring Boot configurations are launched by java-debug itself.
if (config.debugAdapter === JAVA_ADAPTER && !isJvmApplication(config))
if (JVM_ADAPTERS.includes(config.debugAdapter ?? "") && !isJvmApplication(config))
return { ...config, env: withOption(config.env, "JAVA_TOOL_OPTIONS", JDWP_AGENT) };
return null;
}