Skip to content

Commit

Permalink
Merge pull request #11886 from microsoft/main
Browse files Browse the repository at this point in the history
Merge for 1.19.2 (2nd time)
  • Loading branch information
sean-mcmanus authored Jan 20, 2024
2 parents f38926f + 3f1e851 commit 5077edf
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 24 deletions.
4 changes: 3 additions & 1 deletion Extension/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# C/C++ for Visual Studio Code Changelog

## Version 1.19.2: January 17, 2024
## Version 1.19.2: January 22, 2024
### Enhancements
* Implement progressive population of IntelliSense results. [#7759](https://github.com/microsoft/vscode-cpptools/issues/7759)
* Improve memory efficiency by using token parsing in the 'Add #include' feature. [#11515](https://github.com/microsoft/vscode-cpptools/issues/11515)
* Improve the types supported for the 'Add #include' code action.
* Various performance improvements.

Expand All @@ -16,6 +17,7 @@
* Fix German code analysis translations. [PR #11845](https://github.com/microsoft/vscode-cpptools/pull/11845)
* Thank you for the contribution [@Sir2B (Tobias Obermayer)](https://github.com/Sir2B)
* Fix an EACCES error when using include wildcards with system includes. [#11833](https://github.com/microsoft/vscode-cpptools/issues/11833)
* Fix IntelliSense passes occurring while a user is typing, not honoring the `C_Cpp.intelliSenseUpdateDelay` setting.
* Fix a call hierarchy bug leading to use of header-only TU's unnecessarily.
* Fix a bug that could lead to missing TU source file candidates.
* Fix a "random" IntelliSense crash during completion.
Expand Down
6 changes: 3 additions & 3 deletions Extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5811,17 +5811,17 @@
},
"configurationDefaults": {
"[cpp]": {
"editor.wordBasedSuggestions": false,
"editor.wordBasedSuggestions": "off",
"editor.suggest.insertMode": "replace",
"editor.semanticHighlighting.enabled": true
},
"[cuda-cpp]": {
"editor.wordBasedSuggestions": false,
"editor.wordBasedSuggestions": "off",
"editor.suggest.insertMode": "replace",
"editor.semanticHighlighting.enabled": true
},
"[c]": {
"editor.wordBasedSuggestions": false,
"editor.wordBasedSuggestions": "off",
"editor.suggest.insertMode": "replace",
"editor.semanticHighlighting.enabled": true
}
Expand Down
6 changes: 3 additions & 3 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import {
import { Location, TextEdit, WorkspaceEdit } from './commonTypes';
import * as configs from './configurations';
import { DataBinding } from './dataBinding';
import { CppSourceStr, clients, configPrefix, updateLanguageConfigurations } from './extension';
import { CppSourceStr, clients, configPrefix, updateLanguageConfigurations, watchForCrashes } from './extension';
import { LocalizeStringParams, getLocaleId, getLocalizedString } from './localization';
import { PersistentFolderState, PersistentWorkspaceState } from './persistentState';
import { createProtocolFilter } from './protocolFilter';
Expand Down Expand Up @@ -536,7 +536,7 @@ interface DidChangeActiveEditorParams {
}

// Requests
const InitializationRequest: RequestType<CppInitializationParams, void, void> = new RequestType<CppInitializationParams, void, void>('cpptools/initialize');
const InitializationRequest: RequestType<CppInitializationParams, string, void> = new RequestType<CppInitializationParams, string, void>('cpptools/initialize');
const QueryCompilerDefaultsRequest: RequestType<QueryDefaultCompilerParams, configs.CompilerDefaults, void> = new RequestType<QueryDefaultCompilerParams, configs.CompilerDefaults, void>('cpptools/queryCompilerDefaults');
const QueryTranslationUnitSourceRequest: RequestType<QueryTranslationUnitSourceParams, QueryTranslationUnitSourceResult, void> = new RequestType<QueryTranslationUnitSourceParams, QueryTranslationUnitSourceResult, void>('cpptools/queryTranslationUnitSource');
const SwitchHeaderSourceRequest: RequestType<SwitchHeaderSourceParams, string, void> = new RequestType<SwitchHeaderSourceParams, string, void>('cpptools/didSwitchHeaderSource');
Expand Down Expand Up @@ -1572,7 +1572,7 @@ export class DefaultClient implements Client {
// Move initialization to a separate message, so we can see log output from it.
// A request is used in order to wait for completion and ensure that no subsequent
// higher priority message may be processed before the Initialization request.
await languageClient.sendRequest(InitializationRequest, cppInitializationParams);
watchForCrashes(await languageClient.sendRequest(InitializationRequest, cppInitializationParams));
}

public async sendDidChangeSettings(): Promise<void> {
Expand Down
135 changes: 126 additions & 9 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as vscode from 'vscode';
import { Range } from 'vscode-languageclient';
import * as nls from 'vscode-nls';
import { TargetPopulation } from 'vscode-tas-client';
import * as which from 'which';
import { logAndReturn } from '../Utility/Async/returns';
import * as util from '../common';
import { PlatformInformation } from '../platform';
Expand Down Expand Up @@ -922,8 +923,8 @@ function reportMacCrashes(): void {
const crashObject: Record<string, string> = {};
if (err?.code) {
// If the directory isn't there, we have a problem...
crashObject["fs.stat: err.code"] = err.code;
telemetry.logLanguageServerEvent("MacCrash", crashObject, undefined);
crashObject["errCode"] = err.code;
telemetry.logLanguageServerEvent("MacCrash", crashObject);
return;
}

Expand Down Expand Up @@ -959,17 +960,64 @@ function reportMacCrashes(): void {
}
}

let previousMacCrashData: string;
let previousMacCrashCount: number = 0;
export function watchForCrashes(crashDirectory: string): void {
if (process.platform !== "win32") {
prevCrashFile = "";
fs.stat(crashDirectory, (err) => {
const crashObject: Record<string, string> = {};
if (err?.code) {
// If the directory isn't there, we have a problem...
crashObject["errCode"] = err.code;
telemetry.logLanguageServerEvent("CppCrash", crashObject);
return;
}

function logMacCrashTelemetry(data: string): void {
// vscode.workspace.createFileSystemWatcher only works in workspace folders.
try {
fs.watch(crashDirectory, (event, filename) => {
if (event !== "rename") {
return;
}
if (!filename || filename === prevCrashFile) {
return;
}
prevCrashFile = filename;
if (!filename.startsWith("cpptools")) {
return;
}
// Wait 5 seconds to allow time for the crash log to finish being written.
setTimeout(() => {
fs.readFile(path.resolve(crashDirectory, filename), 'utf8', (err, data) => {
void handleCrashFileRead(crashDirectory, filename, err, data);
});
}, 5000);
});
} catch (e) {
// The file watcher limit is hit (may not be possible on Mac, but just in case).
}
});
}
}

let previousCrashData: string;
let previousCrashCount: number = 0;

function logCrashTelemetry(data: string, type: string): void {
const crashObject: Record<string, string> = {};
const crashCountObject: Record<string, number> = {};
crashObject.CrashingThreadCallStack = data;
previousMacCrashCount = data === previousMacCrashData ? previousMacCrashCount + 1 : 0;
previousMacCrashData = data;
crashCountObject.CrashCount = previousMacCrashCount;
telemetry.logLanguageServerEvent("MacCrash", crashObject, crashCountObject);
previousCrashCount = data === previousCrashData ? previousCrashCount + 1 : 0;
previousCrashData = data;
crashCountObject.CrashCount = previousCrashCount + 1;
telemetry.logLanguageServerEvent(type, crashObject, crashCountObject);
}

function logMacCrashTelemetry(data: string): void {
logCrashTelemetry(data, "MacCrash");
}

function logCppCrashTelemetry(data: string): void {
logCrashTelemetry(data, "CppCrash");
}

function handleMacCrashFileRead(err: NodeJS.ErrnoException | undefined | null, data: string): void {
Expand Down Expand Up @@ -1062,6 +1110,75 @@ function handleMacCrashFileRead(err: NodeJS.ErrnoException | undefined | null, d
logMacCrashTelemetry(data);
}

async function handleCrashFileRead(crashDirectory: string, crashFile: string, err: NodeJS.ErrnoException | undefined | null, data: string): Promise<void> {
if (err) {
if (err.code === "ENOENT") {
return; // ignore known issue
}
return logCppCrashTelemetry("readFile: " + err.code);
}

const lines: string[] = data.split("\n");
data = crashFile + "\n";
const filtPath: string | null = which.sync("c++filt", { nothrow: true });
const isMac: boolean = process.platform === "darwin";
const startStr: string = isMac ? " _" : "(_";
const offsetStr: string = isMac ? " + " : "+0x";
const dotStr: string = "…";
for (let lineNum: number = 2; lineNum < lines.length - 3; ++lineNum) { // skip first/last lines
if (lineNum > 2) {
data += "\n";
}
const line: string = lines[lineNum];
const startPos: number = line.indexOf(startStr);
if (startPos === -1) {
data += dotStr;
continue; // expected
}
const offsetPos: number = line.indexOf(offsetStr, startPos + startStr.length);
if (offsetPos === -1) {
data += `missing "${offsetStr}"`;
continue; // unexpected
}
const startPos2: number = startPos + 1;
let funcStr: string = line.substring(startPos2, offsetPos);
if (filtPath) {
const ret = await util.spawnChildProcess(filtPath, [funcStr], undefined, true).catch(logAndReturn.undefined);
if (ret !== undefined) {
funcStr = ret.output;
funcStr = funcStr.replace(/std::(?:__1|__cxx11)/g, "std"); // simplify std namespaces.
funcStr = funcStr.replace(/std::basic_/g, "std::");
funcStr = funcStr.replace(/ >/g, ">");
funcStr = funcStr.replace(/, std::(?:allocator|char_traits)<char>/g, "");
funcStr = funcStr.replace(/<char>/g, "");
funcStr = funcStr.replace(/, std::allocator<std::string>/g, "");
}
}
data += funcStr + offsetStr;
const offsetPos2: number = offsetPos + offsetStr.length;
if (isMac) {
data += line.substring(offsetPos2);
} else {
const endPos: number = line.indexOf(")", offsetPos2);
if (endPos === -1) {
data += "missing )";
continue; // unexpected
}
data += line.substring(offsetPos2, endPos);
}
}

if (data.length > 8192) { // The API has an 8k limit.
data = data.substring(0, 8191) + "…";
}

console.log(`Crash call stack:\n${data}`);
logCppCrashTelemetry(data);

await util.deleteFile(path.resolve(crashDirectory, crashFile)).catch(logAndReturn.undefined);
void util.deleteDirectory(crashDirectory).catch(logAndReturn.undefined);
}

export function deactivate(): Thenable<void> {
clients.timeTelemetryCollector.clear();
console.log("deactivating extension");
Expand Down
34 changes: 26 additions & 8 deletions Extension/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,22 @@ export function deleteFile(filePath: string): Promise<void> {
});
}

export function deleteDirectory(directoryPath: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
if (fs.existsSync(directoryPath)) {
fs.rmdir(directoryPath, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
} else {
resolve();
}
});
}

export function getReadmeMessage(): string {
const readmePath: string = getExtensionFilePath("README.md");
const readmeMessage: string = localize("refer.read.me", "Please refer to {0} for troubleshooting information. Issues can be created at {1}", readmePath, "https://github.com/Microsoft/vscode-cpptools/issues");
Expand Down Expand Up @@ -736,14 +752,16 @@ export interface ProcessReturnType {
output: string;
}

export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, skipLogging?: boolean, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
// Do not use CppSettings to avoid circular require()
const settings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("C_Cpp", null);
const loggingLevel: string | undefined = settings.get<string>("loggingLevel");
if (loggingLevel === "Information" || loggingLevel === "Debug") {
getOutputChannelLogger().appendLine(`$ ${program} ${args.join(' ')}`);
if (skipLogging === undefined || !skipLogging) {
const settings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("C_Cpp", null);
const loggingLevel: string | undefined = settings.get<string>("loggingLevel");
if (loggingLevel === "Information" || loggingLevel === "Debug") {
getOutputChannelLogger().appendLine(`$ ${program} ${args.join(' ')}`);
}
}
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, cancellationToken);
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, skipLogging, cancellationToken);
const exitCode: number | NodeJS.Signals | undefined = programOutput.exitCode;
if (programOutput.exitCode) {
return { succeeded: false, exitCode, output: programOutput.stderr || programOutput.stdout || localize('process.exited', 'Process exited with code {0}', exitCode) };
Expand All @@ -765,12 +783,12 @@ interface ProcessOutput {
stderr: string;
}

async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessOutput> {
async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, skipLogging?: boolean, cancellationToken?: vscode.CancellationToken): Promise<ProcessOutput> {
const result = new ManualPromise<ProcessOutput>();

// Do not use CppSettings to avoid circular require()
const settings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("C_Cpp", null);
const loggingLevel: string | undefined = settings.get<string>("loggingLevel");
const loggingLevel: string | undefined = (skipLogging === undefined || !skipLogging) ? settings.get<string>("loggingLevel") : "None";

let proc: child_process.ChildProcess;
if (await isExecutable(program)) {
Expand Down

0 comments on commit 5077edf

Please sign in to comment.