Skip to content

Commit 473569d

Browse files
authored
Merge pull request #1735 from adityasharad/ast/synthetic-query-pack
Contextual queries: Support running when the library pack is in the package cache
2 parents ab0e8a0 + 97c985b commit 473569d

File tree

4 files changed

+100
-32
lines changed

4 files changed

+100
-32
lines changed

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]

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+
}

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

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,17 @@ import {
2121
KeyType,
2222
} from './keyType';
2323
import { FullLocationLink, getLocationsForUriString, TEMPLATE_NAME } from './locationFinder';
24-
import { qlpackOfDatabase, resolveQueries } from './queryResolver';
24+
import { qlpackOfDatabase, resolveQueries, runContextualQuery } from './queryResolver';
2525
import { isCanary, NO_CACHE_AST_VIEWER } from '../config';
26-
import { createInitialQueryInfo, QueryWithResults } from '../run-queries-shared';
26+
import { QueryWithResults } from '../run-queries-shared';
2727
import { QueryRunner } from '../queryRunner';
2828

2929
/**
30-
* Run templated CodeQL queries to find definitions and references in
30+
* Runs templated CodeQL queries to find definitions in
3131
* source-language files. We may eventually want to find a way to
3232
* generalize this to other custom queries, e.g. showing dataflow to
3333
* or from a selected identifier.
3434
*/
35-
3635
export class TemplateQueryDefinitionProvider implements DefinitionProvider {
3736
private cache: CachedOperation<LocationLink[]>;
3837

@@ -77,6 +76,12 @@ export class TemplateQueryDefinitionProvider implements DefinitionProvider {
7776
}
7877
}
7978

79+
/**
80+
* Runs templated CodeQL queries to find references in
81+
* source-language files. We may eventually want to find a way to
82+
* generalize this to other custom queries, e.g. showing dataflow to
83+
* or from a selected identifier.
84+
*/
8085
export class TemplateQueryReferenceProvider implements ReferenceProvider {
8186
private cache: CachedOperation<FullLocationLink[]>;
8287

@@ -131,6 +136,10 @@ type QueryWithDb = {
131136
dbUri: Uri
132137
};
133138

139+
/**
140+
* Run templated CodeQL queries to produce AST information for
141+
* source-language files.
142+
*/
134143
export class TemplatePrintAstProvider {
135144
private cache: CachedOperation<QueryWithDb>;
136145

@@ -199,29 +208,18 @@ export class TemplatePrintAstProvider {
199208
zippedArchive.pathWithinSourceArchive
200209
};
201210

202-
const initialInfo = await createInitialQueryInfo(
203-
Uri.file(query),
204-
{
205-
name: db.name,
206-
databaseUri: db.databaseUri.toString(),
207-
},
208-
false
209-
);
210-
211+
const queryResult = await runContextualQuery(query, db, this.queryStorageDir, this.qs, this.cli, progress, token, templates);
211212
return {
212-
query: await this.qs.compileAndRunQueryAgainstDatabase(
213-
db,
214-
initialInfo,
215-
this.queryStorageDir,
216-
progress,
217-
token,
218-
templates
219-
),
213+
query: queryResult,
220214
dbUri: db.databaseUri
221215
};
222216
}
223217
}
224218

219+
/**
220+
* Run templated CodeQL queries to produce CFG information for
221+
* source-language files.
222+
*/
225223
export class TemplatePrintCfgProvider {
226224
private cache: CachedOperation<[Uri, Record<string, string>] | undefined>;
227225

0 commit comments

Comments
 (0)