Skip to content

Commit 23f23d4

Browse files
committed
Rust: Rework call resolution and type inference for calls
1 parent d08271d commit 23f23d4

File tree

12 files changed

+2313
-1528
lines changed

12 files changed

+2313
-1528
lines changed

rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class CallableScopeTree extends StandardTree, PreOrderTree, PostOrderTree, Scope
7777

7878
override AstNode getChildNode(int i) {
7979
i = 0 and
80-
result = this.getParamList().getSelfParam()
80+
result = this.getSelfParam()
8181
or
8282
result = this.getParam(i - 1)
8383
or

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ module Impl {
102102
f = resolvePath(path) and
103103
path.getSegment().getIdentifier().getText() = methodName and
104104
exists(SelfParam self |
105-
self = f.getParamList().getSelfParam() and
105+
self = f.getSelfParam() and
106106
if self.isRef() then selfIsRef = true else selfIsRef = false
107107
)
108108
)

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,15 @@ module Impl {
1717
*/
1818
class Callable extends Generated::Callable {
1919
override Param getParam(int index) { result = this.getParamList().getParam(index) }
20+
21+
/**
22+
* Gets the self parameter of this callable, if it exists.
23+
*/
24+
SelfParam getSelfParam() { result = this.getParamList().getSelfParam() }
25+
26+
/**
27+
* Holds if `getSelfParam()` exists.
28+
*/
29+
predicate hasSelfParam() { exists(this.getSelfParam()) }
2030
}
2131
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
1212
* the canonical path `path` and the method name `method`, and if it borrows its
1313
* first `borrows` arguments.
1414
*/
15-
private predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
15+
predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
1616
arity = 1 and
1717
(
1818
// Negation

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ module Impl {
2121
* ```
2222
*/
2323
class Union extends Generated::Union {
24+
/** Gets the record field named `name`, if any. */
25+
pragma[nomagic]
26+
StructField getStructField(string name) {
27+
result = this.getStructFieldList().getAField() and
28+
result.getName().getText() = name
29+
}
30+
2431
override string toStringImpl() { result = "union " + this.getName().getText() }
2532
}
2633
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ module Impl {
109109
text = name.getText() and
110110
// exclude self parameters from functions without a body as these are
111111
// trait method declarations without implementations
112-
not exists(Function f | not f.hasBody() and f.getParamList().getSelfParam() = sp)
112+
not exists(Function f | not f.hasBody() and f.getSelfParam() = sp)
113113
)
114114
or
115115
exists(IdentPat pat |

rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,83 @@ class StringStruct extends Struct {
213213
pragma[nomagic]
214214
StringStruct() { this.getCanonicalPath() = "alloc::string::String" }
215215
}
216+
217+
/**
218+
* The [`Deref` trait][1].
219+
*
220+
* [1]: https://doc.rust-lang.org/core/ops/trait.Deref.html
221+
*/
222+
class DerefTrait extends Trait {
223+
pragma[nomagic]
224+
DerefTrait() { this.getCanonicalPath() = "core::ops::deref::Deref" }
225+
226+
/** Gets the `deref` function. */
227+
Function getDerefFunction() { result = this.(TraitItemNode).getAssocItem("deref") }
228+
229+
/** Gets the `Target` associated type. */
230+
pragma[nomagic]
231+
TypeAlias getTargetType() {
232+
result = this.getAssocItemList().getAnAssocItem() and
233+
result.getName().getText() = "Target"
234+
}
235+
}
236+
237+
/**
238+
* The [`Index` trait][1].
239+
*
240+
* [1]: https://doc.rust-lang.org/std/ops/trait.Index.html
241+
*/
242+
class IndexTrait extends Trait {
243+
pragma[nomagic]
244+
IndexTrait() { this.getCanonicalPath() = "core::ops::index::Index" }
245+
246+
/** Gets the `index` function. */
247+
Function getIndexFunction() { result = this.(TraitItemNode).getAssocItem("index") }
248+
249+
/** Gets the `Output` associated type. */
250+
pragma[nomagic]
251+
TypeAlias getOutputType() {
252+
result = this.getAssocItemList().getAnAssocItem() and
253+
result.getName().getText() = "Output"
254+
}
255+
}
256+
257+
/**
258+
* The [`Box` struct][1].
259+
*
260+
* [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html
261+
*/
262+
class BoxStruct extends Struct {
263+
pragma[nomagic]
264+
BoxStruct() { this.getCanonicalPath() = "alloc::boxed::Box" }
265+
}
266+
267+
/**
268+
* The [`Rc` struct][1].
269+
*
270+
* [1]: https://doc.rust-lang.org/std/rc/struct.Rc.html
271+
*/
272+
class RcStruct extends Struct {
273+
pragma[nomagic]
274+
RcStruct() { this.getCanonicalPath() = "alloc::rc::Rc" }
275+
}
276+
277+
/**
278+
* The [`Arc` struct][1].
279+
*
280+
* [1]: https://doc.rust-lang.org/std/sync/struct.Arc.html
281+
*/
282+
class ArcStruct extends Struct {
283+
pragma[nomagic]
284+
ArcStruct() { this.getCanonicalPath() = "alloc::sync::Arc" }
285+
}
286+
287+
/**
288+
* The [`Pin` struct][1].
289+
*
290+
* [1]: https://doc.rust-lang.org/std/pin/struct.Pin.html
291+
*/
292+
class PinStruct extends Struct {
293+
pragma[nomagic]
294+
PinStruct() { this.getCanonicalPath() = "core::pin::Pin" }
295+
}

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

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
786786
}
787787
}
788788

789-
final private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
789+
final class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
790790
pragma[nomagic]
791791
Path getABoundPath() {
792792
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
@@ -1317,6 +1317,12 @@ private predicate crateDependency(SourceFileItemNode file, string name, CrateIte
13171317
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) | file = c.getASourceFile())
13181318
}
13191319

1320+
pragma[nomagic]
1321+
private predicate hasDeclOrDep(SourceFileItemNode file, string name) {
1322+
declaresDirectly(file, TTypeNamespace(), name) or
1323+
crateDependency(file, name, _)
1324+
}
1325+
13201326
/**
13211327
* Holds if `file` depends on crate `dep` named `name`.
13221328
*/
@@ -1330,8 +1336,7 @@ private predicate crateDependencyEdge(SourceFileItemNode file, string name, Crat
13301336
// a given file to its crate (for example, if the file is `mod` imported inside a macro that the
13311337
// extractor is unable to expand).
13321338
name = dep.getName() and
1333-
not declaresDirectly(file, TTypeNamespace(), name) and
1334-
not crateDependency(file, name, _)
1339+
not hasDeclOrDep(file, name)
13351340
}
13361341

13371342
private predicate useTreeDeclares(UseTree tree, string name) {
@@ -1505,25 +1510,55 @@ signature predicate relevantTraitVisibleSig(Element element, Trait trait);
15051510
* at a given element.
15061511
*/
15071512
module TraitIsVisible<relevantTraitVisibleSig/2 relevantTraitVisible> {
1508-
/** Holds if the trait might be looked up in `encl`. */
1509-
private predicate traitLookup(ItemNode encl, Element element, Trait trait) {
1510-
// lookup in immediately enclosing item
1511-
relevantTraitVisible(element, trait) and
1512-
encl.getADescendant() = element
1513+
private newtype TNode =
1514+
TTrait(Trait t) { relevantTraitVisible(_, t) } or
1515+
TItemNode(ItemNode i) or
1516+
TElement(Element e) { relevantTraitVisible(e, _) }
1517+
1518+
private predicate isTrait(TNode n) { n instanceof TTrait }
1519+
1520+
private predicate step(TNode n1, TNode n2) {
1521+
exists(Trait t1, ItemNode i2 |
1522+
n1 = TTrait(t1) and
1523+
n2 = TItemNode(i2) and
1524+
t1 = i2.getASuccessor(_, _, _)
1525+
)
15131526
or
1514-
// lookup in an outer scope, but only if the trait is not declared in inner scope
1515-
exists(ItemNode mid |
1516-
traitLookup(mid, element, trait) and
1517-
not trait = mid.getASuccessor(_, _, _) and
1518-
encl = getOuterScope(mid)
1527+
exists(ItemNode i1, ItemNode i2 |
1528+
n1 = TItemNode(i1) and
1529+
n2 = TItemNode(i2) and
1530+
i1 = getOuterScope(i2)
1531+
)
1532+
or
1533+
exists(ItemNode i1, Element e2 |
1534+
n1 = TItemNode(i1) and
1535+
n2 = TElement(e2) and
1536+
i1.getADescendant() = e2
1537+
)
1538+
}
1539+
1540+
private predicate isElement(TNode n) { n instanceof TElement }
1541+
1542+
private predicate traitIsVisibleTC(TNode trait, TNode element) =
1543+
doublyBoundedFastTC(step/2, isTrait/1, isElement/1)(trait, element)
1544+
1545+
pragma[nomagic]
1546+
private predicate relevantTraitVisibleLift(TNode trait, TElement element) {
1547+
exists(Trait t, Element e |
1548+
trait = TTrait(t) and
1549+
element = TElement(e) and
1550+
relevantTraitVisible(e, t)
15191551
)
15201552
}
15211553

15221554
/** Holds if the trait `trait` is visible at `element`. */
15231555
pragma[nomagic]
15241556
predicate traitIsVisible(Element element, Trait trait) {
1525-
exists(ItemNode encl |
1526-
traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _, _)
1557+
exists(TNode t, TNode e |
1558+
traitIsVisibleTC(t, e) and
1559+
relevantTraitVisibleLift(t, e) and
1560+
t = TTrait(trait) and
1561+
e = TElement(element)
15271562
)
15281563
}
15291564
}

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

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ newtype TType =
4242
TStruct(Struct s) or
4343
TEnum(Enum e) or
4444
TTrait(Trait t) or
45+
TUnion(Union u) or
4546
TArrayType() or // todo: add size?
4647
TRefType() or // todo: add mut?
4748
TImplTraitType(ImplTraitTypeRepr impl) or
4849
TDynTraitType(Trait t) { t = any(DynTraitTypeRepr dt).getTrait() } or
4950
TSliceType() or
51+
TNeverType() or
52+
TPtrType() or
5053
TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or
5154
TTypeParamTypeParameter(TypeParam t) or
5255
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
@@ -57,7 +60,8 @@ newtype TType =
5760
} or
5861
TRefTypeParameter() or
5962
TSelfTypeParameter(Trait t) or
60-
TSliceTypeParameter()
63+
TSliceTypeParameter() or
64+
TPtrTypeParameter()
6165

6266
private predicate implTraitTypeParam(ImplTraitTypeRepr implTrait, int i, TypeParam tp) {
6367
implTrait.isInReturnPos() and
@@ -224,6 +228,31 @@ class TraitType extends Type, TTrait {
224228
override Location getLocation() { result = trait.getLocation() }
225229
}
226230

231+
/** A union type. */
232+
class UnionType extends StructOrEnumType, TUnion {
233+
private Union union;
234+
235+
UnionType() { this = TUnion(union) }
236+
237+
override ItemNode asItemNode() { result = union }
238+
239+
override StructField getStructField(string name) { result = union.getStructField(name) }
240+
241+
override TupleField getTupleField(int i) { none() }
242+
243+
override TypeParameter getPositionalTypeParameter(int i) {
244+
result = TTypeParamTypeParameter(union.getGenericParamList().getTypeParam(i))
245+
}
246+
247+
override TypeMention getTypeParameterDefault(int i) {
248+
result = union.getGenericParamList().getTypeParam(i).getDefaultType()
249+
}
250+
251+
override string toString() { result = union.getName().getText() }
252+
253+
override Location getLocation() { result = union.getLocation() }
254+
}
255+
227256
/**
228257
* An array type.
229258
*
@@ -374,6 +403,33 @@ class SliceType extends Type, TSliceType {
374403
override Location getLocation() { result instanceof EmptyLocation }
375404
}
376405

406+
class NeverType extends Type, TNeverType {
407+
override StructField getStructField(string name) { none() }
408+
409+
override TupleField getTupleField(int i) { none() }
410+
411+
override TypeParameter getPositionalTypeParameter(int i) { none() }
412+
413+
override string toString() { result = "!" }
414+
415+
override Location getLocation() { result instanceof EmptyLocation }
416+
}
417+
418+
class PtrType extends Type, TPtrType {
419+
override StructField getStructField(string name) { none() }
420+
421+
override TupleField getTupleField(int i) { none() }
422+
423+
override TypeParameter getPositionalTypeParameter(int i) {
424+
i = 0 and
425+
result = TPtrTypeParameter()
426+
}
427+
428+
override string toString() { result = "*" }
429+
430+
override Location getLocation() { result instanceof EmptyLocation }
431+
}
432+
377433
/** A type parameter. */
378434
abstract class TypeParameter extends Type {
379435
override StructField getStructField(string name) { none() }
@@ -529,6 +585,12 @@ class SliceTypeParameter extends TypeParameter, TSliceTypeParameter {
529585
override Location getLocation() { result instanceof EmptyLocation }
530586
}
531587

588+
class PtrTypeParameter extends TypeParameter, TPtrTypeParameter {
589+
override string toString() { result = "*T" }
590+
591+
override Location getLocation() { result instanceof EmptyLocation }
592+
}
593+
532594
/**
533595
* The implicit `Self` type parameter of a trait, that refers to the
534596
* implementing type of the trait.

0 commit comments

Comments
 (0)