Skip to content

Commit b333a16

Browse files
committed
Merge remote-tracking branch 'origin/main' into koesie10/new-variant-analysis-statuses
2 parents d711d80 + 03e48b7 commit b333a16

29 files changed

+898
-119
lines changed

extensions/ql-vscode/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [UNRELEASED]
44

5+
## 1.7.5 - 8 November 2022
6+
7+
- Fix a bug where the AST Viewer was not working unless the associated CodeQL library pack is in the workspace. [#1735](https://github.com/github/vscode-codeql/pull/1735)
8+
59
## 1.7.4 - 29 October 2022
610

711
No user facing changes.

extensions/ql-vscode/package-lock.json

Lines changed: 9 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/ql-vscode/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "CodeQL for Visual Studio Code",
55
"author": "GitHub",
66
"private": true,
7-
"version": "1.7.5",
7+
"version": "1.7.6",
88
"publisher": "GitHub",
99
"license": "MIT",
1010
"icon": "media/VS-marketplace-CodeQL-icon.png",
@@ -1299,6 +1299,7 @@
12991299
"@primer/react": "^35.0.0",
13001300
"@vscode/codicons": "^0.0.31",
13011301
"@vscode/webview-ui-toolkit": "^1.0.1",
1302+
"ajv": "^8.11.0",
13021303
"child-process-promise": "^2.2.1",
13031304
"chokidar": "^3.5.3",
13041305
"classnames": "~2.2.6",
@@ -1389,7 +1390,6 @@
13891390
"@typescript-eslint/eslint-plugin": "^4.26.0",
13901391
"@typescript-eslint/parser": "^4.26.0",
13911392
"@vscode/test-electron": "^2.2.0",
1392-
"ajv": "^8.11.0",
13931393
"ansi-colors": "^4.1.1",
13941394
"applicationinsights": "^2.3.5",
13951395
"babel-loader": "^8.2.5",

extensions/ql-vscode/src/cli.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,12 @@ export class CodeQLCliServer implements Disposable {
970970
}
971971
}
972972

973+
async packResolveDependencies(dir: string): Promise<{ [pack: string]: string }> {
974+
// Uses the default `--mode use-lock`, which creates the lock file if it doesn't exist.
975+
const results: { [pack: string]: string } = await this.runJsonCodeQlCliCommand(['pack', 'resolve-dependencies'], [dir], 'Resolving pack dependencies');
976+
return results;
977+
}
978+
973979
async generateDil(qloFile: string, outFile: string): Promise<void> {
974980
const extraArgs = await this.cliConstraints.supportsDecompileDil()
975981
? ['--kind', 'dil', '-o', outFile, qloFile]
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Represents a result that can be either a value or some errors.
3+
*/
4+
export class ValueResult<TValue> {
5+
private constructor(
6+
private readonly errorMsgs: string[],
7+
private readonly val?: TValue,
8+
) {
9+
}
10+
11+
public static ok<TValue>(value: TValue): ValueResult<TValue> {
12+
if (value === undefined) {
13+
throw new Error('Value must be set for successful result');
14+
}
15+
16+
return new ValueResult([], value);
17+
}
18+
19+
public static fail<TValue>(errorMsgs: string[]): ValueResult<TValue> {
20+
if (errorMsgs.length === 0) {
21+
throw new Error('At least one error message must be set for a failed result');
22+
}
23+
24+
return new ValueResult<TValue>(errorMsgs, undefined);
25+
}
26+
27+
public get isOk(): boolean {
28+
return this.errorMsgs.length === 0;
29+
}
30+
31+
public get isFailure(): boolean {
32+
return this.errorMsgs.length > 0;
33+
}
34+
35+
public get errors(): string[] {
36+
if (!this.errorMsgs) {
37+
throw new Error('Cannot get error for successful result');
38+
}
39+
40+
return this.errorMsgs;
41+
}
42+
43+
public get value(): TValue {
44+
if (this.val === undefined) {
45+
throw new Error('Cannot get value for unsuccessful result');
46+
}
47+
48+
return this.val;
49+
}
50+
}

extensions/ql-vscode/src/contextual/locationFinder.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { DatabaseManager, DatabaseItem } from '../databases';
55
import fileRangeFromURI from './fileRangeFromURI';
66
import { ProgressCallback } from '../commandRunner';
77
import { KeyType } from './keyType';
8-
import { qlpackOfDatabase, resolveQueries } from './queryResolver';
8+
import { qlpackOfDatabase, resolveQueries, runContextualQuery } from './queryResolver';
99
import { CancellationToken, LocationLink, Uri } from 'vscode';
10-
import { createInitialQueryInfo, QueryWithResults } from '../run-queries-shared';
10+
import { QueryWithResults } from '../run-queries-shared';
1111
import { QueryRunner } from '../queryRunner';
1212

1313
export const SELECT_QUERY_NAME = '#select';
@@ -56,15 +56,7 @@ export async function getLocationsForUriString(
5656

5757
const links: FullLocationLink[] = [];
5858
for (const query of await resolveQueries(cli, qlpack, keyType)) {
59-
const initialInfo = await createInitialQueryInfo(
60-
Uri.file(query),
61-
{
62-
name: db.name,
63-
databaseUri: db.databaseUri.toString(),
64-
},
65-
false
66-
);
67-
const results = await qs.compileAndRunQueryAgainstDatabase(db, initialInfo, queryStorageDir, progress, token, templates);
59+
const results = await runContextualQuery(query, db, queryStorageDir, qs, cli, progress, token, templates);
6860
if (results.successful) {
6961
links.push(...await getLinksFromResults(results, cli, db, filter));
7062
}

extensions/ql-vscode/src/contextual/queryResolver.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as fs from 'fs-extra';
22
import * as yaml from 'js-yaml';
33
import * as tmp from 'tmp-promise';
4+
import * as path from 'path';
45

56
import * as helpers from '../helpers';
67
import {
@@ -12,6 +13,11 @@ import {
1213
import { CodeQLCliServer } from '../cli';
1314
import { DatabaseItem } from '../databases';
1415
import { QlPacksForLanguage } from '../helpers';
16+
import { logger } from '../logging';
17+
import { createInitialQueryInfo } from '../run-queries-shared';
18+
import { CancellationToken, Uri } from 'vscode';
19+
import { ProgressCallback } from '../commandRunner';
20+
import { QueryRunner } from '../queryRunner';
1521

1622
export async function qlpackOfDatabase(cli: CodeQLCliServer, db: DatabaseItem): Promise<QlPacksForLanguage> {
1723
if (db.contents === undefined) {
@@ -104,3 +110,69 @@ export async function resolveQueries(cli: CodeQLCliServer, qlpacks: QlPacksForLa
104110
void helpers.showAndLogErrorMessage(errorMessage);
105111
throw new Error(`Couldn't find any queries tagged ${tagOfKeyType(keyType)} in any of the following packs: ${packsToSearch.join(', ')}.`);
106112
}
113+
114+
async function resolveContextualQuery(cli: CodeQLCliServer, query: string): Promise<{ packPath: string, createdTempLockFile: boolean }> {
115+
// Contextual queries now live within the standard library packs.
116+
// This simplifies distribution (you don't need the standard query pack to use the AST viewer),
117+
// but if the library pack doesn't have a lockfile, we won't be able to find
118+
// other pack dependencies of the library pack.
119+
120+
// Work out the enclosing pack.
121+
const packContents = await cli.packPacklist(query, false);
122+
const packFilePath = packContents.find((p) => ['codeql-pack.yml', 'qlpack.yml'].includes(path.basename(p)));
123+
if (packFilePath === undefined) {
124+
// Should not happen; we already resolved this query.
125+
throw new Error(`Could not find a CodeQL pack file for the pack enclosing the contextual query ${query}`);
126+
}
127+
const packPath = path.dirname(packFilePath);
128+
const lockFilePath = packContents.find((p) => ['codeql-pack.lock.yml', 'qlpack.lock.yml'].includes(path.basename(p)));
129+
let createdTempLockFile = false;
130+
if (!lockFilePath) {
131+
// No lock file, likely because this library pack is in the package cache.
132+
// Create a lock file so that we can resolve dependencies and library path
133+
// for the contextual query.
134+
void logger.log(`Library pack ${packPath} is missing a lock file; creating a temporary lock file`);
135+
await cli.packResolveDependencies(packPath);
136+
createdTempLockFile = true;
137+
// Clear CLI server pack cache before installing dependencies,
138+
// so that it picks up the new lock file, not the previously cached pack.
139+
void logger.log('Clearing the CodeQL CLI server\'s pack cache');
140+
await cli.clearCache();
141+
// Install dependencies.
142+
void logger.log(`Installing package dependencies for library pack ${packPath}`);
143+
await cli.packInstall(packPath);
144+
}
145+
return { packPath, createdTempLockFile };
146+
}
147+
148+
async function removeTemporaryLockFile(packPath: string) {
149+
const tempLockFilePath = path.resolve(packPath, 'codeql-pack.lock.yml');
150+
void logger.log(`Deleting temporary package lock file at ${tempLockFilePath}`);
151+
// It's fine if the file doesn't exist.
152+
await fs.promises.rm(path.resolve(packPath, 'codeql-pack.lock.yml'), { force: true });
153+
}
154+
155+
export async function runContextualQuery(query: string, db: DatabaseItem, queryStorageDir: string, qs: QueryRunner, cli: CodeQLCliServer, progress: ProgressCallback, token: CancellationToken, templates: Record<string, string>) {
156+
const { packPath, createdTempLockFile } = await resolveContextualQuery(cli, query);
157+
const initialInfo = await createInitialQueryInfo(
158+
Uri.file(query),
159+
{
160+
name: db.name,
161+
databaseUri: db.databaseUri.toString(),
162+
},
163+
false
164+
);
165+
void logger.log(`Running contextual query ${query}; results will be stored in ${queryStorageDir}`);
166+
const queryResult = await qs.compileAndRunQueryAgainstDatabase(
167+
db,
168+
initialInfo,
169+
queryStorageDir,
170+
progress,
171+
token,
172+
templates
173+
);
174+
if (createdTempLockFile) {
175+
await removeTemporaryLockFile(packPath);
176+
}
177+
return queryResult;
178+
}

0 commit comments

Comments
 (0)