-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: Restructure classes representing calls #20863
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
27fdd29 to
d068588
Compare
b044b33 to
f829afd
Compare
e2f85cf to
e98f41f
Compare
| private import internal.MethodCallExprImpl | ||
| import codeql.rust.elements.CallExprBase | ||
| import codeql.rust.elements.ArgList | ||
| import codeql.rust.elements.Attr |
Check warning
Code scanning / CodeQL
Redundant import Warning
codeql.rust.elements.ArgList
2559678 to
9971a0c
Compare
34f250c to
eea12e2
Compare
f4524d3 to
eef0cfa
Compare
eef0cfa to
7378fbc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors the Rust call expression class hierarchy to better distinguish between syntactic and semantic representations of calls. The main goal is to encourage query writers to use semantic classes (Call and MethodCall) instead of syntactic ones (CallExpr and MethodCallExpr).
Key Changes:
- Removed
CallExprBaseunion type and introducedArgsExpras a base class for all expressions with arguments - Restructured
CallandMethodCallhierarchy with proper inheritance relationships - Introduced
TupleStructExprandTupleVariantExprto distinguish instantiations from actual function calls - Renamed methods for clarity:
getArg()→getPositionalArgument(),getStaticTarget()→getResolvedTarget() - Moved type inference logic from public API to internal libraries
- Updated all security queries and frameworks to use the new API
Reviewed changes
Copilot reviewed 59 out of 79 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| rust/schema/annotations.py | Updated documentation for CallExpr and MethodCallExpr with deprecation notes |
| rust/ql/test/library-tests/dataflow/pointers/main.rs | Fixed test expectation - dataflow now works correctly |
| rust/ql/test/library-tests/dataflow/pointers/inline-flow.expected | Updated expected dataflow results |
| rust/ql/test/extractor-tests/macro-expansion/PrintAst.expected | Updated AST classification from CallExpr to TupleStructExpr |
| rust/ql/test/extractor-tests/generated/MethodCallExpr/* | Updated generated tests to remove getArg predicate |
| rust/ql/test/extractor-tests/generated/CallExpr/* | Updated generated tests with new example and removed getArg predicate |
| rust/ql/lib/upgrades/30a0713e5bf69c60d003e4994e5abd1c78a36826/* | Database upgrade scripts for backward compatibility |
| rust/ql/lib/rust.dbscheme | Schema changes removing @call_expr_base union and restructuring |
| rust/ql/lib/rust.qll | Updated imports to include new classes |
| rust/ql/lib/codeql/rust/security/* | Updated security queries to use new API (Call, MethodCall, getPositionalArgument) |
| rust/ql/lib/codeql/rust/internal/TypeInference.qll | Major refactoring of method resolution and type inference logic |
| rust/ql/lib/codeql/rust/elements/* | Updated generated and implementation files for new class hierarchy |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
geoffw0
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just want to say that I really appreciate the CallExprBase situation being sorted out here. I haven't fully reviewed.
| * Use the subclass `CallExpr`, where the following predicates are available. | ||
| */ | ||
| class CallExpr extends Synth::TCallExpr, CallExprBaseImpl::CallExprBase { | ||
| class CallExpr extends Synth::TCallExpr, ExprImpl::Expr { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like CallExpr may not be the best possible name for this. I appreciate that you've pointed out in the doc the possibility of using Call instead, and that CallExpr is probably Rust terminology from some layer or another - but this is still bound to lead to some amount of confusion I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CallExpr comes from the extractor, and it matches the Rust terminology.
paldepind
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! 😎 This looks really great and like a very well thought out class hierarchy 👍. Definitely a big improvement over what we have now.
I've left a bunch of comments, the vast majority of which are just minor nitpick things. I do think it would be nice to get some more mileage out of ArgumentPosition such as keeping the
Expr getArgument(ArgumentPosition pos);predicate for Call. There's a few comments that allude to that.
| CallExprMethodCall() { callIsMethodCall(this, _, methodName, selfIsRef) } | ||
|
|
||
| /** | ||
| * A method call. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * A method call. | |
| * An expression that calls a method. |
abd19d2 to
c388fd5
Compare
| // extract the algorithm name from the type of `ce` or its receiver. | ||
| exists(Type t, TypePath tp | | ||
| t = inferType([ce, ce.(MethodCallExpr).getReceiver()], tp) and | ||
| t = inferType([call, call.(MethodCall).getReceiver()], tp) and |
Check warning
Code scanning / CodeQL
Omittable 'exists' variable Warning
in this argument
03238f0 to
4a737b6
Compare
4a737b6 to
bc6d38e
Compare
paldepind
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for answering and addressing my comments!
There's a few comments that are still open (I've resolved all the others) and that I still agree with (lol). You can give it a second thought, but let's not block the PR on those in case you still disagree 😀
This PR refactors the various existing classes we have for things that represent call (or call-like) expressions. We also move logic that is only relevant to type inference inside the type inference library.
With the new structure, query writers should almost never use the QL classes representing the various syntactic call expressions such as
CallExprandMethodCallExpr, instead they should use the semantic classesCallandMethodCall, which cover all the different syntactic ways a function/method might be invoked.Before
The diagram below illustrates the class hierarchy before this PR:
graph TD; A[Expr]; B[CallExpr]; C[MethodCallExpr]; D[Operation]; E[IndexExpr]; F[Call]; G[CallExprCall]; H["CallExprMethodCall (private)"]; I["OperatorCall (private)"]; J["IndexCall (private)"]; K[CallExprBase]; A-->K; K-->B; K-->C; A-->D; A-->E; A-->F; F-->G; B-->G; F-->H; C-->H; F-->I; D-->I; F-->J; E-->J;Note in particular that the
Callclass sits next to the various AST classes, and it includes all ofCallExpr, meaning also tuple struct (and tuple enum variant) instantiations.After
graph TD; A[Expr]; B[ArgsExpr]; C[Call]; D[CallExpr]; E[MethodCallExpr]; F[Operation]; G[IndexExpr]; H["CallExprCall (private)"]; I["OperationMethodCall (private)"]; J["TupleStructExpr"]; K["TupleVariantExpr"]; L[MethodCall]; M["CallExprMethodCall (private)"]; A-->B; B-->C; B-->D; C-->L; L-->E; B-->F; L-->G; C-->H; H-->M; L-->M; D-->H; L-->I; F-->I; D-->J; D-->K;CallExprBasehas been removed, and instead we introduceArgsExpr, which covers all expressions with arguments (including tuple struct and tuple enum variant instantiations).ArgsExprhas the predicategetSyntacticArgument(int i), which gets theith syntactic argument, including receivers in method calls.Call, which is a sub class ofArgsExpr, is now a base classMethodCall, which is in turn a base class ofMethodCallExprandIndexExpr, since we know they will always target a method.OperationMethodCall, is part ofMethodCall.CallExprCall, is part ofCall, and the subset that target methods,CallExprMethodCall, is part ofMethodCall.TupleStructExprandTupleVariantExprare new classes for instantiation of tuple structs and tuple enum variants, respecetively.