Add feature to jump to the .ql file referenced by a .qlref

This commit is contained in:
Edoardo Pirovano
2021-03-26 18:09:27 +00:00
committed by Andrew Eisenberg
parent c082a38b6b
commit e033578cd2
4 changed files with 75 additions and 4 deletions

View File

@@ -8,6 +8,7 @@
- Avoid showing an error popup when user runs a query without `@kind` metadata. [#801](https://github.com/github/vscode-codeql/pull/801)
- Fix running of tests when the `ms-python` extension is installed. [#803](https://github.com/github/vscode-codeql/pull/803)
- Add an option to jump from a .qlref file to the .ql file it references.
## 1.4.4 - 19 March 2021

View File

@@ -34,6 +34,7 @@
"onCommand:codeQLDatabases.chooseDatabaseLgtm",
"onCommand:codeQL.setCurrentDatabase",
"onCommand:codeQL.viewAst",
"onCommand:codeQL.openReferencedFile",
"onCommand:codeQL.chooseDatabaseFolder",
"onCommand:codeQL.chooseDatabaseArchive",
"onCommand:codeQL.chooseDatabaseInternet",
@@ -229,6 +230,10 @@
"command": "codeQL.quickEval",
"title": "CodeQL: Quick Evaluation"
},
{
"command": "codeQL.openReferencedFile",
"title": "CodeQL: Open Referenced File"
},
{
"command": "codeQL.quickQuery",
"title": "CodeQL: Quick Query"
@@ -619,6 +624,11 @@
"command": "codeQL.runQueries",
"group": "9_qlCommands",
"when": "resourceScheme != codeql-zip-archive"
},
{
"command": "codeQL.openReferencedFile",
"group": "9_qlCommands",
"when": "resourceExtname == .qlref"
}
],
"commandPalette": [
@@ -634,6 +644,10 @@
"command": "codeQL.quickEval",
"when": "editorLangId == ql"
},
{
"command": "codeQL.openReferencedFile",
"when": "resourceExtname == .qlref"
},
{
"command": "codeQL.setCurrentDatabase",
"when": "false"
@@ -771,6 +785,10 @@
{
"command": "codeQL.quickEval",
"when": "editorLangId == ql"
},
{
"command": "codeQL.openReferencedFile",
"when": "resourceExtname == .qlref"
}
]
},

View File

@@ -73,6 +73,11 @@ export interface UpgradesInfo {
*/
export type QlpacksInfo = { [name: string]: string[] };
/**
* The expected output of `codeql resolve qlref`.
*/
export type QlrefInfo = { resolvedPath: string };
// `codeql bqrs interpret` requires both of these to be present or
// both absent.
export interface SourceInfo {
@@ -143,6 +148,11 @@ export class CodeQLCliServer implements Disposable {
*/
private static CLI_VERSION_WITH_DOWNGRADES = new SemVer('2.4.4');
/**
* CLI version where the `codeql resolve qlref` command is available.
*/
private static CLI_VERSION_WITH_RESOLVE_QLREF = new SemVer('2.5.1');
/** The process for the cli server, or undefined if one doesn't exist yet */
process?: child_process.ChildProcessWithoutNullStreams;
/** Queue of future commands*/
@@ -461,12 +471,15 @@ export class CodeQLCliServer implements Disposable {
* @param command The `codeql` command to be run, provided as an array of command/subcommand names.
* @param commandArgs The arguments to pass to the `codeql` command.
* @param description Description of the action being run, to be shown in log and error messages.
* @param addFormat Whether or not to add commandline arguments to specify the format as JSON.
* @param progressReporter Used to output progress messages, e.g. to the status bar.
* @returns The contents of the command's stdout, if the command succeeded.
*/
async runJsonCodeQlCliCommand<OutputType>(command: string[], commandArgs: string[], description: string, progressReporter?: ProgressReporter): Promise<OutputType> {
// Add format argument first, in case commandArgs contains positional parameters.
const args = ['--format', 'json'].concat(commandArgs);
async runJsonCodeQlCliCommand<OutputType>(command: string[], commandArgs: string[], description: string, addFormat = true, progressReporter?: ProgressReporter): Promise<OutputType> {
let args: string[] = [];
if (addFormat) // Add format argument first, in case commandArgs contains positional parameters.
args = args.concat(['--format', 'json']);
args = args.concat(commandArgs);
const result = await this.runCodeQlCliCommand(command, args, description, progressReporter);
try {
return JSON.parse(result) as OutputType;
@@ -505,6 +518,18 @@ export class CodeQLCliServer implements Disposable {
);
}
public async resolveQlref(qlref: string): Promise<QlrefInfo> {
const subcommandArgs = [
qlref
];
return await this.runJsonCodeQlCliCommand<QlrefInfo>(
['resolve', 'qlref'],
subcommandArgs,
'Resolving qlref',
false
);
}
/**
* Runs QL tests.
* @param testPaths Full paths of the tests to run.
@@ -549,7 +574,7 @@ export class CodeQLCliServer implements Disposable {
if (queryMemoryMb !== undefined) {
args.push('--ram', queryMemoryMb.toString());
}
return await this.runJsonCodeQlCliCommand<string[]>(['resolve', 'ram'], args, 'Resolving RAM settings', progressReporter);
return await this.runJsonCodeQlCliCommand<string[]>(['resolve', 'ram'], args, 'Resolving RAM settings', true, progressReporter);
}
/**
* Gets the headers (and optionally pagination info) of a bqrs.
@@ -773,6 +798,10 @@ export class CodeQLCliServer implements Disposable {
return (await this.getVersion()).compare(CodeQLCliServer.CLI_VERSION_WITH_DOWNGRADES) >= 0;
}
public async supportsResolveQlref() {
return (await this.getVersion()).compare(CodeQLCliServer.CLI_VERSION_WITH_RESOLVE_QLREF) >= 0;
}
private async refreshVersion() {
const distribution = await this.distributionProvider.getDistribution();
switch (distribution.kind) {

View File

@@ -480,6 +480,23 @@ async function activateWithInstalledDistribution(
}
}
async function openReferencedFile(
selectedQuery: Uri
): Promise<void> {
if (qs !== undefined) {
if (await cliServer.supportsResolveQlref()) {
const resolved = await cliServer.resolveQlref(selectedQuery.path);
const uri = Uri.file(resolved.resolvedPath);
await window.showTextDocument(uri, { preview: false });
} else {
helpers.showAndLogErrorMessage(
'Jumping from a .qlref file to the .ql file it references is not '
+ 'supported with the CLI version you are running.\n'
+ 'Please upgrade your CLI to use this feature.');
}
}
}
ctx.subscriptions.push(tmpDirDisposal);
logger.log('Initializing CodeQL language server.');
@@ -616,6 +633,12 @@ async function activateWithInstalledDistribution(
}
)
);
ctx.subscriptions.push(
commandRunner(
'codeQL.openReferencedFile',
openReferencedFile
)
);
ctx.subscriptions.push(
commandRunnerWithProgress('codeQL.restartQueryServer', async (