Skip to content

Commit cfa1ed3

Browse files
authored
Merge pull request #17844 from hvitved/rust/location-impl
Rust: Cache `Locatable.getLocation` and `Location`
2 parents 2326861 + 711dfc3 commit cfa1ed3

File tree

7 files changed

+94
-49
lines changed

7 files changed

+94
-49
lines changed

rust/ql/lib/codeql/rust/elements/internal/FormatArgumentImpl.qll

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,9 @@ module Impl {
4747
) {
4848
// TODO: handle locations in multi-line comments
4949
// TODO: handle the case where the template is from a nested macro call
50-
Synth::convertFormatArgsExprFromRaw(parent)
51-
.(FormatArgsExpr)
52-
.getTemplate()
53-
.getLocation()
54-
.hasLocationInfo(file.getAbsolutePath(), startline, startcolumn - offset, _, _) and
50+
LocatableImpl::getLocationDefault(Synth::convertFormatArgsExprFromRaw(parent)
51+
.(FormatArgsExpr)
52+
.getTemplate()).hasLocationFileInfo(file, startline, startcolumn - offset, _, _) and
5553
endline = startline and
5654
endcolumn = startcolumn + name.length() - 1
5755
}

rust/ql/lib/codeql/rust/elements/internal/FormatConstructor.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
private import codeql.rust.elements.internal.generated.Raw
8+
private import codeql.rust.internal.CachedStages
89

910
/**
1011
* The characteristic predicate of `Format` synthesized instances.
@@ -22,6 +23,7 @@ predicate constructFormat(Raw::FormatArgsExpr parent, int index, string text, in
2223
* Match an element of a format string, either text (`Hello`) or a format placeholder (`{}`).
2324
*/
2425
string formatElement(Raw::FormatArgsExpr parent, int occurrenceIndex, int occurrenceOffset) {
26+
Stages::AstStage::ref() and
2527
result =
2628
parent
2729
.getTemplate()

rust/ql/lib/codeql/rust/elements/internal/FormatImpl.qll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,8 @@ module Impl {
7979
override predicate hasSynthLocationInfo(
8080
File file, int startline, int startcolumn, int endline, int endcolumn
8181
) {
82-
this.getParent()
83-
.getTemplate()
84-
.getLocation()
85-
.hasLocationInfo(file.getAbsolutePath(), startline, startcolumn - offset, _, _) and
82+
LocatableImpl::getLocationDefault(this.getParent().getTemplate())
83+
.hasLocationFileInfo(file, startline, startcolumn - offset, _, _) and
8684
endline = startline and
8785
endcolumn = startcolumn + text.length() - 1
8886
}

rust/ql/lib/codeql/rust/elements/internal/LocatableImpl.qll

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,45 @@ private import codeql.rust.elements.internal.LocationImpl
99
private import codeql.rust.elements.internal.generated.Locatable
1010
private import codeql.rust.elements.internal.generated.Synth
1111
private import codeql.rust.elements.internal.generated.Raw
12+
private import codeql.rust.internal.CachedStages
1213

1314
/**
1415
* INTERNAL: This module contains the customizable definition of `Locatable` and should not
1516
* be referenced directly.
1617
*/
1718
module Impl {
1819
abstract class SynthLocatable extends Locatable {
20+
pragma[nomagic]
1921
abstract predicate hasSynthLocationInfo(
2022
File file, int startline, int startcolumn, int endline, int endcolumn
2123
);
2224

2325
final override Location getLocation() {
24-
not locatable_locations(Synth::convertLocatableToRaw(this), _) and
25-
exists(File file, int beginLine, int beginColumn, int endLine, int endColumn |
26-
this.hasSynthLocationInfo(file, beginLine, beginColumn, endLine, endColumn)
27-
|
28-
result = LocationImpl::TLocationSynth(file, beginLine, beginColumn, endLine, endColumn)
29-
or
30-
exists(@location_default location |
31-
result = LocationImpl::TLocationDefault(location) and
32-
locations_default(location, file, beginLine, beginColumn, endLine, endColumn)
33-
)
26+
exists(File file, int startline, int startcolumn, int endline, int endcolumn |
27+
this.hasSynthLocationInfo(file, startline, startcolumn, endline, endcolumn) and
28+
result.hasLocationFileInfo(file, startline, startcolumn, endline, endcolumn)
3429
)
3530
}
3631
}
3732

3833
class Locatable extends Generated::Locatable {
39-
pragma[nomagic]
34+
cached
4035
Location getLocation() {
41-
exists(@location_default location |
42-
result = LocationImpl::TLocationDefault(location) and
43-
locatable_locations(Synth::convertLocatableToRaw(this), location)
44-
)
36+
Stages::AstStage::ref() and
37+
result = getLocationDefault(this)
4538
}
4639

4740
/**
4841
* Gets the primary file where this element occurs.
4942
*/
5043
File getFile() { result = this.getLocation().getFile() }
5144
}
45+
46+
/** Gets the non-synthesized location of `l`, if any. */
47+
LocationImpl::LocationDefault getLocationDefault(Locatable l) {
48+
exists(@location_default location |
49+
result = LocationImpl::TLocationDefault(location) and
50+
locatable_locations(Synth::convertLocatableToRaw(l), location)
51+
)
52+
}
5253
}

rust/ql/lib/codeql/rust/elements/internal/LocationImpl.qll

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ private import codeql.rust.elements.internal.LocatableImpl::Impl as LocatableImp
33
private import codeql.rust.elements.Locatable
44
private import codeql.rust.elements.Format
55
private import codeql.rust.elements.FormatArgument
6+
private import codeql.rust.internal.CachedStages
67

78
module LocationImpl {
9+
cached
810
newtype TLocation =
9-
TLocationDefault(@location_default location) or
11+
TLocationDefault(@location_default location) { Stages::AstStage::ref() } or
1012
TLocationSynth(File file, int beginLine, int beginColumn, int endLine, int endColumn) {
1113
not locations_default(_, file, beginLine, beginColumn, endLine, endColumn) and
1214
any(LocatableImpl::SynthLocatable l)
@@ -55,10 +57,26 @@ module LocationImpl {
5557
* For more information, see
5658
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
5759
*/
58-
abstract predicate hasLocationInfo(
59-
string filepath, int startline, int startcolumn, int endline, int endcolumn
60+
abstract predicate hasLocationFileInfo(
61+
File file, int startline, int startcolumn, int endline, int endcolumn
6062
);
6163

64+
/**
65+
* Holds if this element is at the specified location.
66+
* The location spans column `startcolumn` of line `startline` to
67+
* column `endcolumn` of line `endline` in file `filepath`.
68+
* For more information, see
69+
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
70+
*/
71+
final predicate hasLocationInfo(
72+
string filepath, int startline, int startcolumn, int endline, int endcolumn
73+
) {
74+
exists(File file |
75+
this.hasLocationFileInfo(file, startline, startcolumn, endline, endcolumn) and
76+
filepath = file.getAbsolutePath()
77+
)
78+
}
79+
6280
/** Holds if this location starts strictly before the specified location. */
6381
pragma[inline]
6482
predicate strictlyBefore(Location other) {
@@ -68,18 +86,15 @@ module LocationImpl {
6886
}
6987
}
7088

71-
private class LocationDefault extends Location, TLocationDefault {
89+
class LocationDefault extends Location, TLocationDefault {
7290
@location_default self;
7391

7492
LocationDefault() { this = TLocationDefault(self) }
7593

76-
override predicate hasLocationInfo(
77-
string filepath, int startline, int startcolumn, int endline, int endcolumn
94+
override predicate hasLocationFileInfo(
95+
File file, int startline, int startcolumn, int endline, int endcolumn
7896
) {
79-
exists(File f |
80-
locations_default(self, f, startline, startcolumn, endline, endcolumn) and
81-
filepath = f.getAbsolutePath()
82-
)
97+
locations_default(self, file, startline, startcolumn, endline, endcolumn)
8398
}
8499
}
85100

@@ -88,13 +103,11 @@ module LocationImpl {
88103
EmptyLocation() { empty_location(self) }
89104
}
90105

91-
private class LocationSynth extends Location, TLocationSynth {
92-
override predicate hasLocationInfo(
93-
string filepath, int startline, int startcolumn, int endline, int endcolumn
106+
class LocationSynth extends Location, TLocationSynth {
107+
override predicate hasLocationFileInfo(
108+
File file, int startline, int startcolumn, int endline, int endcolumn
94109
) {
95-
this =
96-
TLocationSynth(any(File f | f.getAbsolutePath() = filepath), startline, startcolumn,
97-
endline, endcolumn)
110+
this = TLocationSynth(file, startline, startcolumn, endline, endcolumn)
98111
}
99112
}
100113
}

rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,41 +229,41 @@ module Impl {
229229
name = v.getName() and
230230
(
231231
parameterDeclInScope(_, v, scope) and
232-
scope.getLocation().hasLocationInfo(_, line, column, _, _)
232+
scope.getLocation().hasLocationFileInfo(_, line, column, _, _)
233233
or
234234
exists(Pat pat | pat = getAVariablePatAncestor(v) |
235235
scope =
236236
any(MatchArmScope arm |
237237
arm.getPat() = pat and
238-
arm.getLocation().hasLocationInfo(_, line, column, _, _)
238+
arm.getLocation().hasLocationFileInfo(_, line, column, _, _)
239239
)
240240
or
241241
exists(LetStmt let |
242242
let.getPat() = pat and
243243
scope = getEnclosingScope(let) and
244244
// for `let` statements, variables are bound _after_ the statement, i.e.
245245
// not in the RHS
246-
let.getLocation().hasLocationInfo(_, _, _, line, column)
246+
let.getLocation().hasLocationFileInfo(_, _, _, line, column)
247247
)
248248
or
249249
exists(IfExpr ie, LetExpr let |
250250
let.getPat() = pat and
251251
ie.getCondition() = let and
252252
scope = ie.getThen() and
253-
scope.getLocation().hasLocationInfo(_, line, column, _, _)
253+
scope.getLocation().hasLocationFileInfo(_, line, column, _, _)
254254
)
255255
or
256256
exists(ForExpr fe |
257257
fe.getPat() = pat and
258258
scope = fe.getLoopBody() and
259-
scope.getLocation().hasLocationInfo(_, line, column, _, _)
259+
scope.getLocation().hasLocationFileInfo(_, line, column, _, _)
260260
)
261261
or
262262
exists(WhileExpr we, LetExpr let |
263263
let.getPat() = pat and
264264
we.getCondition() = let and
265265
scope = we.getLoopBody() and
266-
scope.getLocation().hasLocationInfo(_, line, column, _, _)
266+
scope.getLocation().hasLocationFileInfo(_, line, column, _, _)
267267
)
268268
)
269269
)
@@ -283,7 +283,7 @@ module Impl {
283283
) {
284284
name = cand.getName() and
285285
scope = [cand.(VariableScope), getEnclosingScope(cand)] and
286-
cand.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn) and
286+
cand.getLocation().hasLocationFileInfo(_, startline, startcolumn, endline, endcolumn) and
287287
nestLevel = 0
288288
or
289289
exists(VariableScope inner |
@@ -292,7 +292,7 @@ module Impl {
292292
// Use the location of the inner scope as the location of the access, instead of the
293293
// actual access location. This allows us to collapse multiple accesses in inner
294294
// scopes to a single entity
295-
inner.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn)
295+
inner.getLocation().hasLocationFileInfo(_, startline, startcolumn, endline, endcolumn)
296296
)
297297
}
298298

rust/ql/lib/codeql/rust/internal/CachedStages.qll

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,39 @@ import rust
3030
* The `backref` predicate starts with `1 = 1 or` to ensure that the predicate will be optimized down to a constant by the optimizer.
3131
*/
3232
module Stages {
33+
/**
34+
* The abstract syntex tree (AST) stage.
35+
*/
36+
cached
37+
module AstStage {
38+
private import codeql.rust.controlflow.internal.Splitting
39+
private import codeql.rust.controlflow.internal.SuccessorType
40+
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl
41+
42+
/**
43+
* Always holds.
44+
* Ensures that a predicate is evaluated as part of the AST stage.
45+
*/
46+
cached
47+
predicate ref() { 1 = 1 }
48+
49+
/**
50+
* DO NOT USE!
51+
*
52+
* Contains references to each predicate that use the above `ref` predicate.
53+
*/
54+
cached
55+
predicate backref() {
56+
1 = 1
57+
or
58+
exists(Location l)
59+
or
60+
exists(any(Locatable l).getLocation())
61+
or
62+
exists(Format f)
63+
}
64+
}
65+
3366
/**
3467
* The control flow graph (CFG) stage.
3568
*/
@@ -41,7 +74,7 @@ module Stages {
4174

4275
/**
4376
* Always holds.
44-
* Ensures that a predicate is evaluated as part of the BasicBlocks stage.
77+
* Ensures that a predicate is evaluated as part of the CFG stage.
4578
*/
4679
cached
4780
predicate ref() { 1 = 1 }

0 commit comments

Comments
 (0)