Skip to content

Conversation

@hvitved
Copy link
Contributor

@hvitved hvitved commented Nov 18, 2025

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 CallExpr and MethodCallExpr, instead they should use the semantic classes Call and MethodCall, 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;
Loading

Note in particular that the Call class sits next to the various AST classes, and it includes all of CallExpr, 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;
Loading
  • CallExprBase has been removed, and instead we introduce ArgsExpr, which covers all expressions with arguments (including tuple struct and tuple enum variant instantiations). ArgsExpr has the predicate getSyntacticArgument(int i), which gets the ith syntactic argument, including receivers in method calls.
  • Call, which is a sub class of ArgsExpr, is now a base class MethodCall, which is in turn a base class of MethodCallExpr and IndexExpr, since we know they will always target a method.
  • The subset of overloadable operations, OperationMethodCall, is part of MethodCall.
  • The subset of call expressions that are not instantiations of tuple structs or tuple enum variants, CallExprCall, is part of Call, and the subset that target methods, CallExprMethodCall, is part of MethodCall.
  • TupleStructExpr and TupleVariantExpr are new classes for instantiation of tuple structs and tuple enum variants, respecetively.

@github-actions github-actions bot added the Rust Pull requests that update Rust code label Nov 18, 2025
@hvitved hvitved force-pushed the rust/call-refactor branch 2 times, most recently from 27fdd29 to d068588 Compare November 19, 2025 13:40
@hvitved hvitved force-pushed the rust/call-refactor branch 5 times, most recently from b044b33 to f829afd Compare November 20, 2025 10:37
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

Redundant import, the module is already imported inside
codeql.rust.elements.ArgList
.
@hvitved hvitved force-pushed the rust/call-refactor branch 6 times, most recently from 2559678 to 9971a0c Compare November 21, 2025 13:43
@hvitved hvitved force-pushed the rust/call-refactor branch 9 times, most recently from 34f250c to eea12e2 Compare November 24, 2025 13:04
@hvitved hvitved force-pushed the rust/call-refactor branch from eef0cfa to 7378fbc Compare December 2, 2025 09:08
@hvitved hvitved added the no-change-note-required This PR does not need a change note label Dec 2, 2025
@hvitved hvitved marked this pull request as ready for review December 2, 2025 12:16
@hvitved hvitved requested review from a team as code owners December 2, 2025 12:16
@hvitved hvitved requested review from Copilot and paldepind December 2, 2025 12:16
Copy link
Contributor

Copilot AI left a 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 CallExprBase union type and introduced ArgsExpr as a base class for all expressions with arguments
  • Restructured Call and MethodCall hierarchy with proper inheritance relationships
  • Introduced TupleStructExpr and TupleVariantExpr to 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.

Copy link
Contributor

@geoffw0 geoffw0 left a 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 {
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

@paldepind paldepind left a 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* A method call.
* An expression that calls a method.

@hvitved hvitved force-pushed the rust/call-refactor branch from abd19d2 to c388fd5 Compare December 4, 2025 08:46
// 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

This exists variable can be omitted by using a don't-care expression
in this argument
.
@hvitved hvitved force-pushed the rust/call-refactor branch 2 times, most recently from 03238f0 to 4a737b6 Compare December 4, 2025 09:15
@hvitved hvitved force-pushed the rust/call-refactor branch from 4a737b6 to bc6d38e Compare December 4, 2025 09:39
@hvitved hvitved requested a review from paldepind December 4, 2025 09:39
Copy link
Contributor

@paldepind paldepind left a 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 😀

@hvitved hvitved merged commit 8b89e15 into github:main Dec 4, 2025
20 of 21 checks passed
@hvitved hvitved deleted the rust/call-refactor branch December 4, 2025 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-change-note-required This PR does not need a change note Rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants