Skip to content

Unified: Add flow through calls (static calls only) - #22611

Open
asgerf wants to merge 31 commits into
github:mainfrom
asgerf:unified/call-graph-static
Open

asgerf wants to merge 31 commits into
github:mainfrom
asgerf:unified/call-graph-static

Conversation

@asgerf

@asgerf asgerf commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Enables flow through calls, using a basic call graph derived from static name resolution.

Most of the work is wiring up argument/parameter positions and post-update nodes correctly. The actual call graph is fairly trivial so far.

The PR also performs a few drive-by fixes:

  • The AST mapping now expands a lone parameter name p: Int into one with an external name and a pattern p p: Int. This mirrors how JS desugars short-hand properties { p } into { p: p }. In my experience with JS, that desugaring has proven useful and has never caused any issues so I decided to do the same here.
  • There was an issue with way we use a synthetic read to model post-updates in SSA; SSA use-use chains now properly skips over the synthetic read (previously it would break the use-use chain). Ideally we should move more of this logic into SSA proper, but I wanted to avoid further scope creep.

Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll Fixed
Comment thread unified/ql/lib/codeql/unified/internal/dev/debugDataFlowGraph.ql Fixed
@asgerf
asgerf force-pushed the unified/call-graph-static branch 4 times, most recently from e9da755 to a916e8b Compare September 18, 2026 12:02
@asgerf asgerf changed the title Unified: Static calls Unified: Add flow through calls (static calls only) Sep 18, 2026
@asgerf
asgerf force-pushed the unified/call-graph-static branch from 0f11ca1 to 032b47b Compare September 19, 2026 08:11
A parameter with only one name has that name as its internal and external parameter name.
The previous commit resulted in data-flow consistency errors due to
having local flow into a post-update node (for good reason).

We now skip over the synthetic read node in use-use flow, so the use-use
flow is not seen as a mutation of a variable.
This changes the type from Expr -> AstNode and renames the column.

This should just be an arbitrary representative for the access; it
does not have to be an Expr.
Note that some of them are failing because 'self.store()' is not
resolved by static name binding.
This should be taken from the CFG node instead of the AST node
This fixes a data flow consistency error due to ArgumentNodes for
constructor patterns missing their PostUpdateNode.
@asgerf
asgerf force-pushed the unified/call-graph-static branch from 032b47b to 832dfb4 Compare September 19, 2026 08:20
@asgerf asgerf added the no-change-note-required This PR does not need a change note label Sep 21, 2026
@asgerf
asgerf requested a balanced review from Copilot September 21, 2026 08:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Call flow currently misses implicit returns, trailing closures, variadics, and high-arity calls, while diagnostics miscount excluded calls.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 3 Medium severity · 4 Low severity

Open (7)
What changed in this PR

Adds static-call interprocedural data flow to the unified analysis.

Changes:

  • Models arguments, parameters, returns, receivers, and post-call updates.
  • Adds call-graph diagnostics and quality metrics.
  • Normalizes Swift parameter labels and expands data-flow tests.
File Description
unified/​ql/​test/​library-tests/​dataflow/​test.swift Updates baseline data-flow tests.
unified/​ql/​test/​library-tests/​dataflow/​test.expected Regenerated data-flow expectations.
unified/​ql/​test/​library-tests/​dataflow/​implicit-self.swift Tests implicit receiver flow.
unified/​ql/​test/​library-tests/​dataflow/​calls.swift Adds interprocedural call tests.
unified/​ql/​test/​library-tests/​BasicTest/​test.expected Updates generated identifier expectations.
unified/​ql/​src/​diagnostic/​ExtractorInformation.ql Reports call-graph statistics.
unified/​ql/​src/​diagnostic/​CallGraph.ql Adds call-graph diagnostics.
unified/​ql/​lib/​codeql/​unified/​internal/​LocalNameBinding.qll Exposes implicit receiver variables.
unified/​ql/​lib/​codeql/​unified/​internal/​FacadeAst.qll Adds argument and parameter positions.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​ParameterPositions.qll Defines call-position matching.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​LocalSsa.qll Handles synthetic post-update reads.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowNode.qll Adds receiver and control-flow nodes.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowInstantiation.qll Connects interprocedural nodes.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowGraph.qll Adds receiver-flow edges.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowCallable.qll Models callable entities.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowCall.qll Models explicit call sites.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​CallGraph.qll Resolves static call targets.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​AllDataFlow.qll Re-exports new data-flow modules.
unified/​ql/​lib/​codeql/​unified/​internal/​AnalysisQuality.qll Adds call-graph quality metrics.
unified/​ql/​consistency-queries/​DataFlowConsistency.ql Excludes unreachable argument nodes.
unified/​extractor/​tests/​corpus/​swift/​types/​class-with-initializer.output Regenerated initializer AST output.
unified/​extractor/​tests/​corpus/​swift/​functions/​function-with-default-parameter-value.output Regenerated parameter AST output.
unified/​extractor/​src/​languages/​swift/​swift.rs Duplicates single Swift parameter names as labels.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread unified/ql/lib/codeql/unified/internal/AnalysisQuality.qll
Comment on lines +25 to +26
class ReturnNode extends Node {
ReturnNode() { none() } // TODO
ReturnNode() { this.asExpr() = any(ReturnExpr r).getValue() }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Adding a TODO for now


private newtype TParameterPosition =
TReceiverParameter() or
TPositionalParameter(int n) { n = [0 .. 20] } or

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Deliberately not implementing the accurate charpred yet. It will inevitably have to reference MaD models as possibly tuple arity and will result in time wasted on debugging if not updated at the right point in time.

Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowCall.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowCallable.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/LocalSsa.qll Outdated
asgerf and others added 2 commits September 21, 2026 10:16
Some typos and exclude constructor patterns from call graph stats

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@asgerf
asgerf marked this pull request as ready for review September 21, 2026 08:28
@asgerf
asgerf requested review from a team as code owners September 21, 2026 08:28
@asgerf
asgerf requested a review from hvitved September 21, 2026 08:28

@hvitved hvitved left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks great 💪 Minor comments only.

or
result = this.asPositional().toString()
or
result = "\"" + this.asNamed() + "\""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why the quotes?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

To avoid a potentially confusing name clash with receiver. But come to think of it, suffixing with a colon would be more aligned with MaD so I'll switch to that.

/** Gets the `CallExpr` wrapped by this dataflow call, if any. */
CallExpr asExplicitCall() { this = TExplicitCall(result) }

/** Gets a string representation of this call. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

string -> textual

predicate isBindingSite() { this instanceof NameBinding }
}

/** Gets implicitly-declared variable through which the given callable refers to its receiver. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Gets the

@hvitved

hvitved commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Did you run DCA?

@asgerf

asgerf commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

Latest DCA run should still be accurate but I'll run kick off another one.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants