src/goDebugFactory.ts: fix problem with attach requests

The current launch logic for delve dap assumes that the program
attribute is set. This is not true for attach requests. Use the current
directory to launch delve dap for attach requests.

Change-Id: I9acdc81c3227b5134c4858400e2df95abbc68b81
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/322030
Trust: Suzy Mueller <suzmue@golang.org>
Run-TryBot: Suzy Mueller <suzmue@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/src/debugAdapter/goDebug.ts b/src/debugAdapter/goDebug.ts
index 55a779c..1322e02 100644
--- a/src/debugAdapter/goDebug.ts
+++ b/src/debugAdapter/goDebug.ts
@@ -357,7 +357,7 @@
 }
 
 export function findPathSeparator(filePath: string) {
-	return filePath.includes('\\') ? '\\' : '/';
+	return filePath && filePath.includes('\\') ? '\\' : '/';
 }
 
 // Comparing two different file paths while ignoring any different path separators.
diff --git a/src/goDebugConfiguration.ts b/src/goDebugConfiguration.ts
index 78a66fc..f0b8479 100644
--- a/src/goDebugConfiguration.ts
+++ b/src/goDebugConfiguration.ts
@@ -186,7 +186,12 @@
 		if (!debugConfiguration.hasOwnProperty('substitutePath') && dlvConfig.hasOwnProperty('substitutePath')) {
 			debugConfiguration['substitutePath'] = dlvConfig['substitutePath'];
 		}
-		if (debugConfiguration.request === 'attach' && !debugConfiguration['cwd']) {
+		if (
+			debugAdapter !== 'dlv-dap' &&
+			debugConfiguration.request === 'attach' &&
+			debugConfiguration.mode === 'remote' &&
+			!debugConfiguration['cwd']
+		) {
 			debugConfiguration['cwd'] = '${workspaceFolder}';
 			if (vscode.workspace.workspaceFolders?.length > 1) {
 				debugConfiguration['cwd'] = '${fileWorkspaceFolder}';
diff --git a/src/goDebugFactory.ts b/src/goDebugFactory.ts
index b1341d3..e019f26 100644
--- a/src/goDebugFactory.ts
+++ b/src/goDebugFactory.ts
@@ -16,6 +16,7 @@
 import { getTool } from './goTools';
 import { Logger, TimestampedLogger } from './goLogging';
 import { DebugProtocol } from 'vscode-debugprotocol';
+import { getWorkspaceFolderPath } from './util';
 
 export class GoDebugAdapterDescriptorFactory implements vscode.DebugAdapterDescriptorFactory {
 	constructor(private outputChannel?: vscode.OutputChannel) {}
@@ -194,7 +195,7 @@
 // VSCode and a dlv dap process spawned and managed by this adapter.
 // It turns the process's stdout/stderrr into OutputEvent.
 export class DelveDAPOutputAdapter extends ProxyDebugAdapter {
-	constructor(private config: vscode.DebugConfiguration, logger?: Logger) {
+	constructor(private configuration: vscode.DebugConfiguration, logger?: Logger) {
 		super(logger);
 		this.connected = this.startAndConnectToServer();
 	}
@@ -276,7 +277,7 @@
 	private async startAndConnectToServer() {
 		try {
 			const { port, host, dlvDapServer } = await startDapServer(
-				this.config,
+				this.configuration,
 				(msg) => this.outputEvent('stdout', msg),
 				(msg) => this.outputEvent('stderr', msg),
 				(msg) => {
@@ -336,17 +337,17 @@
 }
 
 function spawnDlvDapServerProcess(
-	launchArgs: vscode.DebugConfiguration,
+	launchAttachArgs: vscode.DebugConfiguration,
 	host: string,
 	port: number,
 	log: (msg: string) => void,
 	logErr: (msg: string) => void,
 	logConsole: (msg: string) => void
 ): Promise<ChildProcess> {
-	const launchArgsEnv = launchArgs.env || {};
+	const launchArgsEnv = launchAttachArgs.env || {};
 	const env = Object.assign({}, process.env, launchArgsEnv);
 
-	const dlvPath = launchArgs.dlvToolPath ?? getTool('dlv-dap');
+	const dlvPath = launchAttachArgs.dlvToolPath ?? getTool('dlv-dap');
 
 	if (!fs.existsSync(dlvPath)) {
 		const envPath = process.env['PATH'] || (process.platform === 'win32' ? process.env['Path'] : null);
@@ -358,27 +359,29 @@
 		);
 		throw new Error('Cannot find Delve debugger (dlv dap)');
 	}
-	let dir = '';
-	try {
-		dir = parseProgramArgSync(launchArgs).dirname;
-	} catch (err) {
-		logErr(`Program arg: ${launchArgs.program}\n${err}\n`);
-		throw err; // rethrow so the caller knows it failed.
+	let dir = getWorkspaceFolderPath();
+	if (launchAttachArgs.request === 'launch') {
+		try {
+			dir = parseProgramArgSync(launchAttachArgs).dirname;
+		} catch (err) {
+			logErr(`Program arg: ${launchAttachArgs.program}\n${err}\n`);
+			throw err; // rethrow so the caller knows it failed.
+		}
 	}
 
 	const dlvArgs = new Array<string>();
 	dlvArgs.push('dap');
 	// add user-specified dlv flags first. When duplicate flags are specified,
 	// dlv doesn't mind but accepts the last flag value.
-	if (launchArgs.dlvFlags && launchArgs.dlvFlags.length > 0) {
-		dlvArgs.push(...launchArgs.dlvFlags);
+	if (launchAttachArgs.dlvFlags && launchAttachArgs.dlvFlags.length > 0) {
+		dlvArgs.push(...launchAttachArgs.dlvFlags);
 	}
 	dlvArgs.push(`--listen=${host}:${port}`);
-	if (launchArgs.showLog) {
-		dlvArgs.push('--log=' + launchArgs.showLog.toString());
+	if (launchAttachArgs.showLog) {
+		dlvArgs.push('--log=' + launchAttachArgs.showLog.toString());
 	}
-	if (launchArgs.logOutput) {
-		dlvArgs.push('--log-output=' + launchArgs.logOutput);
+	if (launchAttachArgs.logOutput) {
+		dlvArgs.push('--log-output=' + launchAttachArgs.logOutput);
 	}
 
 	const onWindows = process.platform === 'win32';
@@ -387,7 +390,7 @@
 		dlvArgs.push('--log-dest=3');
 	}
 
-	const logDest = launchArgs.logDest;
+	const logDest = launchAttachArgs.logDest;
 	if (typeof logDest === 'number') {
 		logErr(`Using a file descriptor for 'logDest' (${logDest}) is not allowed.\n`);
 		throw new Error('Using a file descriptor for `logDest` is not allowed.');
@@ -511,9 +514,9 @@
 }
 
 export function parseProgramArgSync(
-	launchArgs: vscode.DebugConfiguration
+	launchAttachArgs: vscode.DebugConfiguration
 ): { program: string; dirname: string; programIsDirectory: boolean } {
-	const program = launchArgs.program;
+	const program = launchAttachArgs.program;
 	if (!program) {
 		throw new Error('The program attribute is missing in the debug configuration in launch.json');
 	}
@@ -524,7 +527,7 @@
 		// TODO(hyangah): why can't the program be a package name?
 		throw new Error('The program attribute must point to valid directory, .go file or executable.');
 	}
-	if (!programIsDirectory && launchArgs.mode !== 'exec' && path.extname(program) !== '.go') {
+	if (!programIsDirectory && launchAttachArgs.mode !== 'exec' && path.extname(program) !== '.go') {
 		throw new Error('The program attribute must be a directory or .go file in debug and test mode');
 	}
 	const dirname = programIsDirectory ? program : path.dirname(program);