Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 8 additions & 37 deletions rust/ql/lib/codeql/rust/internal/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
)
)
or
n1 = n2.(RefExpr).getExpr() and
prefix1.isEmpty() and
prefix2 = TypePath::singleton(TRefTypeParameter())
or
n1 = n2.(DerefExpr).getExpr() and
prefix1 = TypePath::singleton(TRefTypeParameter()) and
prefix2.isEmpty()
Expand Down Expand Up @@ -973,43 +977,9 @@ private Type inferFieldExprType(AstNode n, TypePath path) {
)
}

/**
* Gets the type of `n` at `path`, where `n` is either a reference expression
* `& x` or an expression `x` inside a reference expression `& x`.
*/
/** Gets the root type of the reference expression `re`. */
pragma[nomagic]
private Type inferRefExprType(Expr e, TypePath path) {
exists(RefExpr re |
e = re and
path.isEmpty() and
result = TRefType()
or
e = re and
exists(TypePath exprPath | result = inferType(re.getExpr(), exprPath) |
if exprPath.isCons(TRefTypeParameter(), _)
then
// `&x` simply means `x` when `x` already has reference type
path = exprPath
else (
path = TypePath::cons(TRefTypeParameter(), exprPath) and
not (exprPath.isEmpty() and result = TRefType())
)
)
or
e = re.getExpr() and
exists(TypePath exprPath, TypePath refPath, Type exprType |
result = inferType(re, exprPath) and
exprPath.isCons(TRefTypeParameter(), refPath) and
exprType = inferType(e)
|
if exprType = TRefType()
then
// `&x` simply means `x` when `x` already has reference type
path = exprPath
else path = refPath
)
)
}
private Type inferRefExprType(RefExpr re) { exists(re) and result = TRefType() }

pragma[nomagic]
private Type inferTryExprType(TryExpr te, TypePath path) {
Expand Down Expand Up @@ -1505,7 +1475,8 @@ private module Cached {
or
result = inferFieldExprType(n, path)
or
result = inferRefExprType(n, path)
result = inferRefExprType(n) and
path.isEmpty()
or
result = inferTryExprType(n, path)
or
Expand Down
19 changes: 19 additions & 0 deletions rust/ql/test/library-tests/type-inference/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,17 @@ mod implicit_self_borrow {
}

mod borrowed_typed {
#[derive(Debug, Copy, Clone, Default)]
struct MyFlag {
bool: bool,
}

impl MyFlag {
fn flip(&mut self) {
self.bool = !self.bool; // $ fieldof=MyFlag method=not
}
}

struct S;

impl S {
Expand All @@ -1179,6 +1190,14 @@ mod borrowed_typed {
x.f1(); // $ method=f1
x.f2(); // $ method=f2
S::f3(&x);

let n = **&&true; // $ type=n:bool

// In this example the type of `flag` must be inferred at the call to
// `flip` and flow through the borrow in the argument.
let mut flag = Default::default();
MyFlag::flip(&mut flag);
println!("{:?}", flag); // $ type=flag:MyFlag
}
}

Expand Down
Loading