merge microsoft/vscode-go@430362e

Modified src/goLanguageServer.ts to include missing import
of ProvideCompletionItemsSignature, which was removed by a locally
commited cl.

Change-Id: If6b10d60573095a40e652068f49bc378188b5e80
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 466cf56..2e9768d 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -27,7 +27,7 @@
 	- <Paste VS Code version here>
 - Check your installed extensions to get the version of the VS Code Go extension 
 	- <Paste Go extension version here>
-- Run `go env GOOS GOARCH` to get the operating system and processor arhcitecture details
+- Run `go env GOOS GOARCH` to get the operating system and processor architecture details
 	- <Paste OS and arch details here>
 
 ### Share the Go related settings you have added/edited
diff --git a/.travis.yml b/.travis.yml
index 2ef17c0..b15bd22 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,6 @@
 
 os:
   - osx
-  - linux
 
 before_install:
   # Call xvfb directly on linux runs and give it time to start
diff --git a/src/debugAdapter/Readme.md b/src/debugAdapter/Readme.md
index 65e37e7..d80f71c 100644
--- a/src/debugAdapter/Readme.md
+++ b/src/debugAdapter/Readme.md
@@ -4,7 +4,7 @@
 
 Please see [The Debug Adapter Protocol](https://code.visualstudio.com/blogs/2018/08/07/debug-adapter-protocol-website) to understand how the Debug Adapter acts as an intermediary between VS Code and the debugger which in case of Go is [delve](https://github.com/derekparker/delve)
 
-# Preliminary steps
+## Set up local dev environment
 
 Clone this [repo](https://github.com/Microsoft/vscode-go) and then run `npm install`
 
diff --git a/src/debugAdapter/goDebug.ts b/src/debugAdapter/goDebug.ts
index c83a2a0..0e02e2b 100644
--- a/src/debugAdapter/goDebug.ts
+++ b/src/debugAdapter/goDebug.ts
@@ -132,6 +132,7 @@
 	id: number;
 	line: number;
 	pc: number;
+	goroutineID: number;
 	function?: DebugFunction;
 }
 
@@ -153,6 +154,7 @@
 	goType: number;
 	args: DebugVariable[];
 	locals: DebugVariable[];
+	optimized: boolean;
 }
 
 interface ListVarsOut {
@@ -305,9 +307,16 @@
 	logger.error(logArgsToString(args));
 }
 
+function findPathSeparator(filePath: string) {
+	return filePath.includes('/') ? '/' : '\\';
+}
+
 function normalizePath(filePath: string) {
 	if (process.platform === 'win32') {
+		const pathSeparator = findPathSeparator(filePath);
 		filePath = path.normalize(filePath);
+		// Normalize will replace everything with backslash on Windows.
+		filePath = filePath.replace(/\\/g, pathSeparator);
 		return fixDriveCasingInWindows(filePath);
 	}
 	return filePath;
@@ -693,7 +702,7 @@
 					await this.callPromise('Detach', [this.isApiV1 ? true : { Kill: isLocalDebugging }]);
 				} catch (err) {
 					log('DetachResponse');
-					logError(`Failed to detach - ${err.toString() || ''}`);
+					logError(err, 'Failed to detach');
 					shouldForceClean = isLocalDebugging;
 				}
 			}
@@ -754,13 +763,6 @@
 		log('InitializeResponse');
 	}
 
-	protected findPathSeperator(filePath: string) {
-		if (/^(\w:[\\/]|\\\\)/.test(filePath)) {
-			return '\\';
-		}
-		return filePath.includes('/') ? '/' : '\\';
-	}
-
 	protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
 		if (!args.program) {
 			this.sendErrorResponse(
@@ -835,10 +837,12 @@
 		if (this.delve.remotePath.length === 0) {
 			return this.convertClientPathToDebugger(filePath);
 		}
+		// The filePath may have a different path separator than the localPath
+		// So, update it to use the same separator as the remote path to ease
+		// in replacing the local path in it with remote path
+		filePath = filePath.replace(/\/|\\/g, this.remotePathSeparator);
 		return filePath
-			.replace(this.delve.program, this.delve.remotePath)
-			.split(this.localPathSeparator)
-			.join(this.remotePathSeparator);
+			.replace(this.delve.program.replace(/\/|\\/g, this.remotePathSeparator), this.delve.remotePath);
 	}
 
 	protected toLocalPath(pathToConvert: string): string {
@@ -872,7 +876,7 @@
 			// We use NonBlocking so the call would return immediately.
 			this.debugState = await this.delve.getDebugState();
 		} catch (error) {
-			logError(`Failed to get state ${String(error)}`);
+			this.logDelveError(error, 'Failed to get state');
 		}
 
 		if (!this.debugState.Running && !this.continueRequestRunning) {
@@ -883,15 +887,13 @@
 				() => {
 					return this.setBreakPoints(response, args).then(() => {
 						return this.continue(true).then(null, (err) => {
-							logError(
-								`Failed to continue delve after halting it to set breakpoints: "${err.toString()}"`
-							);
+							this.logDelveError(err, 'Failed to continue delve after halting it to set breakpoints');
 						});
 					});
 				},
 				(err) => {
 					this.skipStopEventOnce = false;
-					logError(err);
+					this.logDelveError(err, 'Failed to halt delve before attempting to set breakpoint');
 					return this.sendErrorResponse(
 						response,
 						2008,
@@ -919,7 +921,7 @@
 			}
 
 			if (err) {
-				logError('Failed to get threads - ' + err.toString());
+				this.logDelveError(err, 'Failed to get threads');
 				return this.sendErrorResponse(response, 2003, 'Unable to display threads: "{e}"', {
 					e: err.toString()
 				});
@@ -961,7 +963,7 @@
 			[stackTraceIn],
 			(err, out) => {
 				if (err) {
-					logError('Failed to produce stack trace!');
+					this.logDelveError(err, 'Failed to produce stacktrace');
 					return this.sendErrorResponse(response, 2004, 'Unable to produce stack trace: "{e}"', {
 						e: err.toString()
 					});
@@ -1002,7 +1004,7 @@
 			this.delve.isApiV1 ? [listLocalVarsIn] : [{ scope: listLocalVarsIn, cfg: this.delve.loadConfig }],
 			(err, out) => {
 				if (err) {
-					logError('Failed to list local variables - ' + err.toString());
+					this.logDelveError(err, 'Failed to get list local variables');
 					return this.sendErrorResponse(response, 2005, 'Unable to list locals: "{e}"', {
 						e: err.toString()
 					});
@@ -1018,7 +1020,7 @@
 						: [{ scope: listLocalFunctionArgsIn, cfg: this.delve.loadConfig }],
 					(listFunctionErr, outArgs) => {
 						if (listFunctionErr) {
-							logError('Failed to list function args - ' + listFunctionErr.toString());
+							this.logDelveError(listFunctionErr, 'Failed to list function args');
 							return this.sendErrorResponse(response, 2006, 'Unable to list args: "{e}"', {
 								e: listFunctionErr.toString()
 							});
@@ -1098,7 +1100,7 @@
 								this.delve.isApiV1 ? [filter] : [{ filter, cfg: this.delve.loadConfig }],
 								(listPkgVarsErr, listPkgVarsOut) => {
 									if (listPkgVarsErr) {
-										logError('Failed to list global vars - ' + listPkgVarsErr.toString());
+										this.logDelveError(listPkgVarsErr, 'Failed to list global vars');
 										return this.sendErrorResponse(
 											response,
 											2007,
@@ -1170,7 +1172,7 @@
 						const variable = this.delve.isApiV1 ? <DebugVariable>result : (<EvalOut>result).Variable;
 						v.children = variable.children;
 					},
-					(err) => logError('Failed to evaluate expression - ' + err.toString())
+					(err) => this.logDelveError(err, 'Failed to evaluate expression')
 				);
 			}
 		};
@@ -1249,7 +1251,7 @@
 		log('NextRequest');
 		this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'next' }], (err, out) => {
 			if (err) {
-				logError('Failed to next - ' + err.toString());
+				this.logDelveError(err, 'Failed to next');
 			}
 			const state = this.delve.isApiV1 ? <DebuggerState>out : (<CommandOut>out).State;
 			log('next state', state);
@@ -1264,7 +1266,7 @@
 		log('StepInRequest');
 		this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'step' }], (err, out) => {
 			if (err) {
-				logError('Failed to step - ' + err.toString());
+				this.logDelveError(err, 'Failed to step in');
 			}
 			const state = this.delve.isApiV1 ? <DebuggerState>out : (<CommandOut>out).State;
 			log('stop state', state);
@@ -1279,7 +1281,7 @@
 		log('StepOutRequest');
 		this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'stepOut' }], (err, out) => {
 			if (err) {
-				logError('Failed to stepout - ' + err.toString());
+				this.logDelveError(err, 'Failed to step out');
 			}
 			const state = this.delve.isApiV1 ? <DebuggerState>out : (<CommandOut>out).State;
 			log('stepout state', state);
@@ -1294,7 +1296,7 @@
 		log('PauseRequest');
 		this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'halt' }], (err, out) => {
 			if (err) {
-				logError('Failed to halt - ' + err.toString());
+				this.logDelveError(err, 'Failed to halt');
 				return this.sendErrorResponse(response, 2010, 'Unable to halt execution: "{e}"', {
 					e: err.toString()
 				});
@@ -1343,7 +1345,7 @@
 		this.delve.call(this.delve.isApiV1 ? 'SetSymbol' : 'Set', [setSymbolArgs], (err) => {
 			if (err) {
 				const errMessage = `Failed to set variable: ${err.toString()}`;
-				logError(errMessage);
+				this.logDelveError(err, 'Failed to set variable');
 				return this.sendErrorResponse(response, 2010, errMessage);
 			}
 			response.body = { value: args.value };
@@ -1392,8 +1394,8 @@
 		}
 
 		if (args.remotePath.length > 0) {
-			this.localPathSeparator = this.findPathSeperator(localPath);
-			this.remotePathSeparator = this.findPathSeperator(args.remotePath);
+			this.localPathSeparator = findPathSeparator(localPath);
+			this.remotePathSeparator = findPathSeparator(args.remotePath);
 
 			const llist = localPath.split(/\/|\\/).reverse();
 			const rlist = args.remotePath.split(/\/|\\/).reverse();
@@ -1741,7 +1743,7 @@
 			// [TODO] Can we avoid doing this? https://github.com/Microsoft/vscode/issues/40#issuecomment-161999881
 			this.delve.call<DebugGoroutine[] | ListGoroutinesOut>('ListGoroutines', [], (err, out) => {
 				if (err) {
-					logError('Failed to get threads - ' + err.toString());
+					this.logDelveError(err, 'Failed to get threads');
 				}
 				const goroutines = this.delve.isApiV1 ? <DebugGoroutine[]>out : (<ListGoroutinesOut>out).Goroutines;
 				this.updateGoroutinesList(goroutines);
@@ -1781,7 +1783,7 @@
 		if (!calledWhenSettingBreakpoint) {
 			errorCallback = (err: any) => {
 				if (err) {
-					logError('Failed to continue - ' + err.toString());
+					this.logDelveError(err, 'Failed to continue');
 				}
 				this.handleReenterDebug('breakpoint');
 				throw err;
@@ -1818,7 +1820,7 @@
 			.then(
 				(val) => val,
 				(err) => {
-					logError(
+					log(
 						'Failed to eval expression: ',
 						JSON.stringify(evalSymbolArgs, null, ' '),
 						'\n\rEval error:',
@@ -1838,6 +1840,87 @@
 			});
 		});
 	}
+
+	private logDelveError(err: any, message: string) {
+		if (err === undefined) {
+			return;
+		}
+
+		let errorMessage = err.toString();
+		// Handle unpropagated fatalpanic errors with a more user friendly message:
+		// https://github.com/microsoft/vscode-go/issues/1903#issuecomment-460126884
+		// https://github.com/go-delve/delve/issues/852
+		// This affects macOS only although we're agnostic of the OS at this stage, only handle the error
+		if (errorMessage === 'bad access') {
+			errorMessage = 'unpropagated fatalpanic: signal SIGSEGV (EXC_BAD_ACCESS). This fatalpanic is not traceable on macOS, see https://github.com/go-delve/delve/issues/852';
+		}
+
+		logError(message + ' - ' + errorMessage);
+
+		if (errorMessage === 'bad access') {
+			logError('WARNING: this stack might not be from the expected active goroutine');
+		}
+
+		this.dumpStacktrace();
+	}
+
+	private async dumpStacktrace() {
+		// Get current goroutine
+		// Debugger may be stopped at this point but we still can (and need) to obtain state and stacktrace
+		let goroutineId = 0;
+		try {
+			const stateCallResult = await this.delve.getDebugState();
+			// In some fault scenarios there may not be a currentGoroutine available from the debugger state
+			// Use the current thread
+			if (!stateCallResult.currentGoroutine) {
+				goroutineId = stateCallResult.currentThread.goroutineID;
+			} else {
+				goroutineId = stateCallResult.currentGoroutine.id;
+			}
+		} catch (error) {
+			logError('dumpStacktrace - Failed to get debugger state ' + error);
+		}
+
+		// Get goroutine stacktrace
+		const stackTraceIn = { id: goroutineId, depth: this.delve.stackTraceDepth };
+		if (!this.delve.isApiV1) {
+			Object.assign(stackTraceIn, { full: false, cfg: this.delve.loadConfig });
+		}
+		this.delve.call<DebugLocation[] | StacktraceOut>(
+			this.delve.isApiV1 ?
+				'StacktraceGoroutine' : 'Stacktrace', [stackTraceIn], (err, out) => {
+					if (err) {
+						logError('dumpStacktrace: Failed to produce stack trace' + err);
+						return;
+					}
+					const locations = this.delve.isApiV1 ? <DebugLocation[]>out : (<StacktraceOut>out).Locations;
+					log('locations', locations);
+					const stackFrames = locations.map((location, frameId) => {
+						const uniqueStackFrameId = this.stackFrameHandles.create([goroutineId, frameId]);
+						return new StackFrame(
+							uniqueStackFrameId,
+							location.function ? location.function.name : '<unknown>',
+							location.file === '<autogenerated>' ? null : new Source(
+								path.basename(location.file),
+								this.toLocalPath(location.file)
+							),
+							location.line,
+							0
+						);
+					});
+
+					// Dump stacktrace into error logger
+					logError(`Last known immediate stacktrace (goroutine id ${goroutineId}):`);
+					let output = '';
+					stackFrames.forEach((stackFrame) => {
+						output = output.concat(`\t${stackFrame.source.path}:${stackFrame.line}\n`);
+						if (stackFrame.name) {
+							output = output.concat(`\t\t${stackFrame.name}\n`);
+						}
+					});
+					logError(output);
+				});
+	}
 }
 
 function random(low: number, high: number): number {
diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts
index 9f4e3ff..a2be111 100644
--- a/src/goInstallTools.ts
+++ b/src/goInstallTools.ts
@@ -360,11 +360,18 @@
 	}
 	const goVersion = await getGoVersion();
 	const updateMsg = `Your version of ${tool.name} appears to be out of date. Please update for an improved experience.`;
-	vscode.window.showInformationMessage(updateMsg, 'Update').then((selected) => {
+	const choices: string[] = ['Update'];
+	if (toolName === `gopls`) {
+		choices.push('Release Notes');  // TODO(hyangah): pass more info such as version, release note location.
+	}
+	vscode.window.showInformationMessage(updateMsg, ...choices).then((selected) => {
 		switch (selected) {
 			case 'Update':
 				installTools([tool], goVersion);
 				break;
+			case 'Release Notes':
+				vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://github.com/golang/go/issues/33030#issuecomment-510151934'));
+				break;
 			default:
 				declinedUpdates.push(tool);
 				break;
diff --git a/src/goLanguageServer.ts b/src/goLanguageServer.ts
index 0679313..cf0d0f2 100644
--- a/src/goLanguageServer.ts
+++ b/src/goLanguageServer.ts
@@ -12,9 +12,11 @@
 import util = require('util');
 import vscode = require('vscode');
 import {
+	Command,
 	FormattingOptions,
 	HandleDiagnosticsSignature,
 	LanguageClient,
+	ProvideCompletionItemsSignature,
 	ProvideDocumentFormattingEditsSignature,
 	ProvideDocumentLinksSignature,
 	RevealOutputChannelOn
@@ -132,6 +134,55 @@
 						return null;
 					}
 					return next(document, token);
+				},
+				provideCompletionItem: (
+					document: vscode.TextDocument,
+					position: vscode.Position,
+					context: vscode.CompletionContext,
+					token: vscode.CancellationToken,
+					next: ProvideCompletionItemsSignature
+				) => {
+					// TODO(hyangah): when v1.42+ api is available, we can simplify
+					// language-specific configuration lookup using the new
+					// ConfigurationScope.
+					//    const paramHintsEnabled = vscode.workspace.getConfiguration(
+					//          'editor.parameterHints',
+					//          { languageId: 'go', uri: document.uri });
+
+					const editorParamHintsEnabled = vscode.workspace.getConfiguration(
+						'editor.parameterHints', document.uri)['enabled'];
+					const goParamHintsEnabled = vscode.workspace.getConfiguration(
+						'[go]', document.uri)['editor.parameterHints.enabled'];
+
+					let paramHintsEnabled: boolean = false;
+					if (typeof goParamHintsEnabled === 'undefined') {
+						paramHintsEnabled = editorParamHintsEnabled;
+					} else {
+						paramHintsEnabled = goParamHintsEnabled;
+					}
+					let cmd: Command;
+					if (paramHintsEnabled) {
+						cmd = { title: 'triggerParameterHints', command: 'editor.action.triggerParameterHints' };
+					}
+
+					function configureCommands(
+						r: vscode.CompletionItem[] | vscode.CompletionList | null | undefined):
+						vscode.CompletionItem[] | vscode.CompletionList | null | undefined {
+						if (r) {
+							(Array.isArray(r) ? r : r.items).forEach((i: vscode.CompletionItem) => {
+								i.command = cmd;
+							});
+						}
+						return r;
+					}
+					const ret = next(document, position, context, token);
+
+					const isThenable = <T>(obj: vscode.ProviderResult<T>): obj is Thenable<T> => obj && (<any>obj)['then'];
+					if (isThenable<vscode.CompletionItem[] | vscode.CompletionList | null | undefined>(ret)) {
+						return ret.then(configureCommands);
+					}
+					return configureCommands(ret);
+
 				}
 			}
 		}
diff --git a/src/goLint.ts b/src/goLint.ts
index d014566..818e115 100644
--- a/src/goLint.ts
+++ b/src/goLint.ts
@@ -120,6 +120,11 @@
 			// print only file:number:column
 			args.push('--print-issued-lines=false');
 		}
+		if (args.indexOf('--out-format=colored-line-number') === -1) {
+			// print file:number:column.
+			// Explicit override in case .golangci.yml calls for a format we don't understand
+			args.push('--out-format=colored-line-number');
+		}
 	}
 
 	if (scope === 'workspace' && currentWorkspace) {