From b25fb3fd0e852fcc50fd71c9f25f7e38718cb576 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Mon, 16 May 2022 17:56:51 -0700 Subject: [PATCH 1/9] Update Mac crash telemetry for cpptools-wordexp. (#9308) * Update Mac crash telemetry for cpptools-wordexp. --- Extension/src/LanguageServer/extension.ts | 24 ++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 1b4837b4f..92400207c 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -872,17 +872,19 @@ function handleMacCrashFileRead(err: NodeJS.ErrnoException | undefined | null, d data = data.replace(/0x1........ \+ 0/g, ""); // Get rid of the process names on each line and just add it to the start. - const process1: string = "cpptools-srv"; - const process2: string = "cpptools"; - if (data.includes(process1)) { - data = data.replace(new RegExp(process1 + "\\s+", "g"), ""); - data = `${process1}\t${binaryVersion}\n${data}`; - } else if (data.includes(process2)) { - data = data.replace(new RegExp(process2 + "\\s+", "g"), ""); - data = `${process2}\t${binaryVersion}\n${data}`; - } else { - // Not expected, but just in case. - data = `cpptools?\t${binaryVersion}\n${data}`; + const processNames: string[] = ["cpptools-srv", "cpptools-wordexp", "cpptools" ]; + let processNameFound: boolean = false; + for (const processName of processNames) { + if (data.includes(processName)) { + data = data.replace(new RegExp(processName + "\\s+", "g"), ""); + data = `${processName}\t${binaryVersion}\n${data}`; + processNameFound = true; + break; + } + } + if (!processNameFound) { + // Not expected, but just in case a new binary gets added. + data = `cpptools???\t${binaryVersion}\n${data}`; } // Remove runtime lines because they can be different on different machines. From b294eb7a9c5bbcebfaf2141991520b1233d20bd2 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Wed, 18 May 2022 10:59:19 -0700 Subject: [PATCH 2/9] Remove [Log] editor.wordWrap "off" default. (#9313) --- Extension/package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index 5a41ed75b..86dc3e0ba 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -3953,9 +3953,6 @@ "editor.wordBasedSuggestions": false, "editor.suggest.insertMode": "replace", "editor.semanticHighlighting.enabled": true - }, - "[Log]": { - "editor.wordWrap": "off" } }, "semanticTokenTypes": [ From 9cc30c2ccdc688572c46aaee219cebc398e7ca36 Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Wed, 18 May 2022 15:31:15 -0700 Subject: [PATCH 3/9] Microsoft mandatory file (#9326) Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> --- SECURITY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..869fdfe2b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + + From bf2674fd0c3d390fba0eddaa0465ae01cffeff92 Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Wed, 18 May 2022 16:10:20 -0700 Subject: [PATCH 4/9] Add code analysis code action fixes (#9202) * Add code analysis code action fixes --- Extension/package.json | 78 ++- Extension/package.nls.json | 9 +- .../Providers/codeActionProvider.ts | 180 +++++ .../documentFormattingEditProvider.ts | 10 +- .../documentRangeFormattingEditProvider.ts | 11 +- .../Providers/documentSymbolProvider.ts | 5 +- .../Providers/onTypeFormattingEditProvider.ts | 13 +- .../Providers/workspaceSymbolProvider.ts | 5 +- Extension/src/LanguageServer/client.ts | 636 ++++++++++++++---- Extension/src/LanguageServer/extension.ts | 68 +- Extension/src/LanguageServer/settings.ts | 11 + Extension/src/LanguageServer/utils.ts | 40 ++ Extension/src/nativeStrings.json | 5 +- 13 files changed, 899 insertions(+), 172 deletions(-) create mode 100644 Extension/src/LanguageServer/Providers/codeActionProvider.ts create mode 100644 Extension/src/LanguageServer/utils.ts diff --git a/Extension/package.json b/Extension/package.json index 86dc3e0ba..454e6fa80 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -73,7 +73,7 @@ "onCommand:C_Cpp.RunCodeAnalysisOnActiveFile", "onCommand:C_Cpp.RunCodeAnalysisOnOpenFiles", "onCommand:C_Cpp.RunCodeAnalysisOnAllFiles", - "onCommand:C_Cpp.ClearCodeAnalysisSquiggles", + "onCommand:C_Cpp.RemoveAllCodeAnalysisProblems", "onDebugResolve:cppdbg", "onDebugResolve:cppvsdbg", "workspaceContains:/.vscode/c_cpp_properties.json", @@ -416,6 +416,36 @@ }, "scope": "resource" }, + "C_Cpp.codeAnalysis.clangTidy.codeAction.showClear": { + "type": "string", + "description": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.description%", + "enum": [ + "None", + "AllOnly", + "AllAndAllType", + "AllAndAllTypeAndThis" + ], + "enumDescriptions": [ + "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.None.description%", + "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllOnly.description%", + "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllType.description%", + "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllTypeAndThis.description%" + ], + "default": "AllAndAllTypeAndThis", + "scope": "application" + }, + "C_Cpp.codeAnalysis.clangTidy.codeAction.showDisable": { + "type": "boolean", + "markdownDescription": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDisable.markdownDescription%", + "default": true, + "scope": "application" + }, + "C_Cpp.codeAnalysis.clangTidy.codeAction.showDocumentation": { + "type": "boolean", + "markdownDescription": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDocumentation.markdownDescription%", + "default": true, + "scope": "application" + }, "C_Cpp.codeAnalysis.runAutomatically": { "type": "boolean", "markdownDescription": "%c_cpp.configuration.codeAnalysis.runAutomatically.markdownDescription%", @@ -473,6 +503,7 @@ "enum": [ "*", "abseil-*", + "abseil-cleanup-ctad", "abseil-duration-*", "abseil-duration-addition", "abseil-duration-comparison", @@ -567,9 +598,11 @@ "bugprone-string-constructor", "bugprone-string-integer-assignment", "bugprone-string-literal-with-embedded-nul", + "bugprone-stringview-nullptr", "bugprone-suspicious-*", "bugprone-suspicious-enum-usage", "bugprone-suspicious-include", + "bugprone-suspicious-memory-comparison", "bugprone-suspicious-memset-usage", "bugprone-suspicious-missing-comma", "bugprone-suspicious-semicolon", @@ -604,13 +637,17 @@ "cert-env33-c", "cert-err*", "cert-err09-cpp", + "cert-err33-c", "cert-err34-c", "cert-err52-cpp", "cert-err58-cpp", "cert-err60-cpp", "cert-err61-cpp", + "cert-exp42-c", "cert-fio38-c", + "cert-flp*", "cert-flp30-c", + "cert-flp37-c", "cert-mem57-cpp", "cert-msc*", "cert-msc30-c", @@ -622,7 +659,9 @@ "cert-oop54-cpp", "cert-oop57-cpp", "cert-oop58-cpp", + "cert-pos*", "cert-pos44-c", + "cert-pos47-c", "cert-sig30-c", "cert-str34-c", "clang-analyzer-*", @@ -763,6 +802,7 @@ "cppcoreguidelines-pro-type-vararg", "cppcoreguidelines-slicing", "cppcoreguidelines-special-member-functions", + "cppcoreguidelines-virtual-class-destructor", "darwin-*", "darwin-avoid-spinlock", "darwin-dispatch-once-nonstatic", @@ -853,6 +893,9 @@ "llvmlibc-restrict-system-libc-headers", "misc-*", "misc-definitions-in-headers", + "misc-misleading-*", + "misc-misleading-bidirectional", + "misc-misleading-identifier", "misc-misplaced-const", "misc-new-delete-overloads", "misc-no-recursion", @@ -910,6 +953,7 @@ "mpi-buffer-deref", "mpi-type-mismatch", "objc-*", + "objc-assert-equals", "objc-avoid-nserror-init", "objc-dealloc-in-category", "objc-forbidden-subclassing", @@ -947,13 +991,19 @@ "readability-avoid-const-params-in-decls", "readability-braces-around-statements", "readability-const-return-type", + "readability-container-*", + "readability-container-contains", + "readability-container-data-pointer", "readability-container-size-empty", "readability-convert-member-functions-to-static", "readability-delete-null-pointer", + "readability-duplicate-include", "readability-else-after-return", "readability-function-*", "readability-function-cognitive-complexity", "readability-function-size", + "readability-identifier-*", + "readability-identifier-length", "readability-identifier-naming", "readability-implicit-bool-conversion", "readability-inconsistent-declaration-parameter-name", @@ -983,6 +1033,7 @@ "readability-static-accessed-through-instance", "readability-static-definition-in-anonymous-namespace", "readability-string-compare", + "readability-suspicious-call-argument", "readability-uniqueptr-delete-release", "readability-uppercase-literal-suffix", "readability-use-anyofallof", @@ -999,6 +1050,7 @@ "enum": [ "*", "abseil-*", + "abseil-cleanup-ctad", "abseil-duration-*", "abseil-duration-addition", "abseil-duration-comparison", @@ -1093,9 +1145,11 @@ "bugprone-string-constructor", "bugprone-string-integer-assignment", "bugprone-string-literal-with-embedded-nul", + "bugprone-stringview-nullptr", "bugprone-suspicious-*", "bugprone-suspicious-enum-usage", "bugprone-suspicious-include", + "bugprone-suspicious-memory-comparison", "bugprone-suspicious-memset-usage", "bugprone-suspicious-missing-comma", "bugprone-suspicious-semicolon", @@ -1130,13 +1184,17 @@ "cert-env33-c", "cert-err*", "cert-err09-cpp", + "cert-err33-c", "cert-err34-c", "cert-err52-cpp", "cert-err58-cpp", "cert-err60-cpp", "cert-err61-cpp", + "cert-exp42-c", "cert-fio38-c", + "cert-flp*", "cert-flp30-c", + "cert-flp37-c", "cert-mem57-cpp", "cert-msc*", "cert-msc30-c", @@ -1148,7 +1206,9 @@ "cert-oop54-cpp", "cert-oop57-cpp", "cert-oop58-cpp", + "cert-pos*", "cert-pos44-c", + "cert-pos47-c", "cert-sig30-c", "cert-str34-c", "clang-analyzer-*", @@ -1289,6 +1349,7 @@ "cppcoreguidelines-pro-type-vararg", "cppcoreguidelines-slicing", "cppcoreguidelines-special-member-functions", + "cppcoreguidelines-virtual-class-destructor", "darwin-*", "darwin-avoid-spinlock", "darwin-dispatch-once-nonstatic", @@ -1379,6 +1440,9 @@ "llvmlibc-restrict-system-libc-headers", "misc-*", "misc-definitions-in-headers", + "misc-misleading-*", + "misc-misleading-bidirectional", + "misc-misleading-identifier", "misc-misplaced-const", "misc-new-delete-overloads", "misc-no-recursion", @@ -1436,6 +1500,7 @@ "mpi-buffer-deref", "mpi-type-mismatch", "objc-*", + "objc-assert-equals", "objc-avoid-nserror-init", "objc-dealloc-in-category", "objc-forbidden-subclassing", @@ -1473,13 +1538,19 @@ "readability-avoid-const-params-in-decls", "readability-braces-around-statements", "readability-const-return-type", + "readability-container-*", + "readability-container-contains", + "readability-container-data-pointer", "readability-container-size-empty", "readability-convert-member-functions-to-static", "readability-delete-null-pointer", + "readability-duplicate-include", "readability-else-after-return", "readability-function-*", "readability-function-cognitive-complexity", "readability-function-size", + "readability-identifier-*", + "readability-identifier-length", "readability-identifier-naming", "readability-implicit-bool-conversion", "readability-inconsistent-declaration-parameter-name", @@ -1509,6 +1580,7 @@ "readability-static-accessed-through-instance", "readability-static-definition-in-anonymous-namespace", "readability-string-compare", + "readability-suspicious-call-argument", "readability-uniqueptr-delete-release", "readability-uppercase-literal-suffix", "readability-use-anyofallof", @@ -2736,8 +2808,8 @@ "category": "C/C++" }, { - "command": "C_Cpp.ClearCodeAnalysisSquiggles", - "title": "%c_cpp.command.ClearCodeAnalysisSquiggles.title%", + "command": "C_Cpp.RemoveAllCodeAnalysisProblems", + "title": "%c_cpp.command.RemoveAllCodeAnalysisProblems.title%", "category": "C/C++" }, { diff --git a/Extension/package.nls.json b/Extension/package.nls.json index ce077de1d..dc5262c15 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -24,7 +24,7 @@ "c_cpp.command.RunCodeAnalysisOnActiveFile.title": "Run Code Analysis on Active File", "c_cpp.command.RunCodeAnalysisOnOpenFiles.title": "Run Code Analysis on Open Files", "c_cpp.command.RunCodeAnalysisOnAllFiles.title": "Run Code Analysis on All Files", - "c_cpp.command.ClearCodeAnalysisSquiggles.title": "Clear Code Analysis Squiggles", + "c_cpp.command.RemoveAllCodeAnalysisProblems.title": "Clear All Code Analysis Problems", "c_cpp.command.BuildAndDebugFile.title": "Debug C/C++ File", "c_cpp.command.BuildAndRunFile.title": "Run C/C++ File", "c_cpp.command.AddDebugConfiguration.title": "Add Debug Configuration", @@ -43,6 +43,13 @@ "c_cpp.configuration.codeAnalysis.excludeBoolean.markdownDescription": { "message": "The glob pattern to match file paths against. Set to `true` or `false` to enable or disable the pattern.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, "c_cpp.configuration.codeAnalysis.excludeWhen.markdownDescription": { "message": "Additional check on the siblings of a matching file. Use `$(basename)` as variable for the matching file name.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, "c_cpp.configuration.codeAnalysis.runAutomatically.markdownDescription": { "message": "If `true`, code analysis will run automatically on a file after it is opened or saved.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDisable.markdownDescription": { "message": "If `true`, the 'Disable' code action will be shown when available (the next time code analysis is run). When the 'Disable' code action is used, it adds the warning code to the `C_Cpp.codeAnalysis.clangTidy.checks.disabled` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDocumentation.markdownDescription": { "message": "If `true`, the 'Show Documentation for' code action will be shown when available (the next time code analysis is run).", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.description": "Controls which 'Clear' code analysis problem code action options are available. Changing the setting to show more options may require re-running code analysis.", + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.None.description": "Show no 'Clear' code actions.", + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllOnly.description": "Show only the 'Clear all' code action (or 'Clear all ' if there is only one type or 'Clear this' if there is only one problem).", + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllType.description": "Show the 'Clear all' code action (if there are multiple problem types) and the 'Clear all ' code action (or 'Clear this' if there is only one problem for the )", + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllTypeAndThis.description": "Show the 'Clear all' (if there are multiple problem types), 'Clear all ' (if there are multiple problems for the ), and 'Clear this' code actions", "c_cpp.configuration.codeAnalysis.clangTidy.enabled.markdownDescription": { "message": "If `true`, code analysis using `clang-tidy` will be enabled and run automatically if `#C_Cpp.codeAnalysis.runAutomatically#` is `true` (the default).", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, "c_cpp.configuration.codeAnalysis.clangTidy.path.markdownDescription": { "message": "The full path of the `clang-tidy` executable. If not specified, and `clang-tidy` is available in the environment path, that is used. If not found in the environment path, the `clang-tidy` bundled with the extension will be used.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, "c_cpp.configuration.codeAnalysis.clangTidy.config.markdownDescription": { "message": "Specifies a `clang-tidy` configuration in YAML/JSON format: `{Checks: '-*,clang-analyzer-*', CheckOptions: [{key: x, value: y}]}`. When the value is empty, `clang-tidy` will attempt to find a file named `.clang-tidy` for each source file in its parent directories.", "comment": [ "Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, diff --git a/Extension/src/LanguageServer/Providers/codeActionProvider.ts b/Extension/src/LanguageServer/Providers/codeActionProvider.ts new file mode 100644 index 000000000..d9b19c33f --- /dev/null +++ b/Extension/src/LanguageServer/Providers/codeActionProvider.ts @@ -0,0 +1,180 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. + * See 'LICENSE' in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +import * as vscode from 'vscode'; +import { Position, Range, RequestType, TextEdit } from 'vscode-languageclient'; +import * as util from '../../common'; +import { CodeActionCodeInfo, CodeActionDiagnosticInfo, codeAnalysisFileToCodeActions, codeAnalysisCodeToFixes, + codeAnalysisAllFixes, DefaultClient } from '../client'; +import { makeVscodeRange } from '../utils'; +import { CppSettings } from '../settings'; + +type LocalizeStringParams = util.LocalizeStringParams; + +interface GetCodeActionsRequestParams { + uri: string; + range: Range; +} + +interface CodeActionCommand { + localizeStringParams: LocalizeStringParams; + command: string; + arguments?: any[]; + edit?: TextEdit; + uri?: string; +} + +export const GetCodeActionsRequest: RequestType = + new RequestType('cpptools/getCodeActions'); + +export class CodeActionProvider implements vscode.CodeActionProvider { + private client: DefaultClient; + constructor(client: DefaultClient) { + this.client = client; + } + + public async provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, + context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise<(vscode.Command | vscode.CodeAction)[]> { + return this.client.requestWhenReady(async () => { + let r: Range; + if (range instanceof vscode.Selection) { + if (range.active.isBefore(range.anchor)) { + r = Range.create(Position.create(range.active.line, range.active.character), + Position.create(range.anchor.line, range.anchor.character)); + } else { + r = Range.create(Position.create(range.anchor.line, range.anchor.character), + Position.create(range.active.line, range.active.character)); + } + } else { + r = Range.create(Position.create(range.start.line, range.start.character), + Position.create(range.end.line, range.end.character)); + } + + const params: GetCodeActionsRequestParams = { + range: r, + uri: document.uri.toString() + }; + + const commands: CodeActionCommand[] = await this.client.languageClient.sendRequest( + GetCodeActionsRequest, params, token); + const resultCodeActions: vscode.CodeAction[] = []; + + // Convert to vscode.CodeAction array + commands.forEach((command) => { + const title: string = util.getLocalizedString(command.localizeStringParams); + let wsEdit: vscode.WorkspaceEdit | undefined; + let codeActionKind: vscode.CodeActionKind = vscode.CodeActionKind.QuickFix; + if (command.edit) { + // Inline macro feature. + codeActionKind = vscode.CodeActionKind.RefactorInline; + wsEdit = new vscode.WorkspaceEdit(); + wsEdit.replace(document.uri, makeVscodeRange(command.edit.range), command.edit.newText); + } else if (command.command === "C_Cpp.RemoveAllCodeAnalysisProblems" && command.uri !== undefined) { + // The "RemoveAll" message is sent for all code analysis squiggles. + const vsCodeRange: vscode.Range = makeVscodeRange(r); + const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(command.uri); + if (codeActionDiagnosticInfo === undefined) { + return; + } + const fixCodeActions: vscode.CodeAction[] = []; + const disableCodeActions: vscode.CodeAction[] = []; + const removeCodeActions: vscode.CodeAction[] = []; + const docCodeActions: vscode.CodeAction[] = []; + const showClear: string = new CppSettings().clangTidyCodeActionShowClear; + + // Check which code actions to show. This can get called a lot + // (after every cursor change) so all the checks should be relatively fast. + for (const codeAction of codeActionDiagnosticInfo) { + if (!codeAction.range.contains(vsCodeRange)) { + continue; + } + let codeActionCodeInfo: CodeActionCodeInfo | undefined; + if (codeAnalysisCodeToFixes.has(codeAction.code)) { + codeActionCodeInfo = codeAnalysisCodeToFixes.get(codeAction.code); + } + if (codeAction.fixCodeAction !== undefined) { + // Potentially we could make the "fix all" or "fix all type" preferred instead. + codeAction.fixCodeAction.isPreferred = true; + fixCodeActions.push(codeAction.fixCodeAction); + if (codeActionCodeInfo !== undefined) { + if (codeActionCodeInfo.fixAllTypeCodeAction !== undefined && + (codeActionCodeInfo.uriToInfo.size > 1 || + codeActionCodeInfo.uriToInfo.values().next().value.numValidWorkspaceEdits > 1)) { + // Only show the "fix all type" if there is more than one fix for the type. + fixCodeActions.push(codeActionCodeInfo.fixAllTypeCodeAction); + } + } + } + if (codeAction.removeCodeAction === undefined) { + continue; + } + let removeAllTypeAvailable: boolean = false; + if (codeActionCodeInfo !== undefined) { + if (codeActionCodeInfo.disableAllTypeCodeAction !== undefined) { + disableCodeActions.push(codeActionCodeInfo.disableAllTypeCodeAction); + } + if (codeActionCodeInfo.removeAllTypeCodeAction !== undefined && + codeActionCodeInfo.uriToInfo.size > 0 && + (codeActionCodeInfo.uriToInfo.size > 1 || + codeActionCodeInfo.uriToInfo.values().next().value.identifiers.length > 1)) { + // Only show the "clear all type" if there is more than one fix for the type. + removeAllTypeAvailable = true; + } + } + if (showClear !== "None") { + if (!removeAllTypeAvailable || showClear === "AllAndAllTypeAndThis") { + // The "Clear this" command is useful when you need to manually fix + // some of the cases, and then run "fix all type" for the rest. + removeCodeActions.push(codeAction.removeCodeAction); + } + if (removeAllTypeAvailable && codeActionCodeInfo?.removeAllTypeCodeAction) { + removeCodeActions.push(codeActionCodeInfo.removeAllTypeCodeAction); + } + } + + if (codeActionCodeInfo === undefined || codeActionCodeInfo.docCodeAction === undefined) { + continue; + } + docCodeActions.push(codeActionCodeInfo.docCodeAction); + } + if (fixCodeActions.length > 0) { + resultCodeActions.push(...fixCodeActions); + if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments?.[1] !== undefined) { + // Only show "fix all" if there are multiple types of fixes. + // The arguments[1] only gets set when there are multiple types. + resultCodeActions.push(codeAnalysisAllFixes.fixAllCodeAction); + } + } + if (showClear !== "None") { + let showClearAllAvailable: boolean = false; + if ((codeActionDiagnosticInfo.length > 1 || codeAnalysisFileToCodeActions.size > 1)) { + showClearAllAvailable = true; + } + if (!showClearAllAvailable || showClear !== "AllOnly") { + resultCodeActions.push(...removeCodeActions); + } + if (showClearAllAvailable) { + resultCodeActions.push(codeAnalysisAllFixes.removeAllCodeAction); + } + } + resultCodeActions.push(...disableCodeActions); + resultCodeActions.push(...docCodeActions); + return; + } + const vscodeCodeAction: vscode.CodeAction = { + title: title, + command: command.command === "edit" ? undefined : { + title: title, + command: command.command, + arguments: command.arguments + }, + edit: wsEdit, + kind: codeActionKind + }; + resultCodeActions.push(vscodeCodeAction); + }); + return resultCodeActions; + }); + } +} diff --git a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts index c35127c20..1a82337e0 100644 --- a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts @@ -5,6 +5,7 @@ import * as vscode from 'vscode'; import { DefaultClient, FormatParams, FormatDocumentRequest } from '../client'; import { CppSettings, getEditorConfigSettings } from '../settings'; +import { makeVscodeTextEdits } from '../utils'; export class DocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider { private client: DefaultClient; @@ -40,14 +41,7 @@ export class DocumentFormattingEditProvider implements vscode.DocumentFormatting // because there is not currently cancellation logic for formatting // in the native process. Formatting is currently done directly in // message handling thread. - const textEdits: any = await this.client.languageClient.sendRequest(FormatDocumentRequest, params); - const results: vscode.TextEdit[] = []; - textEdits.forEach((textEdit: any) => { - results.push({ - range: new vscode.Range(textEdit.range.start.line, textEdit.range.start.character, textEdit.range.end.line, textEdit.range.end.character), - newText: textEdit.newText - }); - }); + const results: vscode.TextEdit[] = makeVscodeTextEdits(await this.client.languageClient.sendRequest(FormatDocumentRequest, params)); // Apply insert_final_newline from .editorconfig if (document.lineCount > 0 && editorConfigSettings !== undefined && editorConfigSettings.insert_final_newline) { // Check if there is already a newline at the end. If so, formatting edits should not replace it. diff --git a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts index e25a95f9e..01ad323f1 100644 --- a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts @@ -5,6 +5,7 @@ import * as vscode from 'vscode'; import { DefaultClient, FormatParams, FormatRangeRequest } from '../client'; import { CppSettings, getEditorConfigSettings } from '../settings'; +import { makeVscodeTextEdits } from '../utils'; export class DocumentRangeFormattingEditProvider implements vscode.DocumentRangeFormattingEditProvider { private client: DefaultClient; @@ -40,15 +41,7 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange // because there is not currently cancellation logic for formatting // in the native process. Formatting is currently done directly in // message handling thread. - const textEdits: any = await this.client.languageClient.sendRequest(FormatRangeRequest, params); - const result: vscode.TextEdit[] = []; - textEdits.forEach((textEdit: any) => { - result.push({ - range: new vscode.Range(textEdit.range.start.line, textEdit.range.start.character, textEdit.range.end.line, textEdit.range.end.character), - newText: textEdit.newText - }); - }); - return result; + return makeVscodeTextEdits(await this.client.languageClient.sendRequest(FormatRangeRequest, params)); }; if (!useVcFormat) { return configCallBack(undefined); diff --git a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts index ab39b13e2..fb9c8572d 100644 --- a/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentSymbolProvider.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; import { DefaultClient, LocalizeDocumentSymbol, GetDocumentSymbolRequestParams, GetDocumentSymbolRequest, SymbolScope } from '../client'; import * as util from '../../common'; import { processDelayedDidOpen } from '../extension'; +import { makeVscodeRange } from '../utils'; export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider { private client: DefaultClient; @@ -44,8 +45,8 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider { } } - let r: vscode.Range = new vscode.Range(symbol.range.start.line, symbol.range.start.character, symbol.range.end.line, symbol.range.end.character); - const sr: vscode.Range = new vscode.Range(symbol.selectionRange.start.line, symbol.selectionRange.start.character, symbol.selectionRange.end.line, symbol.selectionRange.end.character); + let r: vscode.Range = makeVscodeRange(symbol.range); + const sr: vscode.Range = makeVscodeRange(symbol.selectionRange); if (!r.contains(sr)) { r = sr; } diff --git a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts index 225928f41..b4747022f 100644 --- a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts @@ -3,8 +3,9 @@ * See 'LICENSE' in the project root for license information. * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import {DefaultClient, FormatParams, FormatOnTypeRequest} from '../client'; +import { DefaultClient, FormatParams, FormatOnTypeRequest } from '../client'; import { CppSettings, getEditorConfigSettings } from '../settings'; +import { makeVscodeTextEdits } from '../utils'; export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEditProvider { private client: DefaultClient; @@ -40,15 +41,7 @@ export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEdit // because there is not currently cancellation logic for formatting // in the native process. Formatting is currently done directly in // message handling thread. - const textEdits: any[] = await this.client.languageClient.sendRequest(FormatOnTypeRequest, params); - const result: vscode.TextEdit[] = []; - textEdits.forEach((textEdit) => { - result.push({ - range: new vscode.Range(textEdit.range.start.line, textEdit.range.start.character, textEdit.range.end.line, textEdit.range.end.character), - newText: textEdit.newText - }); - }); - return result; + return makeVscodeTextEdits(await this.client.languageClient.sendRequest(FormatOnTypeRequest, params)); }; if (!useVcFormat) { // If not using vcFormat, only process on-type requests for ';' diff --git a/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts b/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts index 927095522..0efec7147 100644 --- a/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts +++ b/Extension/src/LanguageServer/Providers/workspaceSymbolProvider.ts @@ -4,6 +4,7 @@ * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; import { DefaultClient, GetSymbolInfoRequest, WorkspaceSymbolParams, LocalizeSymbolInformation, SymbolScope } from '../client'; +import { makeVscodeLocation } from '../utils'; import * as util from '../../common'; export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider { @@ -38,13 +39,11 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider { name = name + " (protected)"; } } - const range: vscode.Range = new vscode.Range(symbol.location.range.start.line, symbol.location.range.start.character, symbol.location.range.end.line, symbol.location.range.end.character); - const uri: vscode.Uri = vscode.Uri.parse(symbol.location.uri.toString()); const vscodeSymbol: vscode.SymbolInformation = new vscode.SymbolInformation( name, symbol.kind, symbol.containerName, - new vscode.Location(uri, range) + makeVscodeLocation(symbol.location) ); resultSymbols.push(vscodeSymbol); }); diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index 57d609dc9..d934b6daf 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -17,12 +17,14 @@ import { DocumentSymbolProvider } from './Providers/documentSymbolProvider'; import { WorkspaceSymbolProvider } from './Providers/workspaceSymbolProvider'; import { RenameProvider } from './Providers/renameProvider'; import { FindAllReferencesProvider } from './Providers/findAllReferencesProvider'; +import { CodeActionProvider } from './Providers/codeActionProvider'; // End provider imports import { LanguageClient, LanguageClientOptions, ServerOptions, NotificationType, TextDocumentIdentifier, RequestType, ErrorAction, CloseAction, DidOpenTextDocumentParams, Range, Position, DocumentFilter } from 'vscode-languageclient'; import { SourceFileConfigurationItem, WorkspaceBrowseConfiguration, SourceFileConfiguration, Version } from 'vscode-cpptools'; import { Status, IntelliSenseStatus } from 'vscode-cpptools/out/testApi'; import * as util from '../common'; +import { Location, makeVscodeRange, makeVscodeLocation, makeVscodeTextEdits, rangeEquals, TextEdit } from './utils'; import * as configs from './configurations'; import { CppSettings, getEditorConfigSettings, OtherSettings } from './settings'; import * as telemetry from '../telemetry'; @@ -64,6 +66,73 @@ let debugChannel: vscode.OutputChannel; let warningChannel: vscode.OutputChannel; let diagnosticsCollectionIntelliSense: vscode.DiagnosticCollection; let diagnosticsCollectionCodeAnalysis: vscode.DiagnosticCollection; + +export interface CodeActionDiagnosticInfo { + version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 . + + // Used to work around https://github.com/microsoft/vscode/issues/126393. + // If that bug were fixed, then we could use the vscode.CodeAction.diagnostic directly. + range: vscode.Range; + code: string; + + fixCodeAction?: vscode.CodeAction; + // suppressCodeAction?: vscode.CodeAction; // TODO? + removeCodeAction?: vscode.CodeAction; +} + +// Used to handle fix invalidation after an edit, +// i.e. it's set to undefined if it becomes invalid. +interface CodeActionWorkspaceEdit { + workspaceEdit?: vscode.WorkspaceEdit; +} + +interface CodeActionPerUriInfo { + // These two arrays have the same length, i.e. index i of identifiers + // is usee to index into workspaceEdits to get the corresponding edit. + identifiers: CodeAnalysisDiagnosticIdentifier[]; + workspaceEdits?: CodeActionWorkspaceEdit[]; + + // Used to quickly determine how many non-undefined entries are in "workspaceEdits" + // (so the array doesn't have to be iterated through). + numValidWorkspaceEdits: number; +} + +// Tracks the "type" code actions (i.e. "code" is a synonym for "type" in this context). +export interface CodeActionCodeInfo { + version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 . + + // Needed to quickly update the "type" action for a file. + uriToInfo: Map; + + fixAllTypeCodeAction?: vscode.CodeAction; + disableAllTypeCodeAction?: vscode.CodeAction; + removeAllTypeCodeAction?: vscode.CodeAction; + docCodeAction?: vscode.CodeAction; +} + +interface CodeActionAllInfo { + version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 . + fixAllCodeAction: vscode.CodeAction; + removeAllCodeAction: vscode.CodeAction; +} + +export const codeAnalysisFileToCodeActions: Map = new Map(); +export const codeAnalysisCodeToFixes: Map = new Map(); +export const codeAnalysisAllFixes: CodeActionAllInfo = { + version: 0, + fixAllCodeAction: { + title: localize("fix_all_code_analysis_problems", "Fix all code analysis problems"), + command: { title: 'FixAllCodeAnalysisProblems', command: 'C_Cpp.FixAllCodeAnalysisProblems', + arguments: [ 0, undefined, true, [] ] }, + kind: vscode.CodeActionKind.QuickFix + }, + removeAllCodeAction: { + title: localize("clear_all_code_analysis_problems", "Clear all code analysis problems"), + command: { title: "RemoveAllCodeAnalysisProblems", command: "C_Cpp.RemoveAllCodeAnalysisProblems" }, + kind: vscode.CodeActionKind.QuickFix + } +}; + let workspaceDisposables: vscode.Disposable[] = []; export let workspaceReferences: refs.ReferencesManager; export const openFileVersions: Map = new Map(); @@ -148,7 +217,7 @@ function showWarning(params: ShowWarningParams): void { } } -function publishDiagnostics(params: PublishDiagnosticsParams): void { +function publishIntelliSenseDiagnostics(params: PublishIntelliSenseDiagnosticsParams): void { if (!diagnosticsCollectionIntelliSense) { diagnosticsCollectionIntelliSense = vscode.languages.createDiagnosticCollection(CppSourceStr); } @@ -157,16 +226,13 @@ function publishDiagnostics(params: PublishDiagnosticsParams): void { const diagnosticsIntelliSense: vscode.Diagnostic[] = []; params.diagnostics.forEach((d) => { const message: string = util.getLocalizedString(d.localizeStringParams); - const r: vscode.Range = new vscode.Range(d.range.start.line, d.range.start.character, d.range.end.line, d.range.end.character); - const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(r, message, d.severity); + const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(makeVscodeRange(d.range), message, d.severity); diagnostic.code = d.code; diagnostic.source = CppSourceStr; if (d.relatedInformation) { diagnostic.relatedInformation = []; for (const info of d.relatedInformation) { - const infoRange: vscode.Range = new vscode.Range(info.location.range.start.line, info.location.range.start.character, info.location.range.end.line, info.location.range.end.character); - diagnostic.relatedInformation.push(new vscode.DiagnosticRelatedInformation( - new vscode.Location(vscode.Uri.parse(info.location.uri), infoRange), info.message)); + diagnostic.relatedInformation.push(new vscode.DiagnosticRelatedInformation(makeVscodeLocation(info.location), info.message)); } } @@ -179,45 +245,328 @@ function publishDiagnostics(params: PublishDiagnosticsParams): void { clientCollection.timeTelemetryCollector.setUpdateRangeTime(realUri); } -function publishCodeAnalysisDiagnostics(params: PublishDiagnosticsParams): void { +// Rebuild codeAnalysisCodeToFixes and codeAnalysisAllFixes.fixAllCodeActions. +function rebuildCodeAnalysisCodeAndAllFixes(): void { + if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) { + codeAnalysisAllFixes.fixAllCodeAction.command.arguments[0] = ++codeAnalysisAllFixes.version; + codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = undefined; + codeAnalysisAllFixes.fixAllCodeAction.command.arguments[3] = []; + } + + const identifiersAndUrisForAllFixes: CodeAnalysisDiagnosticIdentifiersAndUri[] = []; + const uriToEditsForAll: Map = new Map(); + let numFixTypes: number = 0; + for (const codeToFixes of codeAnalysisCodeToFixes) { + const identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = []; + const uriToEdits: Map = new Map(); + codeToFixes[1].uriToInfo.forEach((perUriInfo: CodeActionPerUriInfo, uri: string) => { + const newIdentifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = { uri: uri, identifiers: perUriInfo.identifiers }; + identifiersAndUris.push(newIdentifiersAndUri); + if (perUriInfo.workspaceEdits === undefined || perUriInfo.numValidWorkspaceEdits === 0) { + return; + } + identifiersAndUrisForAllFixes.push(newIdentifiersAndUri); + for (const edit of perUriInfo.workspaceEdits) { + if (edit.workspaceEdit === undefined) { + continue; + } + for (const [uri, edits] of edit.workspaceEdit.entries()) { + const textEdits: vscode.TextEdit[] = uriToEdits.get(uri) ?? []; + textEdits.push(...edits); + uriToEdits.set(uri, textEdits); + const textEditsForAll: vscode.TextEdit[] = uriToEditsForAll.get(uri) ?? []; + textEditsForAll.push(...edits); + uriToEditsForAll.set(uri, textEdits); + } + } + }); + if (uriToEdits.size > 0) { + const allTypeWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit(); + for (const [uri, edits] of uriToEdits.entries()) { + allTypeWorkspaceEdit.set(uri, edits); + } + ++numFixTypes; + codeToFixes[1].fixAllTypeCodeAction = { + title: localize("fix_all_type_problems", "Fix all {0} problems", codeToFixes[0]), + command: { title: 'FixAllTypeCodeAnalysisProblems', command: 'C_Cpp.FixAllTypeCodeAnalysisProblems', + arguments: [ codeToFixes[0], ++codeToFixes[1].version, allTypeWorkspaceEdit, true, identifiersAndUris ] }, + kind: vscode.CodeActionKind.QuickFix + }; + } + + if (new CppSettings().clangTidyCodeActionShowDisable) { + codeToFixes[1].disableAllTypeCodeAction = { + title: localize("disable_all_type_problems", "Disable all {0} problems", codeToFixes[0]), + command: { title: 'DisableAllTypeCodeAnalysisProblems', command: 'C_Cpp.DisableAllTypeCodeAnalysisProblems', + arguments: [ codeToFixes[0], identifiersAndUris ] }, + kind: vscode.CodeActionKind.QuickFix + }; + } else { + codeToFixes[1].disableAllTypeCodeAction = undefined; + } + + if (new CppSettings().clangTidyCodeActionShowClear !== "None") { + codeToFixes[1].removeAllTypeCodeAction = { + title: localize("clear_all_type_problems", "Clear all {0} problems", codeToFixes[0]), + command: { title: 'RemoveAllTypeCodeAnalysisProblems', command: 'C_Cpp.RemoveCodeAnalysisProblems', + arguments: [ false, identifiersAndUris ] }, + kind: vscode.CodeActionKind.QuickFix + }; + } + } + if (numFixTypes > 1) { + const allWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit(); + for (const [uri, edits] of uriToEditsForAll.entries()) { + allWorkspaceEdit.set(uri, edits); + } + if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) { + codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = allWorkspaceEdit; + codeAnalysisAllFixes.fixAllCodeAction.command.arguments[3] = identifiersAndUrisForAllFixes; + } + } else { + if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) { + codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = undefined; + } + } +} + +function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagnosticsParams): void { if (!diagnosticsCollectionCodeAnalysis) { diagnosticsCollectionCodeAnalysis = vscode.languages.createDiagnosticCollection("clang-tidy"); } // Convert from our Diagnostic objects to vscode Diagnostic objects const diagnosticsCodeAnalysis: vscode.Diagnostic[] = []; - params.diagnostics.forEach((d) => { - const message: string = util.getLocalizedString(d.localizeStringParams); - const r: vscode.Range = new vscode.Range(d.range.start.line, d.range.start.character, d.range.end.line, d.range.end.character); - const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(r, message, d.severity); - if (typeof d.code === "string" && d.code.length !== 0 && !d.code.startsWith("clang-diagnostic-")) { - const codes: string[] = d.code.split(','); - let codeIndex: number = codes.length - 1; - if (codes[codeIndex] === "cert-dcl51-cpp") { // Handle aliasing - codeIndex = 0; - } - diagnostic.code = { value: d.code, - target: vscode.Uri.parse(`https://releases.llvm.org/13.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/${codes[codeIndex]}.html`) }; - } else { - diagnostic.code = d.code; + const realUri: vscode.Uri = vscode.Uri.parse(params.uri); + + // Reset codeAnalysisCodeToFixes for the file. + for (const codeToFixes of codeAnalysisCodeToFixes) { + ++codeToFixes[1].version; + if (codeToFixes[1].uriToInfo.has(params.uri)) { + codeToFixes[1].uriToInfo.delete(params.uri); + } + } + + const previousDiagnostics: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(params.uri); + let nextVersion: number = 0; + if (previousDiagnostics !== undefined) { + for (const diagnostic of previousDiagnostics) { + if (diagnostic.version > nextVersion) { + nextVersion = diagnostic.version; + } + } + } + ++nextVersion; + const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] = []; + for (const d of params.diagnostics) { + const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(makeVscodeRange(d.range), + util.getLocalizedString(d.localizeStringParams), d.severity); + const identifier: CodeAnalysisDiagnosticIdentifier = { range: d.range, code: d.code }; + const identifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = { uri: params.uri, identifiers: [ identifier ] }; + const codeAction: CodeActionDiagnosticInfo = { + version: nextVersion, + range: makeVscodeRange(identifier.range), + code: identifier.code, + removeCodeAction: { + title: localize("clear_this_problem", "Clear this {0} problem", d.code), + command: { title: 'RemoveCodeAnalysisProblems', command: 'C_Cpp.RemoveCodeAnalysisProblems', + arguments: [ false, [ identifiersAndUri ] ] }, + kind: vscode.CodeActionKind.QuickFix + } + }; + const workspaceEdit: CodeActionWorkspaceEdit = {}; + if (d.workspaceEdit) { + workspaceEdit.workspaceEdit = new vscode.WorkspaceEdit(); + for (const [uriStr, edits] of Object.entries(d.workspaceEdit.changes)) { + workspaceEdit.workspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits)); + } + const fixThisCodeAction: vscode.CodeAction = { + title: localize("fix_this_problem", "Fix this {0} problem", d.code), + command: { title: 'FixThisCodeAnalysisProblem', command: 'C_Cpp.FixThisCodeAnalysisProblem', + arguments: [ nextVersion, workspaceEdit.workspaceEdit, true, [ identifiersAndUri ] ] }, + kind: vscode.CodeActionKind.QuickFix + }; + codeAction.fixCodeAction = fixThisCodeAction; + } + + // Edits from clang-tidy can be associated with the related information instead of the root diagnostic. + const relatedCodeActions: CodeActionDiagnosticInfo[] = []; + const rootAndRelatedWorkspaceEdits: CodeActionWorkspaceEdit[] = []; + const rootAndRelatedIdentifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = []; + if (workspaceEdit.workspaceEdit !== undefined) { + rootAndRelatedWorkspaceEdits.push(workspaceEdit); + rootAndRelatedIdentifiersAndUris.push(identifiersAndUri); } - diagnostic.source = CppSourceStr; if (d.relatedInformation) { diagnostic.relatedInformation = []; for (const info of d.relatedInformation) { - const infoRange: vscode.Range = new vscode.Range(info.location.range.start.line, info.location.range.start.character, info.location.range.end.line, info.location.range.end.character); - diagnostic.relatedInformation.push(new vscode.DiagnosticRelatedInformation( - new vscode.Location(vscode.Uri.parse(info.location.uri), infoRange), info.message)); + diagnostic.relatedInformation.push(new vscode.DiagnosticRelatedInformation(makeVscodeLocation(info.location), info.message)); + if (info.workspaceEdit === undefined) { + continue; + } + const relatedWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit(); + for (const [uriStr, edits] of Object.entries(info.workspaceEdit.changes)) { + relatedWorkspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits)); + } + const relatedIdentifier: CodeAnalysisDiagnosticIdentifier = { range: info.location.range, code: d.code }; + const relatedIdentifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = { + uri: info.location.uri, identifiers: [ relatedIdentifier ] }; + const relatedCodeAction: vscode.CodeAction = { + title: localize("fix_this_problem", "Fix this {0} problem", d.code), + command: { title: 'FixThisCodeAnalysisProblem', command: 'C_Cpp.FixThisCodeAnalysisProblem', + arguments: [ nextVersion, relatedWorkspaceEdit, true, [ relatedIdentifiersAndUri ] ] }, + kind: vscode.CodeActionKind.QuickFix + }; + if (codeAction.fixCodeAction === undefined) { + codeAction.fixCodeAction = relatedCodeAction; + } else { + const relatedCodeActionInfo: CodeActionDiagnosticInfo = { + version: nextVersion, + range: makeVscodeRange(relatedIdentifier.range), + code: relatedIdentifier.code, + fixCodeAction: relatedCodeAction + }; + relatedCodeActions.push(relatedCodeActionInfo); + } + rootAndRelatedWorkspaceEdits.push({ workspaceEdit: relatedWorkspaceEdit}); + rootAndRelatedIdentifiersAndUris.push(relatedIdentifiersAndUri); } } - + if (identifier.code.length !== 0) { + const codeActionCodeInfo: CodeActionCodeInfo = codeAnalysisCodeToFixes.get(identifier.code) ?? + { version: 0, uriToInfo: new Map() }; + let rootAndRelatedWorkspaceEditsIndex: number = 0; + for (const rootAndRelatedIdentifiersAndUri of rootAndRelatedIdentifiersAndUris) { + const existingInfo: CodeActionPerUriInfo = codeActionCodeInfo.uriToInfo.get(rootAndRelatedIdentifiersAndUri.uri) ?? + { identifiers: [], numValidWorkspaceEdits: 0 }; + existingInfo.identifiers.push(...rootAndRelatedIdentifiersAndUri.identifiers); + const rootAndRelatedWorkspaceEdit: CodeActionWorkspaceEdit = rootAndRelatedWorkspaceEdits[rootAndRelatedWorkspaceEditsIndex]; + if (rootAndRelatedWorkspaceEdit !== undefined) { + if (existingInfo.workspaceEdits === undefined) { + existingInfo.workspaceEdits = [ rootAndRelatedWorkspaceEdit ]; + } else { + existingInfo.workspaceEdits.push(rootAndRelatedWorkspaceEdit); + } + ++existingInfo.numValidWorkspaceEdits; + } + codeActionCodeInfo.uriToInfo.set(rootAndRelatedIdentifiersAndUri.uri, existingInfo); + ++rootAndRelatedWorkspaceEditsIndex; + } + if (!identifier.code.startsWith("clang-diagnostic-")) { + const codes: string[] = identifier.code.split(','); + let codeIndex: number = codes.length - 1; + if (codes[codeIndex] === "cert-dcl51-cpp") { // Handle aliasing + codeIndex = 0; + } + // TODO: Is the ideal code always selected as the primary one? + const primaryCode: string = codes[codeIndex]; + const docPage: string = primaryCode === "clang-tidy-nolint" ? "#suppressing-undesired-diagnostics" : + `checks/${primaryCode}.html`; + const primaryDocUri: vscode.Uri = vscode.Uri.parse(`https://releases.llvm.org/14.0.0/tools/clang/tools/extra/docs/clang-tidy/${docPage}`); + diagnostic.code = { value: identifier.code, target: primaryDocUri }; + + if (new CppSettings().clangTidyCodeActionShowDocumentation) { + if (codeActionCodeInfo.docCodeAction === undefined) { + codeActionCodeInfo.docCodeAction = { + title: localize("show_documentation_for", "Show documentation for {0}", primaryCode), + command: { title: 'ShowDocumentation', command: 'C_Cpp.ShowCodeAnalysisDocumentation', + arguments: [ primaryDocUri ] }, + kind: vscode.CodeActionKind.QuickFix + }; + } + } else { + codeActionCodeInfo.docCodeAction = undefined; + } + } else { + diagnostic.code = d.code; + } + codeAnalysisCodeToFixes.set(identifier.code, codeActionCodeInfo); + } else { + diagnostic.code = d.code; + } + diagnostic.source = CppSourceStr; + codeActionDiagnosticInfo.push(codeAction); + if (relatedCodeActions.length > 0) { + codeActionDiagnosticInfo.push(...relatedCodeActions); + } diagnosticsCodeAnalysis.push(diagnostic); - }); + } + + codeAnalysisFileToCodeActions.set(params.uri, codeActionDiagnosticInfo); + + rebuildCodeAnalysisCodeAndAllFixes(); - const realUri: vscode.Uri = vscode.Uri.parse(params.uri); diagnosticsCollectionCodeAnalysis.set(realUri, diagnosticsCodeAnalysis); } +function removeCodeAnalysisCodeActions(identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[], + removeFixesOnly: boolean): void { + for (const identifiersAndUri of identifiersAndUris) { + const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(identifiersAndUri.uri); + if (codeActionDiagnosticInfo === undefined) { + return; + } + for (const identifier of identifiersAndUri.identifiers) { + const updatedCodeActions: CodeActionDiagnosticInfo[] = []; + for (const codeAction of codeActionDiagnosticInfo) { + if (rangeEquals(codeAction.range, identifier.range) && codeAction.code === identifier.code) { + if (removeFixesOnly) { + ++codeAction.version; + codeAction.fixCodeAction = undefined; + } else { + continue; + } + } + updatedCodeActions.push(codeAction); + } + codeAnalysisFileToCodeActions.set(identifiersAndUri.uri, updatedCodeActions); + + let codeActionInfoChanged: boolean = false; + for (const codeFixes of codeAnalysisCodeToFixes) { + const codeActionInfo: CodeActionPerUriInfo | undefined = codeFixes[1].uriToInfo.get(identifiersAndUri.uri); + if (codeActionInfo === undefined) { + continue; + } + let removedCodeActionInfoIndex: number = -1; + for (let codeActionInfoIndex: number = 0; codeActionInfoIndex < codeActionInfo.identifiers.length; ++codeActionInfoIndex) { + if (identifier.code === codeActionInfo.identifiers[codeActionInfoIndex].code && + rangeEquals(identifier.range, codeActionInfo.identifiers[codeActionInfoIndex].range)) { + removedCodeActionInfoIndex = codeActionInfoIndex; + codeActionInfoChanged = true; + break; + } + } + if (removedCodeActionInfoIndex !== -1) { + if (removeFixesOnly) { + if (codeActionInfo.workspaceEdits !== undefined) { + codeActionInfo.workspaceEdits[removedCodeActionInfoIndex].workspaceEdit = undefined; + --codeActionInfo.numValidWorkspaceEdits; + } + } else { + codeActionInfo.identifiers.splice(removedCodeActionInfoIndex, 1); + if (codeActionInfo.workspaceEdits !== undefined) { + codeActionInfo.workspaceEdits.splice(removedCodeActionInfoIndex, 1); + --codeActionInfo.numValidWorkspaceEdits; + } + } + if (codeActionInfo.identifiers.length === 0) { + codeFixes[1].uriToInfo.delete(identifiersAndUri.uri); + } else { + codeFixes[1].uriToInfo.set(identifiersAndUri.uri, codeActionInfo); + } + } + } + if (codeActionInfoChanged) { + rebuildCodeAnalysisCodeAndAllFixes(); + } + } + } +} + +function publishRemoveCodeAnalysisCodeActionFixes(params: RemoveCodeAnalysisCodeActionFixesParams): void { + removeCodeAnalysisCodeActions(params.identifiersAndUris, true); +} + interface WorkspaceFolderParams { workspaceFolderUri?: string; } @@ -314,35 +663,61 @@ interface GetDiagnosticsResult { diagnostics: string; } -interface CppDiagnosticRelatedInformation { +interface IntelliSenseDiagnosticRelatedInformation { + location: Location; + message: string; +} + +interface CodeAnalysisDiagnosticRelatedInformation { location: Location; message: string; + workspaceEdit?: WorkspaceEdit; } -interface Diagnostic { +interface IntelliSenseDiagnostic { range: Range; - code?: number | string; - source?: string; + code?: number; severity: vscode.DiagnosticSeverity; localizeStringParams: LocalizeStringParams; - relatedInformation?: CppDiagnosticRelatedInformation[]; + relatedInformation?: IntelliSenseDiagnosticRelatedInformation[]; } -interface PublishDiagnosticsParams { +interface CodeAnalysisDiagnostic { + range: Range; + code: string; + severity: vscode.DiagnosticSeverity; + localizeStringParams: LocalizeStringParams; + relatedInformation?: CodeAnalysisDiagnosticRelatedInformation[]; + workspaceEdit?: WorkspaceEdit; +} + +interface CodeAnalysisDiagnosticIdentifier { + range: Range; + code: string; +} + +export interface CodeAnalysisDiagnosticIdentifiersAndUri { uri: string; - diagnostics: Diagnostic[]; + identifiers: CodeAnalysisDiagnosticIdentifier[]; } -interface GetCodeActionsRequestParams { +interface RemoveCodeAnalysisProblemsParams { + identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]; + refreshSquigglesOnSave: boolean; +}; + +interface RemoveCodeAnalysisCodeActionFixesParams { + identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]; +}; + +interface PublishIntelliSenseDiagnosticsParams { uri: string; - range: Range; + diagnostics: IntelliSenseDiagnostic[]; } -interface CodeActionCommand { - localizeStringParams: LocalizeStringParams; - command: string; - arguments?: any[]; - edit?: TextEdit; +interface PublishCodeAnalysisDiagnosticsParams { + uri: string; + diagnostics: CodeAnalysisDiagnostic[]; } interface ShowMessageWindowParams { @@ -378,12 +753,6 @@ export interface LocalizeDocumentSymbol { children: LocalizeDocumentSymbol[]; } -/** Differs from vscode.Location, which has a uri of type vscode.Uri. */ -interface Location { - uri: string; - range: Range; -} - export interface LocalizeSymbolInformation { name: string; kind: vscode.SymbolKind; @@ -418,9 +787,8 @@ export interface FormatParams { useVcFormat: boolean; } -interface TextEdit { - range: Range; - newText: string; +interface WorkspaceEdit { + changes: { [uri: string]: TextEdit[] }; } export interface GetFoldingRangesParams { @@ -536,7 +904,6 @@ const QueryCompilerDefaultsRequest: RequestType = new RequestType('cpptools/queryTranslationUnitSource'); const SwitchHeaderSourceRequest: RequestType = new RequestType('cpptools/didSwitchHeaderSource'); const GetDiagnosticsRequest: RequestType = new RequestType('cpptools/getDiagnostics'); -const GetCodeActionsRequest: RequestType = new RequestType('cpptools/getCodeActions'); export const GetDocumentSymbolRequest: RequestType = new RequestType('cpptools/getDocumentSymbols'); export const GetSymbolInfoRequest: RequestType = new RequestType('cpptools/getWorkspaceSymbols'); export const GetFoldingRangesRequest: RequestType = new RequestType('cpptools/getFoldingRanges'); @@ -554,9 +921,6 @@ const FileDeletedNotification: NotificationType = new N const ResetDatabaseNotification: NotificationType = new NotificationType('cpptools/resetDatabase'); const PauseParsingNotification: NotificationType = new NotificationType('cpptools/pauseParsing'); const ResumeParsingNotification: NotificationType = new NotificationType('cpptools/resumeParsing'); -const PauseCodeAnalysisNotification: NotificationType = new NotificationType('cpptools/pauseCodeAnalysis'); -const ResumeCodeAnalysisNotification: NotificationType = new NotificationType('cpptools/resumeCodeAnalysis'); -const CancelCodeAnalysisNotification: NotificationType = new NotificationType('cpptools/cancelCodeAnalysis'); const ActiveDocumentChangeNotification: NotificationType = new NotificationType('cpptools/activeDocumentChange'); const RestartIntelliSenseForFileNotification: NotificationType = new NotificationType('cpptools/restartIntelliSenseForFile'); const TextEditorSelectionChangeNotification: NotificationType = new NotificationType('cpptools/textEditorSelectionChange'); @@ -575,7 +939,12 @@ const FinishedRequestCustomConfig: NotificationType = new Notifica const FindAllReferencesNotification: NotificationType = new NotificationType('cpptools/findAllReferences'); const RenameNotification: NotificationType = new NotificationType('cpptools/rename'); const DidChangeSettingsNotification: NotificationType = new NotificationType('cpptools/didChangeSettings'); + const CodeAnalysisNotification: NotificationType = new NotificationType('cpptools/runCodeAnalysis'); +const PauseCodeAnalysisNotification: NotificationType = new NotificationType('cpptools/pauseCodeAnalysis'); +const ResumeCodeAnalysisNotification: NotificationType = new NotificationType('cpptools/resumeCodeAnalysis'); +const CancelCodeAnalysisNotification: NotificationType = new NotificationType('cpptools/cancelCodeAnalysis'); +const RemoveCodeAnalysisProblemsNotification: NotificationType = new NotificationType('cpptools/removeCodeAnalysisProblems'); // Notifications from the server const ReloadWindowNotification: NotificationType = new NotificationType('cpptools/reloadWindow'); @@ -589,8 +958,8 @@ const CompileCommandsPathsNotification: NotificationType = new NotificationType('cpptools/references'); const ReportReferencesProgressNotification: NotificationType = new NotificationType('cpptools/reportReferencesProgress'); const RequestCustomConfig: NotificationType = new NotificationType('cpptools/requestCustomConfig'); -const PublishDiagnosticsNotification: NotificationType = new NotificationType('cpptools/publishDiagnostics'); -const PublishCodeAnalysisDiagnosticsNotification: NotificationType = new NotificationType('cpptools/publishCodeAnalysisDiagnostics'); +const PublishIntelliSenseDiagnosticsNotification: NotificationType = new NotificationType('cpptools/publishIntelliSenseDiagnostics'); +const PublishCodeAnalysisDiagnosticsNotification: NotificationType = new NotificationType('cpptools/publishCodeAnalysisDiagnostics'); const ShowMessageWindowNotification: NotificationType = new NotificationType('cpptools/showMessageWindow'); const ShowWarningNotification: NotificationType = new NotificationType('cpptools/showWarning'); const ReportTextDocumentLanguage: NotificationType = new NotificationType('cpptools/reportTextDocumentLanguage'); @@ -599,6 +968,7 @@ const IntelliSenseSetupNotification: NotificationType = const SetTemporaryTextDocumentLanguageNotification: NotificationType = new NotificationType('cpptools/setTemporaryTextDocumentLanguage'); const ReportCodeAnalysisProcessedNotification: NotificationType = new NotificationType('cpptools/reportCodeAnalysisProcessed'); const ReportCodeAnalysisTotalNotification: NotificationType = new NotificationType('cpptools/reportCodeAnalysisTotal'); +const PublishRemoveCodeAnalysisCodeActionFixesNotification: NotificationType = new NotificationType('cpptools/publishRemoveCodeAnalysisCodeActionFixes'); let failureMessageShown: boolean = false; @@ -751,7 +1121,10 @@ export interface Client { handleRunCodeAnalysisOnActiveFile(): Promise; handleRunCodeAnalysisOnOpenFiles(): Promise; handleRunCodeAnalysisOnAllFiles(): Promise; - handleClearCodeAnalysisSquiggles(): Promise; + handleRemoveAllCodeAnalysisProblems(): Promise; + handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise; + handleFixCodeAnalysisProblems(workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise; + handleDisableAllTypeCodeAnalysisProblems(code: string, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise; onInterval(): void; dispose(): void; addFileAssociations(fileAssociations: string, languageId: string): void; @@ -932,62 +1305,6 @@ export class DefaultClient implements Client { telemetry.logLanguageServerEvent("NonDefaultInitialCppSettings", this.settingsTracker.getUserModifiedSettings()); failureMessageShown = false; - class CodeActionProvider implements vscode.CodeActionProvider { - private client: DefaultClient; - constructor(client: DefaultClient) { - this.client = client; - } - - public async provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise<(vscode.Command | vscode.CodeAction)[]> { - return this.client.requestWhenReady(async () => { - let r: Range; - if (range instanceof vscode.Selection) { - if (range.active.isBefore(range.anchor)) { - r = Range.create(Position.create(range.active.line, range.active.character), Position.create(range.anchor.line, range.anchor.character)); - } else { - r = Range.create(Position.create(range.anchor.line, range.anchor.character), Position.create(range.active.line, range.active.character)); - } - } else { - r = Range.create(Position.create(range.start.line, range.start.character), Position.create(range.end.line, range.end.character)); - } - - const params: GetCodeActionsRequestParams = { - range: r, - uri: document.uri.toString() - }; - - const commands: CodeActionCommand[] = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token); - const resultCodeActions: vscode.CodeAction[] = []; - - // Convert to vscode.CodeAction array - commands.forEach((command) => { - const title: string = util.getLocalizedString(command.localizeStringParams); - let edit: vscode.WorkspaceEdit | undefined; - if (command.edit) { - edit = new vscode.WorkspaceEdit(); - edit.replace(document.uri, new vscode.Range( - new vscode.Position(command.edit.range.start.line, command.edit.range.start.character), - new vscode.Position(command.edit.range.end.line, command.edit.range.end.character)), - command.edit.newText); - } - const vscodeCodeAction: vscode.CodeAction = { - title: title, - command: command.command === "edit" ? undefined : { - title: title, - command: command.command, - arguments: command.arguments - }, - edit: edit, - kind: edit === undefined ? vscode.CodeActionKind.QuickFix : vscode.CodeActionKind.RefactorInline - }; - resultCodeActions.push(vscodeCodeAction); - }); - - return resultCodeActions; - }); - } - } - // Semantic token types are identified by indexes in this list of types, in the legend. const tokenTypesLegend: string[] = []; for (const e in SemanticTokenTypes) { @@ -1830,9 +2147,7 @@ export class DefaultClient implements Client { } this.clearCustomConfigurations(); - if (diagnosticsCollectionCodeAnalysis) { - diagnosticsCollectionCodeAnalysis.clear(); - } + this.handleRemoveAllCodeAnalysisProblems(); this.trackedDocuments.forEach(document => { this.provideCustomConfiguration(document.uri, undefined, true); }); @@ -2269,8 +2584,9 @@ export class DefaultClient implements Client { const client: DefaultClient = clientCollection.getClientFor(vscode.Uri.file(requestFile)); client.handleRequestCustomConfig(requestFile); }); - this.languageClient.onNotification(PublishDiagnosticsNotification, publishDiagnostics); + this.languageClient.onNotification(PublishIntelliSenseDiagnosticsNotification, publishIntelliSenseDiagnostics); this.languageClient.onNotification(PublishCodeAnalysisDiagnosticsNotification, publishCodeAnalysisDiagnostics); + this.languageClient.onNotification(PublishRemoveCodeAnalysisCodeActionFixesNotification, publishRemoveCodeAnalysisCodeActionFixes); this.languageClient.onNotification(ShowMessageWindowNotification, showMessageWindow); this.languageClient.onNotification(ShowWarningNotification, showWarning); this.languageClient.onNotification(ReportTextDocumentLanguage, (e) => this.setTextDocumentLanguage(e)); @@ -2561,11 +2877,7 @@ export class DefaultClient implements Client { rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen }); // We must convert to vscode.Ranges in order to make use of the API's - const ranges: vscode.Range[] = []; - params.regions.forEach(element => { - const newRange: vscode.Range = new vscode.Range(element.startLine, 0, element.endLine, 0); - ranges.push(newRange); - }); + const ranges: vscode.Range[] = params.regions.map(element => new vscode.Range(element.startLine, 0, element.endLine, 0)); // Find entry for cached file and act accordingly const valuePair: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(params.uri); if (valuePair) { @@ -3170,14 +3482,81 @@ export class DefaultClient implements Client { this.languageClient.sendNotification(CodeAnalysisNotification, CodeAnalysisScope.AllFiles); } - public async handleClearCodeAnalysisSquiggles(): Promise { + public async handleRemoveAllCodeAnalysisProblems(): Promise { await this.awaitUntilLanguageClientReady(); - if (diagnosticsCollectionCodeAnalysis) { - diagnosticsCollectionCodeAnalysis.clear(); + if (!diagnosticsCollectionCodeAnalysis) { + return; } + diagnosticsCollectionCodeAnalysis.clear(); + codeAnalysisFileToCodeActions.clear(); + codeAnalysisCodeToFixes.clear(); + rebuildCodeAnalysisCodeAndAllFixes(); this.languageClient.sendNotification(CodeAnalysisNotification, CodeAnalysisScope.ClearSquiggles); } + public async handleFixCodeAnalysisProblems(workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + if (await vscode.workspace.applyEdit(workspaceEdit)) { + return this.handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave, identifiersAndUris); + } + } + + public async handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + await this.awaitUntilLanguageClientReady(); + if (!diagnosticsCollectionCodeAnalysis) { + return; + } + + // A deep copy is needed because the call to identifiers.splice below can + // remove elements in identifiersAndUris[...].identifiers. + const identifiersAndUrisCopy: CodeAnalysisDiagnosticIdentifiersAndUri[] = []; + for (const identifiersAndUri of identifiersAndUris) { + identifiersAndUrisCopy.push({ uri: identifiersAndUri.uri, identifiers: [...identifiersAndUri.identifiers] }); + } + + // Remove the diagnostics. + for (const identifiersAndUri of identifiersAndUris) { + const uri: vscode.Uri = vscode.Uri.parse(identifiersAndUri.uri); + const diagnostics: readonly vscode.Diagnostic[] | undefined = diagnosticsCollectionCodeAnalysis.get(uri); + if (diagnostics === undefined) { + continue; + } + const newDiagnostics: vscode.Diagnostic[] = []; + for (const diagnostic of diagnostics) { + const code: string = typeof diagnostic.code === "string" ? diagnostic.code : + (typeof diagnostic.code === "object" && typeof diagnostic.code.value === "string" ? + diagnostic.code.value : ""); + let removed: boolean = false; + for (const identifier of identifiersAndUri.identifiers) { + if (code !== identifier.code || !rangeEquals(diagnostic.range, identifier.range)) { + continue; + } + removed = true; + break; + } + if (!removed) { + newDiagnostics.push(diagnostic); + } + } + diagnosticsCollectionCodeAnalysis.set(uri, newDiagnostics); + } + + removeCodeAnalysisCodeActions(identifiersAndUris, false); + + // Need to notify the language client of the removed diagnostics so it doesn't re-send them. + this.languageClient.sendNotification(RemoveCodeAnalysisProblemsNotification, { + identifiersAndUris: identifiersAndUrisCopy, refreshSquigglesOnSave: refreshSquigglesOnSave }); + } + + public async handleDisableAllTypeCodeAnalysisProblems(code: string, + identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + const settings: CppSettings = new CppSettings(this.RootUri); + const codes: string[] = code.split(','); + for (const code of codes) { + settings.addClangTidyChecksDisabled(code); + } + this.handleRemoveCodeAnalysisProblems(false, identifiersAndUris); + } + public onInterval(): void { // These events can be discarded until the language client is ready. // Don't queue them up with this.notifyWhenLanguageClientReady calls. @@ -3359,7 +3738,10 @@ class NullClient implements Client { handleRunCodeAnalysisOnActiveFile(): Promise { return Promise.resolve(); } handleRunCodeAnalysisOnOpenFiles(): Promise { return Promise.resolve(); } handleRunCodeAnalysisOnAllFiles(): Promise { return Promise.resolve(); } - handleClearCodeAnalysisSquiggles(): Promise { return Promise.resolve(); } + handleRemoveAllCodeAnalysisProblems(): Promise { return Promise.resolve(); } + handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { return Promise.resolve(); } + handleFixCodeAnalysisProblems(workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { return Promise.resolve(); } + handleDisableAllTypeCodeAnalysisProblems(code: string, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { return Promise.resolve(); } onInterval(): void { } dispose(): void { this.booleanEvent.dispose(); diff --git a/Extension/src/LanguageServer/extension.ts b/Extension/src/LanguageServer/extension.ts index 92400207c..4daa274bc 100644 --- a/Extension/src/LanguageServer/extension.ts +++ b/Extension/src/LanguageServer/extension.ts @@ -12,13 +12,14 @@ import * as util from '../common'; import * as telemetry from '../telemetry'; import { TreeNode, NodeType } from './referencesModel'; import { UI, getUI } from './ui'; -import { Client, openFileVersions } from './client'; +import { Client, openFileVersions, CodeAnalysisDiagnosticIdentifiersAndUri, CodeActionDiagnosticInfo, codeAnalysisCodeToFixes, + codeAnalysisFileToCodeActions, codeAnalysisAllFixes } from './client'; +import { makeCpptoolsRange, rangeEquals } from './utils'; import { ClientCollection } from './clientCollection'; import { CppSettings, OtherSettings } from './settings'; import { PersistentState } from './persistentState'; import { getLanguageConfig } from './languageConfig'; import { getCustomConfigProviders } from './customProviders'; -import { Range } from 'vscode-languageclient'; import * as rd from 'readline'; import * as yauzl from 'yauzl'; import { Readable } from 'stream'; @@ -298,7 +299,7 @@ export function onDidChangeActiveTextEditor(editor?: vscode.TextEditor): void { } else { activeDocument = editor.document.uri.toString(); clients.activeDocumentChanged(editor.document); - clients.ActiveClient.selectionChanged(Range.create(editor.selection.start, editor.selection.end)); + clients.ActiveClient.selectionChanged(makeCpptoolsRange(editor.selection)); } ui.activeDocumentChanged(); } @@ -317,7 +318,7 @@ function onDidChangeTextEditorSelection(event: vscode.TextEditorSelectionChangeE clients.activeDocumentChanged(event.textEditor.document); ui.activeDocumentChanged(); } - clients.ActiveClient.selectionChanged(Range.create(event.selections[0].start, event.selections[0].end)); + clients.ActiveClient.selectionChanged(makeCpptoolsRange(event.selections[0])); } export function processDelayedDidOpen(document: vscode.TextDocument): boolean { @@ -417,7 +418,13 @@ export function registerCommands(): void { disposables.push(vscode.commands.registerCommand('C_Cpp.RunCodeAnalysisOnActiveFile', onRunCodeAnalysisOnActiveFile)); disposables.push(vscode.commands.registerCommand('C_Cpp.RunCodeAnalysisOnOpenFiles', onRunCodeAnalysisOnOpenFiles)); disposables.push(vscode.commands.registerCommand('C_Cpp.RunCodeAnalysisOnAllFiles', onRunCodeAnalysisOnAllFiles)); - disposables.push(vscode.commands.registerCommand('C_Cpp.ClearCodeAnalysisSquiggles', onClearCodeAnalysisSquiggles)); + disposables.push(vscode.commands.registerCommand('C_Cpp.RemoveCodeAnalysisProblems', onRemoveCodeAnalysisProblems)); + disposables.push(vscode.commands.registerCommand('C_Cpp.RemoveAllCodeAnalysisProblems', onRemoveAllCodeAnalysisProblems)); + disposables.push(vscode.commands.registerCommand('C_Cpp.FixThisCodeAnalysisProblem', onFixThisCodeAnalysisProblem)); + disposables.push(vscode.commands.registerCommand('C_Cpp.FixAllTypeCodeAnalysisProblems', onFixAllTypeCodeAnalysisProblems)); + disposables.push(vscode.commands.registerCommand('C_Cpp.FixAllCodeAnalysisProblems', onFixAllCodeAnalysisProblems)); + disposables.push(vscode.commands.registerCommand('C_Cpp.DisableAllTypeCodeAnalysisProblems', onDisableAllTypeCodeAnalysisProblems)); + disposables.push(vscode.commands.registerCommand('C_Cpp.ShowCodeAnalysisDocumentation', (uri) => vscode.env.openExternal(uri))); disposables.push(vscode.commands.registerCommand('cpptools.activeConfigName', onGetActiveConfigName)); disposables.push(vscode.commands.registerCommand('cpptools.activeConfigCustomVariable', onGetActiveConfigCustomVariable)); disposables.push(vscode.commands.registerCommand('cpptools.setActiveConfigName', onSetActiveConfigName)); @@ -594,8 +601,55 @@ async function onRunCodeAnalysisOnAllFiles(): Promise { getActiveClient().handleRunCodeAnalysisOnAllFiles(); } -async function onClearCodeAnalysisSquiggles(): Promise { - getActiveClient().handleClearCodeAnalysisSquiggles(); +async function onRemoveAllCodeAnalysisProblems(): Promise { + getActiveClient().handleRemoveAllCodeAnalysisProblems(); +} + +async function onRemoveCodeAnalysisProblems(refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + getActiveClient().handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave, identifiersAndUris); +} + +// Needed due to https://github.com/microsoft/vscode/issues/148723 . +const codeActionAbortedString: string = localize('code.action.aborted', "The code analysis fix could not be applied because the document has changed."); + +async function onFixThisCodeAnalysisProblem(version: number, workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + if (identifiersAndUris.length < 1) { + return; + } + const codeActions: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(identifiersAndUris[0].uri); + if (codeActions === undefined) { + return; + } + for (const codeAction of codeActions) { + if (codeAction.code === identifiersAndUris[0].identifiers[0].code && rangeEquals(codeAction.range, identifiersAndUris[0].identifiers[0].range)) { + if (version !== codeAction.version) { + vscode.window.showErrorMessage(codeActionAbortedString); + return; + } + break; + } + } + getActiveClient().handleFixCodeAnalysisProblems(workspaceEdit, refreshSquigglesOnSave, identifiersAndUris); +} + +async function onFixAllTypeCodeAnalysisProblems(type: string, version: number, workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + if (version === codeAnalysisCodeToFixes.get(type)?.version) { + getActiveClient().handleFixCodeAnalysisProblems(workspaceEdit, refreshSquigglesOnSave, identifiersAndUris); + } else { + vscode.window.showErrorMessage(codeActionAbortedString); + } +} + +async function onFixAllCodeAnalysisProblems(version: number, workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + if (version === codeAnalysisAllFixes.version) { + getActiveClient().handleFixCodeAnalysisProblems(workspaceEdit, refreshSquigglesOnSave, identifiersAndUris); + } else { + vscode.window.showErrorMessage(codeActionAbortedString); + } +} + +async function onDisableAllTypeCodeAnalysisProblems(code: string, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { + getActiveClient().handleDisableAllTypeCodeAnalysisProblems(code, identifiersAndUris); } function onAddToIncludePath(path: string): void { diff --git a/Extension/src/LanguageServer/settings.ts b/Extension/src/LanguageServer/settings.ts index 064069642..4183beb11 100644 --- a/Extension/src/LanguageServer/settings.ts +++ b/Extension/src/LanguageServer/settings.ts @@ -186,6 +186,17 @@ export class CppSettings extends Settings { public get clangTidyUseBuildPath(): boolean | undefined { return super.Section.get("codeAnalysis.clangTidy.useBuildPath"); } public get clangTidyChecksEnabled(): string[] | undefined { return super.Section.get("codeAnalysis.clangTidy.checks.enabled"); } public get clangTidyChecksDisabled(): string[] | undefined { return super.Section.get("codeAnalysis.clangTidy.checks.disabled"); } + public get clangTidyCodeActionShowDisable(): boolean | undefined { return super.Section.get("codeAnalysis.clangTidy.codeAction.showDisable"); } + public get clangTidyCodeActionShowClear(): string { return super.Section.get("codeAnalysis.clangTidy.codeAction.showClear") ?? "AllAndAllType"; } + public get clangTidyCodeActionShowDocumentation(): boolean | undefined { return super.Section.get("codeAnalysis.clangTidy.codeAction.showDocumentation"); } + public addClangTidyChecksDisabled(value: string): void { + const checks: string[] | undefined = this.clangTidyChecksDisabled; + if (checks === undefined) { + return; + } + checks.push(value); + super.Section.update("codeAnalysis.clangTidy.checks.disabled", checks, vscode.ConfigurationTarget.WorkspaceFolder); + } public get clangFormatStyle(): string | undefined { return super.Section.get("clang_format_style"); } public get clangFormatFallbackStyle(): string | undefined { return super.Section.get("clang_format_fallbackStyle"); } public get clangFormatSortIncludes(): string | undefined { return super.Section.get("clang_format_sortIncludes"); } diff --git a/Extension/src/LanguageServer/utils.ts b/Extension/src/LanguageServer/utils.ts new file mode 100644 index 000000000..a139065f2 --- /dev/null +++ b/Extension/src/LanguageServer/utils.ts @@ -0,0 +1,40 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All Rights Reserved. + * See 'LICENSE' in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; +import * as vscode from 'vscode'; +import { Range } from 'vscode-languageclient'; + +/** Differs from vscode.Location, which has a uri of type vscode.Uri. */ +export interface Location { + uri: string; + range: Range; +} + +export interface TextEdit { + range: Range; + newText: string; +} + +export function makeCpptoolsRange(vscRange: vscode.Range): Range { + return { start: { line: vscRange.start.line, character: vscRange.start.character }, + end: { line: vscRange.end.line, character: vscRange.end.character } }; +} + +export function makeVscodeRange(cpptoolsRange: Range): vscode.Range { + return new vscode.Range(cpptoolsRange.start.line, cpptoolsRange.start.character, cpptoolsRange.end.line, cpptoolsRange.end.character); +} + +export function makeVscodeLocation(cpptoolsLocation: Location): vscode.Location { + return new vscode.Location(vscode.Uri.parse(cpptoolsLocation.uri), makeVscodeRange(cpptoolsLocation.range)); +} + +export function makeVscodeTextEdits(cpptoolsTextEdits: TextEdit[]): vscode.TextEdit[] { + return cpptoolsTextEdits.map(textEdit => new vscode.TextEdit(makeVscodeRange(textEdit.range), textEdit.newText)); +} + +export function rangeEquals(range1: vscode.Range | Range, range2: vscode.Range | Range): boolean { + return range1.start.line === range2.start.line && range1.start.character === range2.start.character && + range1.end.line === range2.end.line && range1.end.character === range2.end.character; +} diff --git a/Extension/src/nativeStrings.json b/Extension/src/nativeStrings.json index c6b244549..d9fb5a84c 100644 --- a/Extension/src/nativeStrings.json +++ b/Extension/src/nativeStrings.json @@ -235,9 +235,10 @@ }, "unable_to_access_browse_database": "Unable to access browse database. ({0})", "default_compiler_path_modified_explicit_intellisense_mode": "IntelliSenseMode was changed because it didn't match the detected compiler. Consider setting \"compilerPath\" instead. Set \"compilerPath\" to \"\" to disable detection of system includes and defines.", - "clear_code_analysis_squiggles": "Clear code analysis squiggles", + "remove_all_code_analysis_problems": "Remove all code analysis problems", "multiple_locations_note": "(Multiple locations)", "folder_tag": "Folder", "file_tag": "File", - "compiler_default_language_standard_version_old" : "Compiler returned default language standard version: {0}. Since this version is old, will try to use newer version {1} as default." + "compiler_default_language_standard_version_old" : "Compiler returned default language standard version: {0}. Since this version is old, will try to use newer version {1} as default.", + "unexpected_output_from_clang_tidy": "Unexpected output from clang-tidy: {0}. Expected: {1}." } From feb8a6421a6317d5ad0e52fc8d692b61d8ad4848 Mon Sep 17 00:00:00 2001 From: Elaheh Rashedi Date: Thu, 19 May 2022 13:45:15 -0700 Subject: [PATCH 5/9] Make Play Button available to all users (#9311) --- Extension/package.json | 5 +---- Extension/package.nls.json | 2 +- .../src/Debugger/configurationProvider.ts | 16 +++++++-------- .../LanguageServer/cppBuildTaskProvider.ts | 20 +++++++------------ 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/Extension/package.json b/Extension/package.json index 454e6fa80..5345b78c8 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -2662,10 +2662,7 @@ }, "C_Cpp.debugShortcut": { "type": "boolean", - "default": false, - "tags": [ - "experimental" - ], + "default": true, "description": "%c_cpp.configuration.debugShortcut.description%", "scope": "application" }, diff --git a/Extension/package.nls.json b/Extension/package.nls.json index dc5262c15..e44bb9a67 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -222,7 +222,7 @@ "c_cpp.configuration.legacyCompilerArgsBehavior.deprecationMessage": "This setting is temporary to support transitioning to corrected behavior in v1.10.0.", "c_cpp.contributes.views.cppReferencesView.title": "C/C++: Other references results", "c_cpp.contributes.viewsWelcome.contents": { "message": "To learn more about launch.json, see [Configuring C/C++ debugging](https://code.visualstudio.com/docs/cpp/launch-json-reference).", "comment": [ "Markdown text between () should not be altered: https://en.wikipedia.org/wiki/Markdown" ] }, - "c_cpp.configuration.debugShortcut.description": "Show the Run and Debug play button in the editor title bar for C++ files.", + "c_cpp.configuration.debugShortcut.description": "Show the \"Run and Debug\" play button and \"Add Debug Configuration\" gear in the editor title bar for C++ files.", "c_cpp.debuggers.pipeTransport.description": "When present, this tells the debugger to connect to a remote computer using another executable as a pipe that will relay standard input/output between VS Code and the MI-enabled debugger backend executable (such as gdb).", "c_cpp.debuggers.pipeTransport.default.pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'.", "c_cpp.debuggers.pipeTransport.default.debuggerPath": "The full path to the debugger on the target machine, for example /usr/bin/gdb.", diff --git a/Extension/src/Debugger/configurationProvider.ts b/Extension/src/Debugger/configurationProvider.ts index 8e8c7f9db..ffbba5147 100644 --- a/Extension/src/Debugger/configurationProvider.ts +++ b/Extension/src/Debugger/configurationProvider.ts @@ -125,12 +125,8 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv } const items: MenuItem[] = configs.map(config => { - const reducedConfig: vscode.DebugConfiguration = {...config}; - // Remove the extra properties that are not a part of the DebugConfiguration. - reducedConfig.detail = undefined; - reducedConfig.existing = undefined; - reducedConfig.isDefault = undefined; - const menuItem: MenuItem = { label: config.name, configuration: reducedConfig, description: config.detail, detail: config.existing }; + const quickPickConfig: vscode.DebugConfiguration = {...config}; + const menuItem: MenuItem = { label: config.name, configuration: quickPickConfig, description: config.detail, detail: config.existing }; // Rename the menu item for the default configuration as its name is non-descriptive. if (isDebugLaunchStr(menuItem.label)) { menuItem.label = localize("default.configuration.menuitem", "Default Configuration"); @@ -148,6 +144,10 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv this.showErrorIfClNotAvailable(selection.label); } + // Remove the extra properties that are not a part of the DebugConfiguration, as these properties will be written in launch.json. + selection.configuration.detail = undefined; + selection.configuration.existing = undefined; + selection.configuration.isDefault = undefined; return [selection.configuration]; } @@ -665,7 +665,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv if (!folder) { return; } - const selectedConfig: vscode.DebugConfiguration | undefined = await this.selectConfiguration(textEditor, true); + const selectedConfig: vscode.DebugConfiguration | undefined = await this.selectConfiguration(textEditor, false); if (!selectedConfig) { Telemetry.logDebuggerEvent(DebuggerEvent.launchPlayButton, { "debugType": "AddConfigurationOnly", "folderMode": folder ? "folder" : "singleFile", "cancelled": "true" }); return; // User canceled it. @@ -751,7 +751,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv if (configuration.preLaunchTask) { try { if (folder) { - await cppBuildTaskProvider.writeBuildTask(configuration.preLaunchTask); + await cppBuildTaskProvider.writeDefaultBuildTask(configuration.preLaunchTask); } else { // In case of singleFile, remove the preLaunch task from the debug configuration and run it here instead. await cppBuildTaskProvider.runBuildTask(configuration.preLaunchTask); diff --git a/Extension/src/LanguageServer/cppBuildTaskProvider.ts b/Extension/src/LanguageServer/cppBuildTaskProvider.ts index af2755321..955737428 100644 --- a/Extension/src/LanguageServer/cppBuildTaskProvider.ts +++ b/Extension/src/LanguageServer/cppBuildTaskProvider.ts @@ -227,25 +227,19 @@ export class CppBuildTaskProvider implements TaskProvider { } public async writeDefaultBuildTask(taskLabel: string): Promise { - return this.checkBuildTaskExists(taskLabel, true, true); + return this.writeBuildTask(taskLabel, true); } - public async writeBuildTask(taskLabel: string): Promise { - return this.checkBuildTaskExists(taskLabel, true); - } - - public async checkBuildTaskExists(taskLabel: string, createTask: boolean = false, setAsDefault: boolean = false): Promise { + public async writeBuildTask(taskLabel: string, setAsDefault: boolean = false): Promise { const rawTasksJson: any = await this.getRawTasksJson(); if (!rawTasksJson.tasks) { rawTasksJson.tasks = new Array(); } - // Ensure that the task exists in the user's task.json. Task will not be found otherwise. + // Check if the task exists in the user's task.json. let selectedTask: any; - if (!createTask) { - selectedTask = rawTasksJson.tasks.find((task: any) => task.label && task.label === taskLabel); - if (selectedTask) { - return; - } + selectedTask = rawTasksJson.tasks.find((task: any) => task.label && task.label === taskLabel); + if (selectedTask) { + return; } // Create the task which should be created based on the selected "debug configuration". @@ -261,7 +255,7 @@ export class CppBuildTaskProvider implements TaskProvider { } rawTasksJson.version = "2.0.0"; - // Modify the current default task + // If the new task should be set as the default task, modify the current default task. if (setAsDefault) { rawTasksJson.tasks.forEach((task: any) => { if (task.label === selectedTask?.definition.label) { From 2238e7347fe41697362f39b6a76facd31695d0a7 Mon Sep 17 00:00:00 2001 From: Colen Garoutte-Carson <49173979+Colengms@users.noreply.github.com> Date: Fri, 20 May 2022 11:47:00 -0700 Subject: [PATCH 6/9] Prevent language service activation for macOS older than 10.12 (#9328) --- Extension/src/main.ts | 54 ++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/Extension/src/main.ts b/Extension/src/main.ts index cc59a1d83..927243d18 100644 --- a/Extension/src/main.ts +++ b/Extension/src/main.ts @@ -68,25 +68,43 @@ export async function activate(context: vscode.ExtensionContext): Promise 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined); - if (settings.intelliSenseEngine === "Disabled") { - languageServiceDisabled = true; + let isOldMacOs: boolean = false; + if (info.platform === 'darwin') { + const releaseParts: string[] = os.release().split("."); + if (releaseParts.length >= 1) { + isOldMacOs = parseInt(releaseParts[0]) < 16; + } } - let currentIntelliSenseEngineValue: string | undefined = settings.intelliSenseEngine; - disposables.push(vscode.workspace.onDidChangeConfiguration(() => { - const settings: CppSettings = new CppSettings((vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined); - if (!reloadMessageShown && settings.intelliSenseEngine !== currentIntelliSenseEngineValue) { - if (currentIntelliSenseEngineValue === "Disabled") { - // If switching from disabled to enabled, we can continue activation. - currentIntelliSenseEngineValue = settings.intelliSenseEngine; - languageServiceDisabled = false; - LanguageServer.activate(); - } else { - // We can't deactivate or change engines on the fly, so prompt for window reload. - reloadMessageShown = true; - util.promptForReloadWindowDueToSettingsChange(); - } + + // Read the setting and determine whether we should activate the language server prior to installing callbacks, + // to ensure there is no potential race condition. LanguageServer.activate() is called near the end of this + // function, to allow any further setup to occur here, prior to activation. + const shouldActivateLanguageServer: boolean = (settings.intelliSenseEngine !== "Disabled" && !isOldMacOs); + + if (isOldMacOs) { + languageServiceDisabled = true; + vscode.window.showErrorMessage(localize("macos.version.deprecated", "Versions of the C/C++ extension more recent than {0} require at least macOS version {1}.", "1.9.8", "10.12")); + } else { + if (settings.intelliSenseEngine === "Disabled") { + languageServiceDisabled = true; } - })); + let currentIntelliSenseEngineValue: string | undefined = settings.intelliSenseEngine; + disposables.push(vscode.workspace.onDidChangeConfiguration(() => { + const settings: CppSettings = new CppSettings((vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined); + if (!reloadMessageShown && settings.intelliSenseEngine !== currentIntelliSenseEngineValue) { + if (currentIntelliSenseEngineValue === "Disabled") { + // If switching from disabled to enabled, we can continue activation. + currentIntelliSenseEngineValue = settings.intelliSenseEngine; + languageServiceDisabled = false; + LanguageServer.activate(); + } else { + // We can't deactivate or change engines on the fly, so prompt for window reload. + reloadMessageShown = true; + util.promptForReloadWindowDueToSettingsChange(); + } + } + })); + } if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) { for (let i: number = 0; i < vscode.workspace.workspaceFolders.length; ++i) { @@ -114,7 +132,7 @@ export async function activate(context: vscode.ExtensionContext): Promise Date: Fri, 20 May 2022 16:03:09 -0700 Subject: [PATCH 7/9] Update IntelliSense loc strings. (#9334) * Update IntelliSense loc strings. --- Extension/bin/messages/cs/messages.json | 9 ++++++++- Extension/bin/messages/de/messages.json | 9 ++++++++- Extension/bin/messages/es/messages.json | 9 ++++++++- Extension/bin/messages/fr/messages.json | 9 ++++++++- Extension/bin/messages/it/messages.json | 9 ++++++++- Extension/bin/messages/ja/messages.json | 9 ++++++++- Extension/bin/messages/ko/messages.json | 9 ++++++++- Extension/bin/messages/pl/messages.json | 9 ++++++++- Extension/bin/messages/pt-br/messages.json | 9 ++++++++- Extension/bin/messages/ru/messages.json | 9 ++++++++- Extension/bin/messages/tr/messages.json | 9 ++++++++- Extension/bin/messages/zh-cn/messages.json | 9 ++++++++- Extension/bin/messages/zh-tw/messages.json | 9 ++++++++- 13 files changed, 104 insertions(+), 13 deletions(-) diff --git a/Extension/bin/messages/cs/messages.json b/Extension/bin/messages/cs/messages.json index 484964e29..7197cb4a0 100644 --- a/Extension/bin/messages/cs/messages.json +++ b/Extension/bin/messages/cs/messages.json @@ -3450,5 +3450,12 @@ "výběr člena zahrnuje příliš mnoho vnořených anonymních typů", "mezi operandy není žádný společný typ", "očekával se ukazatel na člen", - "flexibilní člen pole nelze deklarovat v jinak prázdném typu" + "flexibilní člen pole nelze deklarovat v jinak prázdném typu", + "Očekávalo se, že std::source_location::__impl bude definováno pro třídu pouze s datovými členy _M_function_name, _M_file_name, _M_column a _M_line.", + "během inicializace std::source_location::__impl přeteklo číslo sloupce člena _M_column typu %t", + "během inicializace std::source_location::__impl přeteklo číslo řádku člena _M_line typu %t", + "znaková konstanta UTF-16 nemůže zabírat více než jednu jednotku kódu; hodnota byla zkrácena", + "oba argumenty musí mít stejný typ", + "typ %t není platný jako argument pro tento předdefinovan.", + "voláno z %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/de/messages.json b/Extension/bin/messages/de/messages.json index 1bd7a95e5..4b01afe96 100644 --- a/Extension/bin/messages/de/messages.json +++ b/Extension/bin/messages/de/messages.json @@ -3450,5 +3450,12 @@ "Die Mitgliederauswahl umfasst zu viele geschachtelte anonyme Typen", "Es gibt keinen gemeinsamen Typ zwischen den Operanden", "Es wurde ein Pointer-to-Member erwartet", - "Ein flexibles Arrayelement kann nicht in einem ansonsten leeren Typ deklariert werden." + "Ein flexibles Arrayelement kann nicht in einem ansonsten leeren Typ deklariert werden.", + "Es wurde erwartet, dass \"std::source_location::__impl\" für eine Klasse definiert ist, die nur die Datenmember \"_M_function_name\", \"_M_file_name\", \"_M_column\", \"_M_line\" enthält.", + "während der Initialisierung von \"std::source_location::__impl\" überläuft die Spaltennummer den Member \"_M_column\" vom Typ \"%t\".", + "während der Initialisierung von \"std::source_location::__impl\" überläuft die Zeilennummer den Member \"_M_line\" vom Typ \"%t\".", + "Eine UTF-16-Zeichenkonstante darf nicht mehrere Codeeinheiten belegen. Wert abgeschnitten.", + "Beide Argumente müssen denselben Typ aufweisen.", + "Der Typ \"%t\" ist als Argument für dieses integrierte Element ungültig.", + "aufgerufen von %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/es/messages.json b/Extension/bin/messages/es/messages.json index 8c0e55d6d..0b997a425 100644 --- a/Extension/bin/messages/es/messages.json +++ b/Extension/bin/messages/es/messages.json @@ -3450,5 +3450,12 @@ "la selección de miembros implica demasiados tipos anónimos anidados", "no hay ningún tipo común entre los operandos", "se esperaba un puntero a miembro", - "un miembro de matriz flexible no se puede declarar en un tipo que de otro modo estaría vacío" + "un miembro de matriz flexible no se puede declarar en un tipo que de otro modo estaría vacío", + "se esperaba que 'std::source_location::__impl' se definiera a una clase con solo los miembros de datos '_M_function_name', '_M_file_name', '_M_column', '_M_line'", + "durante la inicialización de 'std::source_location::__impl', el número de columna desborda el miembro '_M_column' de tipo %t", + "durante la inicialización de 'std::source_location::__impl', el número de línea desborda el miembro '_M_line' de tipo %t", + "una constante de caracteres UTF-16 no puede ocupar más de una unidad de código; valor truncado", + "ambos argumentos deben tener el mismo tipo", + "el tipo %t no es válido como argumento para este elemento integrado", + "llamado desde %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/fr/messages.json b/Extension/bin/messages/fr/messages.json index 7df498eae..928730967 100644 --- a/Extension/bin/messages/fr/messages.json +++ b/Extension/bin/messages/fr/messages.json @@ -3450,5 +3450,12 @@ "la sélection de membre implique un trop grand nombre de types anonymes imbriqués", "il n’existe aucun type commun entre les opérandes", "pointeur vers membre attendu", - "un membre de tableau flexible ne peut pas être déclaré dans un type autrement vide." + "un membre de tableau flexible ne peut pas être déclaré dans un type autrement vide.", + "expected 'std::source_location::__impl' to be defined to a class with only the data members '_M_function_name', '_M_file_name', '_M_column', '_M_line'", + "lors de l’initialisation de 'std::source_location::__impl', le numéro de colonne dépasse le membre '_M_column' de type %t", + "lors de l’initialisation de 'std::source_location::__impl', le numéro de ligne dépasse le membre '_M_line' de type %t", + "une constante de caractères UTF-16 ne peut pas occuper plusieurs unités de code ; valeur tronquée", + "les deux arguments doivent avoir le même type", + "le type %t n’est pas valide en tant qu’argument pour ce builtin", + "appelé à partir de %nd :" ] \ No newline at end of file diff --git a/Extension/bin/messages/it/messages.json b/Extension/bin/messages/it/messages.json index f09078713..ba4f57571 100644 --- a/Extension/bin/messages/it/messages.json +++ b/Extension/bin/messages/it/messages.json @@ -3450,5 +3450,12 @@ "la selezione dei membri implica troppi tipi anonimi annidati", "non esiste alcun tipo comune tra gli operandi", "è previsto un puntatore a membro", - "un membro di matrice flessibile non può essere dichiarato in un tipo altrimenti vuoto" + "un membro di matrice flessibile non può essere dichiarato in un tipo altrimenti vuoto", + "previsto 'std::source_location::__impl' da definire in una classe con solo i membri dati '_M_function_name', '_M_file_name', '_M_column', '_M_line'", + "durante l'inizializzazione di 'std::source_location::__impl', il membro '_M_column' in overflow del numero di colonna è di tipo %t", + "durante l'inizializzazione di 'std::source_location::__impl', il membro '_M_line' in overflow del numero di riga è di tipo %t", + "una costante di caratteri UTF-16 non può occupare più di un'unità di codice; valore troncato", + "entrambi gli argomenti devono avere lo stesso tipo", + "il tipo %t non è valido come argomento per questa compilazione", + "chiamato da %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/ja/messages.json b/Extension/bin/messages/ja/messages.json index 868b445cc..65906688a 100644 --- a/Extension/bin/messages/ja/messages.json +++ b/Extension/bin/messages/ja/messages.json @@ -3450,5 +3450,12 @@ "メンバーの選択に含まれる、入れ子になった匿名のタイプが多すぎます", "オペランド間に共通型がありません", "メンバーへのポインターが必要です", - "フレキシブル配列メンバーは、otherwise-empty 型で宣言できません" + "フレキシブル配列メンバーは、otherwise-empty 型で宣言できません", + "'std::source_location::__impl' が、データ メンバー '_M_function_name'、'_M_file_name'、'_M_column'、'_M_line' のみを持つクラスに定義される必要があります", + "'std::source_location::__impl' の初期化中に、列番号が型 %t のメンバー '_M_column' をオーバーフローしました", + "'std::source_location::__impl' の初期化中に、行番号が型 %t のメンバー '_M_line' をオーバーフローしました", + "UTF-16 文字定数は複数のコード単位を占有できません。値が切り捨てられました", + "両方の引数は同じ型である必要があります", + "型 %t は、このビルトインの引数として無効です", + "%nd からの呼び出し:" ] \ No newline at end of file diff --git a/Extension/bin/messages/ko/messages.json b/Extension/bin/messages/ko/messages.json index 761c7ff8e..6cf619998 100644 --- a/Extension/bin/messages/ko/messages.json +++ b/Extension/bin/messages/ko/messages.json @@ -3450,5 +3450,12 @@ "멤버 선택에 너무 많은 중첩된 익명 형식이 포함됩니다.", "피연산자 사이에 공통 형식이 없습니다.", "멤버 포인터가 필요합니다.", - "유연한 배열 멤버는 비어 있는 형식으로 선언할 수 없습니다." + "유연한 배열 멤버는 비어 있는 형식으로 선언할 수 없습니다.", + "예상되는 'std::source_location::__impl'이 '_M_function_name', '_M_file_name', '_M_column', '_M_line'의 데이터 멤버만을 포함하는 클래스에 정의되어야 함", + "'std::source_location::__impl' 초기화 중 열 번호가 %t 형식의 '_M_column' 멤버를 오버플로", + "'std::source_location::__impl' 초기화 중 줄 번호가 %t 형식의 '_M_line' 멤버를 오버플로", + "UTF-16 문자 상수는 코드 단위를 두 개 이상 사용할 수 없음; 값 잘림", + "두 인수의 형식이 같아야 함", + "%t 형식은 이 기본 제공의 인수로 사용할 수 없음", + "%nd에서 호출" ] \ No newline at end of file diff --git a/Extension/bin/messages/pl/messages.json b/Extension/bin/messages/pl/messages.json index 47482cb7c..433efa15d 100644 --- a/Extension/bin/messages/pl/messages.json +++ b/Extension/bin/messages/pl/messages.json @@ -3450,5 +3450,12 @@ "wybór elementu członkowskiego obejmuje zbyt wiele zagnieżdżonych typów anonimowych", "nie ma wspólnego typu między argumentami operacji", "oczekiwano wskaźnika do składowej", - "elastyczna składowa tablicy nie może być zadeklarowana w typie pustym w inny sposób" + "elastyczna składowa tablicy nie może być zadeklarowana w typie pustym w inny sposób", + "oczekiwano zdefiniowania elementu „std::source_location::__impl” w klasie z tylko składowymi danych „_M_function_name”, „_M_file_name”, „_M_column”, „_M_line”", + "podczas inicjowania elementu „std::source_location::__impl” liczba kolumn przepełnia składową „_M_column” typu %t", + "podczas inicjowania elementu „std::source_location::__impl” liczba wierszy przepełnia składową „_M_line” typu %t", + "stała znaków UTF-16 nie może zajmować więcej niż jednej jednostki kodu; obcięta wartość", + "oba argumenty muszą mieć ten sam typ", + "typ %t jest nieprawidłowy jako argument dla tej wbudowanej", + "wywołano z %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/pt-br/messages.json b/Extension/bin/messages/pt-br/messages.json index d92f708cc..3d24813b8 100644 --- a/Extension/bin/messages/pt-br/messages.json +++ b/Extension/bin/messages/pt-br/messages.json @@ -3450,5 +3450,12 @@ "a seleção de membro envolve muitos tipos anônimos aninhados", "não há nenhum tipo comum entre os operandos", "esperava-se um ponteiro para membro", - "um membro da matriz flexível não pode ser declarado em um tipo de outro modo vazio" + "um membro da matriz flexível não pode ser declarado em um tipo de outro modo vazio", + "esperado que 'std::source_location::__impl' seja definido para uma classe com apenas os membros de dados '_M_function_name', '_M_file_name', '_M_column', '_M_line'", + "durante a inicialização de 'std::source_location::__impl', o número da coluna estoura o membro '_M_column' do tipo %t", + "durante a inicialização de 'std::source_location::__impl', o número da linha estoura o membro '_M_line' do tipo %t", + "uma constante de caractere UTF-16 não pode ocupar mais de uma unidade de código; valor truncado", + "ambos os argumentos devem ter o mesmo tipo", + "o tipo %téinválido como argumento para este builtin", + "chamado de %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/ru/messages.json b/Extension/bin/messages/ru/messages.json index 911aa148b..825f8cf3e 100644 --- a/Extension/bin/messages/ru/messages.json +++ b/Extension/bin/messages/ru/messages.json @@ -3450,5 +3450,12 @@ "выбор элемента включает слишком много вложенных анонимных типов", "между операндами нет общего типа", "необходим указатель на элемент", - "гибкий элемент массива не может быть объявлен в пустом типе" + "гибкий элемент массива не может быть объявлен в пустом типе", + "ожидается, что ''std::source_location::__impl'' будет определен для класса только с элементами данных ''_M_function_name'', ''_M_file_name'', ''_M_column'', ''_M_line''", + "во время инициализации ''std::source_location::__impl'' номер столбца переполняет элемент ''_M_column'' типа %t", + "во время инициализации ''std::source_location::__impl'' номер строки переполняет элемент ''_M_line'' типа %t", + "символьная константа UTF-16 не может занимать более одной кодовой единицы; значение усечено", + "оба аргумента должны быть одного типа", + "тип %t недопустим в качестве аргумента для этой встроенной функции.", + "вызвано из %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/tr/messages.json b/Extension/bin/messages/tr/messages.json index 88a892d9d..2b1e1e331 100644 --- a/Extension/bin/messages/tr/messages.json +++ b/Extension/bin/messages/tr/messages.json @@ -3450,5 +3450,12 @@ "üye seçimi çok fazla iç içe anonim tür içeriyor", "işlenenler arasında ortak tür yok", "üye işaretçisi bekleniyordu", - "esnek bir dizi üyesi diğer türlü boş olan bir türde bildirilemez" + "esnek bir dizi üyesi diğer türlü boş olan bir türde bildirilemez", + "'std::source_location::__impl', yalnızca '_M_function_name', '_M_file_name', '_M_column', '_M_line' veri üyelerine sahip bir sınıfa tanımlanmalıdır", + "'std::source_location::__impl' başlatılırken, sütun numarası %t türündeki '_M_column' üyesini aşıyor", + "'std::source_location::__impl' başlatılırken, satır numarası %t türündeki '_M_line' üyesini aşıyor", + "UTF-16 karakter sabit değeri, bir kod biriminden fazla yer kaplayamaz; kesilmiş değer", + "her iki bağımsız değişken de aynı türe sahip olmalıdır", + "%t türü bu yerleşik için bağımsız değişken olarak geçersiz", + "%nd kaynağından çağrı:" ] \ No newline at end of file diff --git a/Extension/bin/messages/zh-cn/messages.json b/Extension/bin/messages/zh-cn/messages.json index 758e5c722..08d301f37 100644 --- a/Extension/bin/messages/zh-cn/messages.json +++ b/Extension/bin/messages/zh-cn/messages.json @@ -3450,5 +3450,12 @@ "成员选择涉及太多嵌套的匿名类型", "操作数之间没有通用类型", "需要指向成员的指针", - "不能在其他空类型中声明灵活数组成员" + "不能在其他空类型中声明灵活数组成员", + "应将“std::source_location::__impl”定义为仅包含数据成员“__M_function_name”、“_M_file_name”、“_M_column”、“_M_line”的类", + "在初始化“std::source_location::__impl”期间,列号将溢出类型为 %t 的成员“_M_column”", + "在初始化“std::source_location::__impl”期间,行号将溢出类型为 %t 的成员“_M_line”", + "UTF-16 字符常量不能占用多个代码单元;值已截断", + "两个参数的类型必须相同", + "类型 %t 无效,不能用作此内置项的参数", + "调用自 %nd:" ] \ No newline at end of file diff --git a/Extension/bin/messages/zh-tw/messages.json b/Extension/bin/messages/zh-tw/messages.json index 0a5c06ff4..1d2687d5f 100644 --- a/Extension/bin/messages/zh-tw/messages.json +++ b/Extension/bin/messages/zh-tw/messages.json @@ -3450,5 +3450,12 @@ "成員選取涉及太多巢狀匿名型別", "運算元之間沒有通用類型", "必須是指標對成員", - "彈性陣列成員不能在非空白的類型中宣告" + "彈性陣列成員不能在非空白的類型中宣告", + "必須將 'std::source_location::__impl' 定義為只有資料成員為 '_M_function_name', '_M_file_name', '_M_column', '_M_line' 的類別", + "在初始化 'std::source_location::__impl' 時,欄位數會溢出類型為 %t 的成員 '_M_column'", + "在初始化 'std::source_location::__impl' 時,行數會溢出類型為 %t 的成員 '_M_line'", + "UTF-16 字元常數不可佔用多個程式碼單位; 已截斷值", + "兩個引數的類型必須相同", + "類型 %t 對此內建的引數無效", + "呼叫自 %nd:" ] \ No newline at end of file From 1120cb728056b9c68b4549d64e2cd820e082fbff Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Fri, 20 May 2022 16:14:54 -0700 Subject: [PATCH 8/9] Update changelog. (#9342) --- Extension/CHANGELOG.md | 8 ++++++++ Extension/package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Extension/CHANGELOG.md b/Extension/CHANGELOG.md index f5588347c..c00f6d850 100644 --- a/Extension/CHANGELOG.md +++ b/Extension/CHANGELOG.md @@ -1,5 +1,13 @@ # C/C++ for Visual Studio Code Change Log +## Version 1.10.3: May 23, 2022 +### New Feature +* Add code actions to apply clang-tidy fixes. [#8476](https://github.com/microsoft/vscode-cpptools/issues/8476) +* Make the "Run and Debug" button feature available to all users. [#9306](https://github.com/microsoft/vscode-cpptools/issues/9306) + +### Bug Fixes +* Fix several IntelliSense bugs. [#6226](https://github.com/microsoft/vscode-cpptools/issues/6226), [#8294](https://github.com/microsoft/vscode-cpptools/issues/8294), [#8530](https://github.com/microsoft/vscode-cpptools/issues/8530), [#8725](https://github.com/microsoft/vscode-cpptools/issues/8725), [#8751](https://github.com/microsoft/vscode-cpptools/issues/8751), [#9076](https://github.com/microsoft/vscode-cpptools/issues/9076), [#9224](https://github.com/microsoft/vscode-cpptools/issues/9224), [#9336](https://github.com/microsoft/vscode-cpptools/issues/9336) + ## Version 1.10.2: May 12, 2022 ### Bug Fix * Fix abnormal process termination (causing core dump creation on some systems) during process creation on Linux/Mac. [#9301](https://github.com/microsoft/vscode-cpptools/issues/9301) diff --git a/Extension/package.json b/Extension/package.json index 5345b78c8..24f9fee8c 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -2,7 +2,7 @@ "name": "cpptools", "displayName": "C/C++", "description": "C/C++ IntelliSense, debugging, and code browsing.", - "version": "1.10.2-main", + "version": "1.10.3-main", "publisher": "ms-vscode", "icon": "LanguageCCPP_color_128x.png", "readme": "README.md", From 617261dc524f1f40aa01f34531676420f6074dce Mon Sep 17 00:00:00 2001 From: Sean McManus Date: Fri, 20 May 2022 16:24:18 -0700 Subject: [PATCH 9/9] Add a missed change. (#9343) --- Extension/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Extension/CHANGELOG.md b/Extension/CHANGELOG.md index c00f6d850..25e58ea2b 100644 --- a/Extension/CHANGELOG.md +++ b/Extension/CHANGELOG.md @@ -7,6 +7,7 @@ ### Bug Fixes * Fix several IntelliSense bugs. [#6226](https://github.com/microsoft/vscode-cpptools/issues/6226), [#8294](https://github.com/microsoft/vscode-cpptools/issues/8294), [#8530](https://github.com/microsoft/vscode-cpptools/issues/8530), [#8725](https://github.com/microsoft/vscode-cpptools/issues/8725), [#8751](https://github.com/microsoft/vscode-cpptools/issues/8751), [#9076](https://github.com/microsoft/vscode-cpptools/issues/9076), [#9224](https://github.com/microsoft/vscode-cpptools/issues/9224), [#9336](https://github.com/microsoft/vscode-cpptools/issues/9336) +* Prevent language service activation for macOS older than 10.12. [PR #9328](https://github.com/microsoft/vscode-cpptools/pull/9328) ## Version 1.10.2: May 12, 2022 ### Bug Fix