Skip to content

Commit 4c30374

Browse files
committed
Extract tryGetResolvableLocation from semmle-bqrs
1 parent 26d83b5 commit 4c30374

4 files changed

Lines changed: 67 additions & 3 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { StringLocation, LocationValue, LocationStyle, ResolvableLocationValue } from './bqrs-types';
2+
3+
/**
4+
* The CodeQL filesystem libraries use this pattern in `getURL()` predicates
5+
* to describe the location of an entire filesystem resource.
6+
* Such locations appear as `StringLocation`s instead of `FivePartLocation`s.
7+
*
8+
* Folder resources also get similar URLs, but with the `folder` scheme.
9+
* They are deliberately ignored here, since there is no suitable location to show the user.
10+
*/
11+
const FILE_LOCATION_REGEX = /file:\/\/(.+):([0-9]+):([0-9]+):([0-9]+):([0-9]+)/;
12+
/**
13+
* Gets a resolvable source file location for the specified `LocationValue`, if possible.
14+
* @param loc The location to test.
15+
*/
16+
export function tryGetResolvableLocation(
17+
loc: LocationValue | undefined
18+
): ResolvableLocationValue | undefined {
19+
if (loc === undefined) {
20+
return undefined;
21+
} else if (loc.t === LocationStyle.FivePart && loc.file) {
22+
return loc;
23+
} else if (loc.t === LocationStyle.WholeFile && loc.file) {
24+
return loc;
25+
} else if (loc.t === LocationStyle.String && loc.loc) {
26+
return tryGetLocationFromString(loc);
27+
} else {
28+
return undefined;
29+
}
30+
}
31+
32+
export function tryGetLocationFromString(
33+
loc: StringLocation
34+
): ResolvableLocationValue | undefined {
35+
const matches = FILE_LOCATION_REGEX.exec(loc.loc);
36+
if (matches && matches.length > 1 && matches[1]) {
37+
if (isWholeFileMatch(matches)) {
38+
return {
39+
t: LocationStyle.WholeFile,
40+
file: matches[1],
41+
};
42+
} else {
43+
return {
44+
t: LocationStyle.FivePart,
45+
file: matches[1],
46+
lineStart: Number(matches[2]),
47+
colStart: Number(matches[3]),
48+
lineEnd: Number(matches[4]),
49+
colEnd: Number(matches[5]),
50+
}
51+
}
52+
} else {
53+
return undefined;
54+
}
55+
}
56+
57+
function isWholeFileMatch(matches: RegExpExecArray): boolean {
58+
return (
59+
matches[2] === "0" &&
60+
matches[3] === "0" &&
61+
matches[4] === "0" &&
62+
matches[5] === "0"
63+
);
64+
}

extensions/ql-vscode/src/interface-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
} from './bqrs-types';
2222
import {
2323
tryGetResolvableLocation,
24-
} from 'semmle-bqrs';
24+
} from './bqrs-utils';
2525
import { DatabaseItem, DatabaseManager } from './databases';
2626
import { ViewSourceFileMsg } from './interface-types';
2727
import { Logger } from './logging';

extensions/ql-vscode/src/view/result-table-utils.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { LocationValue, ResolvableLocationValue } from '../bqrs-types';
3-
import { tryGetResolvableLocation } from 'semmle-bqrs';
3+
import { tryGetResolvableLocation } from '../bqrs-utils';
44
import { RawResultsSortState, QueryMetadata, SortDirection } from '../interface-types';
55
import { assertNever } from '../helpers-pure';
66
import { ResultSet } from '../interface-types';

extensions/ql-vscode/test/pure-tests/location.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from 'chai';
22
import 'mocha';
33
import { LocationStyle, StringLocation } from '../../src/bqrs-types';
4-
import { tryGetResolvableLocation } from 'semmle-bqrs';
4+
import { tryGetResolvableLocation } from '../../src/bqrs-utils';
55

66
describe('processing string locations', function () {
77
it('should detect Windows whole-file locations', function () {

0 commit comments

Comments
 (0)