Skip to content

Commit 90e50b8

Browse files
committed
Rust: Rework call resolution and type inference for calls
1 parent 64336ef commit 90e50b8

File tree

12 files changed

+2314
-1527
lines changed

12 files changed

+2314
-1527
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: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
733733
}
734734
}
735735

736-
final private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
736+
final class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
737737
pragma[nomagic]
738738
Path getABoundPath() {
739739
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
@@ -1260,6 +1260,12 @@ private predicate crateDependency(SourceFileItemNode file, string name, CrateIte
12601260
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) | file = c.getASourceFile())
12611261
}
12621262

1263+
pragma[nomagic]
1264+
private predicate hasDeclOrDep(SourceFileItemNode file, string name) {
1265+
declaresDirectly(file, TTypeNamespace(), name) or
1266+
crateDependency(file, name, _)
1267+
}
1268+
12631269
/**
12641270
* Holds if `file` depends on crate `dep` named `name`.
12651271
*/
@@ -1273,8 +1279,7 @@ private predicate crateDependencyEdge(SourceFileItemNode file, string name, Crat
12731279
// a given file to its crate (for example, if the file is `mod` imported inside a macro that the
12741280
// extractor is unable to expand).
12751281
name = dep.getName() and
1276-
not declaresDirectly(file, TTypeNamespace(), name) and
1277-
not crateDependency(file, name, _)
1282+
not hasDeclOrDep(file, name)
12781283
}
12791284

12801285
private predicate useTreeDeclares(UseTree tree, string name) {
@@ -1445,24 +1450,56 @@ signature predicate relevantTraitVisibleSig(Element element, Trait trait);
14451450
* at a given element.
14461451
*/
14471452
module TraitIsVisible<relevantTraitVisibleSig/2 relevantTraitVisible> {
1448-
/** Holds if the trait might be looked up in `encl`. */
1449-
private predicate traitLookup(ItemNode encl, Element element, Trait trait) {
1450-
// lookup in immediately enclosing item
1451-
relevantTraitVisible(element, trait) and
1452-
encl.getADescendant() = element
1453+
private newtype TNode =
1454+
TTrait(Trait t) { relevantTraitVisible(_, t) } or
1455+
TItemNode(ItemNode i) or
1456+
TElement(Element e) { relevantTraitVisible(e, _) }
1457+
1458+
private predicate isTrait(TNode n) { n instanceof TTrait }
1459+
1460+
private predicate step(TNode n1, TNode n2) {
1461+
exists(Trait t1, ItemNode i2 |
1462+
n1 = TTrait(t1) and
1463+
n2 = TItemNode(i2) and
1464+
t1 = i2.getASuccessor(_, _)
1465+
)
14531466
or
1454-
// lookup in an outer scope, but only if the trait is not declared in inner scope
1455-
exists(ItemNode mid |
1456-
traitLookup(mid, element, trait) and
1457-
not trait = mid.getASuccessor(_, _) and
1458-
encl = getOuterScope(mid)
1467+
exists(ItemNode i1, ItemNode i2 |
1468+
n1 = TItemNode(i1) and
1469+
n2 = TItemNode(i2) and
1470+
i1 = getOuterScope(i2)
1471+
)
1472+
or
1473+
exists(ItemNode i1, Element e2 |
1474+
n1 = TItemNode(i1) and
1475+
n2 = TElement(e2) and
1476+
i1.getADescendant() = e2
1477+
)
1478+
}
1479+
1480+
private predicate isElement(TNode n) { n instanceof TElement }
1481+
1482+
private predicate traitIsVisibleTC(TNode trait, TNode element) =
1483+
doublyBoundedFastTC(step/2, isTrait/1, isElement/1)(trait, element)
1484+
1485+
pragma[nomagic]
1486+
private predicate relevantTraitVisibleLift(TNode trait, TElement element) {
1487+
exists(Trait t, Element e |
1488+
trait = TTrait(t) and
1489+
element = TElement(e) and
1490+
relevantTraitVisible(e, t)
14591491
)
14601492
}
14611493

14621494
/** Holds if the trait `trait` is visible at `element`. */
14631495
pragma[nomagic]
14641496
predicate traitIsVisible(Element element, Trait trait) {
1465-
exists(ItemNode encl | traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _))
1497+
exists(TNode t, TNode e |
1498+
traitIsVisibleTC(t, e) and
1499+
relevantTraitVisibleLift(t, e) and
1500+
t = TTrait(trait) and
1501+
e = TElement(element)
1502+
)
14661503
}
14671504
}
14681505

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)