Skip to content

Commit 882e8f7

Browse files
committed
Rust: Type inference and path resolution for builtins
1 parent 14ede4e commit 882e8f7

File tree

15 files changed

+856
-270
lines changed

15 files changed

+856
-270
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/** Provides sub classes of literal expressions. */
2+
3+
private import internal.LiteralExprImpl
4+
5+
final class CharLiteralExpr = Impl::CharLiteralExpr;
6+
7+
final class StringLiteralExpr = Impl::StringLiteralExpr;
8+
9+
final class NumberLiteralExpr = Impl::NumberLiteralExpr;
10+
11+
final class IntegerLiteralExpr = Impl::IntegerLiteralExpr;
12+
13+
final class FloatLiteralExpr = Impl::FloatLiteralExpr;
14+
15+
final class BooleanLiteralExpr = Impl::BooleanLiteralExpr;

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

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,189 @@ module Impl {
4242
)
4343
}
4444
}
45+
46+
/**
47+
* A [character literal][1]. For example:
48+
*
49+
* ```rust
50+
* 'x';
51+
* ```
52+
*
53+
* [1]: https://doc.rust-lang.org/reference/tokens.html#character-literals
54+
*/
55+
class CharLiteralExpr extends LiteralExpr {
56+
CharLiteralExpr() {
57+
// todo: proper implementation
58+
this.getTextValue().regexpMatch("'.*'")
59+
}
60+
61+
override string getAPrimaryQlClass() { result = "CharLiteralExpr" }
62+
}
63+
64+
/**
65+
* A [string literal][1]. For example:
66+
*
67+
* ```rust
68+
* "Hello, world!";
69+
* ```
70+
*
71+
* [1]: https://doc.rust-lang.org/reference/tokens.html#string-literals
72+
*/
73+
class StringLiteralExpr extends LiteralExpr {
74+
StringLiteralExpr() {
75+
// todo: proper implementation
76+
this.getTextValue().regexpMatch("\".*\"")
77+
}
78+
79+
override string getAPrimaryQlClass() { result = "StringLiteralExpr" }
80+
}
81+
82+
/**
83+
* A number literal.
84+
*/
85+
abstract class NumberLiteralExpr extends LiteralExpr { }
86+
87+
// https://doc.rust-lang.org/reference/tokens.html#integer-literals
88+
private module IntegerLiteralRegexs {
89+
bindingset[s]
90+
string paren(string s) { result = "(" + s + ")" }
91+
92+
string integerLiteral() {
93+
result =
94+
paren(paren(decLiteral()) + "|" + paren(binLiteral()) + "|" + paren(octLiteral()) + "|" +
95+
paren(hexLiteral())) + paren(suffix()) + "?"
96+
}
97+
98+
private string suffix() { result = "u8|i8|u16|i16|u32|i32|u64|i64|u128|i128|usize|isize" }
99+
100+
string decLiteral() { result = decDigit() + "(" + decDigit() + "|_)*" }
101+
102+
string binLiteral() {
103+
result = "0b(" + binDigit() + "|_)*" + binDigit() + "(" + binDigit() + "|_)*"
104+
}
105+
106+
string octLiteral() {
107+
result = "0o(" + octDigit() + "|_)*" + octDigit() + "(" + octDigit() + "|_)*"
108+
}
109+
110+
string hexLiteral() {
111+
result = "0x(" + hexDigit() + "|_)*" + hexDigit() + "(" + hexDigit() + "|_)*"
112+
}
113+
114+
string decDigit() { result = "[0-9]" }
115+
116+
string binDigit() { result = "[01]" }
117+
118+
string octDigit() { result = "[0-7]" }
119+
120+
string hexDigit() { result = "[0-9a-fA-F]" }
121+
}
122+
123+
/**
124+
* An [integer literal][1]. For example:
125+
*
126+
* ```rust
127+
* 42;
128+
* ```
129+
*
130+
* [1]: https://doc.rust-lang.org/reference/tokens.html#integer-literals
131+
*/
132+
class IntegerLiteralExpr extends NumberLiteralExpr {
133+
IntegerLiteralExpr() { this.getTextValue().regexpMatch(IntegerLiteralRegexs::integerLiteral()) }
134+
135+
/**
136+
* Get the suffix of this integer literal, if any.
137+
*
138+
* For example, `42u8` has the suffix `u8`.
139+
*/
140+
string getSuffix() {
141+
exists(string s, string reg, int last |
142+
s = this.getTextValue() and
143+
reg = IntegerLiteralRegexs::integerLiteral() and
144+
last = strictcount(reg.indexOf("(")) and
145+
result = s.regexpCapture(reg, last)
146+
)
147+
}
148+
149+
override string getAPrimaryQlClass() { result = "IntegerLiteralExpr" }
150+
}
151+
152+
// https://doc.rust-lang.org/reference/tokens.html#floating-point-literals
153+
private module FloatLiteralRegexs {
154+
private import IntegerLiteralRegexs
155+
156+
string floatLiteral() {
157+
result =
158+
paren(decLiteral() + "\\.") + "|" + paren(floatLiteralSuffix1()) + "|" +
159+
paren(floatLiteralSuffix2())
160+
}
161+
162+
string floatLiteralSuffix1() {
163+
result = decLiteral() + "\\." + decLiteral() + paren(suffix()) + "?"
164+
}
165+
166+
string floatLiteralSuffix2() {
167+
result =
168+
decLiteral() + paren("\\." + decLiteral()) + "?" + paren(exponent()) + paren(suffix()) + "?"
169+
}
170+
171+
string integerSuffixLiteral() {
172+
result =
173+
paren(paren(decLiteral()) + "|" + paren(binLiteral()) + "|" + paren(octLiteral()) + "|" +
174+
paren(hexLiteral())) + paren(suffix())
175+
}
176+
177+
private string suffix() { result = "f32|f64" }
178+
179+
string exponent() {
180+
result = "(e|E)(\\+|-)?(" + decDigit() + "|_)*" + decDigit() + "(" + decDigit() + "|_)*"
181+
}
182+
}
183+
184+
/**
185+
* A [floating-point literal][1]. For example:
186+
*
187+
* ```rust
188+
* 42.0;
189+
* ```
190+
*
191+
* [1]: https://doc.rust-lang.org/reference/tokens.html#floating-point-literals
192+
*/
193+
class FloatLiteralExpr extends NumberLiteralExpr {
194+
FloatLiteralExpr() {
195+
this.getTextValue()
196+
.regexpMatch([
197+
FloatLiteralRegexs::floatLiteral(), FloatLiteralRegexs::integerSuffixLiteral()
198+
])
199+
}
200+
201+
/**
202+
* Get the suffix of this floating-point literal, if any.
203+
*
204+
* For example, `42.0f32` has the suffix `f32`.
205+
*/
206+
string getSuffix() {
207+
exists(string s, string reg, int last |
208+
s = this.getTextValue() and
209+
reg =
210+
[
211+
FloatLiteralRegexs::floatLiteralSuffix1(), FloatLiteralRegexs::floatLiteralSuffix2(),
212+
FloatLiteralRegexs::integerSuffixLiteral()
213+
] and
214+
last = strictcount(reg.indexOf("(")) and
215+
result = s.regexpCapture(reg, last)
216+
)
217+
}
218+
219+
override string getAPrimaryQlClass() { result = "FloatLiteralExpr" }
220+
}
221+
222+
/**
223+
* A Boolean literal. Either `true` or `false`.
224+
*/
225+
class BooleanLiteralExpr extends LiteralExpr {
226+
BooleanLiteralExpr() { this.getTextValue().regexpMatch("true|false") }
227+
228+
override string getAPrimaryQlClass() { result = "BooleanLiteralExpr" }
229+
}
45230
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Provides classes for builtins.
3+
*/
4+
5+
private import rust
6+
7+
/** The folder containing builtins. */
8+
class BuiltinsFolder extends Folder {
9+
BuiltinsFolder() {
10+
this.getBaseName() = "builtins" and
11+
this.getParentContainer().getBaseName() = "tools"
12+
}
13+
}
14+
15+
private class BuiltinsTypesFile extends File {
16+
BuiltinsTypesFile() {
17+
this.getBaseName() = "types.rs" and
18+
this.getParentContainer() instanceof BuiltinsFolder
19+
}
20+
}
21+
22+
private class BuiltinType extends Struct {
23+
BuiltinType() { this.getFile() instanceof BuiltinsTypesFile }
24+
}
25+
26+
/** The builtin `bool` type. */
27+
class Bool extends BuiltinType {
28+
Bool() { this.getName().getText() = "bool" }
29+
}
30+
31+
/** The builtin `char` type. */
32+
class Char extends BuiltinType {
33+
Char() { this.getName().getText() = "char" }
34+
}
35+
36+
/** The builtin `str` type. */
37+
class Str extends BuiltinType {
38+
Str() { this.getName().getText() = "str" }
39+
}
40+
41+
/** The builtin `i8` type. */
42+
class I8 extends BuiltinType {
43+
I8() { this.getName().getText() = "i8" }
44+
}
45+
46+
/** The builtin `i16` type. */
47+
class I16 extends BuiltinType {
48+
I16() { this.getName().getText() = "i16" }
49+
}
50+
51+
/** The builtin `i32` type. */
52+
class I32 extends BuiltinType {
53+
I32() { this.getName().getText() = "i32" }
54+
}
55+
56+
/** The builtin `i64` type. */
57+
class I64 extends BuiltinType {
58+
I64() { this.getName().getText() = "i64" }
59+
}
60+
61+
/** The builtin `i128` type. */
62+
class I128 extends BuiltinType {
63+
I128() { this.getName().getText() = "i128" }
64+
}
65+
66+
/** The builtin `u8` type. */
67+
class U8 extends BuiltinType {
68+
U8() { this.getName().getText() = "u8" }
69+
}
70+
71+
/** The builtin `u16` type. */
72+
class U16 extends BuiltinType {
73+
U16() { this.getName().getText() = "u16" }
74+
}
75+
76+
/** The builtin `u32` type. */
77+
class U32 extends BuiltinType {
78+
U32() { this.getName().getText() = "u32" }
79+
}
80+
81+
/** The builtin `u64` type. */
82+
class U64 extends BuiltinType {
83+
U64() { this.getName().getText() = "u64" }
84+
}
85+
86+
/** The builtin `u128` type. */
87+
class U128 extends BuiltinType {
88+
U128() { this.getName().getText() = "u128" }
89+
}
90+
91+
/** The builtin `usize` type. */
92+
class USize extends BuiltinType {
93+
USize() { this.getName().getText() = "usize" }
94+
}
95+
96+
/** The builtin `isize` type. */
97+
class ISize extends BuiltinType {
98+
ISize() { this.getName().getText() = "isize" }
99+
}
100+
101+
/** The builtin `f32` type. */
102+
class F32 extends BuiltinType {
103+
F32() { this.getName().getText() = "f32" }
104+
}
105+
106+
/** The builtin `f64` type. */
107+
class F64 extends BuiltinType {
108+
F64() { this.getName().getText() = "f64" }
109+
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ abstract class ItemNode extends Locatable {
180180
or
181181
preludeEdge(this, name, result) and not declares(this, _, name)
182182
or
183+
builtinEdge(this, name, result)
184+
or
183185
name = "super" and
184186
if this instanceof Module or this instanceof SourceFile
185187
then result = this.getImmediateParentModule()
@@ -1184,6 +1186,21 @@ private predicate preludeEdge(SourceFile f, string name, ItemNode i) {
11841186
)
11851187
}
11861188

1189+
private import codeql.rust.frameworks.stdlib.Bultins as Builtins
1190+
1191+
pragma[nomagic]
1192+
private predicate builtinEdge(ModuleLikeNode m, string name, ItemNode i) {
1193+
(
1194+
m instanceof SourceFile
1195+
or
1196+
m = any(CrateItemNode c).getModuleNode()
1197+
) and
1198+
exists(SourceFileItemNode builtins |
1199+
builtins.getFile().getParentContainer() instanceof Builtins::BuiltinsFolder and
1200+
i = builtins.getASuccessorRec(name)
1201+
)
1202+
}
1203+
11871204
/** Provides predicates for debugging the path resolution implementation. */
11881205
private module Debug {
11891206
private Locatable getRelevantLocatable() {

0 commit comments

Comments
 (0)