From eb44a90f86bc40e66545bea9732a8ff20368b75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nora=20Dimitrijevi=C4=87?= Date: Thu, 24 Jul 2025 13:19:05 +0200 Subject: [PATCH 1/4] Add `codeQL.cliFeatures.*` context keys --- extensions/ql-vscode/src/extension.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index f57552d29fd..b6766f3baff 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -463,6 +463,25 @@ export async function activate( ); unsupportedWarningShown = true; }); + + // Expose the CodeQL CLI features to the extension context under `codeQL.cliFeatures.*`. + let cliFeatures: { [feature: string]: boolean | undefined } = {}; + codeQlExtension.cliServer.addVersionChangedListener(async (ver) => { + for (const feat of Object.keys(cliFeatures)) { + cliFeatures[feat] = false; + } + cliFeatures = { + ...cliFeatures, + ...(ver?.features ?? {}), + }; + for (const feat of Object.keys(cliFeatures)) { + await app.commands.execute( + "setContext", + `codeQL.cliFeatures.${feat}`, + cliFeatures[feat] ?? false, + ); + } + }); } return codeQlExtension; From a59f3c9fd0396362d38deaae3d62132e6dfc6eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nora=20Dimitrijevi=C4=87?= Date: Mon, 21 Jul 2025 16:36:07 +0200 Subject: [PATCH 2/4] Add "CodeQL: Trim Overlay Base Cache" command --- extensions/ql-vscode/package.json | 8 +++++++ extensions/ql-vscode/src/common/commands.ts | 1 + .../src/databases/local-databases-ui.ts | 20 ++++++++++++++++ .../ql-vscode/src/query-server/messages.ts | 24 +++++++++++++++++++ .../src/query-server/query-runner.ts | 19 +++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 5ea4536e2cb..8d5ee0dfc6b 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -790,6 +790,10 @@ "command": "codeQL.trimCache", "title": "CodeQL: Trim Cache" }, + { + "command": "codeQL.trimOverlayBaseCache", + "title": "CodeQL: Trim Overlay Base Cache" + }, { "command": "codeQL.installPackDependencies", "title": "CodeQL: Install Pack Dependencies" @@ -1817,6 +1821,10 @@ }, { "command": "codeQL.trimCache" + }, + { + "command": "codeQL.trimOverlayBaseCache", + "when": "codeQL.cliFeatures.queryServerTrimCacheWithMode" } ], "editor/context": [ diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index cfcfabb3f85..64585a8c9e8 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -221,6 +221,7 @@ export type LocalDatabasesCommands = { "codeQL.upgradeCurrentDatabase": () => Promise; "codeQL.clearCache": () => Promise; "codeQL.trimCache": () => Promise; + "codeQL.trimOverlayBaseCache": () => Promise; // Explorer context menu "codeQL.setCurrentDatabase": (uri: Uri) => Promise; diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts index 0a6c4c06442..d1ed2147fe7 100644 --- a/extensions/ql-vscode/src/databases/local-databases-ui.ts +++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts @@ -284,6 +284,7 @@ export class DatabaseUI extends DisposableObject { this.handleUpgradeCurrentDatabase.bind(this), "codeQL.clearCache": this.handleClearCache.bind(this), "codeQL.trimCache": this.handleTrimCache.bind(this), + "codeQL.trimOverlayBaseCache": this.handleTrimOverlayBaseCache.bind(this), "codeQLDatabases.chooseDatabaseFolder": this.handleChooseDatabaseFolder.bind(this), "codeQLDatabases.chooseDatabaseArchive": @@ -688,6 +689,25 @@ export class DatabaseUI extends DisposableObject { ); } + private async handleTrimOverlayBaseCache(): Promise { + return withProgress( + async () => { + if ( + this.queryServer !== undefined && + this.databaseManager.currentDatabaseItem !== undefined + ) { + await this.queryServer.trimCacheWithModeInDatabase( + this.databaseManager.currentDatabaseItem, + "overlay", + ); + } + }, + { + title: "Removing all overlay-dependent data from cache", + }, + ); + } + private async handleGetCurrentDatabase(): Promise { const dbItem = await this.getDatabaseItemInternal(undefined); return dbItem?.databaseUri.fsPath; diff --git a/extensions/ql-vscode/src/query-server/messages.ts b/extensions/ql-vscode/src/query-server/messages.ts index 4edacdc4e54..548e93ad32b 100644 --- a/extensions/ql-vscode/src/query-server/messages.ts +++ b/extensions/ql-vscode/src/query-server/messages.ts @@ -42,6 +42,22 @@ export interface TrimCacheParams { db: string; } +/** + * Parameters for trimming the cache of a dataset with a specific mode. + */ +export interface TrimCacheWithModeParams { + /** + * The dataset that we want to trim the cache of. + */ + db: string; + /** + * The cache cleanup mode to use. + */ + mode: ClearCacheMode; +} + +export type ClearCacheMode = "clear" | "trim" | "fit" | "overlay"; + /** * The result of trimming or clearing the cache. */ @@ -193,6 +209,14 @@ export const trimCache = new RequestType< ClearCacheResult, void >("evaluation/trimCache"); +/** + * Trim the cache of a dataset with a specific mode. + */ +export const trimCacheWithMode = new RequestType< + WithProgressId, + ClearCacheResult, + void +>("evaluation/trimCacheWithMode"); /** * Clear the pack cache diff --git a/extensions/ql-vscode/src/query-server/query-runner.ts b/extensions/ql-vscode/src/query-server/query-runner.ts index 08b9f1507dc..5d42e6056d7 100644 --- a/extensions/ql-vscode/src/query-server/query-runner.ts +++ b/extensions/ql-vscode/src/query-server/query-runner.ts @@ -6,10 +6,12 @@ import { UserCancellationException } from "../common/vscode/progress"; import type { DatabaseItem } from "../databases/local-databases/database-item"; import { QueryOutputDir } from "../local-queries/query-output-dir"; import type { + ClearCacheMode, ClearCacheParams, Position, QueryResultType, TrimCacheParams, + TrimCacheWithModeParams, } from "./messages"; import { clearCache, @@ -17,6 +19,7 @@ import { deregisterDatabases, registerDatabases, trimCache, + trimCacheWithMode, upgradeDatabase, } from "./messages"; import type { BaseLogger, Logger } from "../common/logging"; @@ -142,6 +145,22 @@ export class QueryRunner { await this.qs.sendRequest(trimCache, params); } + async trimCacheWithModeInDatabase( + dbItem: DatabaseItem, + mode: ClearCacheMode, + ): Promise { + if (dbItem.contents === undefined) { + throw new Error("Can't clean the cache in an invalid database."); + } + + const db = dbItem.databaseUri.fsPath; + const params: TrimCacheWithModeParams = { + db, + mode, + }; + await this.qs.sendRequest(trimCacheWithMode, params); + } + public async compileAndRunQueryAgainstDatabaseCore( dbPath: string, queries: CoreQueryTarget[], From 0c4fc07bdba3e0e88658f91c83b52a8c712544bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nora=20Dimitrijevi=C4=87?= Date: Wed, 23 Jul 2025 12:10:58 +0200 Subject: [PATCH 3/4] Add changelog entry --- extensions/ql-vscode/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 85ae4da32e9..3ff85de5196 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,6 +2,8 @@ ## [UNRELEASED] +- Add new command "CodeQL: Trim Overlay Base Cache" that returns a database to the state prior to overlay evaluation, leaving only base predicates and types that may later be referenced during overlay evaluation. [#4082](https://github.com/github/vscode-codeql/pull/4082) + ## 1.17.4 - 10 July 2025 - Fix variant analysis pack creation on some Windows systems [#4068](https://github.com/github/vscode-codeql/pull/4068) From 8fbb6b3367247b48991e4a25915cb1d868e18f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nora=20Dimitrijevi=C4=87?= Date: Fri, 25 Jul 2025 12:13:48 +0200 Subject: [PATCH 4/4] Add query server tests for `clearCache`, `trimCache`, `trimCacheWithMode` --- .../query-server/query-server-client.test.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/query-server/query-server-client.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/query-server/query-server-client.test.ts index c986e69ae62..874cefacc45 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/query-server/query-server-client.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/query-server/query-server-client.test.ts @@ -3,9 +3,12 @@ import { dirSync } from "tmp"; import { CancellationTokenSource } from "vscode-jsonrpc"; import type { RunQueryParams } from "../../../../src/query-server/messages"; import { + clearCache, QueryResultType, registerDatabases, runQuery, + trimCache, + trimCacheWithMode, } from "../../../../src/query-server/messages"; import type { CodeQLCliServer } from "../../../../src/codeql-cli/cli"; import type { BqrsCellValue } from "../../../../src/common/bqrs-cli-types"; @@ -198,5 +201,58 @@ describeWithCodeQL()("using the query server", () => { ); } }); + + it("should invoke codeQL.trimOverlayBaseCache command when queryServerTrimCacheWithMode is enabled", async () => { + const features = (await cliServer.getFeatures()) as { + [feature: string]: boolean | undefined; + }; + + // Register the database first (if not already done) + await qs.sendRequest(registerDatabases, { databases: [db] }); + + try { + // Send the trimCacheWithMode request + const params = { + db, + mode: "overlay", + }; + const result = await qs.sendRequest( + trimCacheWithMode, + params, + token, + () => {}, + ); + + // The result should contain a deletionMessage string + expect(result).toHaveProperty("deletionMessage"); + expect(typeof result.deletionMessage).toBe("string"); + expect(features.queryServerTrimCacheWithMode).toBeTruthy(); + } catch (e) { + expect(features.queryServerTrimCacheWithMode).toBeFalsy(); + expect((e as Error).message).toContain( + "Unsupported request method: evaluation/trimCacheWithMode", + ); + } + }); + + it("should invoke trimCache command and receive a deletionMessage", async () => { + // Register the database first (if not already done) + await qs.sendRequest(registerDatabases, { databases: [db] }); + + const params = { db }; + const result = await qs.sendRequest(trimCache, params, token, () => {}); + expect(result).toHaveProperty("deletionMessage"); + expect(typeof result.deletionMessage).toBe("string"); + }); + + it("should invoke clearCache command and receive a deletionMessage", async () => { + // Register the database first (if not already done) + await qs.sendRequest(registerDatabases, { databases: [db] }); + + const params = { db, dryRun: false }; + const result = await qs.sendRequest(clearCache, params, token, () => {}); + expect(result).toHaveProperty("deletionMessage"); + expect(typeof result.deletionMessage).toBe("string"); + }); } });