Skip to content

Commit 2326861

Browse files
authored
Merge pull request #17805 from github/aibaars/local-defs
Rust: Rust: add jump to definition for format arguments
2 parents 1972532 + fdf99e2 commit 2326861

File tree

6 files changed

+187
-10
lines changed

6 files changed

+187
-10
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* Provides classes and predicates related to jump-to-definition links
3+
* in the code viewer.
4+
*/
5+
6+
private import codeql.rust.elements.Variable
7+
private import codeql.rust.elements.Locatable
8+
private import codeql.rust.elements.FormatArgsExpr
9+
private import codeql.rust.elements.FormatArgsArg
10+
private import codeql.rust.elements.Format
11+
private import codeql.rust.elements.MacroCall
12+
private import codeql.rust.elements.NamedFormatArgument
13+
private import codeql.rust.elements.PositionalFormatArgument
14+
private import codeql.Locations
15+
16+
/** An element with an associated definition. */
17+
abstract class Use extends Locatable {
18+
/** Gets the definition associated with this element. */
19+
abstract Definition getDefinition();
20+
21+
/**
22+
* Gets the type of use.
23+
*/
24+
abstract string getUseType();
25+
}
26+
27+
cached
28+
private module Cached {
29+
cached
30+
newtype TDef =
31+
TVariable(Variable v) or
32+
TFormatArgsArgName(Name name) { name = any(FormatArgsArg a).getName() } or
33+
TFormatArgsArgIndex(Expr e) { e = any(FormatArgsArg a).getExpr() }
34+
35+
/**
36+
* Gets an element, of kind `kind`, that element `use` uses, if any.
37+
*/
38+
cached
39+
Definition definitionOf(Use use, string kind) {
40+
result = use.getDefinition() and
41+
kind = use.getUseType() and
42+
not result.getLocation() = any(MacroCall m).getLocation()
43+
}
44+
}
45+
46+
predicate definitionOf = Cached::definitionOf/2;
47+
48+
/** A definition */
49+
class Definition extends Cached::TDef {
50+
/** Gets the location of this variable. */
51+
Location getLocation() {
52+
result = this.asVariable().getLocation() or
53+
result = this.asName().getLocation() or
54+
result = this.asExpr().getLocation()
55+
}
56+
57+
/** Gets this definition as a `Variable` */
58+
Variable asVariable() { this = Cached::TVariable(result) }
59+
60+
/** Gets this definition as a `Name` */
61+
Name asName() { this = Cached::TFormatArgsArgName(result) }
62+
63+
/** Gets this definition as an `Expr` */
64+
Expr asExpr() { this = Cached::TFormatArgsArgIndex(result) }
65+
66+
/** Gets the string representation of this element. */
67+
string toString() {
68+
result = this.asExpr().toString() or
69+
result = this.asVariable().toString() or
70+
result = this.asName().getText()
71+
}
72+
}
73+
74+
private class LocalVariableUse extends Use instanceof VariableAccess {
75+
private Variable def;
76+
77+
LocalVariableUse() { this = def.getAnAccess() }
78+
79+
override Definition getDefinition() { result.asVariable() = def }
80+
81+
override string getUseType() { result = "local variable" }
82+
}
83+
84+
private class NamedFormatArgumentUse extends Use instanceof NamedFormatArgument {
85+
private Name def;
86+
87+
NamedFormatArgumentUse() {
88+
exists(FormatArgsExpr parent |
89+
parent = this.getParent().getParent() and
90+
parent.getAnArg().getName() = def and
91+
this.getName() = def.getText()
92+
)
93+
}
94+
95+
override Definition getDefinition() { result.asName() = def }
96+
97+
override string getUseType() { result = "format argument" }
98+
}
99+
100+
private class PositionalFormatUse extends Use instanceof Format {
101+
PositionalFormatUse() { not exists(this.getArgumentRef()) }
102+
103+
override Definition getDefinition() {
104+
exists(FormatArgsExpr parent, int index | parent.getFormat(_) = this |
105+
this = rank[index + 1](PositionalFormatUse f, int i | parent.getFormat(i) = f | f order by i) and
106+
result.asExpr() = parent.getArg(index).getExpr()
107+
)
108+
}
109+
110+
override string getUseType() { result = "format argument" }
111+
}
112+
113+
private class PositionalFormatArgumentUse extends Use instanceof PositionalFormatArgument {
114+
private Expr def;
115+
116+
PositionalFormatArgumentUse() {
117+
exists(FormatArgsExpr parent |
118+
parent = this.getParent().getParent() and
119+
def = parent.getArg(this.getIndex()).getExpr()
120+
)
121+
}
122+
123+
override Definition getDefinition() { result.asExpr() = def }
124+
125+
override string getUseType() { result = "format argument" }
126+
}

rust/ql/lib/ide-contextual-queries/localDefinitions.ql

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,17 @@
33
* @description Generates use-definition pairs that provide the data
44
* for jump-to-definition in the code viewer.
55
* @kind definitions
6-
* @id rus/ide-jump-to-definition
6+
* @id rust/ide-jump-to-definition
77
* @tags ide-contextual-queries/local-definitions
88
*/
99

1010
import codeql.IDEContextual
11-
import codeql.rust.elements.Variable
12-
import codeql.rust.elements.Locatable
11+
import codeql.rust.internal.Definitions
1312

1413
external string selectedSourceFile();
1514

16-
predicate localVariable(Locatable e, Variable def) { e = def.getAnAccess() }
17-
18-
from Locatable e, Variable def, string kind
15+
from Use use, Definition def, string kind
1916
where
20-
e.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile()) and
21-
localVariable(e, def) and
22-
kind = "local variable"
23-
select e, def, kind
17+
def = definitionOf(use, kind) and
18+
use.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
19+
select use, def, kind
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @name Find-references links
3+
* @description Generates use-definition pairs that provide the data
4+
* for find-references in the code viewer.
5+
* @kind definitions
6+
* @id rust/ide-find-references
7+
* @tags ide-contextual-queries/local-references
8+
*/
9+
10+
import codeql.IDEContextual
11+
import codeql.rust.internal.Definitions
12+
13+
external string selectedSourceFile();
14+
15+
from Use use, Definition def, string kind
16+
where
17+
def = definitionOf(use, kind) and
18+
def.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
19+
select use, def, kind
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
| main.rs:2:9:2:13 | width | main.rs:5:29:5:33 | width | local variable |
2+
| main.rs:2:9:2:13 | width | main.rs:6:41:6:45 | width | local variable |
3+
| main.rs:2:9:2:13 | width | main.rs:7:36:7:40 | width | local variable |
4+
| main.rs:3:9:3:17 | precision | main.rs:5:36:5:44 | precision | local variable |
5+
| main.rs:3:9:3:17 | precision | main.rs:6:48:6:56 | precision | local variable |
6+
| main.rs:4:9:4:13 | value | main.rs:6:34:6:38 | value | local variable |
7+
| main.rs:4:9:4:13 | value | main.rs:7:29:7:33 | value | local variable |
8+
| main.rs:5:50:5:54 | value | main.rs:5:22:5:26 | value | format argument |
9+
| main.rs:6:34:6:38 | value | main.rs:6:22:6:22 | 0 | format argument |
10+
| main.rs:6:41:6:45 | width | main.rs:6:25:6:25 | 1 | format argument |
11+
| main.rs:6:48:6:56 | precision | main.rs:6:28:6:28 | 2 | format argument |
12+
| main.rs:7:29:7:33 | value | main.rs:7:21:7:22 | {} | format argument |
13+
| main.rs:7:36:7:40 | width | main.rs:7:24:7:25 | {} | format argument |
14+
| main.rs:8:9:8:14 | people | main.rs:9:22:9:27 | people | local variable |
15+
| main.rs:10:31:10:31 | 1 | main.rs:10:19:10:20 | {} | format argument |
16+
| main.rs:10:31:10:31 | 1 | main.rs:10:23:10:23 | 0 | format argument |
17+
| main.rs:10:34:10:34 | 2 | main.rs:10:16:10:16 | 1 | format argument |
18+
| main.rs:10:34:10:34 | 2 | main.rs:10:26:10:27 | {} | format argument |
19+
| main.rs:11:40:11:42 | "x" | main.rs:11:31:11:35 | {:<5} | format argument |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import codeql.rust.internal.Definitions
2+
3+
from Definition def, Use use, string kind
4+
where def = definitionOf(use, kind)
5+
select def, use, kind
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn main() {
2+
let width = 4;
3+
let precision = 2;
4+
let value = 10;
5+
println!("Value {value:#width$.precision$}", value = 10.5);
6+
println!("Value {0:#1$.2$}", value, width, precision);
7+
println!("Value {} {}", value, width);
8+
let people = "Rustaceans";
9+
println!("Hello {people}!");
10+
println!("{1} {} {0} {}", 1, 2);
11+
assert_eq!(format!("Hello {:<5}!", "x"), "Hello x !");
12+
}

0 commit comments

Comments
 (0)