Skip to content

Unified: Add data flow support for getters and setters - #22896

Open
asgerf wants to merge 37 commits into
github:mainfrom
asgerf:unified/accessors
Open

asgerf wants to merge 37 commits into
github:mainfrom
asgerf:unified/accessors

Conversation

@asgerf

@asgerf asgerf commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Adds support calls to getters and setters, called "computed properties" in Swift.

Some complications for Swift:

  • Getters and setters can be declared locally. A local getter/setter can capture variables.
  • Setters have an implicit parameter called newValue. We insert this parameter in the AST mapping.
  • Writebacks: If p refers to a value-typed computed property p.x = y results in a call to p's setter.
  • Writebacks also occur in foo(&p) where p is passed as an inout argument. Full support for inout parameters is out of scope for this PR, however, so this is only half-supported right now.
  • Writebacks also occur for calls like p.mutate() where mutate refers to a mutating func. This is effectively the same as seeing the receiver as an inout argument.

Also does some clean up in CaptureSsa

Commit-by-commit review recommended.

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.

🟡 Changes recommended

Unresolved accessor resolution, state propagation, and capture-ordering gaps can cause valid data flows to be missed.

5 open issues
What changed in this PR

Adds getter and setter modeling to Unified’s data-flow analysis, with Swift extraction support and regression fixtures.

Changes:

  • Extracts accessor return types, parameters, and property modifiers.
  • Models accessor calls, receiver flow, and captured-variable synchronization.
  • Adds local, instance, and static accessor tests and updates expected results.
File Description
unified/​ql/​test/​library-tests/​dataflow/​test.expected Updates accessor and closure-flow expectations.
unified/​ql/​test/​library-tests/​dataflow/​accessors_static.swift Adds static accessor cases.
unified/​ql/​test/​library-tests/​dataflow/​accessors_local.swift Adds local accessor and capture cases.
unified/​ql/​test/​library-tests/​dataflow/​accessors_instance.swift Adds instance accessor and receiver-flow cases.
unified/​ql/​lib/​unified.dbscheme Renames the accessor return-type relation.
unified/​ql/​lib/​codeql/​unified/​internal/​typeinference/​Type.qll Exposes the class represented by a type.
unified/​ql/​lib/​codeql/​unified/​internal/​StaticNameBinding.qll Unifies qualified and unqualified member access.
unified/​ql/​lib/​codeql/​unified/​internal/​NameBindingPlugin.qll Recognizes instance accessors.
unified/​ql/​lib/​codeql/​unified/​internal/​LocalNameBinding.qll Identifies computed local variables.
unified/​ql/​lib/​codeql/​unified/​internal/​ExprPositions.qll Uses the renamed accessor return-type API.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​Step.qll Adds call-graph-only flow steps.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​LocalSsa.qll Excludes computed locals from stored-variable tracking.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowNode.qll Extends receiver APIs and accessor control-flow positions.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowInstantiation.qll Connects getter results and setter arguments.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowGraph.qll Adds accessor receiver and callable edges.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​DataFlowCall.qll Represents implicit getter and setter calls.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​CaptureSsa.qll Revises closure alias and escape tracking.
unified/​ql/​lib/​codeql/​unified/​internal/​dataflow/​CallGraph.qll Resolves accessor call targets.
unified/​ql/​lib/​codeql/​unified/​internal/​Ast.qll Updates generated accessor return-type APIs.
unified/​ql/​consistency-queries/​DataFlowConsistency.ql Exempts setter inputs from post-update checks.
unified/​extractor/​tests/​corpus/​swift/​variables/​property-with-willset-and-didset-observers.output Records synthesized observer parameters.
unified/​extractor/​tests/​corpus/​swift/​types/​protocol-with-read-only-and-read-write-property-requirements.output Updates protocol accessor expectations.
unified/​extractor/​tests/​corpus/​swift/​types/​property-with-getter-and-setter.output Records getter return types and setter parameters.
unified/​extractor/​tests/​corpus/​swift/​types/​computed-property.output Updates computed-property return-type output.
unified/​extractor/​tests/​corpus/​swift/​types/​binding-modifier-does-not-leak-into-accessor-body.output Updates the accessor return-type field.
unified/​extractor/​src/​languages/​swift/​swift.rs Extracts accessor parameters, return types, and modifiers.
unified/​extractor/​ast_types.yml Defines the accessor return-type field.

Review effort: Balanced

Comment thread unified/ql/lib/codeql/unified/internal/dataflow/CallGraph.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/CaptureSsa.qll
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowCall.qll Outdated
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowGraph.qll
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll Outdated
asgerf and others added 26 commits October 27, 2026 14:15
Tests are split into three categories: local, static, and instance. They follow mostly the same structure.
Accessors previously had a 'type' field. Now, it has a return_type instead, which is only set for getters. For set, didSet, and willSet, we insert a synthetic newValue/oldValue parameter, which also carries the type previously stored in accessor_declaration.type.
Modifiers like 'static' did not get preserved when extracting accessors, making most of the tests fail for static getters/setters. All those tests now pass.
This does the minimal change needed to get things working, but it's not
pretty. A later commit will refactor this to have less ad-hoc logic here.
Now that all data flow nodes are in Expr, we get more noise if we don't restrict this
This was already handled in the AST mapping, but no QL test was added initially
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
If `p` is a getter/setter pair for a value type, then `p.f = x` ends with a call to p's setter with the updated value (called "writebacks" in Swift).
Writebacks are a language-specific thing so let's add a hook for it

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.

Comment thread unified/ql/lib/codeql/unified/internal/dataflow/CaptureSsa.qll Outdated
isMutatedByCallOrAssign was a synonym for hasPostUpdateAfterCallOrAssign
@asgerf
asgerf force-pushed the unified/accessors branch from 29a2bc5 to 405e322 Compare October 28, 2026 10:21
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@asgerf asgerf added the no-change-note-required This PR does not need a change note label Oct 28, 2026
UnqualifiedMemberAccess is only populated when static name binding
positively identifies the resolution target, so either the first case
catches it, and if unresolved, the second case will miss it anyway
because it won't be a MemberAccess instance.
@asgerf
asgerf marked this pull request as ready for review October 28, 2026 13:04
@asgerf
asgerf requested review from a team as code owners October 28, 2026 13:04

@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 plausible to me (lots of moving parts).

Comment thread unified/ql/test/library-tests/dataflow/test.expected Outdated
Comment thread unified/ql/lib/codeql/unified/internal/LocalNameBinding.qll
Comment thread unified/ql/lib/codeql/unified/internal/dataflow/DataFlowNode.qll

This branch has not been deployed

No deployments
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 Unified

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants